From ad46b0d34c7dc32e260f9d8ebbe4044fc71b23ae Mon Sep 17 00:00:00 2001 From: Maximilian Attems Date: Thu, 18 Feb 2010 13:22:31 +0000 Subject: [PATCH 01/71] rebase to 2.6.33-rc8 new upstream release fix orig generation * rediff various staging Kconfig and firmware patches * rt3090 is gone nuke evident stable, stable merged, sfc features and MODULE_FIRMWARE (hopefully all merged ;) patches. fix speakup patch to apply to latest staging. auffs needs newer tree and maybe we can get rid of it postsqueeze, so didn't try at all, just nuked. disable vserver again for now. merged all series file into base. TODO: still a some stray patches, but not that urgent.. svn path=/dists/trunk/linux-2.6/; revision=15185 --- debian/changelog | 6 + debian/config/defines | 2 +- ...edia-copy-images-after-building-HTML.patch | 47 - ...ia-create-links-for-included-sources.patch | 47 - ...ation-3c509-document-ethtool-support.patch | 56 - ...-flush_old_exec-setup_new_exec-split.patch | 70 - ...cksum-check-for-custom-sized-eeproms.patch | 104 - ..._task-instead-of-reset_task-and-link.patch | 181 - .../all/atl1e-remove-broken-tsov6.patch | 67 - ...lly-revert-usbnet-Set-link-down-init.patch | 36 - ...-Fix-fallout-of-generic-code-changes.patch | 59 - ...e-handle-DM910x-except-SPARC-onboard.patch | 144 - .../e1000-enhance-fragment-detection.patch | 73 - .../e1000e-enhance-fragment-detection.patch | 80 - ...n-markings-when-creating-nommu-stack.patch | 105 - ...-potential-crash-with-sys_move_pages.patch | 31 - .../modules-Skip-empty-section-notes.patch | 81 - ...x-conntrack-match-v1-ipt-save-output.patch | 175 - ...deon-fix-crtc-vblank-update-for-r600.patch | 46 - ...dd-workspace-for-GMAC-bug-workaround.patch | 38 - ...able-TX-descriptor-prefetch-watchdog.patch | 29 - ...-DMA-mapping-cleanup-on-error-in-TSO.patch | 40 - ...fc-Fix-conditions-for-MDIO-self-test.patch | 40 - ...Fix-polling-for-slow-MCDI-operations.patch | 36 - ...clude-XGXS-in-XMAC-link-status-check.patch | 121 - ...ve-PHY-software-state-initialisation.patch | 510 - ...-message-for-suspected-bad-SFP-cable.patch | 37 - ...025C-Switch-into-self-configure-mode.patch | 185 - .../all/sfc-QT2025C-Work-around-PHY-bug.patch | 97 - ...k-around-PHY-firmware-initialisation.patch | 119 - ...c-QT202x-Remove-unreliable-MMD-check.patch | 33 - ...size-buffers-for-MCDI-NVRAM-requests.patch | 98 - ...it-flush_old_exec-into-two-functions.patch | 245 - .../patches/bugfix/all/stable/2.6.32.1.patch | 1833 - .../patches/bugfix/all/stable/2.6.32.2.patch | 5447 --- .../patches/bugfix/all/stable/2.6.32.3.patch | 4878 --- .../patches/bugfix/all/stable/2.6.32.4.patch | 4651 --- .../patches/bugfix/all/stable/2.6.32.5.patch | 1021 - .../patches/bugfix/all/stable/2.6.32.6.patch | 1324 - .../patches/bugfix/all/stable/2.6.32.7.patch | 4403 --- .../patches/bugfix/all/stable/2.6.32.8.patch | 4706 --- ...a-velocity-give-rx-descriptors-later.patch | 35 - .../bugfix/arm/scsi-osd-build-fix.patch | 26 - .../bugfix/mips/drm-ttm-build-fix.patch | 25 - .../debian/arch-mips-not-embedded.patch | 13 - .../dfsg/drivers-staging-rt2860-disable.patch | 11 +- .../dfsg/drivers-staging-rt2870-disable.patch | 9 +- .../dfsg/drivers-staging-rt3090-disable.patch | 9 - .../drivers-staging-rtl8192su-disable.patch | 10 +- .../debian/dfsg/firmware-cleanup.patch | 12 +- .../dfsg/r8169-rtl8168d-1-2-disable.patch | 4 +- ...onflict-between-2.6.32.7-and-vserver.patch | 19 - .../scripts-kconfig-reportoldconfig.patch | 5 +- ...as-Add-new-driver-for-LSI-3ware-9750.patch | 2385 -- .../features/all/aufs2/aufs2-20091205.patch | 234 - .../features/all/aufs2/aufs2-20100125.patch | 2865 -- .../features/all/aufs2/aufs2-add.patch | 25017 -------------- .../features/all/aufs2/aufs2-base.patch | 81 - .../features/all/aufs2/aufs2-kbuild.patch | 35 - .../features/all/aufs2/aufs2-standalone.patch | 182 - .../features/all/aufs2/mark-as-staging.patch | 15 - .../all/ethtool-Add-reset-operation.patch | 122 - ...ceive-functions-to-return-GRO-result.patch | 242 - ...Name-the-GRO-result-enumeration-type.patch | 149 - ...-touchpads-with-4-directional-button.patch | 263 - ...functions-from-2.6.33-net-core-dev-c.patch | 64 - .../macvlan-Precise-RX-stats-accounting.patch | 183 - .../all/macvlan-cleanup-rx-statistics.patch | 134 - ...-export-macvlan-mode-through-netlink.patch | 143 - ...plement-bridge-VEPA-and-private-mode.patch | 206 - .../0001-netxen-module-firmware-hints.patch | 48 - .../0002-netx-declare-MODULE_FIRMWARE.patch | 26 - ...03-solos-pci-declare-MODULE_FIRMWARE.patch | 28 - ...4-ambassador-declare-MODULE_FIRMWARE.patch | 26 - .../0005-bnx2x-declare-MODULE_FIRMWARE.patch | 81 - .../0006-cxgb3-declare-MODULE_FIRMWARE.patch | 103 - ...007-myri10ge-declare-MODULE_FIRMWARE.patch | 29 - ...8-spider-net-declare-MODULE_FIRMWARE.patch | 26 - ...009-tms380tr-declare-MODULE_FIRMWARE.patch | 27 - ...010-pcnet-cs-declare-MODULE_FIRMWARE.patch | 32 - ...011-speedfax-declare-MODULE_FIRMWARE.patch | 26 - ...at76c50x-usb-declare-MODULE_FIRMWARE.patch | 33 - .../0013-atmel-declare-MODULE_FIRMWARE.patch | 41 - ...0014-ipw2100-declare-MODULE_FIRMWARE.patch | 32 - ...0015-ipw2200-declare-MODULE_FIRMWARE.patch | 31 - ...iwmc3200wifi-declare-MODULE_FIRMWARE.patch | 28 - ...017-libertas-declare-MODULE_FIRMWARE.patch | 74 - ...ertas_tf_usb-declare-MODULE_FIRMWARE.patch | 27 - .../0019-mwl8k-declare-MODULE_FIRMWARE.patch | 28 - ...0020-orinoco-declare-MODULE_FIRMWARE.patch | 32 - ...0021-prism54-declare-MODULE_FIRMWARE.patch | 28 - .../0022-wl12xx-declare-MODULE_FIRMWARE.patch | 17 - .../0023-zd1201-declare-MODULE_FIRMWARE.patch | 28 - ...024-zd1211rw-declare-MODULE_FIRMWARE.patch | 32 - ...e-MODULE_FIRMWARE-in-various-drivers.patch | 69 - ...e-MODULE_FIRMWARE-in-various-drivers.patch | 97 - ...de-driver-name-in-firmware-filenames.patch | 29 - .../0028-sep-declare-MODULE_FIRMWARE.patch | 26 - ...ght-firmware-declare-MODULE_FIRMWARE.patch | 25 - ...-btmrvl-sdio-declare-MODULE_FIRMWARE.patch | 24 - .../all/r8169-init-phy-return-error.patch | 72 - .../r8169-rtl8168d-1-2-request_firmware.patch | 155 - .../patches/features/all/sfc-2.6.33-rc1.patch | 23088 ------------- .../features/all/speakup/speakup-kbuild.patch | 10 +- .../features/all/vserver/bindmount-dev.patch | 41 - .../features/all/vserver/ia64-buildfix.patch | 11 - .../features/all/vserver/s390-buildfix.patch | 23 - .../features/all/vserver/vs2.3.0.36.27.patch | 28738 ---------------- ...-reasonable-bitrate-for-MCS-rates-th.patch | 147 - .../features/arm/dns323-rev-b1-poweroff.patch | 106 - .../patches/features/arm/early-printk.patch | 112 - debian/patches/series/2 | 5 - debian/patches/series/3 | 13 - debian/patches/series/3-extra | 1 - debian/patches/series/4 | 6 - debian/patches/series/4-extra | 2 - debian/patches/series/5 | 9 - debian/patches/series/6 | 39 - debian/patches/series/7 | 4 - debian/patches/series/8 | 15 - debian/patches/series/9 | 10 - debian/patches/series/base | 90 +- debian/patches/series/orig-0 | 1 - 123 files changed, 83 insertions(+), 117567 deletions(-) delete mode 100644 debian/patches/bugfix/all/DocBook-media-copy-images-after-building-HTML.patch delete mode 100644 debian/patches/bugfix/all/DocBook-media-create-links-for-included-sources.patch delete mode 100644 debian/patches/bugfix/all/Documentation-3c509-document-ethtool-support.patch delete mode 100644 debian/patches/bugfix/all/Fix-flush_old_exec-setup_new_exec-split.patch delete mode 100644 debian/patches/bugfix/all/ath5k-Fix-eeprom-checksum-check-for-custom-sized-eeproms.patch delete mode 100644 debian/patches/bugfix/all/atl1c-use-common_task-instead-of-reset_task-and-link.patch delete mode 100644 debian/patches/bugfix/all/atl1e-remove-broken-tsov6.patch delete mode 100644 debian/patches/bugfix/all/cdc_ether-Partially-revert-usbnet-Set-link-down-init.patch delete mode 100644 debian/patches/bugfix/all/clocksource-events-Fix-fallout-of-generic-code-changes.patch delete mode 100644 debian/patches/bugfix/all/dmfe-tulip-Let-dmfe-handle-DM910x-except-SPARC-onboard.patch delete mode 100644 debian/patches/bugfix/all/e1000-enhance-fragment-detection.patch delete mode 100644 debian/patches/bugfix/all/e1000e-enhance-fragment-detection.patch delete mode 100644 debian/patches/bugfix/all/fdpic-respect-pt_gnu_stack-exec-protection-markings-when-creating-nommu-stack.patch delete mode 100644 debian/patches/bugfix/all/fix-potential-crash-with-sys_move_pages.patch delete mode 100644 debian/patches/bugfix/all/modules-Skip-empty-section-notes.patch delete mode 100644 debian/patches/bugfix/all/netfilter-xtables-fix-conntrack-match-v1-ipt-save-output.patch delete mode 100644 debian/patches/bugfix/all/radeon-fix-crtc-vblank-update-for-r600.patch delete mode 100644 debian/patches/bugfix/all/sfc-Add-workspace-for-GMAC-bug-workaround.patch delete mode 100644 debian/patches/bugfix/all/sfc-Disable-TX-descriptor-prefetch-watchdog.patch delete mode 100644 debian/patches/bugfix/all/sfc-Fix-DMA-mapping-cleanup-on-error-in-TSO.patch delete mode 100644 debian/patches/bugfix/all/sfc-Fix-conditions-for-MDIO-self-test.patch delete mode 100644 debian/patches/bugfix/all/sfc-Fix-polling-for-slow-MCDI-operations.patch delete mode 100644 debian/patches/bugfix/all/sfc-Include-XGXS-in-XMAC-link-status-check.patch delete mode 100644 debian/patches/bugfix/all/sfc-Move-PHY-software-state-initialisation.patch delete mode 100644 debian/patches/bugfix/all/sfc-QT2025C-Add-error-message-for-suspected-bad-SFP-cable.patch delete mode 100644 debian/patches/bugfix/all/sfc-QT2025C-Switch-into-self-configure-mode.patch delete mode 100644 debian/patches/bugfix/all/sfc-QT2025C-Work-around-PHY-bug.patch delete mode 100644 debian/patches/bugfix/all/sfc-QT2025C-Work-around-PHY-firmware-initialisation.patch delete mode 100644 debian/patches/bugfix/all/sfc-QT202x-Remove-unreliable-MMD-check.patch delete mode 100644 debian/patches/bugfix/all/sfc-Use-fixed-size-buffers-for-MCDI-NVRAM-requests.patch delete mode 100644 debian/patches/bugfix/all/split-flush_old_exec-into-two-functions.patch delete mode 100644 debian/patches/bugfix/all/stable/2.6.32.1.patch delete mode 100644 debian/patches/bugfix/all/stable/2.6.32.2.patch delete mode 100644 debian/patches/bugfix/all/stable/2.6.32.3.patch delete mode 100644 debian/patches/bugfix/all/stable/2.6.32.4.patch delete mode 100644 debian/patches/bugfix/all/stable/2.6.32.5.patch delete mode 100644 debian/patches/bugfix/all/stable/2.6.32.6.patch delete mode 100644 debian/patches/bugfix/all/stable/2.6.32.7.patch delete mode 100644 debian/patches/bugfix/all/stable/2.6.32.8.patch delete mode 100644 debian/patches/bugfix/all/via-velocity-give-rx-descriptors-later.patch delete mode 100644 debian/patches/bugfix/arm/scsi-osd-build-fix.patch delete mode 100644 debian/patches/bugfix/mips/drm-ttm-build-fix.patch delete mode 100644 debian/patches/debian/arch-mips-not-embedded.patch delete mode 100644 debian/patches/debian/dfsg/drivers-staging-rt3090-disable.patch delete mode 100644 debian/patches/debian/sched-fix-conflict-between-2.6.32.7-and-vserver.patch delete mode 100644 debian/patches/features/all/SCSI-3w-sas-Add-new-driver-for-LSI-3ware-9750.patch delete mode 100644 debian/patches/features/all/aufs2/aufs2-20091205.patch delete mode 100644 debian/patches/features/all/aufs2/aufs2-20100125.patch delete mode 100644 debian/patches/features/all/aufs2/aufs2-add.patch delete mode 100644 debian/patches/features/all/aufs2/aufs2-base.patch delete mode 100644 debian/patches/features/all/aufs2/aufs2-kbuild.patch delete mode 100644 debian/patches/features/all/aufs2/aufs2-standalone.patch delete mode 100644 debian/patches/features/all/aufs2/mark-as-staging.patch delete mode 100644 debian/patches/features/all/ethtool-Add-reset-operation.patch delete mode 100644 debian/patches/features/all/gro-Change-all-receive-functions-to-return-GRO-result.patch delete mode 100644 debian/patches/features/all/gro-Name-the-GRO-result-enumeration-type.patch delete mode 100644 debian/patches/features/all/input-alps-add-support-for-touchpads-with-4-directional-button.patch delete mode 100644 debian/patches/features/all/macvlan-Copy-functions-from-2.6.33-net-core-dev-c.patch delete mode 100644 debian/patches/features/all/macvlan-Precise-RX-stats-accounting.patch delete mode 100644 debian/patches/features/all/macvlan-cleanup-rx-statistics.patch delete mode 100644 debian/patches/features/all/macvlan-export-macvlan-mode-through-netlink.patch delete mode 100644 debian/patches/features/all/macvlan-implement-bridge-VEPA-and-private-mode.patch delete mode 100644 debian/patches/features/all/module-firmware/0001-netxen-module-firmware-hints.patch delete mode 100644 debian/patches/features/all/module-firmware/0002-netx-declare-MODULE_FIRMWARE.patch delete mode 100644 debian/patches/features/all/module-firmware/0003-solos-pci-declare-MODULE_FIRMWARE.patch delete mode 100644 debian/patches/features/all/module-firmware/0004-ambassador-declare-MODULE_FIRMWARE.patch delete mode 100644 debian/patches/features/all/module-firmware/0005-bnx2x-declare-MODULE_FIRMWARE.patch delete mode 100644 debian/patches/features/all/module-firmware/0006-cxgb3-declare-MODULE_FIRMWARE.patch delete mode 100644 debian/patches/features/all/module-firmware/0007-myri10ge-declare-MODULE_FIRMWARE.patch delete mode 100644 debian/patches/features/all/module-firmware/0008-spider-net-declare-MODULE_FIRMWARE.patch delete mode 100644 debian/patches/features/all/module-firmware/0009-tms380tr-declare-MODULE_FIRMWARE.patch delete mode 100644 debian/patches/features/all/module-firmware/0010-pcnet-cs-declare-MODULE_FIRMWARE.patch delete mode 100644 debian/patches/features/all/module-firmware/0011-speedfax-declare-MODULE_FIRMWARE.patch delete mode 100644 debian/patches/features/all/module-firmware/0012-at76c50x-usb-declare-MODULE_FIRMWARE.patch delete mode 100644 debian/patches/features/all/module-firmware/0013-atmel-declare-MODULE_FIRMWARE.patch delete mode 100644 debian/patches/features/all/module-firmware/0014-ipw2100-declare-MODULE_FIRMWARE.patch delete mode 100644 debian/patches/features/all/module-firmware/0015-ipw2200-declare-MODULE_FIRMWARE.patch delete mode 100644 debian/patches/features/all/module-firmware/0016-iwmc3200wifi-declare-MODULE_FIRMWARE.patch delete mode 100644 debian/patches/features/all/module-firmware/0017-libertas-declare-MODULE_FIRMWARE.patch delete mode 100644 debian/patches/features/all/module-firmware/0018-libertas_tf_usb-declare-MODULE_FIRMWARE.patch delete mode 100644 debian/patches/features/all/module-firmware/0019-mwl8k-declare-MODULE_FIRMWARE.patch delete mode 100644 debian/patches/features/all/module-firmware/0020-orinoco-declare-MODULE_FIRMWARE.patch delete mode 100644 debian/patches/features/all/module-firmware/0021-prism54-declare-MODULE_FIRMWARE.patch delete mode 100644 debian/patches/features/all/module-firmware/0022-wl12xx-declare-MODULE_FIRMWARE.patch delete mode 100644 debian/patches/features/all/module-firmware/0023-zd1201-declare-MODULE_FIRMWARE.patch delete mode 100644 debian/patches/features/all/module-firmware/0024-zd1211rw-declare-MODULE_FIRMWARE.patch delete mode 100644 debian/patches/features/all/module-firmware/0025-tty-declare-MODULE_FIRMWARE-in-various-drivers.patch delete mode 100644 debian/patches/features/all/module-firmware/0026-staging-declare-MODULE_FIRMWARE-in-various-drivers.patch delete mode 100644 debian/patches/features/all/module-firmware/0027-sep-include-driver-name-in-firmware-filenames.patch delete mode 100644 debian/patches/features/all/module-firmware/0028-sep-declare-MODULE_FIRMWARE.patch delete mode 100644 debian/patches/features/all/module-firmware/0029-isight-firmware-declare-MODULE_FIRMWARE.patch delete mode 100644 debian/patches/features/all/module-firmware/0030-btmrvl-sdio-declare-MODULE_FIRMWARE.patch delete mode 100644 debian/patches/features/all/r8169-init-phy-return-error.patch delete mode 100644 debian/patches/features/all/r8169-rtl8168d-1-2-request_firmware.patch delete mode 100644 debian/patches/features/all/sfc-2.6.33-rc1.patch delete mode 100644 debian/patches/features/all/vserver/bindmount-dev.patch delete mode 100644 debian/patches/features/all/vserver/ia64-buildfix.patch delete mode 100644 debian/patches/features/all/vserver/s390-buildfix.patch delete mode 100644 debian/patches/features/all/vserver/vs2.3.0.36.27.patch delete mode 100644 debian/patches/features/all/wireless-report-reasonable-bitrate-for-MCS-rates-th.patch delete mode 100644 debian/patches/features/arm/dns323-rev-b1-poweroff.patch delete mode 100644 debian/patches/features/arm/early-printk.patch delete mode 100644 debian/patches/series/2 delete mode 100644 debian/patches/series/3 delete mode 100644 debian/patches/series/3-extra delete mode 100644 debian/patches/series/4 delete mode 100644 debian/patches/series/4-extra delete mode 100644 debian/patches/series/5 delete mode 100644 debian/patches/series/6 delete mode 100644 debian/patches/series/7 delete mode 100644 debian/patches/series/8 delete mode 100644 debian/patches/series/9 diff --git a/debian/changelog b/debian/changelog index e00ea4c15..4fc13835b 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +linux-2.6 (2.6.33~rc8-1~experimental.1) UNRELEASED; urgency=low + + * New upstream release. + + -- maximilian attems Mon, 15 Feb 2010 23:54:52 +0200 + linux-2.6 (2.6.32-9) UNRELEASED; urgency=low [ Ben Hutchings ] diff --git a/debian/config/defines b/debian/config/defines index bc3227688..7381abbc5 100644 --- a/debian/config/defines +++ b/debian/config/defines @@ -23,7 +23,7 @@ featuresets: xen [featureset-vserver_base] -enabled: true +enabled: false [featureset-xen_base] enabled: false diff --git a/debian/patches/bugfix/all/DocBook-media-copy-images-after-building-HTML.patch b/debian/patches/bugfix/all/DocBook-media-copy-images-after-building-HTML.patch deleted file mode 100644 index cdb46487c..000000000 --- a/debian/patches/bugfix/all/DocBook-media-copy-images-after-building-HTML.patch +++ /dev/null @@ -1,47 +0,0 @@ -From 8116c08e4d24087d35f7ad949f754a5207e2eef8 Mon Sep 17 00:00:00 2001 -From: Ben Hutchings -Date: Sat, 21 Nov 2009 04:01:56 +0000 -Subject: [PATCH 1/2] DocBook/media: copy images after building HTML - -The rule for %.html removes the output directory, so there is no point -in copying images before building HTML. ---- - Documentation/DocBook/Makefile | 10 +++++----- - 1 files changed, 5 insertions(+), 5 deletions(-) - -diff --git a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile -index ab8300f..22bbf7e 100644 ---- a/Documentation/DocBook/Makefile -+++ b/Documentation/DocBook/Makefile -@@ -32,7 +32,7 @@ PS_METHOD = $(prefer-db2x) - - ### - # The targets that may be used. --PHONY += xmldocs sgmldocs psdocs pdfdocs htmldocs mandocs installmandocs cleandocs media -+PHONY += xmldocs sgmldocs psdocs pdfdocs htmldocs mandocs installmandocs cleandocs - - BOOKS := $(addprefix $(obj)/,$(DOCBOOKS)) - xmldocs: $(BOOKS) -@@ -45,15 +45,15 @@ PDF := $(patsubst %.xml, %.pdf, $(BOOKS)) - pdfdocs: $(PDF) - - HTML := $(sort $(patsubst %.xml, %.html, $(BOOKS))) --htmldocs: media $(HTML) -+htmldocs: $(HTML) - $(call build_main_index) -+ $(call build_images) - - MAN := $(patsubst %.xml, %.9, $(BOOKS)) - mandocs: $(MAN) - --media: -- mkdir -p $(srctree)/Documentation/DocBook/media/ -- cp $(srctree)/Documentation/DocBook/dvb/*.png $(srctree)/Documentation/DocBook/v4l/*.gif $(srctree)/Documentation/DocBook/media/ -+build_images = mkdir -p $(objtree)/Documentation/DocBook/media/ && \ -+ cp $(srctree)/Documentation/DocBook/dvb/*.png $(srctree)/Documentation/DocBook/v4l/*.gif $(objtree)/Documentation/DocBook/media/ - - installmandocs: mandocs - mkdir -p /usr/local/man/man9/ --- -1.6.5.2 - diff --git a/debian/patches/bugfix/all/DocBook-media-create-links-for-included-sources.patch b/debian/patches/bugfix/all/DocBook-media-create-links-for-included-sources.patch deleted file mode 100644 index 9166aefaf..000000000 --- a/debian/patches/bugfix/all/DocBook-media-create-links-for-included-sources.patch +++ /dev/null @@ -1,47 +0,0 @@ -From 5c9556f8aedbaa6a419b39e4eac6045c6686e944 Mon Sep 17 00:00:00 2001 -From: Ben Hutchings -Date: Sat, 21 Nov 2009 04:06:35 +0000 -Subject: [PATCH 2/2] DocBook/media: create links for included sources - -If docs are being built in a separate directory, xmlto and xsltproc -can't find included sources. Make links back to the source directory. ---- - Documentation/DocBook/Makefile | 13 +++++++++++-- - 1 files changed, 11 insertions(+), 2 deletions(-) - -diff --git a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile -index 22bbf7e..50075df 100644 ---- a/Documentation/DocBook/Makefile -+++ b/Documentation/DocBook/Makefile -@@ -32,10 +32,10 @@ PS_METHOD = $(prefer-db2x) - - ### - # The targets that may be used. --PHONY += xmldocs sgmldocs psdocs pdfdocs htmldocs mandocs installmandocs cleandocs -+PHONY += xmldocs sgmldocs psdocs pdfdocs htmldocs mandocs installmandocs cleandocs xmldoclinks - - BOOKS := $(addprefix $(obj)/,$(DOCBOOKS)) --xmldocs: $(BOOKS) -+xmldocs: $(BOOKS) xmldoclinks - sgmldocs: xmldocs - - PS := $(patsubst %.xml, %.ps, $(BOOKS)) -@@ -55,6 +55,15 @@ mandocs: $(MAN) - build_images = mkdir -p $(objtree)/Documentation/DocBook/media/ && \ - cp $(srctree)/Documentation/DocBook/dvb/*.png $(srctree)/Documentation/DocBook/v4l/*.gif $(objtree)/Documentation/DocBook/media/ - -+xmldoclinks: -+ifneq ($(objtree),$(srctree)) -+ for dep in dvb media-entities.tmpl media-indices.tmpl v4l; do \ -+ rm -f $(objtree)/Documentation/DocBook/$$dep \ -+ && ln -s $(srctree)/Documentation/DocBook/$$dep $(objtree)/Documentation/DocBook/ \ -+ || exit; \ -+ done -+endif -+ - installmandocs: mandocs - mkdir -p /usr/local/man/man9/ - install Documentation/DocBook/man/*.9.gz /usr/local/man/man9/ --- -1.6.5.2 - diff --git a/debian/patches/bugfix/all/Documentation-3c509-document-ethtool-support.patch b/debian/patches/bugfix/all/Documentation-3c509-document-ethtool-support.patch deleted file mode 100644 index 289d96a97..000000000 --- a/debian/patches/bugfix/all/Documentation-3c509-document-ethtool-support.patch +++ /dev/null @@ -1,56 +0,0 @@ -From 9e251f34b1994d31c9553437c7896777df00a410 Mon Sep 17 00:00:00 2001 -From: Ben Hutchings -Date: Mon, 11 Jan 2010 23:28:51 +0000 -Subject: [PATCH] Documentation/3c509: document ethtool support - -3c509 was changed to support ethtool in 2002, making the 'xcvr' module -parameter obsolete in most cases. More recently 3c509 was converted -to the modern driver model and this parameter was removed. Fix the -documentation to refer to ethtool rather than the module parameter. - -Signed-off-by: Ben Hutchings ---- - Documentation/networking/3c509.txt | 12 ++++++++---- - 1 files changed, 8 insertions(+), 4 deletions(-) - -diff --git a/Documentation/networking/3c509.txt b/Documentation/networking/3c509.txt -index 0643e3b..3c45d5d 100644 ---- a/Documentation/networking/3c509.txt -+++ b/Documentation/networking/3c509.txt -@@ -48,11 +48,11 @@ for LILO parameters for doing this: - This configures the first found 3c509 card for IRQ 10, base I/O 0x310, and - transceiver type 3 (10base2). The flag "0x3c509" must be set to avoid conflicts - with other card types when overriding the I/O address. When the driver is --loaded as a module, only the IRQ and transceiver setting may be overridden. --For example, setting two cards to 10base2/IRQ10 and AUI/IRQ11 is done by using --the xcvr and irq module options: -+loaded as a module, only the IRQ may be overridden. For example, -+setting two cards to IRQ10 and IRQ11 is done by using the irq module -+option: - -- options 3c509 xcvr=3,1 irq=10,11 -+ options 3c509 irq=10,11 - - - (2) Full-duplex mode -@@ -77,6 +77,8 @@ operation. - itself full-duplex capable. This is almost certainly one of two things: a full- - duplex-capable Ethernet switch (*not* a hub), or a full-duplex-capable NIC on - another system that's connected directly to the 3c509B via a crossover cable. -+ -+Full-duplex mode can be enabled using 'ethtool'. - - /////Extremely important caution concerning full-duplex mode///// - Understand that the 3c509B's hardware's full-duplex support is much more -@@ -113,6 +115,8 @@ This insured that merely upgrading the driver from an earlier version would - never automatically enable full-duplex mode in an existing installation; - it must always be explicitly enabled via one of these code in order to be - activated. -+ -+The transceiver type can be changed using 'ethtool'. - - - (4a) Interpretation of error messages and common problems --- -1.6.5.7 - diff --git a/debian/patches/bugfix/all/Fix-flush_old_exec-setup_new_exec-split.patch b/debian/patches/bugfix/all/Fix-flush_old_exec-setup_new_exec-split.patch deleted file mode 100644 index ee7136c73..000000000 --- a/debian/patches/bugfix/all/Fix-flush_old_exec-setup_new_exec-split.patch +++ /dev/null @@ -1,70 +0,0 @@ -From 7ab02af428c2d312c0cf8fb0b01cc1eb21131a3d Mon Sep 17 00:00:00 2001 -From: Linus Torvalds -Date: Tue, 2 Feb 2010 12:37:44 -0800 -Subject: [PATCH] Fix 'flush_old_exec()/setup_new_exec()' split - -Commit 221af7f87b9 ("Split 'flush_old_exec' into two functions") split -the function at the point of no return - ie right where there were no -more error cases to check. That made sense from a technical standpoint, -but when we then also combined it with the actual personality setting -going in between flush_old_exec() and setup_new_exec(), it needs to be a -bit more careful. - -In particular, we need to make sure that we really flush the old -personality bits in the 'flush' stage, rather than later in the 'setup' -stage, since otherwise we might be flushing the _new_ personality state -that we're just setting up. - -So this moves the flags and personality flushing (and 'flush_thread()', -which is the arch-specific function that generally resets lazy FP state -etc) of the old process into flush_old_exec(), so that it doesn't affect -any state that execve() is setting up for the new process environment. - -This was reported by Michal Simek as breaking his Microblaze qemu -environment. - -Reported-and-tested-by: Michal Simek -Cc: Peter Anvin -Signed-off-by: Linus Torvalds ---- - fs/exec.c | 10 +++++----- - 1 files changed, 5 insertions(+), 5 deletions(-) - -diff --git a/fs/exec.c b/fs/exec.c -index 675c3f4..0790a10 100644 ---- a/fs/exec.c -+++ b/fs/exec.c -@@ -961,6 +961,11 @@ int flush_old_exec(struct linux_binprm * bprm) - goto out; - - bprm->mm = NULL; /* We're using it now */ -+ -+ current->flags &= ~PF_RANDOMIZE; -+ flush_thread(); -+ current->personality &= ~bprm->per_clear; -+ - return 0; - - out: -@@ -997,9 +1002,6 @@ void setup_new_exec(struct linux_binprm * bprm) - tcomm[i] = '\0'; - set_task_comm(current, tcomm); - -- current->flags &= ~PF_RANDOMIZE; -- flush_thread(); -- - /* Set the new mm task size. We have to do that late because it may - * depend on TIF_32BIT which is only updated in flush_thread() on - * some architectures like powerpc -@@ -1015,8 +1017,6 @@ void setup_new_exec(struct linux_binprm * bprm) - set_dumpable(current->mm, suid_dumpable); - } - -- current->personality &= ~bprm->per_clear; -- - /* - * Flush performance counters when crossing a - * security domain: --- -1.6.6 - diff --git a/debian/patches/bugfix/all/ath5k-Fix-eeprom-checksum-check-for-custom-sized-eeproms.patch b/debian/patches/bugfix/all/ath5k-Fix-eeprom-checksum-check-for-custom-sized-eeproms.patch deleted file mode 100644 index 7965f096f..000000000 --- a/debian/patches/bugfix/all/ath5k-Fix-eeprom-checksum-check-for-custom-sized-eeproms.patch +++ /dev/null @@ -1,104 +0,0 @@ -From 608ad4393323f00eab79828bdfda3ff1d520532e Mon Sep 17 00:00:00 2001 -From: Luis R. Rodriguez -Date: Mon, 28 Dec 2009 15:40:42 -0800 -Subject: [PATCH] ath5k: Fix eeprom checksum check for custom sized eeproms - -Commit 8bf3d79bc401ca417ccf9fc076d3295d1a71dbf5 enabled EEPROM -checksum checks to avoid bogus bug reports but failed to address -updating the code to consider devices with custom EEPROM sizes. -Devices with custom sized EEPROMs have the upper limit size stuffed -in the EEPROM. Use this as the upper limit instead of the static -default size. In case of a checksum error also provide back the -max size and whether or not this was the default size or a custom -one. If the EEPROM is busted we add a failsafe check to ensure -we don't loop forever or try to read bogus areas of hardware. - -For details refer to the bugzilla entry: - -http://bugzilla.kernel.org/show_bug.cgi?id=14874 - -Cc: stable@kernel.org -Cc: David Quan -Reported-by: Joshua Covington -Signed-off-by: Luis R. Rodriguez ---- - drivers/net/wireless/ath/ath5k/eeprom.c | 32 ++++++++++++++++++++++++++++-- - drivers/net/wireless/ath/ath5k/eeprom.h | 8 +++++++ - 2 files changed, 37 insertions(+), 3 deletions(-) - -diff --git a/drivers/net/wireless/ath/ath5k/eeprom.c b/drivers/net/wireless/ath/ath5k/eeprom.c -index 5d1c867..6a3f4da 100644 ---- a/drivers/net/wireless/ath/ath5k/eeprom.c -+++ b/drivers/net/wireless/ath/ath5k/eeprom.c -@@ -97,7 +97,7 @@ ath5k_eeprom_init_header(struct ath5k_hw *ah) - struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; - int ret; - u16 val; -- u32 cksum, offset; -+ u32 cksum, offset, eep_max = AR5K_EEPROM_INFO_MAX; - - /* - * Read values from EEPROM and store them in the capability structure -@@ -116,12 +116,38 @@ ath5k_eeprom_init_header(struct ath5k_hw *ah) - * Validate the checksum of the EEPROM date. There are some - * devices with invalid EEPROMs. - */ -- for (cksum = 0, offset = 0; offset < AR5K_EEPROM_INFO_MAX; offset++) { -+ AR5K_EEPROM_READ(AR5K_EEPROM_SIZE_UPPER, val); -+ if (val) { -+ eep_max = (val & AR5K_EEPROM_SIZE_UPPER_MASK) << -+ AR5K_EEPROM_SIZE_ENDLOC_SHIFT; -+ AR5K_EEPROM_READ(AR5K_EEPROM_SIZE_LOWER, val); -+ eep_max = (eep_max | val) - AR5K_EEPROM_INFO_BASE; -+ -+ /* -+ * Fail safe check to prevent stupid loops due -+ * to busted EEPROMs. XXX: This value is likely too -+ * big still, waiting on a better value. -+ */ -+ if (eep_max > (3 * AR5K_EEPROM_INFO_MAX)) { -+ ATH5K_ERR(ah->ah_sc, "Invalid max custom EEPROM size: " -+ "%d (0x%04x) max expected: %d (0x%04x)\n", -+ eep_max, eep_max, -+ 3 * AR5K_EEPROM_INFO_MAX, -+ 3 * AR5K_EEPROM_INFO_MAX); -+ return -EIO; -+ } -+ } -+ -+ for (cksum = 0, offset = 0; offset < eep_max; offset++) { - AR5K_EEPROM_READ(AR5K_EEPROM_INFO(offset), val); - cksum ^= val; - } - if (cksum != AR5K_EEPROM_INFO_CKSUM) { -- ATH5K_ERR(ah->ah_sc, "Invalid EEPROM checksum 0x%04x\n", cksum); -+ ATH5K_ERR(ah->ah_sc, "Invalid EEPROM " -+ "checksum: 0x%04x eep_max: 0x%04x (%s)\n", -+ cksum, eep_max, -+ eep_max == AR5K_EEPROM_INFO_MAX ? -+ "default size" : "custom size"); - return -EIO; - } - -diff --git a/drivers/net/wireless/ath/ath5k/eeprom.h b/drivers/net/wireless/ath/ath5k/eeprom.h -index 0123f35..473a483 100644 ---- a/drivers/net/wireless/ath/ath5k/eeprom.h -+++ b/drivers/net/wireless/ath/ath5k/eeprom.h -@@ -37,6 +37,14 @@ - #define AR5K_EEPROM_RFKILL_POLARITY_S 1 - - #define AR5K_EEPROM_REG_DOMAIN 0x00bf /* EEPROM regdom */ -+ -+/* FLASH(EEPROM) Defines for AR531X chips */ -+#define AR5K_EEPROM_SIZE_LOWER 0x1b /* size info -- lower */ -+#define AR5K_EEPROM_SIZE_UPPER 0x1c /* size info -- upper */ -+#define AR5K_EEPROM_SIZE_UPPER_MASK 0xfff0 -+#define AR5K_EEPROM_SIZE_UPPER_SHIFT 4 -+#define AR5K_EEPROM_SIZE_ENDLOC_SHIFT 12 -+ - #define AR5K_EEPROM_CHECKSUM 0x00c0 /* EEPROM checksum */ - #define AR5K_EEPROM_INFO_BASE 0x00c0 /* EEPROM header */ - #define AR5K_EEPROM_INFO_MAX (0x400 - AR5K_EEPROM_INFO_BASE) --- -1.6.3.3 - diff --git a/debian/patches/bugfix/all/atl1c-use-common_task-instead-of-reset_task-and-link.patch b/debian/patches/bugfix/all/atl1c-use-common_task-instead-of-reset_task-and-link.patch deleted file mode 100644 index 56d36c2bf..000000000 --- a/debian/patches/bugfix/all/atl1c-use-common_task-instead-of-reset_task-and-link.patch +++ /dev/null @@ -1,181 +0,0 @@ -From cb19054697e92a793f336380fd72c588521178ff Mon Sep 17 00:00:00 2001 -From: Jie Yang -Date: Sun, 6 Dec 2009 23:16:58 +0000 -Subject: [PATCH] atl1c:use common_task instead of reset_task and link_chg_task - -use common_task instead of reset_task and link_chg_task, so it fix "call cancel_work_sync -from the work itself". - -Signed-off-by: Jie Yang -Signed-off-by: David S. Miller ---- - drivers/net/atl1c/atl1c.h | 6 ++- - drivers/net/atl1c/atl1c_main.c | 72 ++++++++++++++++++--------------------- - 2 files changed, 37 insertions(+), 41 deletions(-) - -diff --git a/drivers/net/atl1c/atl1c.h b/drivers/net/atl1c/atl1c.h -index 7e09084..efe5435 100644 ---- a/drivers/net/atl1c/atl1c.h -+++ b/drivers/net/atl1c/atl1c.h -@@ -555,6 +555,9 @@ struct atl1c_adapter { - #define __AT_TESTING 0x0001 - #define __AT_RESETTING 0x0002 - #define __AT_DOWN 0x0003 -+ u8 work_event; -+#define ATL1C_WORK_EVENT_RESET 0x01 -+#define ATL1C_WORK_EVENT_LINK_CHANGE 0x02 - u32 msg_enable; - - bool have_msi; -@@ -566,8 +569,7 @@ struct atl1c_adapter { - spinlock_t tx_lock; - atomic_t irq_sem; - -- struct work_struct reset_task; -- struct work_struct link_chg_task; -+ struct work_struct common_task; - struct timer_list watchdog_timer; - struct timer_list phy_config_timer; - -diff --git a/drivers/net/atl1c/atl1c_main.c b/drivers/net/atl1c/atl1c_main.c -index 1098dad..666261b 100644 ---- a/drivers/net/atl1c/atl1c_main.c -+++ b/drivers/net/atl1c/atl1c_main.c -@@ -198,27 +198,12 @@ static void atl1c_phy_config(unsigned long data) - - void atl1c_reinit_locked(struct atl1c_adapter *adapter) - { -- - WARN_ON(in_interrupt()); - atl1c_down(adapter); - atl1c_up(adapter); - clear_bit(__AT_RESETTING, &adapter->flags); - } - --static void atl1c_reset_task(struct work_struct *work) --{ -- struct atl1c_adapter *adapter; -- struct net_device *netdev; -- -- adapter = container_of(work, struct atl1c_adapter, reset_task); -- netdev = adapter->netdev; -- -- netif_device_detach(netdev); -- atl1c_down(adapter); -- atl1c_up(adapter); -- netif_device_attach(netdev); --} -- - static void atl1c_check_link_status(struct atl1c_adapter *adapter) - { - struct atl1c_hw *hw = &adapter->hw; -@@ -275,18 +260,6 @@ static void atl1c_check_link_status(struct atl1c_adapter *adapter) - } - } - --/* -- * atl1c_link_chg_task - deal with link change event Out of interrupt context -- * @netdev: network interface device structure -- */ --static void atl1c_link_chg_task(struct work_struct *work) --{ -- struct atl1c_adapter *adapter; -- -- adapter = container_of(work, struct atl1c_adapter, link_chg_task); -- atl1c_check_link_status(adapter); --} -- - static void atl1c_link_chg_event(struct atl1c_adapter *adapter) - { - struct net_device *netdev = adapter->netdev; -@@ -311,20 +284,40 @@ static void atl1c_link_chg_event(struct atl1c_adapter *adapter) - adapter->link_speed = SPEED_0; - } - } -- schedule_work(&adapter->link_chg_task); -+ -+ adapter->work_event |= ATL1C_WORK_EVENT_LINK_CHANGE; -+ schedule_work(&adapter->common_task); - } - --static void atl1c_del_timer(struct atl1c_adapter *adapter) -+static void atl1c_common_task(struct work_struct *work) - { -- del_timer_sync(&adapter->phy_config_timer); -+ struct atl1c_adapter *adapter; -+ struct net_device *netdev; -+ -+ adapter = container_of(work, struct atl1c_adapter, common_task); -+ netdev = adapter->netdev; -+ -+ if (adapter->work_event & ATL1C_WORK_EVENT_RESET) { -+ netif_device_detach(netdev); -+ atl1c_down(adapter); -+ atl1c_up(adapter); -+ netif_device_attach(netdev); -+ return; -+ } -+ -+ if (adapter->work_event & ATL1C_WORK_EVENT_LINK_CHANGE) -+ atl1c_check_link_status(adapter); -+ -+ return; - } - --static void atl1c_cancel_work(struct atl1c_adapter *adapter) -+ -+static void atl1c_del_timer(struct atl1c_adapter *adapter) - { -- cancel_work_sync(&adapter->reset_task); -- cancel_work_sync(&adapter->link_chg_task); -+ del_timer_sync(&adapter->phy_config_timer); - } - -+ - /* - * atl1c_tx_timeout - Respond to a Tx Hang - * @netdev: network interface device structure -@@ -334,7 +327,8 @@ static void atl1c_tx_timeout(struct net_device *netdev) - struct atl1c_adapter *adapter = netdev_priv(netdev); - - /* Do the reset outside of interrupt context */ -- schedule_work(&adapter->reset_task); -+ adapter->work_event |= ATL1C_WORK_EVENT_RESET; -+ schedule_work(&adapter->common_task); - } - - /* -@@ -1539,7 +1533,8 @@ static irqreturn_t atl1c_intr(int irq, void *data) - /* reset MAC */ - hw->intr_mask &= ~ISR_ERROR; - AT_WRITE_REG(hw, REG_IMR, hw->intr_mask); -- schedule_work(&adapter->reset_task); -+ adapter->work_event |= ATL1C_WORK_EVENT_RESET; -+ schedule_work(&adapter->common_task); - break; - } - -@@ -2208,8 +2203,7 @@ void atl1c_down(struct atl1c_adapter *adapter) - struct net_device *netdev = adapter->netdev; - - atl1c_del_timer(adapter); -- atl1c_cancel_work(adapter); -- -+ adapter->work_event = 0; /* clear all event */ - /* signal that we're down so the interrupt handler does not - * reschedule our watchdog timer */ - set_bit(__AT_DOWN, &adapter->flags); -@@ -2609,8 +2603,8 @@ static int __devinit atl1c_probe(struct pci_dev *pdev, - adapter->hw.mac_addr[4], adapter->hw.mac_addr[5]); - - atl1c_hw_set_mac_addr(&adapter->hw); -- INIT_WORK(&adapter->reset_task, atl1c_reset_task); -- INIT_WORK(&adapter->link_chg_task, atl1c_link_chg_task); -+ INIT_WORK(&adapter->common_task, atl1c_common_task); -+ adapter->work_event = 0; - err = register_netdev(netdev); - if (err) { - dev_err(&pdev->dev, "register netdevice failed\n"); --- -1.6.5.3 - diff --git a/debian/patches/bugfix/all/atl1e-remove-broken-tsov6.patch b/debian/patches/bugfix/all/atl1e-remove-broken-tsov6.patch deleted file mode 100644 index c7710b3ca..000000000 --- a/debian/patches/bugfix/all/atl1e-remove-broken-tsov6.patch +++ /dev/null @@ -1,67 +0,0 @@ -From: Jie Yang -Date: Wed, 2 Dec 2009 11:18:34 +0800 -Subject: [PATCH net-next]atl1e:disable NETIF_F_TSO6 for hardware limit - -For hardware limit to support TSOV6, just disable this feature -Signed-off-by: Jie Yang ---- - - drivers/net/atl1e/atl1e_main.c | 36 ------------------------------------ - 1 files changed, 0 insertions(+), 36 deletions(-) - -diff --git a/drivers/net/atl1e/atl1e_main.c b/drivers/net/atl1e/atl1e_main.c -index ad17e74..08f8c09 100644 ---- a/drivers/net/atl1e/atl1e_main.c -+++ b/drivers/net/atl1e/atl1e_main.c -@@ -1664,41 +1664,6 @@ static int atl1e_tso_csum(struct atl1e_adapter *adapter, - } - return 0; - } -- -- if (offload_type & SKB_GSO_TCPV6) { -- real_len = (((unsigned char *)ipv6_hdr(skb) - skb->data) -- + ntohs(ipv6_hdr(skb)->payload_len)); -- if (real_len < skb->len) -- pskb_trim(skb, real_len); -- -- /* check payload == 0 byte ? */ -- hdr_len = (skb_transport_offset(skb) + tcp_hdrlen(skb)); -- if (unlikely(skb->len == hdr_len)) { -- /* only xsum need */ -- dev_warn(&pdev->dev, -- "IPV6 tso with zero data??\n"); -- goto check_sum; -- } else { -- tcp_hdr(skb)->check = ~csum_ipv6_magic( -- &ipv6_hdr(skb)->saddr, -- &ipv6_hdr(skb)->daddr, -- 0, IPPROTO_TCP, 0); -- tpd->word3 |= 1 << TPD_IP_VERSION_SHIFT; -- hdr_len >>= 1; -- tpd->word3 |= (hdr_len & TPD_V6_IPHLLO_MASK) << -- TPD_V6_IPHLLO_SHIFT; -- tpd->word3 |= ((hdr_len >> 3) & -- TPD_V6_IPHLHI_MASK) << -- TPD_V6_IPHLHI_SHIFT; -- tpd->word3 |= (tcp_hdrlen(skb) >> 2 & -- TPD_TCPHDRLEN_MASK) << -- TPD_TCPHDRLEN_SHIFT; -- tpd->word3 |= ((skb_shinfo(skb)->gso_size) & -- TPD_MSS_MASK) << TPD_MSS_SHIFT; -- tpd->word3 |= 1 << TPD_SEGMENT_EN_SHIFT; -- } -- } -- return 0; - } - - check_sum: -@@ -2287,7 +2252,6 @@ static int atl1e_init_netdev(struct net_device *netdev, struct pci_dev *pdev) - NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; - netdev->features |= NETIF_F_LLTX; - netdev->features |= NETIF_F_TSO; -- netdev->features |= NETIF_F_TSO6; - - return 0; - } - - diff --git a/debian/patches/bugfix/all/cdc_ether-Partially-revert-usbnet-Set-link-down-init.patch b/debian/patches/bugfix/all/cdc_ether-Partially-revert-usbnet-Set-link-down-init.patch deleted file mode 100644 index 9549d90a8..000000000 --- a/debian/patches/bugfix/all/cdc_ether-Partially-revert-usbnet-Set-link-down-init.patch +++ /dev/null @@ -1,36 +0,0 @@ -From ee3585e8db845cba146ecfd829b8c37f1447e1a7 Mon Sep 17 00:00:00 2001 -From: Ben Hutchings -Date: Thu, 28 Jan 2010 23:11:20 +0000 -Subject: [PATCH] cdc_ether: Partially revert "usbnet: Set link down initially ..." - -Commit 37e8273cd30592d3a82bcb70cbb1bdc4eaeb6b71 ("usbnet: Set link down -initially for drivers that update link state") changed the initial link -state in cdc_ether and other drivers based on the understanding that the -devices they support generate link change interrupts. However, this is -optional in the CDC Ethernet protocol, and two users have reported in - that the link state -for their devices remains down. Therefore, revert the change in -cdc_ether. - -Signed-off-by: Ben Hutchings -Tested-by: Avi Rozen ---- - drivers/net/usb/cdc_ether.c | 2 +- - 1 files changed, 1 insertions(+), 1 deletions(-) - -diff --git a/drivers/net/usb/cdc_ether.c b/drivers/net/usb/cdc_ether.c -index 21e183a..4f27f02 100644 ---- a/drivers/net/usb/cdc_ether.c -+++ b/drivers/net/usb/cdc_ether.c -@@ -419,7 +419,7 @@ static int cdc_manage_power(struct usbnet *dev, int on) - - static const struct driver_info cdc_info = { - .description = "CDC Ethernet Device", -- .flags = FLAG_ETHER | FLAG_LINK_INTR, -+ .flags = FLAG_ETHER, - // .check_connect = cdc_check_connect, - .bind = cdc_bind, - .unbind = usbnet_cdc_unbind, --- -1.6.6 - diff --git a/debian/patches/bugfix/all/clocksource-events-Fix-fallout-of-generic-code-changes.patch b/debian/patches/bugfix/all/clocksource-events-Fix-fallout-of-generic-code-changes.patch deleted file mode 100644 index 05f21c1d9..000000000 --- a/debian/patches/bugfix/all/clocksource-events-Fix-fallout-of-generic-code-changes.patch +++ /dev/null @@ -1,59 +0,0 @@ -From a362c638bdf052bf424bce7645d39b101090f6ba Mon Sep 17 00:00:00 2001 -From: Thomas Gleixner -Date: Sat, 14 Nov 2009 00:26:34 +0100 -Subject: [PATCH] clocksource/events: Fix fallout of generic code changes - -powerpc grew a new warning due to the type change of clockevent->mult. - -The architectures which use parts of the generic time keeping -infrastructure tripped over my wrong assumption that -clocksource_register is only used when GENERIC_TIME=y. - -I should have looked and also I should have known better. These -renitent Gaul villages are racking my nerves. Some serious deprecating -is due. - -Signed-off-by: Thomas Gleixner ---- - arch/powerpc/kernel/time.c | 2 +- - kernel/time/clocksource.c | 4 ++-- - 2 files changed, 3 insertions(+), 3 deletions(-) - -diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c -index 92dc844..60ceb27 100644 ---- a/arch/powerpc/kernel/time.c -+++ b/arch/powerpc/kernel/time.c -@@ -905,7 +905,7 @@ static void register_decrementer_clockevent(int cpu) - *dec = decrementer_clockevent; - dec->cpumask = cpumask_of(cpu); - -- printk(KERN_DEBUG "clockevent: %s mult[%lx] shift[%d] cpu[%d]\n", -+ printk(KERN_DEBUG "clockevent: %s mult[%x] shift[%d] cpu[%d]\n", - dec->name, dec->mult, dec->shift, cpu); - - clockevents_register_device(dec); -diff --git a/kernel/time/clocksource.c b/kernel/time/clocksource.c -index b65b242..72a2dcb 100644 ---- a/kernel/time/clocksource.c -+++ b/kernel/time/clocksource.c -@@ -466,8 +466,6 @@ void clocksource_touch_watchdog(void) - clocksource_resume_watchdog(); - } - --#ifdef CONFIG_GENERIC_TIME -- - /** - * clocksource_max_deferment - Returns max time the clocksource can be deferred - * @cs: Pointer to clocksource -@@ -509,6 +507,8 @@ static u64 clocksource_max_deferment(struct clocksource *cs) - return max_nsecs - (max_nsecs >> 5); - } - -+#ifdef CONFIG_GENERIC_TIME -+ - /** - * clocksource_select - Select the best clocksource available - * --- -1.6.6 - diff --git a/debian/patches/bugfix/all/dmfe-tulip-Let-dmfe-handle-DM910x-except-SPARC-onboard.patch b/debian/patches/bugfix/all/dmfe-tulip-Let-dmfe-handle-DM910x-except-SPARC-onboard.patch deleted file mode 100644 index 203d8a8d1..000000000 --- a/debian/patches/bugfix/all/dmfe-tulip-Let-dmfe-handle-DM910x-except-SPARC-onboard.patch +++ /dev/null @@ -1,144 +0,0 @@ -From 46d885d4ee0ee63806d8a0b43368b99c451dcbe9 Mon Sep 17 00:00:00 2001 -From: Ben Hutchings -Date: Tue, 29 Dec 2009 17:21:05 +0100 -Subject: [PATCH] dmfe/tulip: Let dmfe handle DM910x except for SPARC on-board chips - -The Davicom DM9100 and DM9102 chips are used on the motherboards of -some SPARC systems (supported by the tulip driver) and also in PCI -expansion cards (supported by the dmfe driver). There is no -difference in the PCI device ids for the two different configurations, -so these drivers both claim the device ids. However, it is possible -to distinguish the two configurations by the presence of Open Firmware -properties for them, so we do that. - -Signed-off-by: Ben Hutchings ---- - drivers/net/tulip/Kconfig | 4 ++++ - drivers/net/tulip/dmfe.c | 21 +++++++++++++++++++++ - drivers/net/tulip/tulip_core.c | 32 +++++++++++++++++++++++++------- - 3 files changed, 50 insertions(+), 7 deletions(-) - -diff --git a/drivers/net/tulip/Kconfig b/drivers/net/tulip/Kconfig -index 1cc8cf4..516713f 100644 ---- a/drivers/net/tulip/Kconfig -+++ b/drivers/net/tulip/Kconfig -@@ -101,6 +101,10 @@ config TULIP_NAPI_HW_MITIGATION - - If in doubt, say Y. - -+config TULIP_DM910X -+ def_bool y -+ depends on TULIP && SPARC -+ - config DE4X5 - tristate "Generic DECchip & DIGITAL EtherWORKS PCI/EISA" - depends on PCI || EISA -diff --git a/drivers/net/tulip/dmfe.c b/drivers/net/tulip/dmfe.c -index ad63621..6f44ebf 100644 ---- a/drivers/net/tulip/dmfe.c -+++ b/drivers/net/tulip/dmfe.c -@@ -92,6 +92,10 @@ - #include - #include - -+#ifdef CONFIG_TULIP_DM910X -+#include -+#endif -+ - - /* Board/System/Debug information/definition ---------------- */ - #define PCI_DM9132_ID 0x91321282 /* Davicom DM9132 ID */ -@@ -377,6 +381,23 @@ static int __devinit dmfe_init_one (struct pci_dev *pdev, - if (!printed_version++) - printk(version); - -+ /* -+ * SPARC on-board DM910x chips should be handled by the main -+ * tulip driver, except for early DM9100s. -+ */ -+#ifdef CONFIG_TULIP_DM910X -+ if ((ent->driver_data == PCI_DM9100_ID && pdev->revision >= 0x30) || -+ ent->driver_data == PCI_DM9102_ID) { -+ struct device_node *dp = pci_device_to_OF_node(pdev); -+ -+ if (dp && of_get_property(dp, "local-mac-address", NULL)) { -+ printk(KERN_INFO DRV_NAME -+ ": skipping on-board DM910x (use tulip)\n"); -+ return -ENODEV; -+ } -+ } -+#endif -+ - /* Init network device */ - dev = alloc_etherdev(sizeof(*db)); - if (dev == NULL) -diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c -index 0fa3140..595777d 100644 ---- a/drivers/net/tulip/tulip_core.c -+++ b/drivers/net/tulip/tulip_core.c -@@ -196,9 +196,13 @@ struct tulip_chip_table tulip_tbl[] = { - | HAS_NWAY | HAS_PCI_MWI, tulip_timer, tulip_media_task }, - - /* DM910X */ -+#ifdef CONFIG_TULIP_DM910X - { "Davicom DM9102/DM9102A", 128, 0x0001ebef, - HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM | HAS_ACPI, - tulip_timer, tulip_media_task }, -+#else -+ { NULL }, -+#endif - - /* RS7112 */ - { "Conexant LANfinity", 256, 0x0001ebef, -@@ -228,8 +232,10 @@ static struct pci_device_id tulip_pci_tbl[] = { - { 0x1259, 0xa120, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET }, - { 0x11F6, 0x9881, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMPEX9881 }, - { 0x8086, 0x0039, PCI_ANY_ID, PCI_ANY_ID, 0, 0, I21145 }, -+#ifdef CONFIG_TULIP_DM910X - { 0x1282, 0x9100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DM910X }, - { 0x1282, 0x9102, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DM910X }, -+#endif - { 0x1113, 0x1216, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET }, - { 0x1113, 0x1217, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MX98715 }, - { 0x1113, 0x9511, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET }, -@@ -1299,18 +1305,30 @@ static int __devinit tulip_init_one (struct pci_dev *pdev, - } - - /* -- * Early DM9100's need software CRC and the DMFE driver -+ * DM910x chips should be handled by the dmfe driver, except -+ * on-board chips on SPARC systems. Also, early DM9100s need -+ * software CRC which only the dmfe driver supports. - */ - -- if (pdev->vendor == 0x1282 && pdev->device == 0x9100) -- { -- /* Read Chip revision */ -- if (pdev->revision < 0x30) -- { -- printk(KERN_ERR PFX "skipping early DM9100 with Crc bug (use dmfe)\n"); -+#ifdef CONFIG_TULIP_DM910X -+ if (chip_idx == DM910X) { -+ struct device_node *dp; -+ -+ if (pdev->vendor == 0x1282 && pdev->device == 0x9100 && -+ pdev->revision < 0x30) { -+ printk(KERN_INFO PFX -+ "skipping early DM9100 with Crc bug (use dmfe)\n"); -+ return -ENODEV; -+ } -+ -+ dp = pci_device_to_OF_node(pdev); -+ if (!(dp && of_get_property(dp, "local-mac-address", NULL))) { -+ printk(KERN_INFO PFX -+ "skipping DM910x expansion card (use dmfe)\n"); - return -ENODEV; - } - } -+#endif - - /* - * Looks for early PCI chipsets where people report hangs --- -1.6.5.7 - diff --git a/debian/patches/bugfix/all/e1000-enhance-fragment-detection.patch b/debian/patches/bugfix/all/e1000-enhance-fragment-detection.patch deleted file mode 100644 index 8ac08e47b..000000000 --- a/debian/patches/bugfix/all/e1000-enhance-fragment-detection.patch +++ /dev/null @@ -1,73 +0,0 @@ -Subject: [net-2.6,1/2] e1000: enhance frame fragment detection -Date: Tue, 19 Jan 2010 14:15:38 -0000 -From: Jesse Brandeburg - -Originally From: Neil Horman -Modified by: Jesse Brandeburg - -Hey all- - A security discussion was recently given: -http://events.ccc.de/congress/2009/Fahrplan//events/3596.en.html -And a patch that I submitted awhile back was brought up. Apparently some of -their testing revealed that they were able to force a buffer fragment in e1000 -in which the trailing fragment was greater than 4 bytes. As a result the -fragment check I introduced failed to detect the fragement and a partial -invalid frame was passed up into the network stack. I've written this patch -to correct it. I'm in the process of testing it now, but it makes good -logical sense to me. Effectively it maintains a per-adapter state variable -which detects a non-EOP frame, and discards it and subsequent non-EOP frames -leading up to _and_ _including_ the next positive-EOP frame (as it is by -definition the last fragment). This should prevent any and all partial frames -from entering the network stack from e1000. - -Signed-off-by: Jesse Brandeburg -Acked-by: Neil Horman -Signed-off-by: Jeff Kirsher - ---- -drivers/net/e1000/e1000.h | 2 ++ - drivers/net/e1000/e1000_main.c | 13 +++++++++++-- - 2 files changed, 13 insertions(+), 2 deletions(-) - -diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h -index 2a567df..e8932db 100644 ---- a/drivers/net/e1000/e1000.h -+++ b/drivers/net/e1000/e1000.h -@@ -326,6 +326,8 @@ struct e1000_adapter { - /* for ioport free */ - int bars; - int need_ioport; -+ -+ bool discarding; - }; - - enum e1000_state_t { -diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c -index 7e855f9..9bc9fcd 100644 ---- a/drivers/net/e1000/e1000_main.c -+++ b/drivers/net/e1000/e1000_main.c -@@ -3850,13 +3850,22 @@ static bool e1000_clean_rx_irq(struct e1000_adapter *adapter, - - length = le16_to_cpu(rx_desc->length); - /* !EOP means multiple descriptors were used to store a single -- * packet, also make sure the frame isn't just CRC only */ -- if (unlikely(!(status & E1000_RXD_STAT_EOP) || (length <= 4))) { -+ * packet, if thats the case we need to toss it. In fact, we -+ * to toss every packet with the EOP bit clear and the next -+ * frame that _does_ have the EOP bit set, as it is by -+ * definition only a frame fragment -+ */ -+ if (unlikely(!(status & E1000_RXD_STAT_EOP))) -+ adapter->discarding = true; -+ -+ if (adapter->discarding) { - /* All receives must fit into a single buffer */ - E1000_DBG("%s: Receive packet consumed multiple" - " buffers\n", netdev->name); - /* recycle */ - buffer_info->skb = skb; -+ if (status & E1000_RXD_STAT_EOP) -+ adapter->discarding = false; - goto next_desc; - } - diff --git a/debian/patches/bugfix/all/e1000e-enhance-fragment-detection.patch b/debian/patches/bugfix/all/e1000e-enhance-fragment-detection.patch deleted file mode 100644 index 7595ffc98..000000000 --- a/debian/patches/bugfix/all/e1000e-enhance-fragment-detection.patch +++ /dev/null @@ -1,80 +0,0 @@ -Based on: - -Subject: [net-2.6,2/2] e1000e: enhance frame fragment detection -Date: Tue, 19 Jan 2010 14:15:59 -0000 -From: Jesse Brandeburg - -Originally patched by Neil Horman - -e1000e could with a jumbo frame enabled interface, and packet split disabled, -receive a packet that would overflow a single rx buffer. While in practice -very hard to craft a packet that could abuse this, it is possible. - -this is related to CVE-2009-4538 - ---- a/drivers/net/e1000e/e1000.h -+++ b/drivers/net/e1000e/e1000.h -@@ -421,6 +421,7 @@ struct e1000_info { - /* CRC Stripping defines */ - #define FLAG2_CRC_STRIPPING (1 << 0) - #define FLAG2_HAS_PHY_WAKEUP (1 << 1) -+#define FLAG2_IS_DISCARDING (1 << 2) - - #define E1000_RX_DESC_PS(R, i) \ - (&(((union e1000_rx_desc_packet_split *)((R).desc))[i])) ---- a/drivers/net/e1000e/netdev.c -+++ b/drivers/net/e1000e/netdev.c -@@ -450,14 +450,24 @@ static bool e1000_clean_rx_irq(struct e1000_adapter *adapter, - - length = le16_to_cpu(rx_desc->length); - -- /* !EOP means multiple descriptors were used to store a single -- * packet, also make sure the frame isn't just CRC only */ -- if (!(status & E1000_RXD_STAT_EOP) || (length <= 4)) { -+ /* -+ * !EOP means multiple descriptors were used to store a single -+ * packet, if that's the case we need to toss it. In fact, we -+ * need to toss every packet with the EOP bit clear and the -+ * next frame that _does_ have the EOP bit set, as it is by -+ * definition only a frame fragment -+ */ -+ if (unlikely(!(status & E1000_RXD_STAT_EOP))) -+ adapter->flags2 |= FLAG2_IS_DISCARDING; -+ -+ if (adapter->flags2 & FLAG2_IS_DISCARDING) { - /* All receives must fit into a single buffer */ - e_dbg("%s: Receive packet consumed multiple buffers\n", - netdev->name); - /* recycle */ - buffer_info->skb = skb; -+ if (status & E1000_RXD_STAT_EOP) -+ adapter->flags2 &= ~FLAG2_IS_DISCARDING; - goto next_desc; - } - -@@ -745,10 +755,16 @@ static bool e1000_clean_rx_irq_ps(struct e1000_adapter *adapter, - PCI_DMA_FROMDEVICE); - buffer_info->dma = 0; - -- if (!(staterr & E1000_RXD_STAT_EOP)) { -+ /* see !EOP comment in other rx routine */ -+ if (!(staterr & E1000_RXD_STAT_EOP)) -+ adapter->flags2 |= FLAG2_IS_DISCARDING; -+ -+ if (adapter->flags2 & FLAG2_IS_DISCARDING) { - e_dbg("%s: Packet Split buffers didn't pick up the " - "full packet\n", netdev->name); - dev_kfree_skb_irq(skb); -+ if (staterr & E1000_RXD_STAT_EOP) -+ adapter->flags2 &= ~FLAG2_IS_DISCARDING; - goto next_desc; - } - -@@ -1118,6 +1134,7 @@ static void e1000_clean_rx_ring(struct e1000_adapter *adapter) - - rx_ring->next_to_clean = 0; - rx_ring->next_to_use = 0; -+ adapter->flags2 &= ~FLAG2_IS_DISCARDING; - - writel(0, adapter->hw.hw_addr + rx_ring->head); - writel(0, adapter->hw.hw_addr + rx_ring->tail); diff --git a/debian/patches/bugfix/all/fdpic-respect-pt_gnu_stack-exec-protection-markings-when-creating-nommu-stack.patch b/debian/patches/bugfix/all/fdpic-respect-pt_gnu_stack-exec-protection-markings-when-creating-nommu-stack.patch deleted file mode 100644 index ba5e8844a..000000000 --- a/debian/patches/bugfix/all/fdpic-respect-pt_gnu_stack-exec-protection-markings-when-creating-nommu-stack.patch +++ /dev/null @@ -1,105 +0,0 @@ -From 04e4f2b18c8de1389d1e00fef0f42a8099910daf Mon Sep 17 00:00:00 2001 -From: Mike Frysinger -Date: Wed, 6 Jan 2010 17:23:17 +0000 -Subject: FDPIC: Respect PT_GNU_STACK exec protection markings when creating NOMMU stack - -From: Mike Frysinger - -commit 04e4f2b18c8de1389d1e00fef0f42a8099910daf upstream. - -The current code will load the stack size and protection markings, but -then only use the markings in the MMU code path. The NOMMU code path -always passes PROT_EXEC to the mmap() call. While this doesn't matter -to most people whilst the code is running, it will cause a pointless -icache flush when starting every FDPIC application. Typically this -icache flush will be of a region on the order of 128KB in size, or may -be the entire icache, depending on the facilities available on the CPU. - -In the case where the arch default behaviour seems to be desired -(EXSTACK_DEFAULT), we probe VM_STACK_FLAGS for VM_EXEC to determine -whether we should be setting PROT_EXEC or not. - -For arches that support an MPU (Memory Protection Unit - an MMU without -the virtual mapping capability), setting PROT_EXEC or not will make an -important difference. - -It should be noted that this change also affects the executability of -the brk region, since ELF-FDPIC has that share with the stack. However, -this is probably irrelevant as NOMMU programs aren't likely to use the -brk region, preferring instead allocation via mmap(). - -Signed-off-by: Mike Frysinger -Signed-off-by: David Howells -Signed-off-by: Linus Torvalds -Signed-off-by: Greg Kroah-Hartman - ---- - arch/blackfin/include/asm/page.h | 5 +++++ - arch/frv/include/asm/page.h | 2 -- - fs/binfmt_elf_fdpic.c | 13 +++++++++++-- - 3 files changed, 16 insertions(+), 4 deletions(-) - ---- a/arch/blackfin/include/asm/page.h -+++ b/arch/blackfin/include/asm/page.h -@@ -10,4 +10,9 @@ - #include - #define MAP_NR(addr) (((unsigned long)(addr)-PAGE_OFFSET) >> PAGE_SHIFT) - -+#define VM_DATA_DEFAULT_FLAGS \ -+ (VM_READ | VM_WRITE | \ -+ ((current->personality & READ_IMPLIES_EXEC) ? VM_EXEC : 0 ) | \ -+ VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC) -+ - #endif ---- a/arch/frv/include/asm/page.h -+++ b/arch/frv/include/asm/page.h -@@ -63,12 +63,10 @@ extern unsigned long max_pfn; - #define virt_addr_valid(kaddr) pfn_valid(__pa(kaddr) >> PAGE_SHIFT) - - --#ifdef CONFIG_MMU - #define VM_DATA_DEFAULT_FLAGS \ - (VM_READ | VM_WRITE | \ - ((current->personality & READ_IMPLIES_EXEC) ? VM_EXEC : 0 ) | \ - VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC) --#endif - - #endif /* __ASSEMBLY__ */ - ---- a/fs/binfmt_elf_fdpic.c -+++ b/fs/binfmt_elf_fdpic.c -@@ -171,6 +171,9 @@ static int load_elf_fdpic_binary(struct - #ifdef ELF_FDPIC_PLAT_INIT - unsigned long dynaddr; - #endif -+#ifndef CONFIG_MMU -+ unsigned long stack_prot; -+#endif - struct file *interpreter = NULL; /* to shut gcc up */ - char *interpreter_name = NULL; - int executable_stack; -@@ -316,6 +319,8 @@ static int load_elf_fdpic_binary(struct - * defunct, deceased, etc. after this point we have to exit via - * error_kill */ - set_personality(PER_LINUX_FDPIC); -+ if (elf_read_implies_exec(&exec_params.hdr, executable_stack)) -+ current->personality |= READ_IMPLIES_EXEC; - set_binfmt(&elf_fdpic_format); - - current->mm->start_code = 0; -@@ -377,9 +382,13 @@ static int load_elf_fdpic_binary(struct - if (stack_size < PAGE_SIZE * 2) - stack_size = PAGE_SIZE * 2; - -+ stack_prot = PROT_READ | PROT_WRITE; -+ if (executable_stack == EXSTACK_ENABLE_X || -+ (executable_stack == EXSTACK_DEFAULT && VM_STACK_FLAGS & VM_EXEC)) -+ stack_prot |= PROT_EXEC; -+ - down_write(¤t->mm->mmap_sem); -- current->mm->start_brk = do_mmap(NULL, 0, stack_size, -- PROT_READ | PROT_WRITE | PROT_EXEC, -+ current->mm->start_brk = do_mmap(NULL, 0, stack_size, stack_prot, - MAP_PRIVATE | MAP_ANONYMOUS | MAP_GROWSDOWN, - 0); - diff --git a/debian/patches/bugfix/all/fix-potential-crash-with-sys_move_pages.patch b/debian/patches/bugfix/all/fix-potential-crash-with-sys_move_pages.patch deleted file mode 100644 index 333695445..000000000 --- a/debian/patches/bugfix/all/fix-potential-crash-with-sys_move_pages.patch +++ /dev/null @@ -1,31 +0,0 @@ -commit 6f5a55f1a6c5abee15a0e878e5c74d9f1569b8b0 -Author: Linus Torvalds -Date: Fri Feb 5 16:16:50 2010 -0800 - - Fix potential crash with sys_move_pages - - We incorrectly depended on the 'node_state/node_isset()' functions - testing the node range, rather than checking it explicitly. That's not - reliable, even if it might often happen to work. So do the proper - explicit test. - - Reported-by: Marcus Meissner - Acked-and-tested-by: Brice Goglin - Acked-by: Hugh Dickins - Cc: stable@kernel.org - Signed-off-by: Linus Torvalds - -diff --git a/mm/migrate.c b/mm/migrate.c -index efddbf0..9a0db5b 100644 ---- a/mm/migrate.c -+++ b/mm/migrate.c -@@ -912,6 +912,9 @@ static int do_pages_move(struct mm_struct *mm, struct task_struct *task, - goto out_pm; - - err = -ENODEV; -+ if (node < 0 || node >= MAX_NUMNODES) -+ goto out_pm; -+ - if (!node_state(node, N_HIGH_MEMORY)) - goto out_pm; - diff --git a/debian/patches/bugfix/all/modules-Skip-empty-section-notes.patch b/debian/patches/bugfix/all/modules-Skip-empty-section-notes.patch deleted file mode 100644 index da1301cde..000000000 --- a/debian/patches/bugfix/all/modules-Skip-empty-section-notes.patch +++ /dev/null @@ -1,81 +0,0 @@ -From 34c7e88db240e008758b97368d6f07631b017c92 Mon Sep 17 00:00:00 2001 -From: Ben Hutchings -Date: Fri, 18 Dec 2009 23:03:03 +0000 -Subject: [PATCH] modules: Skip empty sections when exporting section notes - -Commit 35dead4 "modules: don't export section names of empty sections -via sysfs" changed the set of sections that have attributes, but did -not change the iteration over these attributes in add_notes_attrs(). -This can lead to add_notes_attrs() creating attributes with the wrong -names or with null name pointers. - -Introduce a sect_empty() function and use it in both add_sect_attrs() -and add_notes_attrs(). - -Reported-by: Martin Michlmayr -Signed-off-by: Ben Hutchings -Tested-by: Martin Michlmayr -Cc: stable@kernel.org ---- - kernel/module.c | 17 ++++++++++------- - 1 files changed, 10 insertions(+), 7 deletions(-) - -diff --git a/kernel/module.c b/kernel/module.c -index e96b8ed..f82386b 100644 ---- a/kernel/module.c -+++ b/kernel/module.c -@@ -1010,6 +1010,12 @@ static const struct kernel_symbol *resolve_symbol(Elf_Shdr *sechdrs, - * J. Corbet - */ - #if defined(CONFIG_KALLSYMS) && defined(CONFIG_SYSFS) -+ -+static inline bool sect_empty(const Elf_Shdr *sect) -+{ -+ return !(sect->sh_flags & SHF_ALLOC) || sect->sh_size == 0; -+} -+ - struct module_sect_attr - { - struct module_attribute mattr; -@@ -1051,8 +1057,7 @@ static void add_sect_attrs(struct module *mod, unsigned int nsect, - - /* Count loaded sections and allocate structures */ - for (i = 0; i < nsect; i++) -- if (sechdrs[i].sh_flags & SHF_ALLOC -- && sechdrs[i].sh_size) -+ if (!sect_empty(&sechdrs[i])) - nloaded++; - size[0] = ALIGN(sizeof(*sect_attrs) - + nloaded * sizeof(sect_attrs->attrs[0]), -@@ -1070,9 +1075,7 @@ static void add_sect_attrs(struct module *mod, unsigned int nsect, - sattr = §_attrs->attrs[0]; - gattr = §_attrs->grp.attrs[0]; - for (i = 0; i < nsect; i++) { -- if (! (sechdrs[i].sh_flags & SHF_ALLOC)) -- continue; -- if (!sechdrs[i].sh_size) -+ if (sect_empty(&sechdrs[i])) - continue; - sattr->address = sechdrs[i].sh_addr; - sattr->name = kstrdup(secstrings + sechdrs[i].sh_name, -@@ -1156,7 +1159,7 @@ static void add_notes_attrs(struct module *mod, unsigned int nsect, - /* Count notes sections and allocate structures. */ - notes = 0; - for (i = 0; i < nsect; i++) -- if ((sechdrs[i].sh_flags & SHF_ALLOC) && -+ if (!sect_empty(&sechdrs[i]) && - (sechdrs[i].sh_type == SHT_NOTE)) - ++notes; - -@@ -1172,7 +1175,7 @@ static void add_notes_attrs(struct module *mod, unsigned int nsect, - notes_attrs->notes = notes; - nattr = ¬es_attrs->attrs[0]; - for (loaded = i = 0; i < nsect; ++i) { -- if (!(sechdrs[i].sh_flags & SHF_ALLOC)) -+ if (sect_empty(&sechdrs[i])) - continue; - if (sechdrs[i].sh_type == SHT_NOTE) { - nattr->attr.name = mod->sect_attrs->attrs[loaded].name; --- -1.6.5.7 - diff --git a/debian/patches/bugfix/all/netfilter-xtables-fix-conntrack-match-v1-ipt-save-output.patch b/debian/patches/bugfix/all/netfilter-xtables-fix-conntrack-match-v1-ipt-save-output.patch deleted file mode 100644 index 080a72263..000000000 --- a/debian/patches/bugfix/all/netfilter-xtables-fix-conntrack-match-v1-ipt-save-output.patch +++ /dev/null @@ -1,175 +0,0 @@ -From 3a0429292daa0e1ec848bd26479f5e48b0d54a42 Mon Sep 17 00:00:00 2001 -From: Florian Westphal -Date: Mon, 23 Nov 2009 10:43:57 +0100 -Subject: [PATCH] netfilter: xtables: fix conntrack match v1 ipt-save output - -commit d6d3f08b0fd998b647a05540cedd11a067b72867 -(netfilter: xtables: conntrack match revision 2) does break the -v1 conntrack match iptables-save output in a subtle way. - -Problem is as follows: - - up = kmalloc(sizeof(*up), GFP_KERNEL); -[..] - /* - * The strategy here is to minimize the overhead of v1 matching, - * by prebuilding a v2 struct and putting the pointer into the - * v1 dataspace. - */ - memcpy(up, info, offsetof(typeof(*info), state_mask)); -[..] - *(void **)info = up; - -As the v2 struct pointer is saved in the match data space, -it clobbers the first structure member (->origsrc_addr). - -Because the _v1 match function grabs this pointer and does not actually -look at the v1 origsrc, run time functionality does not break. -But iptables -nvL (or iptables-save) cannot know that v1 origsrc_addr -has been overloaded in this way: - -$ iptables -p tcp -A OUTPUT -m conntrack --ctorigsrc 10.0.0.1 -j ACCEPT -$ iptables-save --A OUTPUT -p tcp -m conntrack --ctorigsrc 128.173.134.206 -j ACCEPT - -(128.173... is the address to the v2 match structure). - -To fix this, we take advantage of the fact that the v1 and v2 structures -are identical with exception of the last two structure members (u8 in v1, -u16 in v2). - -We extract them as early as possible and prevent the v2 matching function -from looking at those two members directly. - -Previously reported by Michel Messerschmidt via Ben Hutchings, also -see Debian Bug tracker #556587. - -Signed-off-by: Florian Westphal -Signed-off-by: Patrick McHardy ---- - net/netfilter/xt_conntrack.c | 61 +++++++++++------------------------------ - 1 files changed, 17 insertions(+), 44 deletions(-) - -diff --git a/net/netfilter/xt_conntrack.c b/net/netfilter/xt_conntrack.c -index 6dc4652..ae66305 100644 ---- a/net/netfilter/xt_conntrack.c -+++ b/net/netfilter/xt_conntrack.c -@@ -113,7 +113,8 @@ ct_proto_port_check(const struct xt_conntrack_mtinfo2 *info, - } - - static bool --conntrack_mt(const struct sk_buff *skb, const struct xt_match_param *par) -+conntrack_mt(const struct sk_buff *skb, const struct xt_match_param *par, -+ u16 state_mask, u16 status_mask) - { - const struct xt_conntrack_mtinfo2 *info = par->matchinfo; - enum ip_conntrack_info ctinfo; -@@ -136,7 +137,7 @@ conntrack_mt(const struct sk_buff *skb, const struct xt_match_param *par) - if (test_bit(IPS_DST_NAT_BIT, &ct->status)) - statebit |= XT_CONNTRACK_STATE_DNAT; - } -- if (!!(info->state_mask & statebit) ^ -+ if (!!(state_mask & statebit) ^ - !(info->invert_flags & XT_CONNTRACK_STATE)) - return false; - } -@@ -172,7 +173,7 @@ conntrack_mt(const struct sk_buff *skb, const struct xt_match_param *par) - return false; - - if ((info->match_flags & XT_CONNTRACK_STATUS) && -- (!!(info->status_mask & ct->status) ^ -+ (!!(status_mask & ct->status) ^ - !(info->invert_flags & XT_CONNTRACK_STATUS))) - return false; - -@@ -192,11 +193,17 @@ conntrack_mt(const struct sk_buff *skb, const struct xt_match_param *par) - static bool - conntrack_mt_v1(const struct sk_buff *skb, const struct xt_match_param *par) - { -- const struct xt_conntrack_mtinfo2 *const *info = par->matchinfo; -- struct xt_match_param newpar = *par; -+ const struct xt_conntrack_mtinfo1 *info = par->matchinfo; - -- newpar.matchinfo = *info; -- return conntrack_mt(skb, &newpar); -+ return conntrack_mt(skb, par, info->state_mask, info->status_mask); -+} -+ -+static bool -+conntrack_mt_v2(const struct sk_buff *skb, const struct xt_match_param *par) -+{ -+ const struct xt_conntrack_mtinfo2 *info = par->matchinfo; -+ -+ return conntrack_mt(skb, par, info->state_mask, info->status_mask); - } - - static bool conntrack_mt_check(const struct xt_mtchk_param *par) -@@ -209,45 +216,11 @@ static bool conntrack_mt_check(const struct xt_mtchk_param *par) - return true; - } - --static bool conntrack_mt_check_v1(const struct xt_mtchk_param *par) --{ -- struct xt_conntrack_mtinfo1 *info = par->matchinfo; -- struct xt_conntrack_mtinfo2 *up; -- int ret = conntrack_mt_check(par); -- -- if (ret < 0) -- return ret; -- -- up = kmalloc(sizeof(*up), GFP_KERNEL); -- if (up == NULL) { -- nf_ct_l3proto_module_put(par->family); -- return -ENOMEM; -- } -- -- /* -- * The strategy here is to minimize the overhead of v1 matching, -- * by prebuilding a v2 struct and putting the pointer into the -- * v1 dataspace. -- */ -- memcpy(up, info, offsetof(typeof(*info), state_mask)); -- up->state_mask = info->state_mask; -- up->status_mask = info->status_mask; -- *(void **)info = up; -- return true; --} -- - static void conntrack_mt_destroy(const struct xt_mtdtor_param *par) - { - nf_ct_l3proto_module_put(par->family); - } - --static void conntrack_mt_destroy_v1(const struct xt_mtdtor_param *par) --{ -- struct xt_conntrack_mtinfo2 **info = par->matchinfo; -- kfree(*info); -- conntrack_mt_destroy(par); --} -- - static struct xt_match conntrack_mt_reg[] __read_mostly = { - { - .name = "conntrack", -@@ -255,8 +228,8 @@ static struct xt_match conntrack_mt_reg[] __read_mostly = { - .family = NFPROTO_UNSPEC, - .matchsize = sizeof(struct xt_conntrack_mtinfo1), - .match = conntrack_mt_v1, -- .checkentry = conntrack_mt_check_v1, -- .destroy = conntrack_mt_destroy_v1, -+ .checkentry = conntrack_mt_check, -+ .destroy = conntrack_mt_destroy, - .me = THIS_MODULE, - }, - { -@@ -264,7 +237,7 @@ static struct xt_match conntrack_mt_reg[] __read_mostly = { - .revision = 2, - .family = NFPROTO_UNSPEC, - .matchsize = sizeof(struct xt_conntrack_mtinfo2), -- .match = conntrack_mt, -+ .match = conntrack_mt_v2, - .checkentry = conntrack_mt_check, - .destroy = conntrack_mt_destroy, - .me = THIS_MODULE, --- -1.6.5.4 - diff --git a/debian/patches/bugfix/all/radeon-fix-crtc-vblank-update-for-r600.patch b/debian/patches/bugfix/all/radeon-fix-crtc-vblank-update-for-r600.patch deleted file mode 100644 index 8a11df6c1..000000000 --- a/debian/patches/bugfix/all/radeon-fix-crtc-vblank-update-for-r600.patch +++ /dev/null @@ -1,46 +0,0 @@ -From: Dave Airlie -To: stable@kernel.org -Cc: linux-kernel@vger.kernel.org, dri-devel@lists.sf.net, Dave Airlie -Subject: [PATCH] stable - drm/radeon/kms: fix crtc vblank update for r600 -Date: Mon, 21 Dec 2009 14:33:52 +1000 - -From: Dave Airlie - -In 2.6.32.2 r600 had no IRQ support, however the patch in -500b758725314ab1b5316eb0caa5b0fa26740e6b to fix vblanks on avivo -cards, needs irqs. - -So check for an R600 card and avoid this path if so. - -This is a stable only patch for 2.6.32.2 as 2.6.33 has IRQs for r600. - -Signed-off-by: Dave Airlie ---- - drivers/gpu/drm/radeon/atombios_crtc.c | 6 ++++-- - 1 files changed, 4 insertions(+), 2 deletions(-) - -diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c -index c6777cb..19f93f2 100644 ---- a/drivers/gpu/drm/radeon/atombios_crtc.c -+++ b/drivers/gpu/drm/radeon/atombios_crtc.c -@@ -249,13 +249,15 @@ void atombios_crtc_dpms(struct drm_crtc *crtc, int mode) - if (ASIC_IS_DCE3(rdev)) - atombios_enable_crtc_memreq(crtc, 1); - atombios_blank_crtc(crtc, 0); -- drm_vblank_post_modeset(dev, radeon_crtc->crtc_id); -+ if (rdev->family < CHIP_R600) -+ drm_vblank_post_modeset(dev, radeon_crtc->crtc_id); - radeon_crtc_load_lut(crtc); - break; - case DRM_MODE_DPMS_STANDBY: - case DRM_MODE_DPMS_SUSPEND: - case DRM_MODE_DPMS_OFF: -- drm_vblank_pre_modeset(dev, radeon_crtc->crtc_id); -+ if (rdev->family < CHIP_R600) -+ drm_vblank_pre_modeset(dev, radeon_crtc->crtc_id); - atombios_blank_crtc(crtc, 1); - if (ASIC_IS_DCE3(rdev)) - atombios_enable_crtc_memreq(crtc, 0); --- -1.6.5.2 - diff --git a/debian/patches/bugfix/all/sfc-Add-workspace-for-GMAC-bug-workaround.patch b/debian/patches/bugfix/all/sfc-Add-workspace-for-GMAC-bug-workaround.patch deleted file mode 100644 index a788200b4..000000000 --- a/debian/patches/bugfix/all/sfc-Add-workspace-for-GMAC-bug-workaround.patch +++ /dev/null @@ -1,38 +0,0 @@ -From 8704a2c8e9db24157a7b08d1678bf840f2318779 Mon Sep 17 00:00:00 2001 -From: Guido Barzini -Date: Mon, 25 Jan 2010 15:49:19 -0800 -Subject: [PATCH 4/5] sfc: Add workspace for GMAC bug workaround to MCDI MAC_STATS buffer - -Due to a hardware bug in the SFC9000 family, the firmware must -transfer raw GMAC statistics to host memory before aggregating them -into the cooked (speed-independent) MAC statistics. Extend the stats -buffer to support this. - -The length of the buffer is explicit in the MAC_STATS command, so this -change is backward-compatible on both sides. - -Signed-off-by: Ben Hutchings -Signed-off-by: David S. Miller ---- - drivers/net/sfc/mcdi_pcol.h | 4 +++- - 1 files changed, 3 insertions(+), 1 deletions(-) - -diff --git a/drivers/net/sfc/mcdi_pcol.h b/drivers/net/sfc/mcdi_pcol.h -index 2a85360..73e71f4 100644 ---- a/drivers/net/sfc/mcdi_pcol.h -+++ b/drivers/net/sfc/mcdi_pcol.h -@@ -1090,8 +1090,10 @@ - #define MC_CMD_MAC_RX_LANES01_DISP_ERR 57 - #define MC_CMD_MAC_RX_LANES23_DISP_ERR 58 - #define MC_CMD_MAC_RX_MATCH_FAULT 59 -+#define MC_CMD_GMAC_DMABUF_START 64 -+#define MC_CMD_GMAC_DMABUF_END 95 - /* Insert new members here. */ --#define MC_CMD_MAC_GENERATION_END 60 -+#define MC_CMD_MAC_GENERATION_END 96 - #define MC_CMD_MAC_NSTATS (MC_CMD_MAC_GENERATION_END+1) - - /* MC_CMD_MAC_STATS: --- -1.6.6 - diff --git a/debian/patches/bugfix/all/sfc-Disable-TX-descriptor-prefetch-watchdog.patch b/debian/patches/bugfix/all/sfc-Disable-TX-descriptor-prefetch-watchdog.patch deleted file mode 100644 index a7590ed33..000000000 --- a/debian/patches/bugfix/all/sfc-Disable-TX-descriptor-prefetch-watchdog.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 286d47ba90315a871f77351f7f61b7e4a96476a9 Mon Sep 17 00:00:00 2001 -From: Ben Hutchings -Date: Wed, 23 Dec 2009 13:49:13 +0000 -Subject: [PATCH 8/8] sfc: Disable TX descriptor prefetch watchdog - -This hardware watchdog can misfire, so it does more harm than good. - -Signed-off-by: Ben Hutchings -Signed-off-by: David S. Miller ---- - drivers/net/sfc/nic.c | 2 ++ - 1 files changed, 2 insertions(+), 0 deletions(-) - -diff --git a/drivers/net/sfc/nic.c b/drivers/net/sfc/nic.c -index a577be2..db44224 100644 ---- a/drivers/net/sfc/nic.c -+++ b/drivers/net/sfc/nic.c -@@ -1576,6 +1576,8 @@ void efx_nic_init_common(struct efx_nic *efx) - EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_SOFT_EVT_EN, 1); - /* Prefetch threshold 2 => fetch when descriptor cache half empty */ - EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_PREF_THRESHOLD, 2); -+ /* Disable hardware watchdog which can misfire */ -+ EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_PREF_WD_TMR, 0x3fffff); - /* Squash TX of packets of 16 bytes or less */ - if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0) - EFX_SET_OWORD_FIELD(temp, FRF_BZ_TX_FLUSH_MIN_LEN_EN, 1); --- -1.6.5.7 - diff --git a/debian/patches/bugfix/all/sfc-Fix-DMA-mapping-cleanup-on-error-in-TSO.patch b/debian/patches/bugfix/all/sfc-Fix-DMA-mapping-cleanup-on-error-in-TSO.patch deleted file mode 100644 index b1efadedf..000000000 --- a/debian/patches/bugfix/all/sfc-Fix-DMA-mapping-cleanup-on-error-in-TSO.patch +++ /dev/null @@ -1,40 +0,0 @@ -From a7ebd27a13757248863cd61e541af7fa9e7727ee Mon Sep 17 00:00:00 2001 -From: Neil Turton -Date: Wed, 23 Dec 2009 13:47:13 +0000 -Subject: [PATCH 3/8] sfc: Fix DMA mapping cleanup in case of an error in TSO - -We need buffer->len to remain valid to work out the correct address to -be unmapped. We therefore need to clear buffer->len after the unmap -operation. - -Signed-off-by: Ben Hutchings -Signed-off-by: David S. Miller ---- - drivers/net/sfc/tx.c | 4 ++-- - 1 files changed, 2 insertions(+), 2 deletions(-) - -diff --git a/drivers/net/sfc/tx.c b/drivers/net/sfc/tx.c -index e669f94..a8b70ef 100644 ---- a/drivers/net/sfc/tx.c -+++ b/drivers/net/sfc/tx.c -@@ -821,8 +821,6 @@ static void efx_enqueue_unwind(struct efx_tx_queue *tx_queue) - EFX_TXQ_MASK]; - efx_tsoh_free(tx_queue, buffer); - EFX_BUG_ON_PARANOID(buffer->skb); -- buffer->len = 0; -- buffer->continuation = true; - if (buffer->unmap_len) { - unmap_addr = (buffer->dma_addr + buffer->len - - buffer->unmap_len); -@@ -836,6 +834,8 @@ static void efx_enqueue_unwind(struct efx_tx_queue *tx_queue) - PCI_DMA_TODEVICE); - buffer->unmap_len = 0; - } -+ buffer->len = 0; -+ buffer->continuation = true; - } - } - --- -1.6.5.7 - diff --git a/debian/patches/bugfix/all/sfc-Fix-conditions-for-MDIO-self-test.patch b/debian/patches/bugfix/all/sfc-Fix-conditions-for-MDIO-self-test.patch deleted file mode 100644 index df68f364d..000000000 --- a/debian/patches/bugfix/all/sfc-Fix-conditions-for-MDIO-self-test.patch +++ /dev/null @@ -1,40 +0,0 @@ -From f3766c26a5d00189e5c0965c66f01956d15a92d6 Mon Sep 17 00:00:00 2001 -From: Ben Hutchings -Date: Wed, 13 Jan 2010 10:59:13 +0000 -Subject: [PATCH 2/5] sfc: Fix conditions for MDIO self-test - -The MDIO self-test should not be run on boards without an MDIO PHY, -such as SFN5122F-R3 and later revisions. It should also not try to -address a specific MMD in an MDIO clause 22 PHY. Check the -mode_support field to decide which mode to use, if any. - -Signed-off-by: Ben Hutchings -Signed-off-by: David S. Miller ---- - drivers/net/sfc/selftest.c | 8 ++++++-- - 1 files changed, 6 insertions(+), 2 deletions(-) - -diff --git a/drivers/net/sfc/selftest.c b/drivers/net/sfc/selftest.c -index af39335..250c882 100644 ---- a/drivers/net/sfc/selftest.c -+++ b/drivers/net/sfc/selftest.c -@@ -79,10 +79,14 @@ struct efx_loopback_state { - static int efx_test_mdio(struct efx_nic *efx, struct efx_self_tests *tests) - { - int rc = 0; -- int devad = __ffs(efx->mdio.mmds); -+ int devad; - u16 physid1, physid2; - -- if (efx->phy_type == PHY_TYPE_NONE) -+ if (efx->mdio.mode_support & MDIO_SUPPORTS_C45) -+ devad = __ffs(efx->mdio.mmds); -+ else if (efx->mdio.mode_support & MDIO_SUPPORTS_C22) -+ devad = MDIO_DEVAD_NONE; -+ else - return 0; - - mutex_lock(&efx->mac_lock); --- -1.6.6 - diff --git a/debian/patches/bugfix/all/sfc-Fix-polling-for-slow-MCDI-operations.patch b/debian/patches/bugfix/all/sfc-Fix-polling-for-slow-MCDI-operations.patch deleted file mode 100644 index d962c049d..000000000 --- a/debian/patches/bugfix/all/sfc-Fix-polling-for-slow-MCDI-operations.patch +++ /dev/null @@ -1,36 +0,0 @@ -From 55029c1d65158aea9672c5dfadb43a57f23e3100 Mon Sep 17 00:00:00 2001 -From: Ben Hutchings -Date: Wed, 13 Jan 2010 04:34:25 +0000 -Subject: [PATCH 1/5] sfc: Fix polling for slow MCDI operations - -When the interface is down and we are using polled mode for MCDI -operations, we busy-wait for completion for approximately 1 jiffy -using udelay() and then back off to schedule(). But the completion -will not wake the task, since we are using polled mode! We must use -schedule_timeout_uninterruptible() instead. - -Signed-off-by: Ben Hutchings -Signed-off-by: David S. Miller ---- - drivers/net/sfc/mcdi.c | 5 +++-- - 1 files changed, 3 insertions(+), 2 deletions(-) - -diff --git a/drivers/net/sfc/mcdi.c b/drivers/net/sfc/mcdi.c -index 683353b..0d4eba7 100644 ---- a/drivers/net/sfc/mcdi.c -+++ b/drivers/net/sfc/mcdi.c -@@ -142,8 +142,9 @@ static int efx_mcdi_poll(struct efx_nic *efx) - if (spins != 0) { - --spins; - udelay(1); -- } else -- schedule(); -+ } else { -+ schedule_timeout_uninterruptible(1); -+ } - - time = get_seconds(); - --- -1.6.6 - diff --git a/debian/patches/bugfix/all/sfc-Include-XGXS-in-XMAC-link-status-check.patch b/debian/patches/bugfix/all/sfc-Include-XGXS-in-XMAC-link-status-check.patch deleted file mode 100644 index e3a1e00c6..000000000 --- a/debian/patches/bugfix/all/sfc-Include-XGXS-in-XMAC-link-status-check.patch +++ /dev/null @@ -1,121 +0,0 @@ -From a355020af415947c7dee7e00a91360d11b6a9b47 Mon Sep 17 00:00:00 2001 -From: Ben Hutchings -Date: Wed, 23 Dec 2009 13:46:47 +0000 -Subject: [PATCH 2/8] sfc: Include XGXS in XMAC link status check except in XGMII loopback - -The XGXS block may not get a link immediately in XGXS or XAUI loopback -modes, so we still need to check it. Split falcon_xaui_link_ok() into -falcon_xgxs_link_ok(), which checks only the Falcon XGXS block, and -falcon_xmac_link_ok(), which checks one or both sides of the link as -appropriate. Also rename falcon_check_xaui_link() to -falcon_xmac_link_ok_retry(). - -Signed-off-by: Ben Hutchings -Signed-off-by: David S. Miller ---- - drivers/net/sfc/falcon_xmac.c | 38 ++++++++++++++++++++++---------------- - 1 files changed, 22 insertions(+), 16 deletions(-) - -diff --git a/drivers/net/sfc/falcon_xmac.c b/drivers/net/sfc/falcon_xmac.c -index 3da933f..8ccab2c 100644 ---- a/drivers/net/sfc/falcon_xmac.c -+++ b/drivers/net/sfc/falcon_xmac.c -@@ -111,16 +111,12 @@ static void falcon_mask_status_intr(struct efx_nic *efx, bool enable) - efx_writeo(efx, ®, FR_AB_XM_MGT_INT_MASK); - } - --/* Get status of XAUI link */ --static bool falcon_xaui_link_ok(struct efx_nic *efx) -+static bool falcon_xgxs_link_ok(struct efx_nic *efx) - { - efx_oword_t reg; - bool align_done, link_ok = false; - int sync_status; - -- if (LOOPBACK_INTERNAL(efx)) -- return true; -- - /* Read link status */ - efx_reado(efx, ®, FR_AB_XX_CORE_STAT); - -@@ -135,14 +131,24 @@ static bool falcon_xaui_link_ok(struct efx_nic *efx) - EFX_SET_OWORD_FIELD(reg, FRF_AB_XX_DISPERR, FFE_AB_XX_STAT_ALL_LANES); - efx_writeo(efx, ®, FR_AB_XX_CORE_STAT); - -- /* If the link is up, then check the phy side of the xaui link */ -- if (efx->link_state.up && link_ok) -- if (efx->mdio.mmds & (1 << MDIO_MMD_PHYXS)) -- link_ok = efx_mdio_phyxgxs_lane_sync(efx); -- - return link_ok; - } - -+static bool falcon_xmac_link_ok(struct efx_nic *efx) -+{ -+ /* -+ * Check MAC's XGXS link status except when using XGMII loopback -+ * which bypasses the XGXS block. -+ * If possible, check PHY's XGXS link status except when using -+ * MAC loopback. -+ */ -+ return (efx->loopback_mode == LOOPBACK_XGMII || -+ falcon_xgxs_link_ok(efx)) && -+ (!(efx->mdio.mmds & (1 << MDIO_MMD_PHYXS)) || -+ LOOPBACK_INTERNAL(efx) || -+ efx_mdio_phyxgxs_lane_sync(efx)); -+} -+ - void falcon_reconfigure_xmac_core(struct efx_nic *efx) - { - unsigned int max_frame_len; -@@ -245,9 +251,9 @@ static void falcon_reconfigure_xgxs_core(struct efx_nic *efx) - - - /* Try to bring up the Falcon side of the Falcon-Phy XAUI link */ --static bool falcon_check_xaui_link_up(struct efx_nic *efx, int tries) -+static bool falcon_xmac_link_ok_retry(struct efx_nic *efx, int tries) - { -- bool mac_up = falcon_xaui_link_ok(efx); -+ bool mac_up = falcon_xmac_link_ok(efx); - - if (LOOPBACK_MASK(efx) & LOOPBACKS_EXTERNAL(efx) & LOOPBACKS_WS || - efx_phy_mode_disabled(efx->phy_mode)) -@@ -261,7 +267,7 @@ static bool falcon_check_xaui_link_up(struct efx_nic *efx, int tries) - falcon_reset_xaui(efx); - udelay(200); - -- mac_up = falcon_xaui_link_ok(efx); -+ mac_up = falcon_xmac_link_ok(efx); - --tries; - } - -@@ -272,7 +278,7 @@ static bool falcon_check_xaui_link_up(struct efx_nic *efx, int tries) - - static bool falcon_xmac_check_fault(struct efx_nic *efx) - { -- return !falcon_check_xaui_link_up(efx, 5); -+ return !falcon_xmac_link_ok_retry(efx, 5); - } - - static int falcon_reconfigure_xmac(struct efx_nic *efx) -@@ -284,7 +290,7 @@ static int falcon_reconfigure_xmac(struct efx_nic *efx) - - falcon_reconfigure_mac_wrapper(efx); - -- efx->xmac_poll_required = !falcon_check_xaui_link_up(efx, 5); -+ efx->xmac_poll_required = !falcon_xmac_link_ok_retry(efx, 5); - falcon_mask_status_intr(efx, true); - - return 0; -@@ -357,7 +363,7 @@ void falcon_poll_xmac(struct efx_nic *efx) - return; - - falcon_mask_status_intr(efx, false); -- efx->xmac_poll_required = !falcon_check_xaui_link_up(efx, 1); -+ efx->xmac_poll_required = !falcon_xmac_link_ok_retry(efx, 1); - falcon_mask_status_intr(efx, true); - } - --- -1.6.5.7 - diff --git a/debian/patches/bugfix/all/sfc-Move-PHY-software-state-initialisation.patch b/debian/patches/bugfix/all/sfc-Move-PHY-software-state-initialisation.patch deleted file mode 100644 index 86dc127ae..000000000 --- a/debian/patches/bugfix/all/sfc-Move-PHY-software-state-initialisation.patch +++ /dev/null @@ -1,510 +0,0 @@ -From ff3b00a0fcaab89ff885e9f0f4ad83c4ced788f4 Mon Sep 17 00:00:00 2001 -From: Steve Hodgson -Date: Wed, 23 Dec 2009 13:46:36 +0000 -Subject: [PATCH 1/8] sfc: Move PHY software state initialisation from init() into probe() - -This prevents efx->link_advertising from being blatted during -a reset. - -The phy_short_reach sysfs node is now destroyed later in the -port shutdown process, so check for STATE_RUNNING after -acquiring the rtnl_lock (just like in set_phy_flash_cfg). - -Signed-off-by: Ben Hutchings -Signed-off-by: David S. Miller ---- - drivers/net/sfc/efx.c | 6 +- - drivers/net/sfc/falcon.c | 1 + - drivers/net/sfc/mcdi_phy.c | 93 +++++++++++------------------ - drivers/net/sfc/net_driver.h | 1 + - drivers/net/sfc/qt202x_phy.c | 20 +++--- - drivers/net/sfc/siena.c | 1 + - drivers/net/sfc/tenxpress.c | 138 +++++++++++++++++++++++------------------ - 7 files changed, 129 insertions(+), 131 deletions(-) - -diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c -index f983e3b..103e8b0 100644 ---- a/drivers/net/sfc/efx.c -+++ b/drivers/net/sfc/efx.c -@@ -741,14 +741,14 @@ static int efx_probe_port(struct efx_nic *efx) - - EFX_LOG(efx, "create port\n"); - -+ if (phy_flash_cfg) -+ efx->phy_mode = PHY_MODE_SPECIAL; -+ - /* Connect up MAC/PHY operations table */ - rc = efx->type->probe_port(efx); - if (rc) - goto err; - -- if (phy_flash_cfg) -- efx->phy_mode = PHY_MODE_SPECIAL; -- - /* Sanity check MAC address */ - if (is_valid_ether_addr(efx->mac_address)) { - memcpy(efx->net_dev->dev_addr, efx->mac_address, ETH_ALEN); -diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c -index 17afcd2..9d009c4 100644 ---- a/drivers/net/sfc/falcon.c -+++ b/drivers/net/sfc/falcon.c -@@ -925,6 +925,7 @@ static int falcon_probe_port(struct efx_nic *efx) - - static void falcon_remove_port(struct efx_nic *efx) - { -+ efx->phy_op->remove(efx); - efx_nic_free_buffer(efx, &efx->stats_buffer); - } - -diff --git a/drivers/net/sfc/mcdi_phy.c b/drivers/net/sfc/mcdi_phy.c -index 0e1bcc5..eb694af 100644 ---- a/drivers/net/sfc/mcdi_phy.c -+++ b/drivers/net/sfc/mcdi_phy.c -@@ -304,31 +304,47 @@ static u32 mcdi_to_ethtool_media(u32 media) - - static int efx_mcdi_phy_probe(struct efx_nic *efx) - { -- struct efx_mcdi_phy_cfg *phy_cfg; -+ struct efx_mcdi_phy_cfg *phy_data; -+ u8 outbuf[MC_CMD_GET_LINK_OUT_LEN]; -+ u32 caps; - int rc; - -- /* TODO: Move phy_data initialisation to -- * phy_op->probe/remove, rather than init/fini */ -- phy_cfg = kzalloc(sizeof(*phy_cfg), GFP_KERNEL); -- if (phy_cfg == NULL) { -- rc = -ENOMEM; -- goto fail_alloc; -- } -- rc = efx_mcdi_get_phy_cfg(efx, phy_cfg); -+ /* Initialise and populate phy_data */ -+ phy_data = kzalloc(sizeof(*phy_data), GFP_KERNEL); -+ if (phy_data == NULL) -+ return -ENOMEM; -+ -+ rc = efx_mcdi_get_phy_cfg(efx, phy_data); - if (rc != 0) - goto fail; - -- efx->phy_type = phy_cfg->type; -+ /* Read initial link advertisement */ -+ BUILD_BUG_ON(MC_CMD_GET_LINK_IN_LEN != 0); -+ rc = efx_mcdi_rpc(efx, MC_CMD_GET_LINK, NULL, 0, -+ outbuf, sizeof(outbuf), NULL); -+ if (rc) -+ goto fail; -+ -+ /* Fill out nic state */ -+ efx->phy_data = phy_data; -+ efx->phy_type = phy_data->type; - -- efx->mdio_bus = phy_cfg->channel; -- efx->mdio.prtad = phy_cfg->port; -- efx->mdio.mmds = phy_cfg->mmd_mask & ~(1 << MC_CMD_MMD_CLAUSE22); -+ efx->mdio_bus = phy_data->channel; -+ efx->mdio.prtad = phy_data->port; -+ efx->mdio.mmds = phy_data->mmd_mask & ~(1 << MC_CMD_MMD_CLAUSE22); - efx->mdio.mode_support = 0; -- if (phy_cfg->mmd_mask & (1 << MC_CMD_MMD_CLAUSE22)) -+ if (phy_data->mmd_mask & (1 << MC_CMD_MMD_CLAUSE22)) - efx->mdio.mode_support |= MDIO_SUPPORTS_C22; -- if (phy_cfg->mmd_mask & ~(1 << MC_CMD_MMD_CLAUSE22)) -+ if (phy_data->mmd_mask & ~(1 << MC_CMD_MMD_CLAUSE22)) - efx->mdio.mode_support |= MDIO_SUPPORTS_C45 | MDIO_EMULATE_C22; - -+ caps = MCDI_DWORD(outbuf, GET_LINK_OUT_CAP); -+ if (caps & (1 << MC_CMD_PHY_CAP_AN_LBN)) -+ efx->link_advertising = -+ mcdi_to_ethtool_cap(phy_data->media, caps); -+ else -+ phy_data->forced_cap = caps; -+ - /* Assert that we can map efx -> mcdi loopback modes */ - BUILD_BUG_ON(LOOPBACK_NONE != MC_CMD_LOOPBACK_NONE); - BUILD_BUG_ON(LOOPBACK_DATA != MC_CMD_LOOPBACK_DATA); -@@ -365,46 +381,6 @@ static int efx_mcdi_phy_probe(struct efx_nic *efx) - * but by convention we don't */ - efx->loopback_modes &= ~(1 << LOOPBACK_NONE); - -- kfree(phy_cfg); -- -- return 0; -- --fail: -- kfree(phy_cfg); --fail_alloc: -- return rc; --} -- --static int efx_mcdi_phy_init(struct efx_nic *efx) --{ -- struct efx_mcdi_phy_cfg *phy_data; -- u8 outbuf[MC_CMD_GET_LINK_OUT_LEN]; -- u32 caps; -- int rc; -- -- phy_data = kzalloc(sizeof(*phy_data), GFP_KERNEL); -- if (phy_data == NULL) -- return -ENOMEM; -- -- rc = efx_mcdi_get_phy_cfg(efx, phy_data); -- if (rc != 0) -- goto fail; -- -- efx->phy_data = phy_data; -- -- BUILD_BUG_ON(MC_CMD_GET_LINK_IN_LEN != 0); -- rc = efx_mcdi_rpc(efx, MC_CMD_GET_LINK, NULL, 0, -- outbuf, sizeof(outbuf), NULL); -- if (rc) -- goto fail; -- -- caps = MCDI_DWORD(outbuf, GET_LINK_OUT_CAP); -- if (caps & (1 << MC_CMD_PHY_CAP_AN_LBN)) -- efx->link_advertising = -- mcdi_to_ethtool_cap(phy_data->media, caps); -- else -- phy_data->forced_cap = caps; -- - return 0; - - fail: -@@ -504,7 +480,7 @@ static bool efx_mcdi_phy_poll(struct efx_nic *efx) - return !efx_link_state_equal(&efx->link_state, &old_state); - } - --static void efx_mcdi_phy_fini(struct efx_nic *efx) -+static void efx_mcdi_phy_remove(struct efx_nic *efx) - { - struct efx_mcdi_phy_data *phy_data = efx->phy_data; - -@@ -586,10 +562,11 @@ static int efx_mcdi_phy_set_settings(struct efx_nic *efx, struct ethtool_cmd *ec - - struct efx_phy_operations efx_mcdi_phy_ops = { - .probe = efx_mcdi_phy_probe, -- .init = efx_mcdi_phy_init, -+ .init = efx_port_dummy_op_int, - .reconfigure = efx_mcdi_phy_reconfigure, - .poll = efx_mcdi_phy_poll, -- .fini = efx_mcdi_phy_fini, -+ .fini = efx_port_dummy_op_void, -+ .remove = efx_mcdi_phy_remove, - .get_settings = efx_mcdi_phy_get_settings, - .set_settings = efx_mcdi_phy_set_settings, - .run_tests = NULL, -diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h -index 34c381f..d5aab5b 100644 ---- a/drivers/net/sfc/net_driver.h -+++ b/drivers/net/sfc/net_driver.h -@@ -524,6 +524,7 @@ struct efx_phy_operations { - int (*probe) (struct efx_nic *efx); - int (*init) (struct efx_nic *efx); - void (*fini) (struct efx_nic *efx); -+ void (*remove) (struct efx_nic *efx); - int (*reconfigure) (struct efx_nic *efx); - bool (*poll) (struct efx_nic *efx); - void (*get_settings) (struct efx_nic *efx, -diff --git a/drivers/net/sfc/qt202x_phy.c b/drivers/net/sfc/qt202x_phy.c -index 3800fc7..7450e3a 100644 ---- a/drivers/net/sfc/qt202x_phy.c -+++ b/drivers/net/sfc/qt202x_phy.c -@@ -137,6 +137,14 @@ static int qt202x_reset_phy(struct efx_nic *efx) - - static int qt202x_phy_probe(struct efx_nic *efx) - { -+ struct qt202x_phy_data *phy_data; -+ -+ phy_data = kzalloc(sizeof(struct qt202x_phy_data), GFP_KERNEL); -+ if (!phy_data) -+ return -ENOMEM; -+ efx->phy_data = phy_data; -+ phy_data->phy_mode = efx->phy_mode; -+ - efx->mdio.mmds = QT202X_REQUIRED_DEVS; - efx->mdio.mode_support = MDIO_SUPPORTS_C45 | MDIO_EMULATE_C22; - efx->loopback_modes = QT202X_LOOPBACKS | FALCON_XMAC_LOOPBACKS; -@@ -145,7 +153,6 @@ static int qt202x_phy_probe(struct efx_nic *efx) - - static int qt202x_phy_init(struct efx_nic *efx) - { -- struct qt202x_phy_data *phy_data; - u32 devid; - int rc; - -@@ -155,17 +162,11 @@ static int qt202x_phy_init(struct efx_nic *efx) - return rc; - } - -- phy_data = kzalloc(sizeof(struct qt202x_phy_data), GFP_KERNEL); -- if (!phy_data) -- return -ENOMEM; -- efx->phy_data = phy_data; -- - devid = efx_mdio_read_id(efx, MDIO_MMD_PHYXS); - EFX_INFO(efx, "PHY ID reg %x (OUI %06x model %02x revision %x)\n", - devid, efx_mdio_id_oui(devid), efx_mdio_id_model(devid), - efx_mdio_id_rev(devid)); - -- phy_data->phy_mode = efx->phy_mode; - return 0; - } - -@@ -224,7 +225,7 @@ static void qt202x_phy_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecm - mdio45_ethtool_gset(&efx->mdio, ecmd); - } - --static void qt202x_phy_fini(struct efx_nic *efx) -+static void qt202x_phy_remove(struct efx_nic *efx) - { - /* Free the context block */ - kfree(efx->phy_data); -@@ -236,7 +237,8 @@ struct efx_phy_operations falcon_qt202x_phy_ops = { - .init = qt202x_phy_init, - .reconfigure = qt202x_phy_reconfigure, - .poll = qt202x_phy_poll, -- .fini = qt202x_phy_fini, -+ .fini = efx_port_dummy_op_void, -+ .remove = qt202x_phy_remove, - .get_settings = qt202x_phy_get_settings, - .set_settings = efx_mdio_set_settings, - }; -diff --git a/drivers/net/sfc/siena.c b/drivers/net/sfc/siena.c -index de07a4f..f8c6771 100644 ---- a/drivers/net/sfc/siena.c -+++ b/drivers/net/sfc/siena.c -@@ -133,6 +133,7 @@ static int siena_probe_port(struct efx_nic *efx) - - void siena_remove_port(struct efx_nic *efx) - { -+ efx->phy_op->remove(efx); - efx_nic_free_buffer(efx, &efx->stats_buffer); - } - -diff --git a/drivers/net/sfc/tenxpress.c b/drivers/net/sfc/tenxpress.c -index ca11572..3009c29 100644 ---- a/drivers/net/sfc/tenxpress.c -+++ b/drivers/net/sfc/tenxpress.c -@@ -202,10 +202,14 @@ static ssize_t set_phy_short_reach(struct device *dev, - int rc; - - rtnl_lock(); -- efx_mdio_set_flag(efx, MDIO_MMD_PMAPMD, MDIO_PMA_10GBT_TXPWR, -- MDIO_PMA_10GBT_TXPWR_SHORT, -- count != 0 && *buf != '0'); -- rc = efx_reconfigure_port(efx); -+ if (efx->state != STATE_RUNNING) { -+ rc = -EBUSY; -+ } else { -+ efx_mdio_set_flag(efx, MDIO_MMD_PMAPMD, MDIO_PMA_10GBT_TXPWR, -+ MDIO_PMA_10GBT_TXPWR_SHORT, -+ count != 0 && *buf != '0'); -+ rc = efx_reconfigure_port(efx); -+ } - rtnl_unlock(); - - return rc < 0 ? rc : (ssize_t)count; -@@ -298,36 +302,62 @@ static int tenxpress_init(struct efx_nic *efx) - return 0; - } - --static int sfx7101_phy_probe(struct efx_nic *efx) -+static int tenxpress_phy_probe(struct efx_nic *efx) - { -- efx->mdio.mmds = TENXPRESS_REQUIRED_DEVS; -- efx->mdio.mode_support = MDIO_SUPPORTS_C45 | MDIO_EMULATE_C22; -- efx->loopback_modes = SFX7101_LOOPBACKS | FALCON_XMAC_LOOPBACKS; -- return 0; --} -+ struct tenxpress_phy_data *phy_data; -+ int rc; -+ -+ /* Allocate phy private storage */ -+ phy_data = kzalloc(sizeof(*phy_data), GFP_KERNEL); -+ if (!phy_data) -+ return -ENOMEM; -+ efx->phy_data = phy_data; -+ phy_data->phy_mode = efx->phy_mode; -+ -+ /* Create any special files */ -+ if (efx->phy_type == PHY_TYPE_SFT9001B) { -+ rc = device_create_file(&efx->pci_dev->dev, -+ &dev_attr_phy_short_reach); -+ if (rc) -+ goto fail; -+ } -+ -+ if (efx->phy_type == PHY_TYPE_SFX7101) { -+ efx->mdio.mmds = TENXPRESS_REQUIRED_DEVS; -+ efx->mdio.mode_support = MDIO_SUPPORTS_C45; -+ -+ efx->loopback_modes = SFX7101_LOOPBACKS | FALCON_XMAC_LOOPBACKS; -+ -+ efx->link_advertising = (ADVERTISED_TP | ADVERTISED_Autoneg | -+ ADVERTISED_10000baseT_Full); -+ } else { -+ efx->mdio.mmds = TENXPRESS_REQUIRED_DEVS; -+ efx->mdio.mode_support = MDIO_SUPPORTS_C45 | MDIO_EMULATE_C22; -+ -+ efx->loopback_modes = (SFT9001_LOOPBACKS | -+ FALCON_XMAC_LOOPBACKS | -+ FALCON_GMAC_LOOPBACKS); -+ -+ efx->link_advertising = (ADVERTISED_TP | ADVERTISED_Autoneg | -+ ADVERTISED_10000baseT_Full | -+ ADVERTISED_1000baseT_Full | -+ ADVERTISED_100baseT_Full); -+ } - --static int sft9001_phy_probe(struct efx_nic *efx) --{ -- efx->mdio.mmds = TENXPRESS_REQUIRED_DEVS; -- efx->mdio.mode_support = MDIO_SUPPORTS_C45 | MDIO_EMULATE_C22; -- efx->loopback_modes = (SFT9001_LOOPBACKS | FALCON_XMAC_LOOPBACKS | -- FALCON_GMAC_LOOPBACKS); - return 0; -+ -+fail: -+ kfree(efx->phy_data); -+ efx->phy_data = NULL; -+ return rc; - } - - static int tenxpress_phy_init(struct efx_nic *efx) - { -- struct tenxpress_phy_data *phy_data; -- int rc = 0; -+ int rc; - - falcon_board(efx)->type->init_phy(efx); - -- phy_data = kzalloc(sizeof(*phy_data), GFP_KERNEL); -- if (!phy_data) -- return -ENOMEM; -- efx->phy_data = phy_data; -- phy_data->phy_mode = efx->phy_mode; -- - if (!(efx->phy_mode & PHY_MODE_SPECIAL)) { - if (efx->phy_type == PHY_TYPE_SFT9001A) { - int reg; -@@ -341,44 +371,27 @@ static int tenxpress_phy_init(struct efx_nic *efx) - - rc = efx_mdio_wait_reset_mmds(efx, TENXPRESS_REQUIRED_DEVS); - if (rc < 0) -- goto fail; -+ return rc; - - rc = efx_mdio_check_mmds(efx, TENXPRESS_REQUIRED_DEVS, 0); - if (rc < 0) -- goto fail; -+ return rc; - } - - rc = tenxpress_init(efx); - if (rc < 0) -- goto fail; -+ return rc; - -- /* Initialise advertising flags */ -- efx->link_advertising = (ADVERTISED_TP | ADVERTISED_Autoneg | -- ADVERTISED_10000baseT_Full); -- if (efx->phy_type != PHY_TYPE_SFX7101) -- efx->link_advertising |= (ADVERTISED_1000baseT_Full | -- ADVERTISED_100baseT_Full); -+ /* Reinitialise flow control settings */ - efx_link_set_wanted_fc(efx, efx->wanted_fc); - efx_mdio_an_reconfigure(efx); - -- if (efx->phy_type == PHY_TYPE_SFT9001B) { -- rc = device_create_file(&efx->pci_dev->dev, -- &dev_attr_phy_short_reach); -- if (rc) -- goto fail; -- } -- - schedule_timeout_uninterruptible(HZ / 5); /* 200ms */ - - /* Let XGXS and SerDes out of reset */ - falcon_reset_xaui(efx); - - return 0; -- -- fail: -- kfree(efx->phy_data); -- efx->phy_data = NULL; -- return rc; - } - - /* Perform a "special software reset" on the PHY. The caller is -@@ -589,25 +602,26 @@ static bool tenxpress_phy_poll(struct efx_nic *efx) - return !efx_link_state_equal(&efx->link_state, &old_state); - } - --static void tenxpress_phy_fini(struct efx_nic *efx) -+static void sfx7101_phy_fini(struct efx_nic *efx) - { - int reg; - -+ /* Power down the LNPGA */ -+ reg = (1 << PMA_PMD_LNPGA_POWERDOWN_LBN); -+ efx_mdio_write(efx, MDIO_MMD_PMAPMD, PMA_PMD_XCONTROL_REG, reg); -+ -+ /* Waiting here ensures that the board fini, which can turn -+ * off the power to the PHY, won't get run until the LNPGA -+ * powerdown has been given long enough to complete. */ -+ schedule_timeout_uninterruptible(LNPGA_PDOWN_WAIT); /* 200 ms */ -+} -+ -+static void tenxpress_phy_remove(struct efx_nic *efx) -+{ - if (efx->phy_type == PHY_TYPE_SFT9001B) - device_remove_file(&efx->pci_dev->dev, - &dev_attr_phy_short_reach); - -- if (efx->phy_type == PHY_TYPE_SFX7101) { -- /* Power down the LNPGA */ -- reg = (1 << PMA_PMD_LNPGA_POWERDOWN_LBN); -- efx_mdio_write(efx, MDIO_MMD_PMAPMD, PMA_PMD_XCONTROL_REG, reg); -- -- /* Waiting here ensures that the board fini, which can turn -- * off the power to the PHY, won't get run until the LNPGA -- * powerdown has been given long enough to complete. */ -- schedule_timeout_uninterruptible(LNPGA_PDOWN_WAIT); /* 200 ms */ -- } -- - kfree(efx->phy_data); - efx->phy_data = NULL; - } -@@ -819,11 +833,12 @@ static void sft9001_set_npage_adv(struct efx_nic *efx, u32 advertising) - } - - struct efx_phy_operations falcon_sfx7101_phy_ops = { -- .probe = sfx7101_phy_probe, -+ .probe = tenxpress_phy_probe, - .init = tenxpress_phy_init, - .reconfigure = tenxpress_phy_reconfigure, - .poll = tenxpress_phy_poll, -- .fini = tenxpress_phy_fini, -+ .fini = sfx7101_phy_fini, -+ .remove = tenxpress_phy_remove, - .get_settings = tenxpress_get_settings, - .set_settings = tenxpress_set_settings, - .set_npage_adv = sfx7101_set_npage_adv, -@@ -832,11 +847,12 @@ struct efx_phy_operations falcon_sfx7101_phy_ops = { - }; - - struct efx_phy_operations falcon_sft9001_phy_ops = { -- .probe = sft9001_phy_probe, -+ .probe = tenxpress_phy_probe, - .init = tenxpress_phy_init, - .reconfigure = tenxpress_phy_reconfigure, - .poll = tenxpress_phy_poll, -- .fini = tenxpress_phy_fini, -+ .fini = efx_port_dummy_op_void, -+ .remove = tenxpress_phy_remove, - .get_settings = tenxpress_get_settings, - .set_settings = tenxpress_set_settings, - .set_npage_adv = sft9001_set_npage_adv, --- -1.6.5.7 - diff --git a/debian/patches/bugfix/all/sfc-QT2025C-Add-error-message-for-suspected-bad-SFP-cable.patch b/debian/patches/bugfix/all/sfc-QT2025C-Add-error-message-for-suspected-bad-SFP-cable.patch deleted file mode 100644 index 47e66d2c1..000000000 --- a/debian/patches/bugfix/all/sfc-QT2025C-Add-error-message-for-suspected-bad-SFP-cable.patch +++ /dev/null @@ -1,37 +0,0 @@ -From 50d6ec552bdd4d9227fe9ed2bac819eced3170ac Mon Sep 17 00:00:00 2001 -From: Ben Hutchings -Date: Wed, 23 Dec 2009 13:48:42 +0000 -Subject: [PATCH 7/8] sfc: QT2025C: Add error message for suspected bad SFP+ cables - -Some cables have EEPROMs that conflict with the PHY's on-board EEPROM -so it cannot load firmware. - -Signed-off-by: Ben Hutchings -Signed-off-by: David S. Miller ---- - drivers/net/sfc/qt202x_phy.c | 8 +++++++- - 1 files changed, 7 insertions(+), 1 deletions(-) - -diff --git a/drivers/net/sfc/qt202x_phy.c b/drivers/net/sfc/qt202x_phy.c -index 326ffa4..ff8f0a4 100644 ---- a/drivers/net/sfc/qt202x_phy.c -+++ b/drivers/net/sfc/qt202x_phy.c -@@ -87,8 +87,14 @@ static int qt2025c_wait_heartbeat(struct efx_nic *efx) - old_counter = counter; - else if (counter != old_counter) - break; -- if (time_after(jiffies, timeout)) -+ if (time_after(jiffies, timeout)) { -+ /* Some cables have EEPROMs that conflict with the -+ * PHY's on-board EEPROM so it cannot load firmware */ -+ EFX_ERR(efx, "If an SFP+ direct attach cable is" -+ " connected, please check that it complies" -+ " with the SFP+ specification\n"); - return -ETIMEDOUT; -+ } - msleep(QT2025C_HEARTB_WAIT); - } - --- -1.6.5.7 - diff --git a/debian/patches/bugfix/all/sfc-QT2025C-Switch-into-self-configure-mode.patch b/debian/patches/bugfix/all/sfc-QT2025C-Switch-into-self-configure-mode.patch deleted file mode 100644 index 9ab24a0a9..000000000 --- a/debian/patches/bugfix/all/sfc-QT2025C-Switch-into-self-configure-mode.patch +++ /dev/null @@ -1,185 +0,0 @@ -From 0d83b2f64c330ee3892cb3117ac5d56e97185ecf Mon Sep 17 00:00:00 2001 -From: Matthew Slattery -Date: Wed, 23 Dec 2009 13:48:04 +0000 -Subject: [PATCH 5/8] sfc: QT2025C: Switch into self-configure mode when not in loopback - -The PHY boots in a mode which is not necessarily optimal. This change -switches it to self-configure mode (except when in loopback, which -won't work in that mode if an SFP+ module is not present) by rebooting -the PHY's microcontroller, and replicating the sequence of configuration -writes from the boot EEPROM with the appropriate changes. - -Signed-off-by: Ben Hutchings -Signed-off-by: David S. Miller ---- - drivers/net/sfc/qt202x_phy.c | 119 ++++++++++++++++++++++++++++++++++++++++++ - 1 files changed, 119 insertions(+), 0 deletions(-) - -diff --git a/drivers/net/sfc/qt202x_phy.c b/drivers/net/sfc/qt202x_phy.c -index e4590fb..0cd6eed 100644 ---- a/drivers/net/sfc/qt202x_phy.c -+++ b/drivers/net/sfc/qt202x_phy.c -@@ -33,6 +33,9 @@ - #define PCS_FW_HEARTBEAT_REG 0xd7ee - #define PCS_FW_HEARTB_LBN 0 - #define PCS_FW_HEARTB_WIDTH 8 -+#define PCS_FW_PRODUCT_CODE_1 0xd7f0 -+#define PCS_FW_VERSION_1 0xd7f3 -+#define PCS_FW_BUILD_1 0xd7f6 - #define PCS_UC8051_STATUS_REG 0xd7fd - #define PCS_UC_STATUS_LBN 0 - #define PCS_UC_STATUS_WIDTH 8 -@@ -54,6 +57,7 @@ struct qt202x_phy_data { - enum efx_phy_mode phy_mode; - bool bug17190_in_bad_state; - unsigned long bug17190_timer; -+ u32 firmware_ver; - }; - - #define QT2022C2_MAX_RESET_TIME 500 -@@ -100,6 +104,25 @@ static int qt2025c_wait_reset(struct efx_nic *efx) - return 0; - } - -+static void qt2025c_firmware_id(struct efx_nic *efx) -+{ -+ struct qt202x_phy_data *phy_data = efx->phy_data; -+ u8 firmware_id[9]; -+ size_t i; -+ -+ for (i = 0; i < sizeof(firmware_id); i++) -+ firmware_id[i] = efx_mdio_read(efx, MDIO_MMD_PCS, -+ PCS_FW_PRODUCT_CODE_1 + i); -+ EFX_INFO(efx, "QT2025C firmware %xr%d v%d.%d.%d.%d [20%02d-%02d-%02d]\n", -+ (firmware_id[0] << 8) | firmware_id[1], firmware_id[2], -+ firmware_id[3] >> 4, firmware_id[3] & 0xf, -+ firmware_id[4], firmware_id[5], -+ firmware_id[6], firmware_id[7], firmware_id[8]); -+ phy_data->firmware_ver = ((firmware_id[3] & 0xf0) << 20) | -+ ((firmware_id[3] & 0x0f) << 16) | -+ (firmware_id[4] << 8) | firmware_id[5]; -+} -+ - static void qt2025c_bug17190_workaround(struct efx_nic *efx) - { - struct qt202x_phy_data *phy_data = efx->phy_data; -@@ -133,6 +156,95 @@ static void qt2025c_bug17190_workaround(struct efx_nic *efx) - } - } - -+static int qt2025c_select_phy_mode(struct efx_nic *efx) -+{ -+ struct qt202x_phy_data *phy_data = efx->phy_data; -+ struct falcon_board *board = falcon_board(efx); -+ int reg, rc, i; -+ uint16_t phy_op_mode; -+ -+ /* Only 2.0.1.0+ PHY firmware supports the more optimal SFP+ -+ * Self-Configure mode. Don't attempt any switching if we encounter -+ * older firmware. */ -+ if (phy_data->firmware_ver < 0x02000100) -+ return 0; -+ -+ /* In general we will get optimal behaviour in "SFP+ Self-Configure" -+ * mode; however, that powers down most of the PHY when no module is -+ * present, so we must use a different mode (any fixed mode will do) -+ * to be sure that loopbacks will work. */ -+ phy_op_mode = (efx->loopback_mode == LOOPBACK_NONE) ? 0x0038 : 0x0020; -+ -+ /* Only change mode if really necessary */ -+ reg = efx_mdio_read(efx, 1, 0xc319); -+ if ((reg & 0x0038) == phy_op_mode) -+ return 0; -+ EFX_LOG(efx, "Switching PHY to mode 0x%04x\n", phy_op_mode); -+ -+ /* This sequence replicates the register writes configured in the boot -+ * EEPROM (including the differences between board revisions), except -+ * that the operating mode is changed, and the PHY is prevented from -+ * unnecessarily reloading the main firmware image again. */ -+ efx_mdio_write(efx, 1, 0xc300, 0x0000); -+ /* (Note: this portion of the boot EEPROM sequence, which bit-bashes 9 -+ * STOPs onto the firmware/module I2C bus to reset it, varies across -+ * board revisions, as the bus is connected to different GPIO/LED -+ * outputs on the PHY.) */ -+ if (board->major == 0 && board->minor < 2) { -+ efx_mdio_write(efx, 1, 0xc303, 0x4498); -+ for (i = 0; i < 9; i++) { -+ efx_mdio_write(efx, 1, 0xc303, 0x4488); -+ efx_mdio_write(efx, 1, 0xc303, 0x4480); -+ efx_mdio_write(efx, 1, 0xc303, 0x4490); -+ efx_mdio_write(efx, 1, 0xc303, 0x4498); -+ } -+ } else { -+ efx_mdio_write(efx, 1, 0xc303, 0x0920); -+ efx_mdio_write(efx, 1, 0xd008, 0x0004); -+ for (i = 0; i < 9; i++) { -+ efx_mdio_write(efx, 1, 0xc303, 0x0900); -+ efx_mdio_write(efx, 1, 0xd008, 0x0005); -+ efx_mdio_write(efx, 1, 0xc303, 0x0920); -+ efx_mdio_write(efx, 1, 0xd008, 0x0004); -+ } -+ efx_mdio_write(efx, 1, 0xc303, 0x4900); -+ } -+ efx_mdio_write(efx, 1, 0xc303, 0x4900); -+ efx_mdio_write(efx, 1, 0xc302, 0x0004); -+ efx_mdio_write(efx, 1, 0xc316, 0x0013); -+ efx_mdio_write(efx, 1, 0xc318, 0x0054); -+ efx_mdio_write(efx, 1, 0xc319, phy_op_mode); -+ efx_mdio_write(efx, 1, 0xc31a, 0x0098); -+ efx_mdio_write(efx, 3, 0x0026, 0x0e00); -+ efx_mdio_write(efx, 3, 0x0027, 0x0013); -+ efx_mdio_write(efx, 3, 0x0028, 0xa528); -+ efx_mdio_write(efx, 1, 0xd006, 0x000a); -+ efx_mdio_write(efx, 1, 0xd007, 0x0009); -+ efx_mdio_write(efx, 1, 0xd008, 0x0004); -+ /* This additional write is not present in the boot EEPROM. It -+ * prevents the PHY's internal boot ROM doing another pointless (and -+ * slow) reload of the firmware image (the microcontroller's code -+ * memory is not affected by the microcontroller reset). */ -+ efx_mdio_write(efx, 1, 0xc317, 0x00ff); -+ efx_mdio_write(efx, 1, 0xc300, 0x0002); -+ msleep(20); -+ -+ /* Restart microcontroller execution from RAM */ -+ efx_mdio_write(efx, 3, 0xe854, 0x00c0); -+ efx_mdio_write(efx, 3, 0xe854, 0x0040); -+ msleep(50); -+ -+ /* Wait for the microcontroller to be ready again */ -+ rc = qt2025c_wait_reset(efx); -+ if (rc < 0) { -+ EFX_ERR(efx, "PHY microcontroller reset during mode switch " -+ "timed out\n"); -+ return rc; -+ } -+ -+ return 0; -+} -+ - static int qt202x_reset_phy(struct efx_nic *efx) - { - int rc; -@@ -206,6 +318,9 @@ static int qt202x_phy_init(struct efx_nic *efx) - devid, efx_mdio_id_oui(devid), efx_mdio_id_model(devid), - efx_mdio_id_rev(devid)); - -+ if (efx->phy_type == PHY_TYPE_QT2025C) -+ qt2025c_firmware_id(efx); -+ - return 0; - } - -@@ -234,6 +349,10 @@ static int qt202x_phy_reconfigure(struct efx_nic *efx) - struct qt202x_phy_data *phy_data = efx->phy_data; - - if (efx->phy_type == PHY_TYPE_QT2025C) { -+ int rc = qt2025c_select_phy_mode(efx); -+ if (rc) -+ return rc; -+ - /* There are several different register bits which can - * disable TX (and save power) on direct-attach cables - * or optical transceivers, varying somewhat between --- -1.6.5.7 - diff --git a/debian/patches/bugfix/all/sfc-QT2025C-Work-around-PHY-bug.patch b/debian/patches/bugfix/all/sfc-QT2025C-Work-around-PHY-bug.patch deleted file mode 100644 index 764fae3b7..000000000 --- a/debian/patches/bugfix/all/sfc-QT2025C-Work-around-PHY-bug.patch +++ /dev/null @@ -1,97 +0,0 @@ -From 17d6aeafe9d8268612d91edc0102659edb382282 Mon Sep 17 00:00:00 2001 -From: Matthew Slattery -Date: Wed, 23 Dec 2009 13:47:37 +0000 -Subject: [PATCH 4/8] sfc: QT2025C: Work around PHY bug - -If we see the PHY remaining stuck in a link-down state due to PCS being -down while PMA/PMD is up, we briefly switch to PMA/PMD loopback and back, -which usually unsticks it. - -Signed-off-by: Ben Hutchings -Signed-off-by: David S. Miller ---- - drivers/net/sfc/qt202x_phy.c | 42 ++++++++++++++++++++++++++++++++++++++++++ - 1 files changed, 42 insertions(+), 0 deletions(-) - -diff --git a/drivers/net/sfc/qt202x_phy.c b/drivers/net/sfc/qt202x_phy.c -index 7450e3a..e4590fb 100644 ---- a/drivers/net/sfc/qt202x_phy.c -+++ b/drivers/net/sfc/qt202x_phy.c -@@ -52,11 +52,15 @@ void falcon_qt202x_set_led(struct efx_nic *p, int led, int mode) - - struct qt202x_phy_data { - enum efx_phy_mode phy_mode; -+ bool bug17190_in_bad_state; -+ unsigned long bug17190_timer; - }; - - #define QT2022C2_MAX_RESET_TIME 500 - #define QT2022C2_RESET_WAIT 10 - -+#define BUG17190_INTERVAL (2 * HZ) -+ - static int qt2025c_wait_reset(struct efx_nic *efx) - { - unsigned long timeout = jiffies + 10 * HZ; -@@ -96,6 +100,39 @@ static int qt2025c_wait_reset(struct efx_nic *efx) - return 0; - } - -+static void qt2025c_bug17190_workaround(struct efx_nic *efx) -+{ -+ struct qt202x_phy_data *phy_data = efx->phy_data; -+ -+ /* The PHY can get stuck in a state where it reports PHY_XS and PMA/PMD -+ * layers up, but PCS down (no block_lock). If we notice this state -+ * persisting for a couple of seconds, we switch PMA/PMD loopback -+ * briefly on and then off again, which is normally sufficient to -+ * recover it. -+ */ -+ if (efx->link_state.up || -+ !efx_mdio_links_ok(efx, MDIO_DEVS_PMAPMD | MDIO_DEVS_PHYXS)) { -+ phy_data->bug17190_in_bad_state = false; -+ return; -+ } -+ -+ if (!phy_data->bug17190_in_bad_state) { -+ phy_data->bug17190_in_bad_state = true; -+ phy_data->bug17190_timer = jiffies + BUG17190_INTERVAL; -+ return; -+ } -+ -+ if (time_after_eq(jiffies, phy_data->bug17190_timer)) { -+ EFX_LOG(efx, "bashing QT2025C PMA/PMD\n"); -+ efx_mdio_set_flag(efx, MDIO_MMD_PMAPMD, MDIO_CTRL1, -+ MDIO_PMA_CTRL1_LOOPBACK, true); -+ msleep(100); -+ efx_mdio_set_flag(efx, MDIO_MMD_PMAPMD, MDIO_CTRL1, -+ MDIO_PMA_CTRL1_LOOPBACK, false); -+ phy_data->bug17190_timer = jiffies + BUG17190_INTERVAL; -+ } -+} -+ - static int qt202x_reset_phy(struct efx_nic *efx) - { - int rc; -@@ -144,6 +181,8 @@ static int qt202x_phy_probe(struct efx_nic *efx) - return -ENOMEM; - efx->phy_data = phy_data; - phy_data->phy_mode = efx->phy_mode; -+ phy_data->bug17190_in_bad_state = false; -+ phy_data->bug17190_timer = 0; - - efx->mdio.mmds = QT202X_REQUIRED_DEVS; - efx->mdio.mode_support = MDIO_SUPPORTS_C45 | MDIO_EMULATE_C22; -@@ -184,6 +223,9 @@ static bool qt202x_phy_poll(struct efx_nic *efx) - efx->link_state.fd = true; - efx->link_state.fc = efx->wanted_fc; - -+ if (efx->phy_type == PHY_TYPE_QT2025C) -+ qt2025c_bug17190_workaround(efx); -+ - return efx->link_state.up != was_up; - } - --- -1.6.5.7 - diff --git a/debian/patches/bugfix/all/sfc-QT2025C-Work-around-PHY-firmware-initialisation.patch b/debian/patches/bugfix/all/sfc-QT2025C-Work-around-PHY-firmware-initialisation.patch deleted file mode 100644 index f1e006c08..000000000 --- a/debian/patches/bugfix/all/sfc-QT2025C-Work-around-PHY-firmware-initialisation.patch +++ /dev/null @@ -1,119 +0,0 @@ -From 1a1284ef97ca79ba747d211b697e996a248a8555 Mon Sep 17 00:00:00 2001 -From: Matthew Slattery -Date: Wed, 23 Dec 2009 13:48:32 +0000 -Subject: [PATCH 6/8] sfc: QT2025C: Work around PHY firmware initialisation bug - -The PHY's firmware very occasionally appears to lock up very early, but -with the heartbeat update still running. Rebooting the microcontroller -core seems to be sufficient to recover. - -Signed-off-by: Ben Hutchings -Signed-off-by: David S. Miller ---- - drivers/net/sfc/qt202x_phy.c | 59 ++++++++++++++++++++++++++++++++++++----- - 1 files changed, 51 insertions(+), 8 deletions(-) - -diff --git a/drivers/net/sfc/qt202x_phy.c b/drivers/net/sfc/qt202x_phy.c -index 0cd6eed..326ffa4 100644 ---- a/drivers/net/sfc/qt202x_phy.c -+++ b/drivers/net/sfc/qt202x_phy.c -@@ -63,11 +63,16 @@ struct qt202x_phy_data { - #define QT2022C2_MAX_RESET_TIME 500 - #define QT2022C2_RESET_WAIT 10 - -+#define QT2025C_MAX_HEARTB_TIME (5 * HZ) -+#define QT2025C_HEARTB_WAIT 100 -+#define QT2025C_MAX_FWSTART_TIME (25 * HZ / 10) -+#define QT2025C_FWSTART_WAIT 100 -+ - #define BUG17190_INTERVAL (2 * HZ) - --static int qt2025c_wait_reset(struct efx_nic *efx) -+static int qt2025c_wait_heartbeat(struct efx_nic *efx) - { -- unsigned long timeout = jiffies + 10 * HZ; -+ unsigned long timeout = jiffies + QT2025C_MAX_HEARTB_TIME; - int reg, old_counter = 0; - - /* Wait for firmware heartbeat to start */ -@@ -84,9 +89,17 @@ static int qt2025c_wait_reset(struct efx_nic *efx) - break; - if (time_after(jiffies, timeout)) - return -ETIMEDOUT; -- msleep(10); -+ msleep(QT2025C_HEARTB_WAIT); - } - -+ return 0; -+} -+ -+static int qt2025c_wait_fw_status_good(struct efx_nic *efx) -+{ -+ unsigned long timeout = jiffies + QT2025C_MAX_FWSTART_TIME; -+ int reg; -+ - /* Wait for firmware status to look good */ - for (;;) { - reg = efx_mdio_read(efx, MDIO_MMD_PCS, PCS_UC8051_STATUS_REG); -@@ -98,12 +111,44 @@ static int qt2025c_wait_reset(struct efx_nic *efx) - break; - if (time_after(jiffies, timeout)) - return -ETIMEDOUT; -- msleep(100); -+ msleep(QT2025C_FWSTART_WAIT); - } - - return 0; - } - -+static void qt2025c_restart_firmware(struct efx_nic *efx) -+{ -+ /* Restart microcontroller execution of firmware from RAM */ -+ efx_mdio_write(efx, 3, 0xe854, 0x00c0); -+ efx_mdio_write(efx, 3, 0xe854, 0x0040); -+ msleep(50); -+} -+ -+static int qt2025c_wait_reset(struct efx_nic *efx) -+{ -+ int rc; -+ -+ rc = qt2025c_wait_heartbeat(efx); -+ if (rc != 0) -+ return rc; -+ -+ rc = qt2025c_wait_fw_status_good(efx); -+ if (rc == -ETIMEDOUT) { -+ /* Bug 17689: occasionally heartbeat starts but firmware status -+ * code never progresses beyond 0x00. Try again, once, after -+ * restarting execution of the firmware image. */ -+ EFX_LOG(efx, "bashing QT2025C microcontroller\n"); -+ qt2025c_restart_firmware(efx); -+ rc = qt2025c_wait_heartbeat(efx); -+ if (rc != 0) -+ return rc; -+ rc = qt2025c_wait_fw_status_good(efx); -+ } -+ -+ return rc; -+} -+ - static void qt2025c_firmware_id(struct efx_nic *efx) - { - struct qt202x_phy_data *phy_data = efx->phy_data; -@@ -229,10 +274,8 @@ static int qt2025c_select_phy_mode(struct efx_nic *efx) - efx_mdio_write(efx, 1, 0xc300, 0x0002); - msleep(20); - -- /* Restart microcontroller execution from RAM */ -- efx_mdio_write(efx, 3, 0xe854, 0x00c0); -- efx_mdio_write(efx, 3, 0xe854, 0x0040); -- msleep(50); -+ /* Restart microcontroller execution of firmware from RAM */ -+ qt2025c_restart_firmware(efx); - - /* Wait for the microcontroller to be ready again */ - rc = qt2025c_wait_reset(efx); --- -1.6.5.7 - diff --git a/debian/patches/bugfix/all/sfc-QT202x-Remove-unreliable-MMD-check.patch b/debian/patches/bugfix/all/sfc-QT202x-Remove-unreliable-MMD-check.patch deleted file mode 100644 index d426bb976..000000000 --- a/debian/patches/bugfix/all/sfc-QT202x-Remove-unreliable-MMD-check.patch +++ /dev/null @@ -1,33 +0,0 @@ -From 357d46a17e54c9a87e0e6ef3930ff4ab2d232b81 Mon Sep 17 00:00:00 2001 -From: Matthew Slattery -Date: Mon, 18 Jan 2010 05:47:16 +0000 -Subject: [PATCH 3/5] sfc: QT202x: Remove unreliable MMD check at initialisation - -Checking the PHY XS MMD here is unnecessary and can give false negatives. - -Signed-off-by: Ben Hutchings -Signed-off-by: David S. Miller ---- - drivers/net/sfc/qt202x_phy.c | 6 ------ - 1 files changed, 0 insertions(+), 6 deletions(-) - -diff --git a/drivers/net/sfc/qt202x_phy.c b/drivers/net/sfc/qt202x_phy.c -index ff8f0a4..e0d13a4 100644 ---- a/drivers/net/sfc/qt202x_phy.c -+++ b/drivers/net/sfc/qt202x_phy.c -@@ -318,12 +318,6 @@ static int qt202x_reset_phy(struct efx_nic *efx) - /* Wait 250ms for the PHY to complete bootup */ - msleep(250); - -- /* Check that all the MMDs we expect are present and responding. We -- * expect faults on some if the link is down, but not on the PHY XS */ -- rc = efx_mdio_check_mmds(efx, QT202X_REQUIRED_DEVS, MDIO_DEVS_PHYXS); -- if (rc < 0) -- goto fail; -- - falcon_board(efx)->type->init_phy(efx); - - return rc; --- -1.6.6 - diff --git a/debian/patches/bugfix/all/sfc-Use-fixed-size-buffers-for-MCDI-NVRAM-requests.patch b/debian/patches/bugfix/all/sfc-Use-fixed-size-buffers-for-MCDI-NVRAM-requests.patch deleted file mode 100644 index 8b671d0d0..000000000 --- a/debian/patches/bugfix/all/sfc-Use-fixed-size-buffers-for-MCDI-NVRAM-requests.patch +++ /dev/null @@ -1,98 +0,0 @@ -From 5a27e86babe79cf5f575394bb1055448458df6c7 Mon Sep 17 00:00:00 2001 -From: Ben Hutchings -Date: Mon, 25 Jan 2010 15:49:59 -0800 -Subject: [PATCH 5/5] sfc: Use fixed-size buffers for MCDI NVRAM requests - -The low-level MCDI code always uses 32-bit MMIO operations, and -callers must pad input and output buffers to multiples of 4 bytes. -The MCDI NVRAM functions are not doing this. Also, their buffers are -declared as variable-length arrays with no explicit maximum length. - -Switch to a fixed buffer size based on the chunk size used by the -MTD driver (which is a multiple of 4). - -Signed-off-by: Ben Hutchings -Signed-off-by: David S. Miller ---- - drivers/net/sfc/mcdi.c | 7 ++++--- - drivers/net/sfc/mcdi.h | 1 + - drivers/net/sfc/mtd.c | 5 ++--- - 3 files changed, 7 insertions(+), 6 deletions(-) - -diff --git a/drivers/net/sfc/mcdi.c b/drivers/net/sfc/mcdi.c -index 0d4eba7..9f035b9 100644 ---- a/drivers/net/sfc/mcdi.c -+++ b/drivers/net/sfc/mcdi.c -@@ -804,7 +804,7 @@ int efx_mcdi_nvram_read(struct efx_nic *efx, unsigned int type, - loff_t offset, u8 *buffer, size_t length) - { - u8 inbuf[MC_CMD_NVRAM_READ_IN_LEN]; -- u8 outbuf[MC_CMD_NVRAM_READ_OUT_LEN(length)]; -+ u8 outbuf[MC_CMD_NVRAM_READ_OUT_LEN(EFX_MCDI_NVRAM_LEN_MAX)]; - size_t outlen; - int rc; - -@@ -828,7 +828,7 @@ fail: - int efx_mcdi_nvram_write(struct efx_nic *efx, unsigned int type, - loff_t offset, const u8 *buffer, size_t length) - { -- u8 inbuf[MC_CMD_NVRAM_WRITE_IN_LEN(length)]; -+ u8 inbuf[MC_CMD_NVRAM_WRITE_IN_LEN(EFX_MCDI_NVRAM_LEN_MAX)]; - int rc; - - MCDI_SET_DWORD(inbuf, NVRAM_WRITE_IN_TYPE, type); -@@ -838,7 +838,8 @@ int efx_mcdi_nvram_write(struct efx_nic *efx, unsigned int type, - - BUILD_BUG_ON(MC_CMD_NVRAM_WRITE_OUT_LEN != 0); - -- rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_WRITE, inbuf, sizeof(inbuf), -+ rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_WRITE, inbuf, -+ ALIGN(MC_CMD_NVRAM_WRITE_IN_LEN(length), 4), - NULL, 0, NULL); - if (rc) - goto fail; -diff --git a/drivers/net/sfc/mcdi.h b/drivers/net/sfc/mcdi.h -index de91672..10ce98f 100644 ---- a/drivers/net/sfc/mcdi.h -+++ b/drivers/net/sfc/mcdi.h -@@ -111,6 +111,7 @@ extern int efx_mcdi_nvram_read(struct efx_nic *efx, unsigned int type, - extern int efx_mcdi_nvram_write(struct efx_nic *efx, unsigned int type, - loff_t offset, const u8 *buffer, - size_t length); -+#define EFX_MCDI_NVRAM_LEN_MAX 128 - extern int efx_mcdi_nvram_erase(struct efx_nic *efx, unsigned int type, - loff_t offset, size_t length); - extern int efx_mcdi_nvram_update_finish(struct efx_nic *efx, -diff --git a/drivers/net/sfc/mtd.c b/drivers/net/sfc/mtd.c -index 3a46452..407bbad 100644 ---- a/drivers/net/sfc/mtd.c -+++ b/drivers/net/sfc/mtd.c -@@ -23,7 +23,6 @@ - #include "mcdi_pcol.h" - - #define EFX_SPI_VERIFY_BUF_LEN 16 --#define EFX_MCDI_CHUNK_LEN 128 - - struct efx_mtd_partition { - struct mtd_info mtd; -@@ -428,7 +427,7 @@ static int siena_mtd_read(struct mtd_info *mtd, loff_t start, - int rc = 0; - - while (offset < end) { -- chunk = min_t(size_t, end - offset, EFX_MCDI_CHUNK_LEN); -+ chunk = min_t(size_t, end - offset, EFX_MCDI_NVRAM_LEN_MAX); - rc = efx_mcdi_nvram_read(efx, part->mcdi.nvram_type, offset, - buffer, chunk); - if (rc) -@@ -491,7 +490,7 @@ static int siena_mtd_write(struct mtd_info *mtd, loff_t start, - } - - while (offset < end) { -- chunk = min_t(size_t, end - offset, EFX_MCDI_CHUNK_LEN); -+ chunk = min_t(size_t, end - offset, EFX_MCDI_NVRAM_LEN_MAX); - rc = efx_mcdi_nvram_write(efx, part->mcdi.nvram_type, offset, - buffer, chunk); - if (rc) --- -1.6.6 - diff --git a/debian/patches/bugfix/all/split-flush_old_exec-into-two-functions.patch b/debian/patches/bugfix/all/split-flush_old_exec-into-two-functions.patch deleted file mode 100644 index 8794a49a4..000000000 --- a/debian/patches/bugfix/all/split-flush_old_exec-into-two-functions.patch +++ /dev/null @@ -1,245 +0,0 @@ -From 221af7f87b97431e3ee21ce4b0e77d5411cf1549 Mon Sep 17 00:00:00 2001 -From: Linus Torvalds -Date: Thu, 28 Jan 2010 22:14:42 -0800 -Subject: Split 'flush_old_exec' into two functions - -From: Linus Torvalds - -commit 221af7f87b97431e3ee21ce4b0e77d5411cf1549 upstream. - -'flush_old_exec()' is the point of no return when doing an execve(), and -it is pretty badly misnamed. It doesn't just flush the old executable -environment, it also starts up the new one. - -Which is very inconvenient for things like setting up the new -personality, because we want the new personality to affect the starting -of the new environment, but at the same time we do _not_ want the new -personality to take effect if flushing the old one fails. - -As a result, the x86-64 '32-bit' personality is actually done using this -insane "I'm going to change the ABI, but I haven't done it yet" bit -(TIF_ABI_PENDING), with SET_PERSONALITY() not actually setting the -personality, but just the "pending" bit, so that "flush_thread()" can do -the actual personality magic. - -This patch in no way changes any of that insanity, but it does split the -'flush_old_exec()' function up into a preparatory part that can fail -(still called flush_old_exec()), and a new part that will actually set -up the new exec environment (setup_new_exec()). All callers are changed -to trivially comply with the new world order. - -Signed-off-by: H. Peter Anvin -Signed-off-by: Linus Torvalds -Signed-off-by: Greg Kroah-Hartman - ---- - arch/sh/kernel/process_64.c | 2 +- - arch/x86/ia32/ia32_aout.c | 10 ++++++---- - fs/binfmt_aout.c | 1 + - fs/binfmt_elf.c | 27 ++------------------------- - fs/binfmt_elf_fdpic.c | 3 +++ - fs/binfmt_flat.c | 1 + - fs/binfmt_som.c | 1 + - fs/exec.c | 26 ++++++++++++++++---------- - include/linux/binfmts.h | 1 + - include/linux/sched.h | 2 +- - 10 files changed, 33 insertions(+), 41 deletions(-) - ---- a/arch/sh/kernel/process_64.c -+++ b/arch/sh/kernel/process_64.c -@@ -367,7 +367,7 @@ void exit_thread(void) - void flush_thread(void) - { - -- /* Called by fs/exec.c (flush_old_exec) to remove traces of a -+ /* Called by fs/exec.c (setup_new_exec) to remove traces of a - * previously running executable. */ - #ifdef CONFIG_SH_FPU - if (last_task_used_math == current) { ---- a/arch/x86/ia32/ia32_aout.c -+++ b/arch/x86/ia32/ia32_aout.c -@@ -308,15 +308,17 @@ static int load_aout_binary(struct linux - if (retval) - return retval; - -- regs->cs = __USER32_CS; -- regs->r8 = regs->r9 = regs->r10 = regs->r11 = regs->r12 = -- regs->r13 = regs->r14 = regs->r15 = 0; -- - /* OK, This is the point of no return */ - set_personality(PER_LINUX); - set_thread_flag(TIF_IA32); - clear_thread_flag(TIF_ABI_PENDING); - -+ setup_new_exec(bprm); -+ -+ regs->cs = __USER32_CS; -+ regs->r8 = regs->r9 = regs->r10 = regs->r11 = regs->r12 = -+ regs->r13 = regs->r14 = regs->r15 = 0; -+ - current->mm->end_code = ex.a_text + - (current->mm->start_code = N_TXTADDR(ex)); - current->mm->end_data = ex.a_data + ---- a/fs/binfmt_aout.c -+++ b/fs/binfmt_aout.c -@@ -263,6 +263,7 @@ static int load_aout_binary(struct linux - #else - set_personality(PER_LINUX); - #endif -+ setup_new_exec(bprm); - - current->mm->end_code = ex.a_text + - (current->mm->start_code = N_TXTADDR(ex)); ---- a/fs/binfmt_elf.c -+++ b/fs/binfmt_elf.c -@@ -662,27 +662,6 @@ static int load_elf_binary(struct linux_ - if (elf_interpreter[elf_ppnt->p_filesz - 1] != '\0') - goto out_free_interp; - -- /* -- * The early SET_PERSONALITY here is so that the lookup -- * for the interpreter happens in the namespace of the -- * to-be-execed image. SET_PERSONALITY can select an -- * alternate root. -- * -- * However, SET_PERSONALITY is NOT allowed to switch -- * this task into the new images's memory mapping -- * policy - that is, TASK_SIZE must still evaluate to -- * that which is appropriate to the execing application. -- * This is because exit_mmap() needs to have TASK_SIZE -- * evaluate to the size of the old image. -- * -- * So if (say) a 64-bit application is execing a 32-bit -- * application it is the architecture's responsibility -- * to defer changing the value of TASK_SIZE until the -- * switch really is going to happen - do this in -- * flush_thread(). - akpm -- */ -- SET_PERSONALITY(loc->elf_ex); -- - interpreter = open_exec(elf_interpreter); - retval = PTR_ERR(interpreter); - if (IS_ERR(interpreter)) -@@ -730,9 +709,6 @@ static int load_elf_binary(struct linux_ - /* Verify the interpreter has a valid arch */ - if (!elf_check_arch(&loc->interp_elf_ex)) - goto out_free_dentry; -- } else { -- /* Executables without an interpreter also need a personality */ -- SET_PERSONALITY(loc->elf_ex); - } - - /* Flush all traces of the currently running executable */ -@@ -752,7 +728,8 @@ static int load_elf_binary(struct linux_ - - if (!(current->personality & ADDR_NO_RANDOMIZE) && randomize_va_space) - current->flags |= PF_RANDOMIZE; -- arch_pick_mmap_layout(current->mm); -+ -+ setup_new_exec(bprm); - - /* Do this so that we can load the interpreter, if need be. We will - change some of these later */ ---- a/fs/binfmt_elf_fdpic.c -+++ b/fs/binfmt_elf_fdpic.c -@@ -321,6 +321,9 @@ static int load_elf_fdpic_binary(struct - set_personality(PER_LINUX_FDPIC); - if (elf_read_implies_exec(&exec_params.hdr, executable_stack)) - current->personality |= READ_IMPLIES_EXEC; -+ -+ setup_new_exec(bprm); -+ - set_binfmt(&elf_fdpic_format); - - current->mm->start_code = 0; ---- a/fs/binfmt_flat.c -+++ b/fs/binfmt_flat.c -@@ -519,6 +519,7 @@ static int load_flat_file(struct linux_b - - /* OK, This is the point of no return */ - set_personality(PER_LINUX_32BIT); -+ setup_new_exec(bprm); - } - - /* ---- a/fs/binfmt_som.c -+++ b/fs/binfmt_som.c -@@ -227,6 +227,7 @@ load_som_binary(struct linux_binprm * bp - /* OK, This is the point of no return */ - current->flags &= ~PF_FORKNOEXEC; - current->personality = PER_HPUX; -+ setup_new_exec(bprm); - - /* Set the task size for HP-UX processes such that - * the gateway page is outside the address space. ---- a/fs/exec.c -+++ b/fs/exec.c -@@ -931,9 +931,7 @@ void set_task_comm(struct task_struct *t - - int flush_old_exec(struct linux_binprm * bprm) - { -- char * name; -- int i, ch, retval; -- char tcomm[sizeof(current->comm)]; -+ int retval; - - /* - * Make sure we have a private signal table and that -@@ -953,6 +951,20 @@ int flush_old_exec(struct linux_binprm * - goto out; - - bprm->mm = NULL; /* We're using it now */ -+ return 0; -+ -+out: -+ return retval; -+} -+EXPORT_SYMBOL(flush_old_exec); -+ -+void setup_new_exec(struct linux_binprm * bprm) -+{ -+ int i, ch; -+ char * name; -+ char tcomm[sizeof(current->comm)]; -+ -+ arch_pick_mmap_layout(current->mm); - - /* This is the point of no return */ - current->sas_ss_sp = current->sas_ss_size = 0; -@@ -1009,14 +1021,8 @@ int flush_old_exec(struct linux_binprm * - - flush_signal_handlers(current, 0); - flush_old_files(current->files); -- -- return 0; -- --out: -- return retval; - } -- --EXPORT_SYMBOL(flush_old_exec); -+EXPORT_SYMBOL(setup_new_exec); - - /* - * Prepare credentials and lock ->cred_guard_mutex. ---- a/include/linux/binfmts.h -+++ b/include/linux/binfmts.h -@@ -101,6 +101,7 @@ extern int prepare_binprm(struct linux_b - extern int __must_check remove_arg_zero(struct linux_binprm *); - extern int search_binary_handler(struct linux_binprm *,struct pt_regs *); - extern int flush_old_exec(struct linux_binprm * bprm); -+extern void setup_new_exec(struct linux_binprm * bprm); - - extern int suid_dumpable; - #define SUID_DUMP_DISABLE 0 /* No setuid dumping */ ---- a/include/linux/sched.h -+++ b/include/linux/sched.h -@@ -1354,7 +1354,7 @@ struct task_struct { - char comm[TASK_COMM_LEN]; /* executable name excluding path - - access with [gs]et_task_comm (which lock - it with task_lock()) -- - initialized normally by flush_old_exec */ -+ - initialized normally by setup_new_exec */ - /* file system info */ - int link_count, total_link_count; - #ifdef CONFIG_SYSVIPC diff --git a/debian/patches/bugfix/all/stable/2.6.32.1.patch b/debian/patches/bugfix/all/stable/2.6.32.1.patch deleted file mode 100644 index 04548f82b..000000000 --- a/debian/patches/bugfix/all/stable/2.6.32.1.patch +++ /dev/null @@ -1,1833 +0,0 @@ -diff --git a/Documentation/filesystems/ext4.txt b/Documentation/filesystems/ext4.txt -index 6d94e06..af6885c 100644 ---- a/Documentation/filesystems/ext4.txt -+++ b/Documentation/filesystems/ext4.txt -@@ -153,8 +153,8 @@ journal_dev=devnum When the external journal device's major/minor numbers - identified through its new major/minor numbers encoded - in devnum. - --noload Don't load the journal on mounting. Note that -- if the filesystem was not unmounted cleanly, -+norecovery Don't load the journal on mounting. Note that -+noload if the filesystem was not unmounted cleanly, - skipping the journal replay will lead to the - filesystem containing inconsistencies that can - lead to any number of problems. -@@ -353,6 +353,12 @@ noauto_da_alloc replacing existing files via patterns such as - system crashes before the delayed allocation - blocks are forced to disk. - -+discard Controls whether ext4 should issue discard/TRIM -+nodiscard(*) commands to the underlying block device when -+ blocks are freed. This is useful for SSD devices -+ and sparse/thinly-provisioned LUNs, but it is off -+ by default until sufficient testing has been done. -+ - Data Mode - ========= - There are 3 different data modes: -diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c -index c968cc3..554626e 100644 ---- a/drivers/scsi/hosts.c -+++ b/drivers/scsi/hosts.c -@@ -180,14 +180,20 @@ void scsi_remove_host(struct Scsi_Host *shost) - EXPORT_SYMBOL(scsi_remove_host); - - /** -- * scsi_add_host - add a scsi host -+ * scsi_add_host_with_dma - add a scsi host with dma device - * @shost: scsi host pointer to add - * @dev: a struct device of type scsi class -+ * @dma_dev: dma device for the host -+ * -+ * Note: You rarely need to worry about this unless you're in a -+ * virtualised host environments, so use the simpler scsi_add_host() -+ * function instead. - * - * Return value: - * 0 on success / != 0 for error - **/ --int scsi_add_host(struct Scsi_Host *shost, struct device *dev) -+int scsi_add_host_with_dma(struct Scsi_Host *shost, struct device *dev, -+ struct device *dma_dev) - { - struct scsi_host_template *sht = shost->hostt; - int error = -EINVAL; -@@ -207,6 +213,7 @@ int scsi_add_host(struct Scsi_Host *shost, struct device *dev) - - if (!shost->shost_gendev.parent) - shost->shost_gendev.parent = dev ? dev : &platform_bus; -+ shost->dma_dev = dma_dev; - - error = device_add(&shost->shost_gendev); - if (error) -@@ -262,7 +269,7 @@ int scsi_add_host(struct Scsi_Host *shost, struct device *dev) - fail: - return error; - } --EXPORT_SYMBOL(scsi_add_host); -+EXPORT_SYMBOL(scsi_add_host_with_dma); - - static void scsi_host_dev_release(struct device *dev) - { -diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c -index 562d8ce..f913f1e 100644 ---- a/drivers/scsi/lpfc/lpfc_init.c -+++ b/drivers/scsi/lpfc/lpfc_init.c -@@ -2408,7 +2408,7 @@ lpfc_create_port(struct lpfc_hba *phba, int instance, struct device *dev) - vport->els_tmofunc.function = lpfc_els_timeout; - vport->els_tmofunc.data = (unsigned long)vport; - -- error = scsi_add_host(shost, dev); -+ error = scsi_add_host_with_dma(shost, dev, &phba->pcidev->dev); - if (error) - goto out_put_shost; - -diff --git a/drivers/scsi/megaraid/megaraid_sas.c b/drivers/scsi/megaraid/megaraid_sas.c -index a39addc..507ccc6 100644 ---- a/drivers/scsi/megaraid/megaraid_sas.c -+++ b/drivers/scsi/megaraid/megaraid_sas.c -@@ -3032,7 +3032,7 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance, - int error = 0, i; - void *sense = NULL; - dma_addr_t sense_handle; -- u32 *sense_ptr; -+ unsigned long *sense_ptr; - - memset(kbuff_arr, 0, sizeof(kbuff_arr)); - -@@ -3109,7 +3109,7 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance, - } - - sense_ptr = -- (u32 *) ((unsigned long)cmd->frame + ioc->sense_off); -+ (unsigned long *) ((unsigned long)cmd->frame + ioc->sense_off); - *sense_ptr = sense_handle; - } - -@@ -3140,8 +3140,8 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance, - * sense_ptr points to the location that has the user - * sense buffer address - */ -- sense_ptr = (u32 *) ((unsigned long)ioc->frame.raw + -- ioc->sense_off); -+ sense_ptr = (unsigned long *) ((unsigned long)ioc->frame.raw + -+ ioc->sense_off); - - if (copy_to_user((void __user *)((unsigned long)(*sense_ptr)), - sense, ioc->sense_len)) { -diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c -index fbcb82a..21e2bc4 100644 ---- a/drivers/scsi/qla2xxx/qla_attr.c -+++ b/drivers/scsi/qla2xxx/qla_attr.c -@@ -1654,7 +1654,8 @@ qla24xx_vport_create(struct fc_vport *fc_vport, bool disable) - fc_vport_set_state(fc_vport, FC_VPORT_LINKDOWN); - } - -- if (scsi_add_host(vha->host, &fc_vport->dev)) { -+ if (scsi_add_host_with_dma(vha->host, &fc_vport->dev, -+ &ha->pdev->dev)) { - DEBUG15(printk("scsi(%ld): scsi_add_host failure for VP[%d].\n", - vha->host_no, vha->vp_idx)); - goto vport_create_failed_2; -diff --git a/drivers/scsi/scsi_lib_dma.c b/drivers/scsi/scsi_lib_dma.c -index ac6855c..dcd1285 100644 ---- a/drivers/scsi/scsi_lib_dma.c -+++ b/drivers/scsi/scsi_lib_dma.c -@@ -23,7 +23,7 @@ int scsi_dma_map(struct scsi_cmnd *cmd) - int nseg = 0; - - if (scsi_sg_count(cmd)) { -- struct device *dev = cmd->device->host->shost_gendev.parent; -+ struct device *dev = cmd->device->host->dma_dev; - - nseg = dma_map_sg(dev, scsi_sglist(cmd), scsi_sg_count(cmd), - cmd->sc_data_direction); -@@ -41,7 +41,7 @@ EXPORT_SYMBOL(scsi_dma_map); - void scsi_dma_unmap(struct scsi_cmnd *cmd) - { - if (scsi_sg_count(cmd)) { -- struct device *dev = cmd->device->host->shost_gendev.parent; -+ struct device *dev = cmd->device->host->dma_dev; - - dma_unmap_sg(dev, scsi_sglist(cmd), scsi_sg_count(cmd), - cmd->sc_data_direction); -diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c -index 1d04189..f3032c9 100644 ---- a/fs/ext4/balloc.c -+++ b/fs/ext4/balloc.c -@@ -761,7 +761,13 @@ static unsigned long ext4_bg_num_gdb_meta(struct super_block *sb, - static unsigned long ext4_bg_num_gdb_nometa(struct super_block *sb, - ext4_group_t group) - { -- return ext4_bg_has_super(sb, group) ? EXT4_SB(sb)->s_gdb_count : 0; -+ if (!ext4_bg_has_super(sb, group)) -+ return 0; -+ -+ if (EXT4_HAS_INCOMPAT_FEATURE(sb,EXT4_FEATURE_INCOMPAT_META_BG)) -+ return le32_to_cpu(EXT4_SB(sb)->s_es->s_first_meta_bg); -+ else -+ return EXT4_SB(sb)->s_gdb_count; - } - - /** -diff --git a/fs/ext4/block_validity.c b/fs/ext4/block_validity.c -index 50784ef..dc79b75 100644 ---- a/fs/ext4/block_validity.c -+++ b/fs/ext4/block_validity.c -@@ -160,7 +160,7 @@ int ext4_setup_system_zone(struct super_block *sb) - if (ext4_bg_has_super(sb, i) && - ((i < 5) || ((i % flex_size) == 0))) - add_system_zone(sbi, ext4_group_first_block_no(sb, i), -- sbi->s_gdb_count + 1); -+ ext4_bg_num_gdb(sb, i) + 1); - gdp = ext4_get_group_desc(sb, i, NULL); - ret = add_system_zone(sbi, ext4_block_bitmap(sb, gdp), 1); - if (ret) -diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h -index 8825515..bd2a9dd 100644 ---- a/fs/ext4/ext4.h -+++ b/fs/ext4/ext4.h -@@ -703,6 +703,13 @@ struct ext4_inode_info { - struct list_head i_aio_dio_complete_list; - /* current io_end structure for async DIO write*/ - ext4_io_end_t *cur_aio_dio; -+ -+ /* -+ * Transactions that contain inode's metadata needed to complete -+ * fsync and fdatasync, respectively. -+ */ -+ tid_t i_sync_tid; -+ tid_t i_datasync_tid; - }; - - /* -@@ -750,6 +757,7 @@ struct ext4_inode_info { - #define EXT4_MOUNT_DELALLOC 0x8000000 /* Delalloc support */ - #define EXT4_MOUNT_DATA_ERR_ABORT 0x10000000 /* Abort on file data write */ - #define EXT4_MOUNT_BLOCK_VALIDITY 0x20000000 /* Block validity checking */ -+#define EXT4_MOUNT_DISCARD 0x40000000 /* Issue DISCARD requests */ - - #define clear_opt(o, opt) o &= ~EXT4_MOUNT_##opt - #define set_opt(o, opt) o |= EXT4_MOUNT_##opt -diff --git a/fs/ext4/ext4_jbd2.h b/fs/ext4/ext4_jbd2.h -index a286598..1892a77 100644 ---- a/fs/ext4/ext4_jbd2.h -+++ b/fs/ext4/ext4_jbd2.h -@@ -49,7 +49,7 @@ - - #define EXT4_DATA_TRANS_BLOCKS(sb) (EXT4_SINGLEDATA_TRANS_BLOCKS(sb) + \ - EXT4_XATTR_TRANS_BLOCKS - 2 + \ -- 2*EXT4_QUOTA_TRANS_BLOCKS(sb)) -+ EXT4_MAXQUOTAS_TRANS_BLOCKS(sb)) - - /* - * Define the number of metadata blocks we need to account to modify data. -@@ -57,7 +57,7 @@ - * This include super block, inode block, quota blocks and xattr blocks - */ - #define EXT4_META_TRANS_BLOCKS(sb) (EXT4_XATTR_TRANS_BLOCKS + \ -- 2*EXT4_QUOTA_TRANS_BLOCKS(sb)) -+ EXT4_MAXQUOTAS_TRANS_BLOCKS(sb)) - - /* Delete operations potentially hit one directory's namespace plus an - * entire inode, plus arbitrary amounts of bitmap/indirection data. Be -@@ -92,6 +92,7 @@ - * but inode, sb and group updates are done only once */ - #define EXT4_QUOTA_INIT_BLOCKS(sb) (test_opt(sb, QUOTA) ? (DQUOT_INIT_ALLOC*\ - (EXT4_SINGLEDATA_TRANS_BLOCKS(sb)-3)+3+DQUOT_INIT_REWRITE) : 0) -+ - #define EXT4_QUOTA_DEL_BLOCKS(sb) (test_opt(sb, QUOTA) ? (DQUOT_DEL_ALLOC*\ - (EXT4_SINGLEDATA_TRANS_BLOCKS(sb)-3)+3+DQUOT_DEL_REWRITE) : 0) - #else -@@ -99,6 +100,9 @@ - #define EXT4_QUOTA_INIT_BLOCKS(sb) 0 - #define EXT4_QUOTA_DEL_BLOCKS(sb) 0 - #endif -+#define EXT4_MAXQUOTAS_TRANS_BLOCKS(sb) (MAXQUOTAS*EXT4_QUOTA_TRANS_BLOCKS(sb)) -+#define EXT4_MAXQUOTAS_INIT_BLOCKS(sb) (MAXQUOTAS*EXT4_QUOTA_INIT_BLOCKS(sb)) -+#define EXT4_MAXQUOTAS_DEL_BLOCKS(sb) (MAXQUOTAS*EXT4_QUOTA_DEL_BLOCKS(sb)) - - int - ext4_mark_iloc_dirty(handle_t *handle, -@@ -254,6 +258,19 @@ static inline int ext4_jbd2_file_inode(handle_t *handle, struct inode *inode) - return 0; - } - -+static inline void ext4_update_inode_fsync_trans(handle_t *handle, -+ struct inode *inode, -+ int datasync) -+{ -+ struct ext4_inode_info *ei = EXT4_I(inode); -+ -+ if (ext4_handle_valid(handle)) { -+ ei->i_sync_tid = handle->h_transaction->t_tid; -+ if (datasync) -+ ei->i_datasync_tid = handle->h_transaction->t_tid; -+ } -+} -+ - /* super.c */ - int ext4_force_commit(struct super_block *sb); - -diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c -index 715264b..8b8bae4 100644 ---- a/fs/ext4/extents.c -+++ b/fs/ext4/extents.c -@@ -1761,7 +1761,9 @@ int ext4_ext_walk_space(struct inode *inode, ext4_lblk_t block, - while (block < last && block != EXT_MAX_BLOCK) { - num = last - block; - /* find extent for this block */ -+ down_read(&EXT4_I(inode)->i_data_sem); - path = ext4_ext_find_extent(inode, block, path); -+ up_read(&EXT4_I(inode)->i_data_sem); - if (IS_ERR(path)) { - err = PTR_ERR(path); - path = NULL; -@@ -2074,7 +2076,7 @@ static int ext4_remove_blocks(handle_t *handle, struct inode *inode, - ext_debug("free last %u blocks starting %llu\n", num, start); - for (i = 0; i < num; i++) { - bh = sb_find_get_block(inode->i_sb, start + i); -- ext4_forget(handle, 0, inode, bh, start + i); -+ ext4_forget(handle, metadata, inode, bh, start + i); - } - ext4_free_blocks(handle, inode, start, num, metadata); - } else if (from == le32_to_cpu(ex->ee_block) -@@ -2167,7 +2169,7 @@ ext4_ext_rm_leaf(handle_t *handle, struct inode *inode, - correct_index = 1; - credits += (ext_depth(inode)) + 1; - } -- credits += 2 * EXT4_QUOTA_TRANS_BLOCKS(inode->i_sb); -+ credits += EXT4_MAXQUOTAS_TRANS_BLOCKS(inode->i_sb); - - err = ext4_ext_truncate_extend_restart(handle, inode, credits); - if (err) -@@ -3064,6 +3066,8 @@ ext4_ext_handle_uninitialized_extents(handle_t *handle, struct inode *inode, - if (flags == EXT4_GET_BLOCKS_DIO_CONVERT_EXT) { - ret = ext4_convert_unwritten_extents_dio(handle, inode, - path); -+ if (ret >= 0) -+ ext4_update_inode_fsync_trans(handle, inode, 1); - goto out2; - } - /* buffered IO case */ -@@ -3091,6 +3095,8 @@ ext4_ext_handle_uninitialized_extents(handle_t *handle, struct inode *inode, - ret = ext4_ext_convert_to_initialized(handle, inode, - path, iblock, - max_blocks); -+ if (ret >= 0) -+ ext4_update_inode_fsync_trans(handle, inode, 1); - out: - if (ret <= 0) { - err = ret; -@@ -3329,10 +3335,16 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode, - allocated = ext4_ext_get_actual_len(&newex); - set_buffer_new(bh_result); - -- /* Cache only when it is _not_ an uninitialized extent */ -- if ((flags & EXT4_GET_BLOCKS_UNINIT_EXT) == 0) -+ /* -+ * Cache the extent and update transaction to commit on fdatasync only -+ * when it is _not_ an uninitialized extent. -+ */ -+ if ((flags & EXT4_GET_BLOCKS_UNINIT_EXT) == 0) { - ext4_ext_put_in_cache(inode, iblock, allocated, newblock, - EXT4_EXT_CACHE_EXTENT); -+ ext4_update_inode_fsync_trans(handle, inode, 1); -+ } else -+ ext4_update_inode_fsync_trans(handle, inode, 0); - out: - if (allocated > max_blocks) - allocated = max_blocks; -@@ -3720,10 +3732,8 @@ int ext4_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, - * Walk the extent tree gathering extent information. - * ext4_ext_fiemap_cb will push extents back to user. - */ -- down_read(&EXT4_I(inode)->i_data_sem); - error = ext4_ext_walk_space(inode, start_blk, len_blks, - ext4_ext_fiemap_cb, fieinfo); -- up_read(&EXT4_I(inode)->i_data_sem); - } - - return error; -diff --git a/fs/ext4/fsync.c b/fs/ext4/fsync.c -index 2b15312..d6049e4 100644 ---- a/fs/ext4/fsync.c -+++ b/fs/ext4/fsync.c -@@ -51,25 +51,30 @@ - int ext4_sync_file(struct file *file, struct dentry *dentry, int datasync) - { - struct inode *inode = dentry->d_inode; -+ struct ext4_inode_info *ei = EXT4_I(inode); - journal_t *journal = EXT4_SB(inode->i_sb)->s_journal; -- int err, ret = 0; -+ int ret; -+ tid_t commit_tid; - - J_ASSERT(ext4_journal_current_handle() == NULL); - - trace_ext4_sync_file(file, dentry, datasync); - -+ if (inode->i_sb->s_flags & MS_RDONLY) -+ return 0; -+ - ret = flush_aio_dio_completed_IO(inode); - if (ret < 0) -- goto out; -+ return ret; -+ -+ if (!journal) -+ return simple_fsync(file, dentry, datasync); -+ - /* -- * data=writeback: -+ * data=writeback,ordered: - * The caller's filemap_fdatawrite()/wait will sync the data. -- * sync_inode() will sync the metadata -- * -- * data=ordered: -- * The caller's filemap_fdatawrite() will write the data and -- * sync_inode() will write the inode if it is dirty. Then the caller's -- * filemap_fdatawait() will wait on the pages. -+ * Metadata is in the journal, we wait for proper transaction to -+ * commit here. - * - * data=journal: - * filemap_fdatawrite won't do anything (the buffers are clean). -@@ -79,32 +84,13 @@ int ext4_sync_file(struct file *file, struct dentry *dentry, int datasync) - * (they were dirtied by commit). But that's OK - the blocks are - * safe in-journal, which is all fsync() needs to ensure. - */ -- if (ext4_should_journal_data(inode)) { -- ret = ext4_force_commit(inode->i_sb); -- goto out; -- } -+ if (ext4_should_journal_data(inode)) -+ return ext4_force_commit(inode->i_sb); - -- if (!journal) -- ret = sync_mapping_buffers(inode->i_mapping); -- -- if (datasync && !(inode->i_state & I_DIRTY_DATASYNC)) -- goto out; -- -- /* -- * The VFS has written the file data. If the inode is unaltered -- * then we need not start a commit. -- */ -- if (inode->i_state & (I_DIRTY_SYNC|I_DIRTY_DATASYNC)) { -- struct writeback_control wbc = { -- .sync_mode = WB_SYNC_ALL, -- .nr_to_write = 0, /* sys_fsync did this */ -- }; -- err = sync_inode(inode, &wbc); -- if (ret == 0) -- ret = err; -- } --out: -- if (journal && (journal->j_flags & JBD2_BARRIER)) -+ commit_tid = datasync ? ei->i_datasync_tid : ei->i_sync_tid; -+ if (jbd2_log_start_commit(journal, commit_tid)) -+ jbd2_log_wait_commit(journal, commit_tid); -+ else if (journal->j_flags & JBD2_BARRIER) - blkdev_issue_flush(inode->i_sb->s_bdev, NULL); - return ret; - } -diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c -index 2c8caa5..1dae9a4 100644 ---- a/fs/ext4/inode.c -+++ b/fs/ext4/inode.c -@@ -1021,10 +1021,12 @@ static int ext4_ind_get_blocks(handle_t *handle, struct inode *inode, - if (!err) - err = ext4_splice_branch(handle, inode, iblock, - partial, indirect_blks, count); -- else -+ if (err) - goto cleanup; - - set_buffer_new(bh_result); -+ -+ ext4_update_inode_fsync_trans(handle, inode, 1); - got_it: - map_bh(bh_result, inode->i_sb, le32_to_cpu(chain[depth-1].key)); - if (count > blocks_to_boundary) -@@ -1052,7 +1054,7 @@ qsize_t ext4_get_reserved_space(struct inode *inode) - EXT4_I(inode)->i_reserved_meta_blocks; - spin_unlock(&EXT4_I(inode)->i_block_reservation_lock); - -- return total; -+ return (total << inode->i_blkbits); - } - /* - * Calculate the number of metadata blocks need to reserve -@@ -1534,6 +1536,16 @@ static int do_journal_get_write_access(handle_t *handle, - return ext4_journal_get_write_access(handle, bh); - } - -+/* -+ * Truncate blocks that were not used by write. We have to truncate the -+ * pagecache as well so that corresponding buffers get properly unmapped. -+ */ -+static void ext4_truncate_failed_write(struct inode *inode) -+{ -+ truncate_inode_pages(inode->i_mapping, inode->i_size); -+ ext4_truncate(inode); -+} -+ - static int ext4_write_begin(struct file *file, struct address_space *mapping, - loff_t pos, unsigned len, unsigned flags, - struct page **pagep, void **fsdata) -@@ -1599,7 +1611,7 @@ retry: - - ext4_journal_stop(handle); - if (pos + len > inode->i_size) { -- ext4_truncate(inode); -+ ext4_truncate_failed_write(inode); - /* - * If truncate failed early the inode might - * still be on the orphan list; we need to -@@ -1709,7 +1721,7 @@ static int ext4_ordered_write_end(struct file *file, - ret = ret2; - - if (pos + len > inode->i_size) { -- ext4_truncate(inode); -+ ext4_truncate_failed_write(inode); - /* - * If truncate failed early the inode might still be - * on the orphan list; we need to make sure the inode -@@ -1751,7 +1763,7 @@ static int ext4_writeback_write_end(struct file *file, - ret = ret2; - - if (pos + len > inode->i_size) { -- ext4_truncate(inode); -+ ext4_truncate_failed_write(inode); - /* - * If truncate failed early the inode might still be - * on the orphan list; we need to make sure the inode -@@ -1814,7 +1826,7 @@ static int ext4_journalled_write_end(struct file *file, - if (!ret) - ret = ret2; - if (pos + len > inode->i_size) { -- ext4_truncate(inode); -+ ext4_truncate_failed_write(inode); - /* - * If truncate failed early the inode might still be - * on the orphan list; we need to make sure the inode -@@ -2788,7 +2800,7 @@ static int ext4_da_writepages_trans_blocks(struct inode *inode) - * number of contiguous block. So we will limit - * number of contiguous block to a sane value - */ -- if (!(inode->i_flags & EXT4_EXTENTS_FL) && -+ if (!(EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL) && - (max_blocks > EXT4_MAX_TRANS_DATA)) - max_blocks = EXT4_MAX_TRANS_DATA; - -@@ -3091,7 +3103,7 @@ retry: - * i_size_read because we hold i_mutex. - */ - if (pos + len > inode->i_size) -- ext4_truncate(inode); -+ ext4_truncate_failed_write(inode); - } - - if (ret == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries)) -@@ -4120,6 +4132,8 @@ static void ext4_clear_blocks(handle_t *handle, struct inode *inode, - __le32 *last) - { - __le32 *p; -+ int is_metadata = S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode); -+ - if (try_to_extend_transaction(handle, inode)) { - if (bh) { - BUFFER_TRACE(bh, "call ext4_handle_dirty_metadata"); -@@ -4150,11 +4164,11 @@ static void ext4_clear_blocks(handle_t *handle, struct inode *inode, - - *p = 0; - tbh = sb_find_get_block(inode->i_sb, nr); -- ext4_forget(handle, 0, inode, tbh, nr); -+ ext4_forget(handle, is_metadata, inode, tbh, nr); - } - } - -- ext4_free_blocks(handle, inode, block_to_free, count, 0); -+ ext4_free_blocks(handle, inode, block_to_free, count, is_metadata); - } - - /** -@@ -4781,8 +4795,8 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino) - struct ext4_iloc iloc; - struct ext4_inode *raw_inode; - struct ext4_inode_info *ei; -- struct buffer_head *bh; - struct inode *inode; -+ journal_t *journal = EXT4_SB(sb)->s_journal; - long ret; - int block; - -@@ -4793,11 +4807,11 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino) - return inode; - - ei = EXT4_I(inode); -+ iloc.bh = 0; - - ret = __ext4_get_inode_loc(inode, &iloc, 0); - if (ret < 0) - goto bad_inode; -- bh = iloc.bh; - raw_inode = ext4_raw_inode(&iloc); - inode->i_mode = le16_to_cpu(raw_inode->i_mode); - inode->i_uid = (uid_t)le16_to_cpu(raw_inode->i_uid_low); -@@ -4820,7 +4834,6 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino) - if (inode->i_mode == 0 || - !(EXT4_SB(inode->i_sb)->s_mount_state & EXT4_ORPHAN_FS)) { - /* this inode is deleted */ -- brelse(bh); - ret = -ESTALE; - goto bad_inode; - } -@@ -4848,11 +4861,35 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino) - ei->i_data[block] = raw_inode->i_block[block]; - INIT_LIST_HEAD(&ei->i_orphan); - -+ /* -+ * Set transaction id's of transactions that have to be committed -+ * to finish f[data]sync. We set them to currently running transaction -+ * as we cannot be sure that the inode or some of its metadata isn't -+ * part of the transaction - the inode could have been reclaimed and -+ * now it is reread from disk. -+ */ -+ if (journal) { -+ transaction_t *transaction; -+ tid_t tid; -+ -+ spin_lock(&journal->j_state_lock); -+ if (journal->j_running_transaction) -+ transaction = journal->j_running_transaction; -+ else -+ transaction = journal->j_committing_transaction; -+ if (transaction) -+ tid = transaction->t_tid; -+ else -+ tid = journal->j_commit_sequence; -+ spin_unlock(&journal->j_state_lock); -+ ei->i_sync_tid = tid; -+ ei->i_datasync_tid = tid; -+ } -+ - if (EXT4_INODE_SIZE(inode->i_sb) > EXT4_GOOD_OLD_INODE_SIZE) { - ei->i_extra_isize = le16_to_cpu(raw_inode->i_extra_isize); - if (EXT4_GOOD_OLD_INODE_SIZE + ei->i_extra_isize > - EXT4_INODE_SIZE(inode->i_sb)) { -- brelse(bh); - ret = -EIO; - goto bad_inode; - } -@@ -4884,10 +4921,7 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino) - - ret = 0; - if (ei->i_file_acl && -- ((ei->i_file_acl < -- (le32_to_cpu(EXT4_SB(sb)->s_es->s_first_data_block) + -- EXT4_SB(sb)->s_gdb_count)) || -- (ei->i_file_acl >= ext4_blocks_count(EXT4_SB(sb)->s_es)))) { -+ !ext4_data_block_valid(EXT4_SB(sb), ei->i_file_acl, 1)) { - ext4_error(sb, __func__, - "bad extended attribute block %llu in inode #%lu", - ei->i_file_acl, inode->i_ino); -@@ -4905,10 +4939,8 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino) - /* Validate block references which are part of inode */ - ret = ext4_check_inode_blockref(inode); - } -- if (ret) { -- brelse(bh); -+ if (ret) - goto bad_inode; -- } - - if (S_ISREG(inode->i_mode)) { - inode->i_op = &ext4_file_inode_operations; -@@ -4936,7 +4968,6 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino) - init_special_inode(inode, inode->i_mode, - new_decode_dev(le32_to_cpu(raw_inode->i_block[1]))); - } else { -- brelse(bh); - ret = -EIO; - ext4_error(inode->i_sb, __func__, - "bogus i_mode (%o) for inode=%lu", -@@ -4949,6 +4980,7 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino) - return inode; - - bad_inode: -+ brelse(iloc.bh); - iget_failed(inode); - return ERR_PTR(ret); - } -@@ -5108,6 +5140,7 @@ static int ext4_do_update_inode(handle_t *handle, - err = rc; - ei->i_state &= ~EXT4_STATE_NEW; - -+ ext4_update_inode_fsync_trans(handle, inode, 0); - out_brelse: - brelse(bh); - ext4_std_error(inode->i_sb, err); -@@ -5227,8 +5260,8 @@ int ext4_setattr(struct dentry *dentry, struct iattr *attr) - - /* (user+group)*(old+new) structure, inode write (sb, - * inode block, ? - but truncate inode update has it) */ -- handle = ext4_journal_start(inode, 2*(EXT4_QUOTA_INIT_BLOCKS(inode->i_sb)+ -- EXT4_QUOTA_DEL_BLOCKS(inode->i_sb))+3); -+ handle = ext4_journal_start(inode, (EXT4_MAXQUOTAS_INIT_BLOCKS(inode->i_sb)+ -+ EXT4_MAXQUOTAS_DEL_BLOCKS(inode->i_sb))+3); - if (IS_ERR(handle)) { - error = PTR_ERR(handle); - goto err_out; -diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c -index c1cdf61..b63d193 100644 ---- a/fs/ext4/ioctl.c -+++ b/fs/ext4/ioctl.c -@@ -221,31 +221,38 @@ setversion_out: - struct file *donor_filp; - int err; - -+ if (!(filp->f_mode & FMODE_READ) || -+ !(filp->f_mode & FMODE_WRITE)) -+ return -EBADF; -+ - if (copy_from_user(&me, - (struct move_extent __user *)arg, sizeof(me))) - return -EFAULT; -+ me.moved_len = 0; - - donor_filp = fget(me.donor_fd); - if (!donor_filp) - return -EBADF; - -- if (!capable(CAP_DAC_OVERRIDE)) { -- if ((current->real_cred->fsuid != inode->i_uid) || -- !(inode->i_mode & S_IRUSR) || -- !(donor_filp->f_dentry->d_inode->i_mode & -- S_IRUSR)) { -- fput(donor_filp); -- return -EACCES; -- } -+ if (!(donor_filp->f_mode & FMODE_WRITE)) { -+ err = -EBADF; -+ goto mext_out; - } - -+ err = mnt_want_write(filp->f_path.mnt); -+ if (err) -+ goto mext_out; -+ - err = ext4_move_extents(filp, donor_filp, me.orig_start, - me.donor_start, me.len, &me.moved_len); -- fput(donor_filp); -+ mnt_drop_write(filp->f_path.mnt); -+ if (me.moved_len > 0) -+ file_remove_suid(donor_filp); - - if (copy_to_user((struct move_extent *)arg, &me, sizeof(me))) -- return -EFAULT; -- -+ err = -EFAULT; -+mext_out: -+ fput(donor_filp); - return err; - } - -diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c -index bba1282..7d71148 100644 ---- a/fs/ext4/mballoc.c -+++ b/fs/ext4/mballoc.c -@@ -2529,7 +2529,6 @@ static void release_blocks_on_commit(journal_t *journal, transaction_t *txn) - struct ext4_group_info *db; - int err, count = 0, count2 = 0; - struct ext4_free_data *entry; -- ext4_fsblk_t discard_block; - struct list_head *l, *ltmp; - - list_for_each_safe(l, ltmp, &txn->t_private_list) { -@@ -2559,13 +2558,19 @@ static void release_blocks_on_commit(journal_t *journal, transaction_t *txn) - page_cache_release(e4b.bd_bitmap_page); - } - ext4_unlock_group(sb, entry->group); -- discard_block = (ext4_fsblk_t) entry->group * EXT4_BLOCKS_PER_GROUP(sb) -- + entry->start_blk -- + le32_to_cpu(EXT4_SB(sb)->s_es->s_first_data_block); -- trace_ext4_discard_blocks(sb, (unsigned long long)discard_block, -- entry->count); -- sb_issue_discard(sb, discard_block, entry->count); -- -+ if (test_opt(sb, DISCARD)) { -+ ext4_fsblk_t discard_block; -+ struct ext4_super_block *es = EXT4_SB(sb)->s_es; -+ -+ discard_block = (ext4_fsblk_t)entry->group * -+ EXT4_BLOCKS_PER_GROUP(sb) -+ + entry->start_blk -+ + le32_to_cpu(es->s_first_data_block); -+ trace_ext4_discard_blocks(sb, -+ (unsigned long long)discard_block, -+ entry->count); -+ sb_issue_discard(sb, discard_block, entry->count); -+ } - kmem_cache_free(ext4_free_ext_cachep, entry); - ext4_mb_release_desc(&e4b); - } -@@ -3006,6 +3011,24 @@ static void ext4_mb_collect_stats(struct ext4_allocation_context *ac) - } - - /* -+ * Called on failure; free up any blocks from the inode PA for this -+ * context. We don't need this for MB_GROUP_PA because we only change -+ * pa_free in ext4_mb_release_context(), but on failure, we've already -+ * zeroed out ac->ac_b_ex.fe_len, so group_pa->pa_free is not changed. -+ */ -+static void ext4_discard_allocated_blocks(struct ext4_allocation_context *ac) -+{ -+ struct ext4_prealloc_space *pa = ac->ac_pa; -+ int len; -+ -+ if (pa && pa->pa_type == MB_INODE_PA) { -+ len = ac->ac_b_ex.fe_len; -+ pa->pa_free += len; -+ } -+ -+} -+ -+/* - * use blocks preallocated to inode - */ - static void ext4_mb_use_inode_pa(struct ext4_allocation_context *ac, -@@ -4290,6 +4313,7 @@ repeat: - ac->ac_status = AC_STATUS_CONTINUE; - goto repeat; - } else if (*errp) { -+ ext4_discard_allocated_blocks(ac); - ac->ac_b_ex.fe_len = 0; - ar->len = 0; - ext4_mb_show_ac(ac); -diff --git a/fs/ext4/migrate.c b/fs/ext4/migrate.c -index a93d5b8..8646149 100644 ---- a/fs/ext4/migrate.c -+++ b/fs/ext4/migrate.c -@@ -238,7 +238,7 @@ static int extend_credit_for_blkdel(handle_t *handle, struct inode *inode) - * So allocate a credit of 3. We may update - * quota (user and group). - */ -- needed = 3 + 2*EXT4_QUOTA_TRANS_BLOCKS(inode->i_sb); -+ needed = 3 + EXT4_MAXQUOTAS_TRANS_BLOCKS(inode->i_sb); - - if (ext4_journal_extend(handle, needed) != 0) - retval = ext4_journal_restart(handle, needed); -@@ -477,7 +477,7 @@ int ext4_ext_migrate(struct inode *inode) - handle = ext4_journal_start(inode, - EXT4_DATA_TRANS_BLOCKS(inode->i_sb) + - EXT4_INDEX_EXTRA_TRANS_BLOCKS + 3 + -- 2 * EXT4_QUOTA_INIT_BLOCKS(inode->i_sb) -+ EXT4_MAXQUOTAS_INIT_BLOCKS(inode->i_sb) - + 1); - if (IS_ERR(handle)) { - retval = PTR_ERR(handle); -diff --git a/fs/ext4/move_extent.c b/fs/ext4/move_extent.c -index 25b6b14..f5b03a1 100644 ---- a/fs/ext4/move_extent.c -+++ b/fs/ext4/move_extent.c -@@ -77,12 +77,14 @@ static int - mext_next_extent(struct inode *inode, struct ext4_ext_path *path, - struct ext4_extent **extent) - { -+ struct ext4_extent_header *eh; - int ppos, leaf_ppos = path->p_depth; - - ppos = leaf_ppos; - if (EXT_LAST_EXTENT(path[ppos].p_hdr) > path[ppos].p_ext) { - /* leaf block */ - *extent = ++path[ppos].p_ext; -+ path[ppos].p_block = ext_pblock(path[ppos].p_ext); - return 0; - } - -@@ -119,9 +121,18 @@ mext_next_extent(struct inode *inode, struct ext4_ext_path *path, - ext_block_hdr(path[cur_ppos+1].p_bh); - } - -+ path[leaf_ppos].p_ext = *extent = NULL; -+ -+ eh = path[leaf_ppos].p_hdr; -+ if (le16_to_cpu(eh->eh_entries) == 0) -+ /* empty leaf is found */ -+ return -ENODATA; -+ - /* leaf block */ - path[leaf_ppos].p_ext = *extent = - EXT_FIRST_EXTENT(path[leaf_ppos].p_hdr); -+ path[leaf_ppos].p_block = -+ ext_pblock(path[leaf_ppos].p_ext); - return 0; - } - } -@@ -155,40 +166,15 @@ mext_check_null_inode(struct inode *inode1, struct inode *inode2, - } - - /** -- * mext_double_down_read - Acquire two inodes' read semaphore -- * -- * @orig_inode: original inode structure -- * @donor_inode: donor inode structure -- * Acquire read semaphore of the two inodes (orig and donor) by i_ino order. -- */ --static void --mext_double_down_read(struct inode *orig_inode, struct inode *donor_inode) --{ -- struct inode *first = orig_inode, *second = donor_inode; -- -- /* -- * Use the inode number to provide the stable locking order instead -- * of its address, because the C language doesn't guarantee you can -- * compare pointers that don't come from the same array. -- */ -- if (donor_inode->i_ino < orig_inode->i_ino) { -- first = donor_inode; -- second = orig_inode; -- } -- -- down_read(&EXT4_I(first)->i_data_sem); -- down_read(&EXT4_I(second)->i_data_sem); --} -- --/** -- * mext_double_down_write - Acquire two inodes' write semaphore -+ * double_down_write_data_sem - Acquire two inodes' write lock of i_data_sem - * - * @orig_inode: original inode structure - * @donor_inode: donor inode structure -- * Acquire write semaphore of the two inodes (orig and donor) by i_ino order. -+ * Acquire write lock of i_data_sem of the two inodes (orig and donor) by -+ * i_ino order. - */ - static void --mext_double_down_write(struct inode *orig_inode, struct inode *donor_inode) -+double_down_write_data_sem(struct inode *orig_inode, struct inode *donor_inode) - { - struct inode *first = orig_inode, *second = donor_inode; - -@@ -203,32 +189,18 @@ mext_double_down_write(struct inode *orig_inode, struct inode *donor_inode) - } - - down_write(&EXT4_I(first)->i_data_sem); -- down_write(&EXT4_I(second)->i_data_sem); -+ down_write_nested(&EXT4_I(second)->i_data_sem, SINGLE_DEPTH_NESTING); - } - - /** -- * mext_double_up_read - Release two inodes' read semaphore -+ * double_up_write_data_sem - Release two inodes' write lock of i_data_sem - * - * @orig_inode: original inode structure to be released its lock first - * @donor_inode: donor inode structure to be released its lock second -- * Release read semaphore of two inodes (orig and donor). -+ * Release write lock of i_data_sem of two inodes (orig and donor). - */ - static void --mext_double_up_read(struct inode *orig_inode, struct inode *donor_inode) --{ -- up_read(&EXT4_I(orig_inode)->i_data_sem); -- up_read(&EXT4_I(donor_inode)->i_data_sem); --} -- --/** -- * mext_double_up_write - Release two inodes' write semaphore -- * -- * @orig_inode: original inode structure to be released its lock first -- * @donor_inode: donor inode structure to be released its lock second -- * Release write semaphore of two inodes (orig and donor). -- */ --static void --mext_double_up_write(struct inode *orig_inode, struct inode *donor_inode) -+double_up_write_data_sem(struct inode *orig_inode, struct inode *donor_inode) - { - up_write(&EXT4_I(orig_inode)->i_data_sem); - up_write(&EXT4_I(donor_inode)->i_data_sem); -@@ -661,6 +633,7 @@ mext_calc_swap_extents(struct ext4_extent *tmp_dext, - * @donor_inode: donor inode - * @from: block offset of orig_inode - * @count: block count to be replaced -+ * @err: pointer to save return value - * - * Replace original inode extents and donor inode extents page by page. - * We implement this replacement in the following three steps: -@@ -671,33 +644,33 @@ mext_calc_swap_extents(struct ext4_extent *tmp_dext, - * 3. Change the block information of donor inode to point at the saved - * original inode blocks in the dummy extents. - * -- * Return 0 on success, or a negative error value on failure. -+ * Return replaced block count. - */ - static int - mext_replace_branches(handle_t *handle, struct inode *orig_inode, - struct inode *donor_inode, ext4_lblk_t from, -- ext4_lblk_t count) -+ ext4_lblk_t count, int *err) - { - struct ext4_ext_path *orig_path = NULL; - struct ext4_ext_path *donor_path = NULL; - struct ext4_extent *oext, *dext; - struct ext4_extent tmp_dext, tmp_oext; - ext4_lblk_t orig_off = from, donor_off = from; -- int err = 0; - int depth; - int replaced_count = 0; - int dext_alen; - -- mext_double_down_write(orig_inode, donor_inode); -+ /* Protect extent trees against block allocations via delalloc */ -+ double_down_write_data_sem(orig_inode, donor_inode); - - /* Get the original extent for the block "orig_off" */ -- err = get_ext_path(orig_inode, orig_off, &orig_path); -- if (err) -+ *err = get_ext_path(orig_inode, orig_off, &orig_path); -+ if (*err) - goto out; - - /* Get the donor extent for the head */ -- err = get_ext_path(donor_inode, donor_off, &donor_path); -- if (err) -+ *err = get_ext_path(donor_inode, donor_off, &donor_path); -+ if (*err) - goto out; - depth = ext_depth(orig_inode); - oext = orig_path[depth].p_ext; -@@ -707,9 +680,9 @@ mext_replace_branches(handle_t *handle, struct inode *orig_inode, - dext = donor_path[depth].p_ext; - tmp_dext = *dext; - -- err = mext_calc_swap_extents(&tmp_dext, &tmp_oext, orig_off, -+ *err = mext_calc_swap_extents(&tmp_dext, &tmp_oext, orig_off, - donor_off, count); -- if (err) -+ if (*err) - goto out; - - /* Loop for the donor extents */ -@@ -718,7 +691,7 @@ mext_replace_branches(handle_t *handle, struct inode *orig_inode, - if (!dext) { - ext4_error(donor_inode->i_sb, __func__, - "The extent for donor must be found"); -- err = -EIO; -+ *err = -EIO; - goto out; - } else if (donor_off != le32_to_cpu(tmp_dext.ee_block)) { - ext4_error(donor_inode->i_sb, __func__, -@@ -726,20 +699,20 @@ mext_replace_branches(handle_t *handle, struct inode *orig_inode, - "extent(%u) should be equal", - donor_off, - le32_to_cpu(tmp_dext.ee_block)); -- err = -EIO; -+ *err = -EIO; - goto out; - } - - /* Set donor extent to orig extent */ -- err = mext_leaf_block(handle, orig_inode, -+ *err = mext_leaf_block(handle, orig_inode, - orig_path, &tmp_dext, &orig_off); -- if (err < 0) -+ if (*err) - goto out; - - /* Set orig extent to donor extent */ -- err = mext_leaf_block(handle, donor_inode, -+ *err = mext_leaf_block(handle, donor_inode, - donor_path, &tmp_oext, &donor_off); -- if (err < 0) -+ if (*err) - goto out; - - dext_alen = ext4_ext_get_actual_len(&tmp_dext); -@@ -753,35 +726,25 @@ mext_replace_branches(handle_t *handle, struct inode *orig_inode, - - if (orig_path) - ext4_ext_drop_refs(orig_path); -- err = get_ext_path(orig_inode, orig_off, &orig_path); -- if (err) -+ *err = get_ext_path(orig_inode, orig_off, &orig_path); -+ if (*err) - goto out; - depth = ext_depth(orig_inode); - oext = orig_path[depth].p_ext; -- if (le32_to_cpu(oext->ee_block) + -- ext4_ext_get_actual_len(oext) <= orig_off) { -- err = 0; -- goto out; -- } - tmp_oext = *oext; - - if (donor_path) - ext4_ext_drop_refs(donor_path); -- err = get_ext_path(donor_inode, donor_off, &donor_path); -- if (err) -+ *err = get_ext_path(donor_inode, donor_off, &donor_path); -+ if (*err) - goto out; - depth = ext_depth(donor_inode); - dext = donor_path[depth].p_ext; -- if (le32_to_cpu(dext->ee_block) + -- ext4_ext_get_actual_len(dext) <= donor_off) { -- err = 0; -- goto out; -- } - tmp_dext = *dext; - -- err = mext_calc_swap_extents(&tmp_dext, &tmp_oext, orig_off, -+ *err = mext_calc_swap_extents(&tmp_dext, &tmp_oext, orig_off, - donor_off, count - replaced_count); -- if (err) -+ if (*err) - goto out; - } - -@@ -795,8 +758,12 @@ out: - kfree(donor_path); - } - -- mext_double_up_write(orig_inode, donor_inode); -- return err; -+ ext4_ext_invalidate_cache(orig_inode); -+ ext4_ext_invalidate_cache(donor_inode); -+ -+ double_up_write_data_sem(orig_inode, donor_inode); -+ -+ return replaced_count; - } - - /** -@@ -808,16 +775,17 @@ out: - * @data_offset_in_page: block index where data swapping starts - * @block_len_in_page: the number of blocks to be swapped - * @uninit: orig extent is uninitialized or not -+ * @err: pointer to save return value - * - * Save the data in original inode blocks and replace original inode extents - * with donor inode extents by calling mext_replace_branches(). -- * Finally, write out the saved data in new original inode blocks. Return 0 -- * on success, or a negative error value on failure. -+ * Finally, write out the saved data in new original inode blocks. Return -+ * replaced block count. - */ - static int - move_extent_per_page(struct file *o_filp, struct inode *donor_inode, - pgoff_t orig_page_offset, int data_offset_in_page, -- int block_len_in_page, int uninit) -+ int block_len_in_page, int uninit, int *err) - { - struct inode *orig_inode = o_filp->f_dentry->d_inode; - struct address_space *mapping = orig_inode->i_mapping; -@@ -829,9 +797,11 @@ move_extent_per_page(struct file *o_filp, struct inode *donor_inode, - long long offs = orig_page_offset << PAGE_CACHE_SHIFT; - unsigned long blocksize = orig_inode->i_sb->s_blocksize; - unsigned int w_flags = 0; -- unsigned int tmp_data_len, data_len; -+ unsigned int tmp_data_size, data_size, replaced_size; - void *fsdata; -- int ret, i, jblocks; -+ int i, jblocks; -+ int err2 = 0; -+ int replaced_count = 0; - int blocks_per_page = PAGE_CACHE_SIZE >> orig_inode->i_blkbits; - - /* -@@ -841,8 +811,8 @@ move_extent_per_page(struct file *o_filp, struct inode *donor_inode, - jblocks = ext4_writepage_trans_blocks(orig_inode) * 2; - handle = ext4_journal_start(orig_inode, jblocks); - if (IS_ERR(handle)) { -- ret = PTR_ERR(handle); -- return ret; -+ *err = PTR_ERR(handle); -+ return 0; - } - - if (segment_eq(get_fs(), KERNEL_DS)) -@@ -858,39 +828,36 @@ move_extent_per_page(struct file *o_filp, struct inode *donor_inode, - * Just swap data blocks between orig and donor. - */ - if (uninit) { -- ret = mext_replace_branches(handle, orig_inode, -- donor_inode, orig_blk_offset, -- block_len_in_page); -- -- /* Clear the inode cache not to refer to the old data */ -- ext4_ext_invalidate_cache(orig_inode); -- ext4_ext_invalidate_cache(donor_inode); -+ replaced_count = mext_replace_branches(handle, orig_inode, -+ donor_inode, orig_blk_offset, -+ block_len_in_page, err); - goto out2; - } - - offs = (long long)orig_blk_offset << orig_inode->i_blkbits; - -- /* Calculate data_len */ -+ /* Calculate data_size */ - if ((orig_blk_offset + block_len_in_page - 1) == - ((orig_inode->i_size - 1) >> orig_inode->i_blkbits)) { - /* Replace the last block */ -- tmp_data_len = orig_inode->i_size & (blocksize - 1); -+ tmp_data_size = orig_inode->i_size & (blocksize - 1); - /* -- * If data_len equal zero, it shows data_len is multiples of -+ * If data_size equal zero, it shows data_size is multiples of - * blocksize. So we set appropriate value. - */ -- if (tmp_data_len == 0) -- tmp_data_len = blocksize; -+ if (tmp_data_size == 0) -+ tmp_data_size = blocksize; - -- data_len = tmp_data_len + -+ data_size = tmp_data_size + - ((block_len_in_page - 1) << orig_inode->i_blkbits); -- } else { -- data_len = block_len_in_page << orig_inode->i_blkbits; -- } -+ } else -+ data_size = block_len_in_page << orig_inode->i_blkbits; -+ -+ replaced_size = data_size; - -- ret = a_ops->write_begin(o_filp, mapping, offs, data_len, w_flags, -+ *err = a_ops->write_begin(o_filp, mapping, offs, data_size, w_flags, - &page, &fsdata); -- if (unlikely(ret < 0)) -+ if (unlikely(*err < 0)) - goto out; - - if (!PageUptodate(page)) { -@@ -911,14 +878,17 @@ move_extent_per_page(struct file *o_filp, struct inode *donor_inode, - /* Release old bh and drop refs */ - try_to_release_page(page, 0); - -- ret = mext_replace_branches(handle, orig_inode, donor_inode, -- orig_blk_offset, block_len_in_page); -- if (ret < 0) -- goto out; -- -- /* Clear the inode cache not to refer to the old data */ -- ext4_ext_invalidate_cache(orig_inode); -- ext4_ext_invalidate_cache(donor_inode); -+ replaced_count = mext_replace_branches(handle, orig_inode, donor_inode, -+ orig_blk_offset, block_len_in_page, -+ &err2); -+ if (err2) { -+ if (replaced_count) { -+ block_len_in_page = replaced_count; -+ replaced_size = -+ block_len_in_page << orig_inode->i_blkbits; -+ } else -+ goto out; -+ } - - if (!page_has_buffers(page)) - create_empty_buffers(page, 1 << orig_inode->i_blkbits, 0); -@@ -928,16 +898,16 @@ move_extent_per_page(struct file *o_filp, struct inode *donor_inode, - bh = bh->b_this_page; - - for (i = 0; i < block_len_in_page; i++) { -- ret = ext4_get_block(orig_inode, -+ *err = ext4_get_block(orig_inode, - (sector_t)(orig_blk_offset + i), bh, 0); -- if (ret < 0) -+ if (*err < 0) - goto out; - - if (bh->b_this_page != NULL) - bh = bh->b_this_page; - } - -- ret = a_ops->write_end(o_filp, mapping, offs, data_len, data_len, -+ *err = a_ops->write_end(o_filp, mapping, offs, data_size, replaced_size, - page, fsdata); - page = NULL; - -@@ -951,7 +921,10 @@ out: - out2: - ext4_journal_stop(handle); - -- return ret < 0 ? ret : 0; -+ if (err2) -+ *err = err2; -+ -+ return replaced_count; - } - - /** -@@ -962,7 +935,6 @@ out2: - * @orig_start: logical start offset in block for orig - * @donor_start: logical start offset in block for donor - * @len: the number of blocks to be moved -- * @moved_len: moved block length - * - * Check the arguments of ext4_move_extents() whether the files can be - * exchanged with each other. -@@ -970,8 +942,8 @@ out2: - */ - static int - mext_check_arguments(struct inode *orig_inode, -- struct inode *donor_inode, __u64 orig_start, -- __u64 donor_start, __u64 *len, __u64 moved_len) -+ struct inode *donor_inode, __u64 orig_start, -+ __u64 donor_start, __u64 *len) - { - ext4_lblk_t orig_blocks, donor_blocks; - unsigned int blkbits = orig_inode->i_blkbits; -@@ -985,6 +957,13 @@ mext_check_arguments(struct inode *orig_inode, - return -EINVAL; - } - -+ if (donor_inode->i_mode & (S_ISUID|S_ISGID)) { -+ ext4_debug("ext4 move extent: suid or sgid is set" -+ " to donor file [ino:orig %lu, donor %lu]\n", -+ orig_inode->i_ino, donor_inode->i_ino); -+ return -EINVAL; -+ } -+ - /* Ext4 move extent does not support swapfile */ - if (IS_SWAPFILE(orig_inode) || IS_SWAPFILE(donor_inode)) { - ext4_debug("ext4 move extent: The argument files should " -@@ -1025,13 +1004,6 @@ mext_check_arguments(struct inode *orig_inode, - return -EINVAL; - } - -- if (moved_len) { -- ext4_debug("ext4 move extent: moved_len should be 0 " -- "[ino:orig %lu, donor %lu]\n", orig_inode->i_ino, -- donor_inode->i_ino); -- return -EINVAL; -- } -- - if ((orig_start > EXT_MAX_BLOCK) || - (donor_start > EXT_MAX_BLOCK) || - (*len > EXT_MAX_BLOCK) || -@@ -1232,16 +1204,16 @@ ext4_move_extents(struct file *o_filp, struct file *d_filp, - return -EINVAL; - } - -- /* protect orig and donor against a truncate */ -+ /* Protect orig and donor inodes against a truncate */ - ret1 = mext_inode_double_lock(orig_inode, donor_inode); - if (ret1 < 0) - return ret1; - -- mext_double_down_read(orig_inode, donor_inode); -+ /* Protect extent tree against block allocations via delalloc */ -+ double_down_write_data_sem(orig_inode, donor_inode); - /* Check the filesystem environment whether move_extent can be done */ - ret1 = mext_check_arguments(orig_inode, donor_inode, orig_start, -- donor_start, &len, *moved_len); -- mext_double_up_read(orig_inode, donor_inode); -+ donor_start, &len); - if (ret1) - goto out; - -@@ -1355,36 +1327,39 @@ ext4_move_extents(struct file *o_filp, struct file *d_filp, - seq_start = le32_to_cpu(ext_cur->ee_block); - rest_blocks = seq_blocks; - -- /* Discard preallocations of two inodes */ -- down_write(&EXT4_I(orig_inode)->i_data_sem); -- ext4_discard_preallocations(orig_inode); -- up_write(&EXT4_I(orig_inode)->i_data_sem); -- -- down_write(&EXT4_I(donor_inode)->i_data_sem); -- ext4_discard_preallocations(donor_inode); -- up_write(&EXT4_I(donor_inode)->i_data_sem); -+ /* -+ * Up semaphore to avoid following problems: -+ * a. transaction deadlock among ext4_journal_start, -+ * ->write_begin via pagefault, and jbd2_journal_commit -+ * b. racing with ->readpage, ->write_begin, and ext4_get_block -+ * in move_extent_per_page -+ */ -+ double_up_write_data_sem(orig_inode, donor_inode); - - while (orig_page_offset <= seq_end_page) { - - /* Swap original branches with new branches */ -- ret1 = move_extent_per_page(o_filp, donor_inode, -+ block_len_in_page = move_extent_per_page( -+ o_filp, donor_inode, - orig_page_offset, - data_offset_in_page, -- block_len_in_page, uninit); -- if (ret1 < 0) -- goto out; -- orig_page_offset++; -+ block_len_in_page, uninit, -+ &ret1); -+ - /* Count how many blocks we have exchanged */ - *moved_len += block_len_in_page; -+ if (ret1 < 0) -+ break; - if (*moved_len > len) { - ext4_error(orig_inode->i_sb, __func__, - "We replaced blocks too much! " - "sum of replaced: %llu requested: %llu", - *moved_len, len); - ret1 = -EIO; -- goto out; -+ break; - } - -+ orig_page_offset++; - data_offset_in_page = 0; - rest_blocks -= block_len_in_page; - if (rest_blocks > blocks_per_page) -@@ -1393,6 +1368,10 @@ ext4_move_extents(struct file *o_filp, struct file *d_filp, - block_len_in_page = rest_blocks; - } - -+ double_down_write_data_sem(orig_inode, donor_inode); -+ if (ret1 < 0) -+ break; -+ - /* Decrease buffer counter */ - if (holecheck_path) - ext4_ext_drop_refs(holecheck_path); -@@ -1414,6 +1393,11 @@ ext4_move_extents(struct file *o_filp, struct file *d_filp, - - } - out: -+ if (*moved_len) { -+ ext4_discard_preallocations(orig_inode); -+ ext4_discard_preallocations(donor_inode); -+ } -+ - if (orig_path) { - ext4_ext_drop_refs(orig_path); - kfree(orig_path); -@@ -1422,7 +1406,7 @@ out: - ext4_ext_drop_refs(holecheck_path); - kfree(holecheck_path); - } -- -+ double_up_write_data_sem(orig_inode, donor_inode); - ret2 = mext_inode_double_unlock(orig_inode, donor_inode); - - if (ret1) -diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c -index 6d2c1b8..17a17e1 100644 ---- a/fs/ext4/namei.c -+++ b/fs/ext4/namei.c -@@ -1292,9 +1292,6 @@ errout: - * add_dirent_to_buf will attempt search the directory block for - * space. It will return -ENOSPC if no space is available, and -EIO - * and -EEXIST if directory entry already exists. -- * -- * NOTE! bh is NOT released in the case where ENOSPC is returned. In -- * all other cases bh is released. - */ - static int add_dirent_to_buf(handle_t *handle, struct dentry *dentry, - struct inode *inode, struct ext4_dir_entry_2 *de, -@@ -1315,14 +1312,10 @@ static int add_dirent_to_buf(handle_t *handle, struct dentry *dentry, - top = bh->b_data + blocksize - reclen; - while ((char *) de <= top) { - if (!ext4_check_dir_entry("ext4_add_entry", dir, de, -- bh, offset)) { -- brelse(bh); -+ bh, offset)) - return -EIO; -- } -- if (ext4_match(namelen, name, de)) { -- brelse(bh); -+ if (ext4_match(namelen, name, de)) - return -EEXIST; -- } - nlen = EXT4_DIR_REC_LEN(de->name_len); - rlen = ext4_rec_len_from_disk(de->rec_len, blocksize); - if ((de->inode? rlen - nlen: rlen) >= reclen) -@@ -1337,7 +1330,6 @@ static int add_dirent_to_buf(handle_t *handle, struct dentry *dentry, - err = ext4_journal_get_write_access(handle, bh); - if (err) { - ext4_std_error(dir->i_sb, err); -- brelse(bh); - return err; - } - -@@ -1377,7 +1369,6 @@ static int add_dirent_to_buf(handle_t *handle, struct dentry *dentry, - err = ext4_handle_dirty_metadata(handle, dir, bh); - if (err) - ext4_std_error(dir->i_sb, err); -- brelse(bh); - return 0; - } - -@@ -1471,7 +1462,9 @@ static int make_indexed_dir(handle_t *handle, struct dentry *dentry, - if (!(de)) - return retval; - -- return add_dirent_to_buf(handle, dentry, inode, de, bh); -+ retval = add_dirent_to_buf(handle, dentry, inode, de, bh); -+ brelse(bh); -+ return retval; - } - - /* -@@ -1514,8 +1507,10 @@ static int ext4_add_entry(handle_t *handle, struct dentry *dentry, - if(!bh) - return retval; - retval = add_dirent_to_buf(handle, dentry, inode, NULL, bh); -- if (retval != -ENOSPC) -+ if (retval != -ENOSPC) { -+ brelse(bh); - return retval; -+ } - - if (blocks == 1 && !dx_fallback && - EXT4_HAS_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_DIR_INDEX)) -@@ -1528,7 +1523,9 @@ static int ext4_add_entry(handle_t *handle, struct dentry *dentry, - de = (struct ext4_dir_entry_2 *) bh->b_data; - de->inode = 0; - de->rec_len = ext4_rec_len_to_disk(blocksize, blocksize); -- return add_dirent_to_buf(handle, dentry, inode, de, bh); -+ retval = add_dirent_to_buf(handle, dentry, inode, de, bh); -+ brelse(bh); -+ return retval; - } - - /* -@@ -1561,10 +1558,8 @@ static int ext4_dx_add_entry(handle_t *handle, struct dentry *dentry, - goto journal_error; - - err = add_dirent_to_buf(handle, dentry, inode, NULL, bh); -- if (err != -ENOSPC) { -- bh = NULL; -+ if (err != -ENOSPC) - goto cleanup; -- } - - /* Block full, should compress but for now just split */ - dxtrace(printk(KERN_DEBUG "using %u of %u node entries\n", -@@ -1657,7 +1652,6 @@ static int ext4_dx_add_entry(handle_t *handle, struct dentry *dentry, - if (!de) - goto cleanup; - err = add_dirent_to_buf(handle, dentry, inode, de, bh); -- bh = NULL; - goto cleanup; - - journal_error: -@@ -1775,7 +1769,7 @@ static int ext4_create(struct inode *dir, struct dentry *dentry, int mode, - retry: - handle = ext4_journal_start(dir, EXT4_DATA_TRANS_BLOCKS(dir->i_sb) + - EXT4_INDEX_EXTRA_TRANS_BLOCKS + 3 + -- 2*EXT4_QUOTA_INIT_BLOCKS(dir->i_sb)); -+ EXT4_MAXQUOTAS_INIT_BLOCKS(dir->i_sb)); - if (IS_ERR(handle)) - return PTR_ERR(handle); - -@@ -1809,7 +1803,7 @@ static int ext4_mknod(struct inode *dir, struct dentry *dentry, - retry: - handle = ext4_journal_start(dir, EXT4_DATA_TRANS_BLOCKS(dir->i_sb) + - EXT4_INDEX_EXTRA_TRANS_BLOCKS + 3 + -- 2*EXT4_QUOTA_INIT_BLOCKS(dir->i_sb)); -+ EXT4_MAXQUOTAS_INIT_BLOCKS(dir->i_sb)); - if (IS_ERR(handle)) - return PTR_ERR(handle); - -@@ -1846,7 +1840,7 @@ static int ext4_mkdir(struct inode *dir, struct dentry *dentry, int mode) - retry: - handle = ext4_journal_start(dir, EXT4_DATA_TRANS_BLOCKS(dir->i_sb) + - EXT4_INDEX_EXTRA_TRANS_BLOCKS + 3 + -- 2*EXT4_QUOTA_INIT_BLOCKS(dir->i_sb)); -+ EXT4_MAXQUOTAS_INIT_BLOCKS(dir->i_sb)); - if (IS_ERR(handle)) - return PTR_ERR(handle); - -@@ -2259,7 +2253,7 @@ static int ext4_symlink(struct inode *dir, - retry: - handle = ext4_journal_start(dir, EXT4_DATA_TRANS_BLOCKS(dir->i_sb) + - EXT4_INDEX_EXTRA_TRANS_BLOCKS + 5 + -- 2*EXT4_QUOTA_INIT_BLOCKS(dir->i_sb)); -+ EXT4_MAXQUOTAS_INIT_BLOCKS(dir->i_sb)); - if (IS_ERR(handle)) - return PTR_ERR(handle); - -diff --git a/fs/ext4/resize.c b/fs/ext4/resize.c -index 3cfc343..3b2c554 100644 ---- a/fs/ext4/resize.c -+++ b/fs/ext4/resize.c -@@ -247,7 +247,7 @@ static int setup_new_group_blocks(struct super_block *sb, - goto exit_bh; - - if (IS_ERR(gdb = bclean(handle, sb, block))) { -- err = PTR_ERR(bh); -+ err = PTR_ERR(gdb); - goto exit_bh; - } - ext4_handle_dirty_metadata(handle, NULL, gdb); -diff --git a/fs/ext4/super.c b/fs/ext4/super.c -index d4ca92a..9ae5217 100644 ---- a/fs/ext4/super.c -+++ b/fs/ext4/super.c -@@ -603,10 +603,6 @@ static void ext4_put_super(struct super_block *sb) - if (sb->s_dirt) - ext4_commit_super(sb, 1); - -- ext4_release_system_zone(sb); -- ext4_mb_release(sb); -- ext4_ext_release(sb); -- ext4_xattr_put_super(sb); - if (sbi->s_journal) { - err = jbd2_journal_destroy(sbi->s_journal); - sbi->s_journal = NULL; -@@ -614,6 +610,12 @@ static void ext4_put_super(struct super_block *sb) - ext4_abort(sb, __func__, - "Couldn't clean up the journal"); - } -+ -+ ext4_release_system_zone(sb); -+ ext4_mb_release(sb); -+ ext4_ext_release(sb); -+ ext4_xattr_put_super(sb); -+ - if (!(sb->s_flags & MS_RDONLY)) { - EXT4_CLEAR_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER); - es->s_state = cpu_to_le16(sbi->s_mount_state); -@@ -704,6 +706,8 @@ static struct inode *ext4_alloc_inode(struct super_block *sb) - spin_lock_init(&(ei->i_block_reservation_lock)); - INIT_LIST_HEAD(&ei->i_aio_dio_complete_list); - ei->cur_aio_dio = NULL; -+ ei->i_sync_tid = 0; -+ ei->i_datasync_tid = 0; - - return &ei->vfs_inode; - } -@@ -899,6 +903,12 @@ static int ext4_show_options(struct seq_file *seq, struct vfsmount *vfs) - if (test_opt(sb, NO_AUTO_DA_ALLOC)) - seq_puts(seq, ",noauto_da_alloc"); - -+ if (test_opt(sb, DISCARD)) -+ seq_puts(seq, ",discard"); -+ -+ if (test_opt(sb, NOLOAD)) -+ seq_puts(seq, ",norecovery"); -+ - ext4_show_quota_options(seq, sb); - - return 0; -@@ -1079,7 +1089,8 @@ enum { - Opt_usrquota, Opt_grpquota, Opt_i_version, - Opt_stripe, Opt_delalloc, Opt_nodelalloc, - Opt_block_validity, Opt_noblock_validity, -- Opt_inode_readahead_blks, Opt_journal_ioprio -+ Opt_inode_readahead_blks, Opt_journal_ioprio, -+ Opt_discard, Opt_nodiscard, - }; - - static const match_table_t tokens = { -@@ -1104,6 +1115,7 @@ static const match_table_t tokens = { - {Opt_acl, "acl"}, - {Opt_noacl, "noacl"}, - {Opt_noload, "noload"}, -+ {Opt_noload, "norecovery"}, - {Opt_nobh, "nobh"}, - {Opt_bh, "bh"}, - {Opt_commit, "commit=%u"}, -@@ -1144,6 +1156,8 @@ static const match_table_t tokens = { - {Opt_auto_da_alloc, "auto_da_alloc=%u"}, - {Opt_auto_da_alloc, "auto_da_alloc"}, - {Opt_noauto_da_alloc, "noauto_da_alloc"}, -+ {Opt_discard, "discard"}, -+ {Opt_nodiscard, "nodiscard"}, - {Opt_err, NULL}, - }; - -@@ -1565,6 +1579,12 @@ set_qf_format: - else - set_opt(sbi->s_mount_opt,NO_AUTO_DA_ALLOC); - break; -+ case Opt_discard: -+ set_opt(sbi->s_mount_opt, DISCARD); -+ break; -+ case Opt_nodiscard: -+ clear_opt(sbi->s_mount_opt, DISCARD); -+ break; - default: - ext4_msg(sb, KERN_ERR, - "Unrecognized mount option \"%s\" " -@@ -1673,14 +1693,14 @@ static int ext4_fill_flex_info(struct super_block *sb) - size_t size; - int i; - -- if (!sbi->s_es->s_log_groups_per_flex) { -+ sbi->s_log_groups_per_flex = sbi->s_es->s_log_groups_per_flex; -+ groups_per_flex = 1 << sbi->s_log_groups_per_flex; -+ -+ if (groups_per_flex < 2) { - sbi->s_log_groups_per_flex = 0; - return 1; - } - -- sbi->s_log_groups_per_flex = sbi->s_es->s_log_groups_per_flex; -- groups_per_flex = 1 << sbi->s_log_groups_per_flex; -- - /* We allocate both existing and potentially added groups */ - flex_group_count = ((sbi->s_groups_count + groups_per_flex - 1) + - ((le16_to_cpu(sbi->s_es->s_reserved_gdt_blocks) + 1) << -@@ -3668,13 +3688,11 @@ static int ext4_statfs(struct dentry *dentry, struct kstatfs *buf) - buf->f_blocks = ext4_blocks_count(es) - sbi->s_overhead_last; - buf->f_bfree = percpu_counter_sum_positive(&sbi->s_freeblocks_counter) - - percpu_counter_sum_positive(&sbi->s_dirtyblocks_counter); -- ext4_free_blocks_count_set(es, buf->f_bfree); - buf->f_bavail = buf->f_bfree - ext4_r_blocks_count(es); - if (buf->f_bfree < ext4_r_blocks_count(es)) - buf->f_bavail = 0; - buf->f_files = le32_to_cpu(es->s_inodes_count); - buf->f_ffree = percpu_counter_sum_positive(&sbi->s_freeinodes_counter); -- es->s_free_inodes_count = cpu_to_le32(buf->f_ffree); - buf->f_namelen = EXT4_NAME_LEN; - fsid = le64_to_cpup((void *)es->s_uuid) ^ - le64_to_cpup((void *)es->s_uuid + sizeof(u64)); -diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c -index fed5b01..0257019 100644 ---- a/fs/ext4/xattr.c -+++ b/fs/ext4/xattr.c -@@ -988,6 +988,10 @@ ext4_xattr_set_handle(handle_t *handle, struct inode *inode, int name_index, - if (error) - goto cleanup; - -+ error = ext4_journal_get_write_access(handle, is.iloc.bh); -+ if (error) -+ goto cleanup; -+ - if (EXT4_I(inode)->i_state & EXT4_STATE_NEW) { - struct ext4_inode *raw_inode = ext4_raw_inode(&is.iloc); - memset(raw_inode, 0, EXT4_SB(inode->i_sb)->s_inode_size); -@@ -1013,9 +1017,6 @@ ext4_xattr_set_handle(handle_t *handle, struct inode *inode, int name_index, - if (flags & XATTR_CREATE) - goto cleanup; - } -- error = ext4_journal_get_write_access(handle, is.iloc.bh); -- if (error) -- goto cleanup; - if (!value) { - if (!is.s.not_found) - error = ext4_xattr_ibody_set(handle, inode, &i, &is); -diff --git a/fs/jbd2/commit.c b/fs/jbd2/commit.c -index d4cfd6d..8896c1d 100644 ---- a/fs/jbd2/commit.c -+++ b/fs/jbd2/commit.c -@@ -636,6 +636,10 @@ void jbd2_journal_commit_transaction(journal_t *journal) - JBUFFER_TRACE(jh, "ph3: write metadata"); - flags = jbd2_journal_write_metadata_buffer(commit_transaction, - jh, &new_jh, blocknr); -+ if (flags < 0) { -+ jbd2_journal_abort(journal, flags); -+ continue; -+ } - set_bit(BH_JWrite, &jh2bh(new_jh)->b_state); - wbuf[bufs++] = jh2bh(new_jh); - -diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c -index fed8538..82c295d 100644 ---- a/fs/jbd2/journal.c -+++ b/fs/jbd2/journal.c -@@ -78,6 +78,7 @@ EXPORT_SYMBOL(jbd2_journal_errno); - EXPORT_SYMBOL(jbd2_journal_ack_err); - EXPORT_SYMBOL(jbd2_journal_clear_err); - EXPORT_SYMBOL(jbd2_log_wait_commit); -+EXPORT_SYMBOL(jbd2_log_start_commit); - EXPORT_SYMBOL(jbd2_journal_start_commit); - EXPORT_SYMBOL(jbd2_journal_force_commit_nested); - EXPORT_SYMBOL(jbd2_journal_wipe); -@@ -358,6 +359,10 @@ repeat: - - jbd_unlock_bh_state(bh_in); - tmp = jbd2_alloc(bh_in->b_size, GFP_NOFS); -+ if (!tmp) { -+ jbd2_journal_put_journal_head(new_jh); -+ return -ENOMEM; -+ } - jbd_lock_bh_state(bh_in); - if (jh_in->b_frozen_data) { - jbd2_free(tmp, bh_in->b_size); -diff --git a/include/linux/sched.h b/include/linux/sched.h -index 75e6e60..0f67914 100644 ---- a/include/linux/sched.h -+++ b/include/linux/sched.h -@@ -2086,11 +2086,18 @@ static inline int is_si_special(const struct siginfo *info) - return info <= SEND_SIG_FORCED; - } - --/* True if we are on the alternate signal stack. */ -- -+/* -+ * True if we are on the alternate signal stack. -+ */ - static inline int on_sig_stack(unsigned long sp) - { -- return (sp - current->sas_ss_sp < current->sas_ss_size); -+#ifdef CONFIG_STACK_GROWSUP -+ return sp >= current->sas_ss_sp && -+ sp - current->sas_ss_sp < current->sas_ss_size; -+#else -+ return sp > current->sas_ss_sp && -+ sp - current->sas_ss_sp <= current->sas_ss_size; -+#endif - } - - static inline int sas_ss_flags(unsigned long sp) -diff --git a/include/scsi/osd_protocol.h b/include/scsi/osd_protocol.h -index 2cc8e8b..6856612 100644 ---- a/include/scsi/osd_protocol.h -+++ b/include/scsi/osd_protocol.h -@@ -17,6 +17,7 @@ - #define __OSD_PROTOCOL_H__ - - #include -+#include - #include - #include - -diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h -index 47941fc..0b4baba 100644 ---- a/include/scsi/scsi_host.h -+++ b/include/scsi/scsi_host.h -@@ -677,6 +677,12 @@ struct Scsi_Host { - void *shost_data; - - /* -+ * Points to the physical bus device we'd use to do DMA -+ * Needed just in case we have virtual hosts. -+ */ -+ struct device *dma_dev; -+ -+ /* - * We should ensure that this is aligned, both for better performance - * and also because some compilers (m68k) don't automatically force - * alignment to a long boundary. -@@ -720,7 +726,9 @@ extern int scsi_queue_work(struct Scsi_Host *, struct work_struct *); - extern void scsi_flush_work(struct Scsi_Host *); - - extern struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *, int); --extern int __must_check scsi_add_host(struct Scsi_Host *, struct device *); -+extern int __must_check scsi_add_host_with_dma(struct Scsi_Host *, -+ struct device *, -+ struct device *); - extern void scsi_scan_host(struct Scsi_Host *); - extern void scsi_rescan_device(struct device *); - extern void scsi_remove_host(struct Scsi_Host *); -@@ -731,6 +739,12 @@ extern const char *scsi_host_state_name(enum scsi_host_state); - - extern u64 scsi_calculate_bounce_limit(struct Scsi_Host *); - -+static inline int __must_check scsi_add_host(struct Scsi_Host *host, -+ struct device *dev) -+{ -+ return scsi_add_host_with_dma(host, dev, dev); -+} -+ - static inline struct device *scsi_get_device(struct Scsi_Host *shost) - { - return shost->shost_gendev.parent; diff --git a/debian/patches/bugfix/all/stable/2.6.32.2.patch b/debian/patches/bugfix/all/stable/2.6.32.2.patch deleted file mode 100644 index c57398fc3..000000000 --- a/debian/patches/bugfix/all/stable/2.6.32.2.patch +++ /dev/null @@ -1,5447 +0,0 @@ -diff --git a/Documentation/Changes b/Documentation/Changes -index 6d0f1ef..f08b313 100644 ---- a/Documentation/Changes -+++ b/Documentation/Changes -@@ -49,6 +49,8 @@ o oprofile 0.9 # oprofiled --version - o udev 081 # udevinfo -V - o grub 0.93 # grub --version - o mcelog 0.6 -+o iptables 1.4.1 # iptables -V -+ - - Kernel compilation - ================== -diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt -index 9107b38..5bc4eaa 100644 ---- a/Documentation/kernel-parameters.txt -+++ b/Documentation/kernel-parameters.txt -@@ -2645,6 +2645,8 @@ and is between 256 and 4096 characters. It is defined in the file - to a common usb-storage quirk flag as follows: - a = SANE_SENSE (collect more than 18 bytes - of sense data); -+ b = BAD_SENSE (don't collect more than 18 -+ bytes of sense data); - c = FIX_CAPACITY (decrease the reported - device capacity by one sector); - h = CAPACITY_HEURISTICS (decrease the -diff --git a/Documentation/video4linux/gspca.txt b/Documentation/video4linux/gspca.txt -index 3f61825..90e85a8 100644 ---- a/Documentation/video4linux/gspca.txt -+++ b/Documentation/video4linux/gspca.txt -@@ -37,6 +37,7 @@ ov519 041e:405f Creative Live! VISTA VF0330 - ov519 041e:4060 Creative Live! VISTA VF0350 - ov519 041e:4061 Creative Live! VISTA VF0400 - ov519 041e:4064 Creative Live! VISTA VF0420 -+ov519 041e:4067 Creative Live! Cam Video IM (VF0350) - ov519 041e:4068 Creative Live! VISTA VF0470 - spca561 0458:7004 Genius VideoCAM Express V2 - sunplus 0458:7006 Genius Dsc 1.3 Smart -diff --git a/MAINTAINERS b/MAINTAINERS -index 4f96ac8..c57d396 100644 ---- a/MAINTAINERS -+++ b/MAINTAINERS -@@ -5594,9 +5594,11 @@ S: Maintained - F: drivers/net/wireless/rndis_wlan.c - - USB XHCI DRIVER --M: Sarah Sharp -+M: Sarah Sharp - L: linux-usb@vger.kernel.org - S: Supported -+F: drivers/usb/host/xhci* -+F: drivers/usb/host/pci-quirks* - - USB ZC0301 DRIVER - M: Luca Risolia -diff --git a/Makefile b/Makefile -index d0d7e9c..23803ce 100644 -diff --git a/arch/arm/mach-pxa/em-x270.c b/arch/arm/mach-pxa/em-x270.c -index aec7f42..86a8732 100644 ---- a/arch/arm/mach-pxa/em-x270.c -+++ b/arch/arm/mach-pxa/em-x270.c -@@ -497,16 +497,15 @@ static int em_x270_usb_hub_init(void) - goto err_free_vbus_gpio; - - /* USB Hub power-on and reset */ -- gpio_direction_output(usb_hub_reset, 0); -+ gpio_direction_output(usb_hub_reset, 1); -+ gpio_direction_output(GPIO9_USB_VBUS_EN, 0); - regulator_enable(em_x270_usb_ldo); -- gpio_set_value(usb_hub_reset, 1); - gpio_set_value(usb_hub_reset, 0); -+ gpio_set_value(usb_hub_reset, 1); - regulator_disable(em_x270_usb_ldo); - regulator_enable(em_x270_usb_ldo); -- gpio_set_value(usb_hub_reset, 1); -- -- /* enable VBUS */ -- gpio_direction_output(GPIO9_USB_VBUS_EN, 1); -+ gpio_set_value(usb_hub_reset, 0); -+ gpio_set_value(GPIO9_USB_VBUS_EN, 1); - - return 0; - -diff --git a/arch/ia64/include/asm/io.h b/arch/ia64/include/asm/io.h -index 0d9d16e..cc8335e 100644 ---- a/arch/ia64/include/asm/io.h -+++ b/arch/ia64/include/asm/io.h -@@ -424,6 +424,8 @@ __writeq (unsigned long val, volatile void __iomem *addr) - extern void __iomem * ioremap(unsigned long offset, unsigned long size); - extern void __iomem * ioremap_nocache (unsigned long offset, unsigned long size); - extern void iounmap (volatile void __iomem *addr); -+extern void __iomem * early_ioremap (unsigned long phys_addr, unsigned long size); -+extern void early_iounmap (volatile void __iomem *addr, unsigned long size); - - /* - * String version of IO memory access ops: -diff --git a/arch/ia64/mm/ioremap.c b/arch/ia64/mm/ioremap.c -index 2a14062..3dccdd8 100644 ---- a/arch/ia64/mm/ioremap.c -+++ b/arch/ia64/mm/ioremap.c -@@ -22,6 +22,12 @@ __ioremap (unsigned long phys_addr) - } - - void __iomem * -+early_ioremap (unsigned long phys_addr, unsigned long size) -+{ -+ return __ioremap(phys_addr); -+} -+ -+void __iomem * - ioremap (unsigned long phys_addr, unsigned long size) - { - void __iomem *addr; -@@ -102,6 +108,11 @@ ioremap_nocache (unsigned long phys_addr, unsigned long size) - EXPORT_SYMBOL(ioremap_nocache); - - void -+early_iounmap (volatile void __iomem *addr, unsigned long size) -+{ -+} -+ -+void - iounmap (volatile void __iomem *addr) - { - if (REGION_NUMBER(addr) == RGN_GATE) -diff --git a/arch/powerpc/kernel/vector.S b/arch/powerpc/kernel/vector.S -index 67b6916..fe46048 100644 ---- a/arch/powerpc/kernel/vector.S -+++ b/arch/powerpc/kernel/vector.S -@@ -58,7 +58,7 @@ _GLOBAL(load_up_altivec) - * all 1's - */ - mfspr r4,SPRN_VRSAVE -- cmpdi 0,r4,0 -+ cmpwi 0,r4,0 - bne+ 1f - li r4,-1 - mtspr SPRN_VRSAVE,r4 -diff --git a/arch/s390/include/asm/kvm.h b/arch/s390/include/asm/kvm.h -index 3dfcaeb..82b32a1 100644 ---- a/arch/s390/include/asm/kvm.h -+++ b/arch/s390/include/asm/kvm.h -@@ -1,6 +1,5 @@ - #ifndef __LINUX_KVM_S390_H - #define __LINUX_KVM_S390_H -- - /* - * asm-s390/kvm.h - KVM s390 specific structures and definitions - * -@@ -15,6 +14,8 @@ - */ - #include - -+#define __KVM_S390 -+ - /* for KVM_GET_REGS and KVM_SET_REGS */ - struct kvm_regs { - /* general purpose regs for s390 */ -diff --git a/arch/s390/kernel/head64.S b/arch/s390/kernel/head64.S -index 6a25080..d984a2a 100644 ---- a/arch/s390/kernel/head64.S -+++ b/arch/s390/kernel/head64.S -@@ -83,6 +83,8 @@ startup_continue: - slr %r0,%r0 # set cpuid to zero - sigp %r1,%r0,0x12 # switch to esame mode - sam64 # switch to 64 bit mode -+ llgfr %r13,%r13 # clear high-order half of base reg -+ lmh %r0,%r15,.Lzero64-.LPG1(%r13) # clear high-order half - lctlg %c0,%c15,.Lctl-.LPG1(%r13) # load control registers - lg %r12,.Lparmaddr-.LPG1(%r13) # pointer to parameter area - # move IPL device to lowcore -@@ -127,6 +129,7 @@ startup_continue: - .L4malign:.quad 0xffffffffffc00000 - .Lscan2g:.quad 0x80000000 + 0x20000 - 8 # 2GB + 128K - 8 - .Lnop: .long 0x07000700 -+.Lzero64:.fill 16,4,0x0 - #ifdef CONFIG_ZFCPDUMP - .Lcurrent_cpu: - .long 0x0 -diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c -index 07ced89..ca2d312 100644 ---- a/arch/s390/kvm/kvm-s390.c -+++ b/arch/s390/kvm/kvm-s390.c -@@ -116,10 +116,16 @@ long kvm_arch_dev_ioctl(struct file *filp, - - int kvm_dev_ioctl_check_extension(long ext) - { -+ int r; -+ - switch (ext) { -+ case KVM_CAP_S390_PSW: -+ r = 1; -+ break; - default: -- return 0; -+ r = 0; - } -+ return r; - } - - /* Section: vm related */ -@@ -419,8 +425,10 @@ static int kvm_arch_vcpu_ioctl_set_initial_psw(struct kvm_vcpu *vcpu, psw_t psw) - vcpu_load(vcpu); - if (atomic_read(&vcpu->arch.sie_block->cpuflags) & CPUSTAT_RUNNING) - rc = -EBUSY; -- else -- vcpu->arch.sie_block->gpsw = psw; -+ else { -+ vcpu->run->psw_mask = psw.mask; -+ vcpu->run->psw_addr = psw.addr; -+ } - vcpu_put(vcpu); - return rc; - } -@@ -508,9 +516,6 @@ rerun_vcpu: - - switch (kvm_run->exit_reason) { - case KVM_EXIT_S390_SIEIC: -- vcpu->arch.sie_block->gpsw.mask = kvm_run->s390_sieic.mask; -- vcpu->arch.sie_block->gpsw.addr = kvm_run->s390_sieic.addr; -- break; - case KVM_EXIT_UNKNOWN: - case KVM_EXIT_INTR: - case KVM_EXIT_S390_RESET: -@@ -519,6 +524,9 @@ rerun_vcpu: - BUG(); - } - -+ vcpu->arch.sie_block->gpsw.mask = kvm_run->psw_mask; -+ vcpu->arch.sie_block->gpsw.addr = kvm_run->psw_addr; -+ - might_fault(); - - do { -@@ -538,8 +546,6 @@ rerun_vcpu: - /* intercept cannot be handled in-kernel, prepare kvm-run */ - kvm_run->exit_reason = KVM_EXIT_S390_SIEIC; - kvm_run->s390_sieic.icptcode = vcpu->arch.sie_block->icptcode; -- kvm_run->s390_sieic.mask = vcpu->arch.sie_block->gpsw.mask; -- kvm_run->s390_sieic.addr = vcpu->arch.sie_block->gpsw.addr; - kvm_run->s390_sieic.ipa = vcpu->arch.sie_block->ipa; - kvm_run->s390_sieic.ipb = vcpu->arch.sie_block->ipb; - rc = 0; -@@ -551,6 +557,9 @@ rerun_vcpu: - rc = 0; - } - -+ kvm_run->psw_mask = vcpu->arch.sie_block->gpsw.mask; -+ kvm_run->psw_addr = vcpu->arch.sie_block->gpsw.addr; -+ - if (vcpu->sigset_active) - sigprocmask(SIG_SETMASK, &sigsaved, NULL); - -diff --git a/arch/s390/kvm/sigp.c b/arch/s390/kvm/sigp.c -index 40c8c67..15ee111 100644 ---- a/arch/s390/kvm/sigp.c -+++ b/arch/s390/kvm/sigp.c -@@ -188,9 +188,9 @@ static int __sigp_set_prefix(struct kvm_vcpu *vcpu, u16 cpu_addr, u32 address, - - /* make sure that the new value is valid memory */ - address = address & 0x7fffe000u; -- if ((copy_from_guest(vcpu, &tmp, -- (u64) (address + vcpu->arch.sie_block->gmsor) , 1)) || -- (copy_from_guest(vcpu, &tmp, (u64) (address + -+ if ((copy_from_user(&tmp, (void __user *) -+ (address + vcpu->arch.sie_block->gmsor) , 1)) || -+ (copy_from_user(&tmp, (void __user *)(address + - vcpu->arch.sie_block->gmsor + PAGE_SIZE), 1))) { - *reg |= SIGP_STAT_INVALID_PARAMETER; - return 1; /* invalid parameter */ -diff --git a/arch/sparc/Makefile b/arch/sparc/Makefile -index dfe272d..113225b 100644 ---- a/arch/sparc/Makefile -+++ b/arch/sparc/Makefile -@@ -27,6 +27,7 @@ AS := $(AS) -32 - LDFLAGS := -m elf32_sparc - CHECKFLAGS += -D__sparc__ - export BITS := 32 -+UTS_MACHINE := sparc - - #KBUILD_CFLAGS += -g -pipe -fcall-used-g5 -fcall-used-g7 - KBUILD_CFLAGS += -m32 -pipe -mno-fpu -fcall-used-g5 -fcall-used-g7 -@@ -46,6 +47,7 @@ CHECKFLAGS += -D__sparc__ -D__sparc_v9__ -D__arch64__ -m64 - - LDFLAGS := -m elf64_sparc - export BITS := 64 -+UTS_MACHINE := sparc64 - - KBUILD_CFLAGS += -m64 -pipe -mno-fpu -mcpu=ultrasparc -mcmodel=medlow \ - -ffixed-g4 -ffixed-g5 -fcall-used-g7 -Wno-sign-compare \ -diff --git a/arch/sparc/kernel/ldc.c b/arch/sparc/kernel/ldc.c -index cb3c72c..e0ba898 100644 ---- a/arch/sparc/kernel/ldc.c -+++ b/arch/sparc/kernel/ldc.c -@@ -1242,13 +1242,13 @@ int ldc_bind(struct ldc_channel *lp, const char *name) - snprintf(lp->tx_irq_name, LDC_IRQ_NAME_MAX, "%s TX", name); - - err = request_irq(lp->cfg.rx_irq, ldc_rx, -- IRQF_SAMPLE_RANDOM | IRQF_DISABLED | IRQF_SHARED, -+ IRQF_SAMPLE_RANDOM | IRQF_DISABLED, - lp->rx_irq_name, lp); - if (err) - return err; - - err = request_irq(lp->cfg.tx_irq, ldc_tx, -- IRQF_SAMPLE_RANDOM | IRQF_DISABLED | IRQF_SHARED, -+ IRQF_SAMPLE_RANDOM | IRQF_DISABLED, - lp->tx_irq_name, lp); - if (err) { - free_irq(lp->cfg.rx_irq, lp); -diff --git a/arch/sparc/kernel/of_device_64.c b/arch/sparc/kernel/of_device_64.c -index 881947e..0a6f2d1 100644 ---- a/arch/sparc/kernel/of_device_64.c -+++ b/arch/sparc/kernel/of_device_64.c -@@ -104,9 +104,19 @@ static int of_bus_pci_map(u32 *addr, const u32 *range, - int i; - - /* Check address type match */ -- if ((addr[0] ^ range[0]) & 0x03000000) -- return -EINVAL; -+ if (!((addr[0] ^ range[0]) & 0x03000000)) -+ goto type_match; -+ -+ /* Special exception, we can map a 64-bit address into -+ * a 32-bit range. -+ */ -+ if ((addr[0] & 0x03000000) == 0x03000000 && -+ (range[0] & 0x03000000) == 0x02000000) -+ goto type_match; -+ -+ return -EINVAL; - -+type_match: - if (of_out_of_range(addr + 1, range + 1, range + na + pna, - na - 1, ns)) - return -EINVAL; -diff --git a/arch/sparc/lib/mcount.S b/arch/sparc/lib/mcount.S -index 7ce9c65..24b8b12 100644 ---- a/arch/sparc/lib/mcount.S -+++ b/arch/sparc/lib/mcount.S -@@ -64,8 +64,9 @@ mcount: - 2: sethi %hi(softirq_stack), %g3 - or %g3, %lo(softirq_stack), %g3 - ldx [%g3 + %g1], %g7 -+ sub %g7, STACK_BIAS, %g7 - cmp %sp, %g7 -- bleu,pt %xcc, 2f -+ bleu,pt %xcc, 3f - sethi %hi(THREAD_SIZE), %g3 - add %g7, %g3, %g7 - cmp %sp, %g7 -@@ -75,7 +76,7 @@ mcount: - * again, we are already trying to output the stack overflow - * message. - */ -- sethi %hi(ovstack), %g7 ! cant move to panic stack fast enough -+3: sethi %hi(ovstack), %g7 ! cant move to panic stack fast enough - or %g7, %lo(ovstack), %g7 - add %g7, OVSTACKSIZE, %g3 - sub %g3, STACK_BIAS + 192, %g3 -diff --git a/arch/x86/Makefile_32.cpu b/arch/x86/Makefile_32.cpu -index 30e9a26..1937226 100644 ---- a/arch/x86/Makefile_32.cpu -+++ b/arch/x86/Makefile_32.cpu -@@ -46,6 +46,13 @@ cflags-$(CONFIG_MGEODEGX1) += -march=pentium-mmx - # cpu entries - cflags-$(CONFIG_X86_GENERIC) += $(call tune,generic,$(call tune,i686)) - -+# Work around the pentium-mmx code generator madness of gcc4.4.x which -+# does stack alignment by generating horrible code _before_ the mcount -+# prologue (push %ebp, mov %esp, %ebp) which breaks the function graph -+# tracer assumptions. For i686, generic, core2 this is set by the -+# compiler anyway -+cflags-$(CONFIG_FUNCTION_GRAPH_TRACER) += $(call cc-option,-maccumulate-outgoing-args) -+ - # Bug fix for binutils: this option is required in order to keep - # binutils from generating NOPL instructions against our will. - ifneq ($(CONFIG_X86_P6_NOP),y) -diff --git a/arch/x86/include/asm/irq_vectors.h b/arch/x86/include/asm/irq_vectors.h -index 5b21f0e..6e90a04 100644 ---- a/arch/x86/include/asm/irq_vectors.h -+++ b/arch/x86/include/asm/irq_vectors.h -@@ -113,7 +113,7 @@ - */ - #define LOCAL_PENDING_VECTOR 0xec - --#define UV_BAU_MESSAGE 0xec -+#define UV_BAU_MESSAGE 0xea - - /* - * Self IPI vector for machine checks -diff --git a/arch/x86/include/asm/kvm_emulate.h b/arch/x86/include/asm/kvm_emulate.h -index b7ed2c4..7c18e12 100644 ---- a/arch/x86/include/asm/kvm_emulate.h -+++ b/arch/x86/include/asm/kvm_emulate.h -@@ -129,7 +129,7 @@ struct decode_cache { - u8 seg_override; - unsigned int d; - unsigned long regs[NR_VCPU_REGS]; -- unsigned long eip; -+ unsigned long eip, eip_orig; - /* modrm */ - u8 modrm; - u8 modrm_mod; -diff --git a/arch/x86/include/asm/mce.h b/arch/x86/include/asm/mce.h -index f1363b7..a479023 100644 ---- a/arch/x86/include/asm/mce.h -+++ b/arch/x86/include/asm/mce.h -@@ -214,5 +214,11 @@ void intel_init_thermal(struct cpuinfo_x86 *c); - - void mce_log_therm_throt_event(__u64 status); - -+#ifdef CONFIG_X86_THERMAL_VECTOR -+extern void mcheck_intel_therm_init(void); -+#else -+static inline void mcheck_intel_therm_init(void) { } -+#endif -+ - #endif /* __KERNEL__ */ - #endif /* _ASM_X86_MCE_H */ -diff --git a/arch/x86/kernel/acpi/cstate.c b/arch/x86/kernel/acpi/cstate.c -index 59cdfa4..2e837f5 100644 ---- a/arch/x86/kernel/acpi/cstate.c -+++ b/arch/x86/kernel/acpi/cstate.c -@@ -48,7 +48,7 @@ void acpi_processor_power_init_bm_check(struct acpi_processor_flags *flags, - * P4, Core and beyond CPUs - */ - if (c->x86_vendor == X86_VENDOR_INTEL && -- (c->x86 > 0xf || (c->x86 == 6 && c->x86_model >= 14))) -+ (c->x86 > 0xf || (c->x86 == 6 && c->x86_model >= 0x0f))) - flags->bm_control = 0; - } - EXPORT_SYMBOL(acpi_processor_power_init_bm_check); -diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c -index 0285521..90b9b55 100644 ---- a/arch/x86/kernel/amd_iommu.c -+++ b/arch/x86/kernel/amd_iommu.c -@@ -2047,10 +2047,10 @@ static void prealloc_protection_domains(void) - struct pci_dev *dev = NULL; - struct dma_ops_domain *dma_dom; - struct amd_iommu *iommu; -- u16 devid; -+ u16 devid, __devid; - - while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { -- devid = calc_devid(dev->bus->number, dev->devfn); -+ __devid = devid = calc_devid(dev->bus->number, dev->devfn); - if (devid > amd_iommu_last_bdf) - continue; - devid = amd_iommu_alias_table[devid]; -@@ -2065,6 +2065,10 @@ static void prealloc_protection_domains(void) - init_unity_mappings_for_device(dma_dom, devid); - dma_dom->target_dev = devid; - -+ attach_device(iommu, &dma_dom->domain, devid); -+ if (__devid != devid) -+ attach_device(iommu, &dma_dom->domain, __devid); -+ - list_add_tail(&dma_dom->list, &iommu_pd_list); - } - } -diff --git a/arch/x86/kernel/amd_iommu_init.c b/arch/x86/kernel/amd_iommu_init.c -index c20001e..e0b3130 100644 ---- a/arch/x86/kernel/amd_iommu_init.c -+++ b/arch/x86/kernel/amd_iommu_init.c -@@ -925,7 +925,7 @@ static int __init init_iommu_all(struct acpi_table_header *table) - * - ****************************************************************************/ - --static int __init iommu_setup_msi(struct amd_iommu *iommu) -+static int iommu_setup_msi(struct amd_iommu *iommu) - { - int r; - -diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c -index 894aa97..c86dbcf 100644 ---- a/arch/x86/kernel/apic/apic.c -+++ b/arch/x86/kernel/apic/apic.c -@@ -246,7 +246,7 @@ static int modern_apic(void) - */ - static void native_apic_write_dummy(u32 reg, u32 v) - { -- WARN_ON_ONCE((cpu_has_apic || !disable_apic)); -+ WARN_ON_ONCE(cpu_has_apic && !disable_apic); - } - - static u32 native_apic_read_dummy(u32 reg) -diff --git a/arch/x86/kernel/cpu/intel_cacheinfo.c b/arch/x86/kernel/cpu/intel_cacheinfo.c -index 804c40e..8178d03 100644 ---- a/arch/x86/kernel/cpu/intel_cacheinfo.c -+++ b/arch/x86/kernel/cpu/intel_cacheinfo.c -@@ -94,7 +94,7 @@ static const struct _cache_table __cpuinitconst cache_table[] = - { 0xd1, LVL_3, 1024 }, /* 4-way set assoc, 64 byte line size */ - { 0xd2, LVL_3, 2048 }, /* 4-way set assoc, 64 byte line size */ - { 0xd6, LVL_3, 1024 }, /* 8-way set assoc, 64 byte line size */ -- { 0xd7, LVL_3, 2038 }, /* 8-way set assoc, 64 byte line size */ -+ { 0xd7, LVL_3, 2048 }, /* 8-way set assoc, 64 byte line size */ - { 0xd8, LVL_3, 4096 }, /* 12-way set assoc, 64 byte line size */ - { 0xdc, LVL_3, 2048 }, /* 12-way set assoc, 64 byte line size */ - { 0xdd, LVL_3, 4096 }, /* 12-way set assoc, 64 byte line size */ -@@ -102,6 +102,9 @@ static const struct _cache_table __cpuinitconst cache_table[] = - { 0xe2, LVL_3, 2048 }, /* 16-way set assoc, 64 byte line size */ - { 0xe3, LVL_3, 4096 }, /* 16-way set assoc, 64 byte line size */ - { 0xe4, LVL_3, 8192 }, /* 16-way set assoc, 64 byte line size */ -+ { 0xea, LVL_3, 12288 }, /* 24-way set assoc, 64 byte line size */ -+ { 0xeb, LVL_3, 18432 }, /* 24-way set assoc, 64 byte line size */ -+ { 0xec, LVL_3, 24576 }, /* 24-way set assoc, 64 byte line size */ - { 0x00, 0, 0} - }; - -diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c -index 721a77c..0f16a2b 100644 ---- a/arch/x86/kernel/cpu/mcheck/mce.c -+++ b/arch/x86/kernel/cpu/mcheck/mce.c -@@ -1374,13 +1374,14 @@ static void mce_init_timer(void) - struct timer_list *t = &__get_cpu_var(mce_timer); - int *n = &__get_cpu_var(mce_next_interval); - -+ setup_timer(t, mcheck_timer, smp_processor_id()); -+ - if (mce_ignore_ce) - return; - - *n = check_interval * HZ; - if (!*n) - return; -- setup_timer(t, mcheck_timer, smp_processor_id()); - t->expires = round_jiffies(jiffies + *n); - add_timer_on(t, smp_processor_id()); - } -@@ -1991,9 +1992,11 @@ mce_cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu) - break; - case CPU_DOWN_FAILED: - case CPU_DOWN_FAILED_FROZEN: -- t->expires = round_jiffies(jiffies + -+ if (!mce_ignore_ce && check_interval) { -+ t->expires = round_jiffies(jiffies + - __get_cpu_var(mce_next_interval)); -- add_timer_on(t, cpu); -+ add_timer_on(t, cpu); -+ } - smp_call_function_single(cpu, mce_reenable_cpu, &action, 1); - break; - case CPU_POST_DEAD: -diff --git a/arch/x86/kernel/cpu/mcheck/therm_throt.c b/arch/x86/kernel/cpu/mcheck/therm_throt.c -index b3a1dba..4fef985 100644 ---- a/arch/x86/kernel/cpu/mcheck/therm_throt.c -+++ b/arch/x86/kernel/cpu/mcheck/therm_throt.c -@@ -49,6 +49,8 @@ static DEFINE_PER_CPU(struct thermal_state, thermal_state); - - static atomic_t therm_throt_en = ATOMIC_INIT(0); - -+static u32 lvtthmr_init __read_mostly; -+ - #ifdef CONFIG_SYSFS - #define define_therm_throt_sysdev_one_ro(_name) \ - static SYSDEV_ATTR(_name, 0444, therm_throt_sysdev_show_##_name, NULL) -@@ -254,6 +256,18 @@ asmlinkage void smp_thermal_interrupt(struct pt_regs *regs) - ack_APIC_irq(); - } - -+void __init mcheck_intel_therm_init(void) -+{ -+ /* -+ * This function is only called on boot CPU. Save the init thermal -+ * LVT value on BSP and use that value to restore APs' thermal LVT -+ * entry BIOS programmed later -+ */ -+ if (cpu_has(&boot_cpu_data, X86_FEATURE_ACPI) && -+ cpu_has(&boot_cpu_data, X86_FEATURE_ACC)) -+ lvtthmr_init = apic_read(APIC_LVTTHMR); -+} -+ - void intel_init_thermal(struct cpuinfo_x86 *c) - { - unsigned int cpu = smp_processor_id(); -@@ -270,7 +284,20 @@ void intel_init_thermal(struct cpuinfo_x86 *c) - * since it might be delivered via SMI already: - */ - rdmsr(MSR_IA32_MISC_ENABLE, l, h); -- h = apic_read(APIC_LVTTHMR); -+ -+ /* -+ * The initial value of thermal LVT entries on all APs always reads -+ * 0x10000 because APs are woken up by BSP issuing INIT-SIPI-SIPI -+ * sequence to them and LVT registers are reset to 0s except for -+ * the mask bits which are set to 1s when APs receive INIT IPI. -+ * Always restore the value that BIOS has programmed on AP based on -+ * BSP's info we saved since BIOS is always setting the same value -+ * for all threads/cores -+ */ -+ apic_write(APIC_LVTTHMR, lvtthmr_init); -+ -+ h = lvtthmr_init; -+ - if ((l & MSR_IA32_MISC_ENABLE_TM1) && (h & APIC_DM_SMI)) { - printk(KERN_DEBUG - "CPU%d: Thermal monitoring handled by SMI\n", cpu); -diff --git a/arch/x86/kernel/cpu/perfctr-watchdog.c b/arch/x86/kernel/cpu/perfctr-watchdog.c -index fab786f..898df97 100644 ---- a/arch/x86/kernel/cpu/perfctr-watchdog.c -+++ b/arch/x86/kernel/cpu/perfctr-watchdog.c -@@ -712,7 +712,7 @@ static void probe_nmi_watchdog(void) - switch (boot_cpu_data.x86_vendor) { - case X86_VENDOR_AMD: - if (boot_cpu_data.x86 != 6 && boot_cpu_data.x86 != 15 && -- boot_cpu_data.x86 != 16) -+ boot_cpu_data.x86 != 16 && boot_cpu_data.x86 != 17) - return; - wd_ops = &k7_wd_ops; - break; -diff --git a/arch/x86/kernel/pci-calgary_64.c b/arch/x86/kernel/pci-calgary_64.c -index 971a3be..e6ec8a2 100644 ---- a/arch/x86/kernel/pci-calgary_64.c -+++ b/arch/x86/kernel/pci-calgary_64.c -@@ -318,13 +318,15 @@ static inline struct iommu_table *find_iommu_table(struct device *dev) - - pdev = to_pci_dev(dev); - -+ /* search up the device tree for an iommu */ - pbus = pdev->bus; -- -- /* is the device behind a bridge? Look for the root bus */ -- while (pbus->parent) -+ do { -+ tbl = pci_iommu(pbus); -+ if (tbl && tbl->it_busno == pbus->number) -+ break; -+ tbl = NULL; - pbus = pbus->parent; -- -- tbl = pci_iommu(pbus); -+ } while (pbus); - - BUG_ON(tbl && (tbl->it_busno != pbus->number)); - -diff --git a/arch/x86/kernel/pci-dma.c b/arch/x86/kernel/pci-dma.c -index a6e804d..6ac3931 100644 ---- a/arch/x86/kernel/pci-dma.c -+++ b/arch/x86/kernel/pci-dma.c -@@ -214,7 +214,7 @@ static __init int iommu_setup(char *p) - if (!strncmp(p, "allowdac", 8)) - forbid_dac = 0; - if (!strncmp(p, "nodac", 5)) -- forbid_dac = -1; -+ forbid_dac = 1; - if (!strncmp(p, "usedac", 6)) { - forbid_dac = -1; - return 1; -diff --git a/arch/x86/kernel/pci-gart_64.c b/arch/x86/kernel/pci-gart_64.c -index a7f1b64..fcc0b5c 100644 ---- a/arch/x86/kernel/pci-gart_64.c -+++ b/arch/x86/kernel/pci-gart_64.c -@@ -856,7 +856,7 @@ void __init gart_parse_options(char *p) - #endif - if (isdigit(*p) && get_option(&p, &arg)) - iommu_size = arg; -- if (!strncmp(p, "fullflush", 8)) -+ if (!strncmp(p, "fullflush", 9)) - iommu_fullflush = 1; - if (!strncmp(p, "nofullflush", 11)) - iommu_fullflush = 0; -diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c -index f930787..6caf260 100644 ---- a/arch/x86/kernel/reboot.c -+++ b/arch/x86/kernel/reboot.c -@@ -259,6 +259,14 @@ static struct dmi_system_id __initdata reboot_dmi_table[] = { - DMI_MATCH(DMI_PRODUCT_NAME, "SBC-FITPC2"), - }, - }, -+ { /* Handle problems with rebooting on ASUS P4S800 */ -+ .callback = set_bios_reboot, -+ .ident = "ASUS P4S800", -+ .matches = { -+ DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."), -+ DMI_MATCH(DMI_BOARD_NAME, "P4S800"), -+ }, -+ }, - { } - }; - -diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c -index 2a34f9c..51aa5b2 100644 ---- a/arch/x86/kernel/setup.c -+++ b/arch/x86/kernel/setup.c -@@ -109,6 +109,7 @@ - #ifdef CONFIG_X86_64 - #include - #endif -+#include - - /* - * end_pfn only includes RAM, while max_pfn_mapped includes all e820 entries. -@@ -1031,6 +1032,8 @@ void __init setup_arch(char **cmdline_p) - #endif - #endif - x86_init.oem.banner(); -+ -+ mcheck_intel_therm_init(); - } - - #ifdef CONFIG_X86_32 -diff --git a/arch/x86/kernel/tlb_uv.c b/arch/x86/kernel/tlb_uv.c -index 1740c85..364d015 100644 ---- a/arch/x86/kernel/tlb_uv.c -+++ b/arch/x86/kernel/tlb_uv.c -@@ -817,10 +817,8 @@ static int __init uv_init_blade(int blade) - */ - apicid = blade_to_first_apicid(blade); - pa = uv_read_global_mmr64(pnode, UVH_BAU_DATA_CONFIG); -- if ((pa & 0xff) != UV_BAU_MESSAGE) { -- uv_write_global_mmr64(pnode, UVH_BAU_DATA_CONFIG, -+ uv_write_global_mmr64(pnode, UVH_BAU_DATA_CONFIG, - ((apicid << 32) | UV_BAU_MESSAGE)); -- } - return 0; - } - -diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c -index 1be5cd6..e02dbb6 100644 ---- a/arch/x86/kvm/emulate.c -+++ b/arch/x86/kvm/emulate.c -@@ -613,6 +613,9 @@ static int do_insn_fetch(struct x86_emulate_ctxt *ctxt, - { - int rc = 0; - -+ /* x86 instructions are limited to 15 bytes. */ -+ if (eip + size - ctxt->decode.eip_orig > 15) -+ return X86EMUL_UNHANDLEABLE; - eip += ctxt->cs_base; - while (size--) { - rc = do_fetch_insn_byte(ctxt, ops, eip++, dest++); -@@ -871,7 +874,7 @@ x86_decode_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops) - /* Shadow copy of register state. Committed on successful emulation. */ - - memset(c, 0, sizeof(struct decode_cache)); -- c->eip = kvm_rip_read(ctxt->vcpu); -+ c->eip = c->eip_orig = kvm_rip_read(ctxt->vcpu); - ctxt->cs_base = seg_base(ctxt, VCPU_SREG_CS); - memcpy(c->regs, ctxt->vcpu->arch.regs, sizeof c->regs); - -diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c -index ae07d26..97b31fa 100644 ---- a/arch/x86/kvm/x86.c -+++ b/arch/x86/kvm/x86.c -@@ -484,16 +484,19 @@ static inline u32 bit(int bitno) - * and KVM_SET_MSRS, and KVM_GET_MSR_INDEX_LIST. - * - * This list is modified at module load time to reflect the -- * capabilities of the host cpu. -+ * capabilities of the host cpu. This capabilities test skips MSRs that are -+ * kvm-specific. Those are put in the beginning of the list. - */ -+ -+#define KVM_SAVE_MSRS_BEGIN 2 - static u32 msrs_to_save[] = { -+ MSR_KVM_SYSTEM_TIME, MSR_KVM_WALL_CLOCK, - MSR_IA32_SYSENTER_CS, MSR_IA32_SYSENTER_ESP, MSR_IA32_SYSENTER_EIP, - MSR_K6_STAR, - #ifdef CONFIG_X86_64 - MSR_CSTAR, MSR_KERNEL_GS_BASE, MSR_SYSCALL_MASK, MSR_LSTAR, - #endif -- MSR_IA32_TSC, MSR_KVM_SYSTEM_TIME, MSR_KVM_WALL_CLOCK, -- MSR_IA32_PERF_STATUS, MSR_IA32_CR_PAT, MSR_VM_HSAVE_PA -+ MSR_IA32_TSC, MSR_IA32_PERF_STATUS, MSR_IA32_CR_PAT, MSR_VM_HSAVE_PA - }; - - static unsigned num_msrs_to_save; -@@ -2433,7 +2436,8 @@ static void kvm_init_msr_list(void) - u32 dummy[2]; - unsigned i, j; - -- for (i = j = 0; i < ARRAY_SIZE(msrs_to_save); i++) { -+ /* skip the first msrs in the list. KVM-specific */ -+ for (i = j = KVM_SAVE_MSRS_BEGIN; i < ARRAY_SIZE(msrs_to_save); i++) { - if (rdmsr_safe(msrs_to_save[i], &dummy[0], &dummy[1]) < 0) - continue; - if (j < i) -diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c -index dfbf70e..79f9738 100644 ---- a/arch/x86/xen/enlighten.c -+++ b/arch/x86/xen/enlighten.c -@@ -138,24 +138,23 @@ static void xen_vcpu_setup(int cpu) - */ - void xen_vcpu_restore(void) - { -- if (have_vcpu_info_placement) { -- int cpu; -+ int cpu; - -- for_each_online_cpu(cpu) { -- bool other_cpu = (cpu != smp_processor_id()); -+ for_each_online_cpu(cpu) { -+ bool other_cpu = (cpu != smp_processor_id()); - -- if (other_cpu && -- HYPERVISOR_vcpu_op(VCPUOP_down, cpu, NULL)) -- BUG(); -+ if (other_cpu && -+ HYPERVISOR_vcpu_op(VCPUOP_down, cpu, NULL)) -+ BUG(); - -- xen_vcpu_setup(cpu); -+ xen_setup_runstate_info(cpu); - -- if (other_cpu && -- HYPERVISOR_vcpu_op(VCPUOP_up, cpu, NULL)) -- BUG(); -- } -+ if (have_vcpu_info_placement) -+ xen_vcpu_setup(cpu); - -- BUG_ON(!have_vcpu_info_placement); -+ if (other_cpu && -+ HYPERVISOR_vcpu_op(VCPUOP_up, cpu, NULL)) -+ BUG(); - } - } - -@@ -1182,6 +1181,8 @@ asmlinkage void __init xen_start_kernel(void) - - xen_raw_console_write("about to get started...\n"); - -+ xen_setup_runstate_info(0); -+ - /* Start the world */ - #ifdef CONFIG_X86_32 - i386_start_kernel(); -diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c -index 3bf7b1d..bf4cd6b 100644 ---- a/arch/x86/xen/mmu.c -+++ b/arch/x86/xen/mmu.c -@@ -185,7 +185,7 @@ static inline unsigned p2m_index(unsigned long pfn) - } - - /* Build the parallel p2m_top_mfn structures */ --static void __init xen_build_mfn_list_list(void) -+void xen_build_mfn_list_list(void) - { - unsigned pfn, idx; - -diff --git a/arch/x86/xen/smp.c b/arch/x86/xen/smp.c -index fe03eee..360f8d8 100644 ---- a/arch/x86/xen/smp.c -+++ b/arch/x86/xen/smp.c -@@ -295,6 +295,7 @@ static int __cpuinit xen_cpu_up(unsigned int cpu) - (unsigned long)task_stack_page(idle) - - KERNEL_STACK_OFFSET + THREAD_SIZE; - #endif -+ xen_setup_runstate_info(cpu); - xen_setup_timer(cpu); - xen_init_lock_cpu(cpu); - -diff --git a/arch/x86/xen/suspend.c b/arch/x86/xen/suspend.c -index 95be7b4..987267f 100644 ---- a/arch/x86/xen/suspend.c -+++ b/arch/x86/xen/suspend.c -@@ -1,4 +1,5 @@ - #include -+#include - - #include - #include -@@ -27,6 +28,8 @@ void xen_pre_suspend(void) - - void xen_post_suspend(int suspend_cancelled) - { -+ xen_build_mfn_list_list(); -+ - xen_setup_shared_info(); - - if (suspend_cancelled) { -@@ -44,7 +47,19 @@ void xen_post_suspend(int suspend_cancelled) - - } - -+static void xen_vcpu_notify_restore(void *data) -+{ -+ unsigned long reason = (unsigned long)data; -+ -+ /* Boot processor notified via generic timekeeping_resume() */ -+ if ( smp_processor_id() == 0) -+ return; -+ -+ clockevents_notify(reason, NULL); -+} -+ - void xen_arch_resume(void) - { -- /* nothing */ -+ smp_call_function(xen_vcpu_notify_restore, -+ (void *)CLOCK_EVT_NOTIFY_RESUME, 1); - } -diff --git a/arch/x86/xen/time.c b/arch/x86/xen/time.c -index 0a5aa44..9d1f853 100644 ---- a/arch/x86/xen/time.c -+++ b/arch/x86/xen/time.c -@@ -100,7 +100,7 @@ bool xen_vcpu_stolen(int vcpu) - return per_cpu(runstate, vcpu).state == RUNSTATE_runnable; - } - --static void setup_runstate_info(int cpu) -+void xen_setup_runstate_info(int cpu) - { - struct vcpu_register_runstate_memory_area area; - -@@ -434,7 +434,7 @@ void xen_setup_timer(int cpu) - name = ""; - - irq = bind_virq_to_irqhandler(VIRQ_TIMER, cpu, xen_timer_interrupt, -- IRQF_DISABLED|IRQF_PERCPU|IRQF_NOBALANCING, -+ IRQF_DISABLED|IRQF_PERCPU|IRQF_NOBALANCING|IRQF_TIMER, - name, NULL); - - evt = &per_cpu(xen_clock_events, cpu); -@@ -442,8 +442,6 @@ void xen_setup_timer(int cpu) - - evt->cpumask = cpumask_of(cpu); - evt->irq = irq; -- -- setup_runstate_info(cpu); - } - - void xen_teardown_timer(int cpu) -@@ -494,6 +492,7 @@ __init void xen_time_init(void) - - setup_force_cpu_cap(X86_FEATURE_TSC); - -+ xen_setup_runstate_info(cpu); - xen_setup_timer(cpu); - xen_setup_cpu_clockevents(); - } -diff --git a/arch/x86/xen/xen-asm_64.S b/arch/x86/xen/xen-asm_64.S -index 02f496a..53adefd 100644 ---- a/arch/x86/xen/xen-asm_64.S -+++ b/arch/x86/xen/xen-asm_64.S -@@ -96,7 +96,7 @@ ENTRY(xen_sysret32) - pushq $__USER32_CS - pushq %rcx - -- pushq $VGCF_in_syscall -+ pushq $0 - 1: jmp hypercall_iret - ENDPATCH(xen_sysret32) - RELOC(xen_sysret32, 1b+1) -@@ -151,7 +151,7 @@ ENTRY(xen_syscall32_target) - ENTRY(xen_sysenter_target) - lea 16(%rsp), %rsp /* strip %rcx, %r11 */ - mov $-ENOSYS, %rax -- pushq $VGCF_in_syscall -+ pushq $0 - jmp hypercall_iret - ENDPROC(xen_syscall32_target) - ENDPROC(xen_sysenter_target) -diff --git a/arch/x86/xen/xen-ops.h b/arch/x86/xen/xen-ops.h -index 355fa6b..f9153a3 100644 ---- a/arch/x86/xen/xen-ops.h -+++ b/arch/x86/xen/xen-ops.h -@@ -25,6 +25,7 @@ extern struct shared_info *HYPERVISOR_shared_info; - - void xen_setup_mfn_list_list(void); - void xen_setup_shared_info(void); -+void xen_build_mfn_list_list(void); - void xen_setup_machphys_mapping(void); - pgd_t *xen_setup_kernel_pagetable(pgd_t *pgd, unsigned long max_pfn); - void xen_ident_map_ISA(void); -@@ -41,6 +42,7 @@ void __init xen_build_dynamic_phys_to_machine(void); - - void xen_init_irq_ops(void); - void xen_setup_timer(int cpu); -+void xen_setup_runstate_info(int cpu); - void xen_teardown_timer(int cpu); - cycle_t xen_clocksource_read(void); - void xen_setup_cpu_clockevents(void); -diff --git a/drivers/ata/pata_hpt37x.c b/drivers/ata/pata_hpt37x.c -index d0a7df2..ec07c53 100644 ---- a/drivers/ata/pata_hpt37x.c -+++ b/drivers/ata/pata_hpt37x.c -@@ -24,7 +24,7 @@ - #include - - #define DRV_NAME "pata_hpt37x" --#define DRV_VERSION "0.6.12" -+#define DRV_VERSION "0.6.14" - - struct hpt_clock { - u8 xfer_speed; -@@ -404,9 +404,8 @@ static void hpt370_set_piomode(struct ata_port *ap, struct ata_device *adev) - - pci_read_config_dword(pdev, addr1, ®); - mode = hpt37x_find_mode(ap, adev->pio_mode); -- mode &= ~0x8000000; /* No FIFO in PIO */ -- mode &= ~0x30070000; /* Leave config bits alone */ -- reg &= 0x30070000; /* Strip timing bits */ -+ mode &= 0xCFC3FFFF; /* Leave DMA bits alone */ -+ reg &= ~0xCFC3FFFF; /* Strip timing bits */ - pci_write_config_dword(pdev, addr1, reg | mode); - } - -@@ -423,8 +422,7 @@ static void hpt370_set_dmamode(struct ata_port *ap, struct ata_device *adev) - { - struct pci_dev *pdev = to_pci_dev(ap->host->dev); - u32 addr1, addr2; -- u32 reg; -- u32 mode; -+ u32 reg, mode, mask; - u8 fast; - - addr1 = 0x40 + 4 * (adev->devno + 2 * ap->port_no); -@@ -436,11 +434,12 @@ static void hpt370_set_dmamode(struct ata_port *ap, struct ata_device *adev) - fast |= 0x01; - pci_write_config_byte(pdev, addr2, fast); - -+ mask = adev->dma_mode < XFER_UDMA_0 ? 0x31C001FF : 0x303C0000; -+ - pci_read_config_dword(pdev, addr1, ®); - mode = hpt37x_find_mode(ap, adev->dma_mode); -- mode |= 0x8000000; /* FIFO in MWDMA or UDMA */ -- mode &= ~0xC0000000; /* Leave config bits alone */ -- reg &= 0xC0000000; /* Strip timing bits */ -+ mode &= mask; -+ reg &= ~mask; - pci_write_config_dword(pdev, addr1, reg | mode); - } - -@@ -508,9 +507,8 @@ static void hpt372_set_piomode(struct ata_port *ap, struct ata_device *adev) - mode = hpt37x_find_mode(ap, adev->pio_mode); - - printk("Find mode for %d reports %X\n", adev->pio_mode, mode); -- mode &= ~0x80000000; /* No FIFO in PIO */ -- mode &= ~0x30070000; /* Leave config bits alone */ -- reg &= 0x30070000; /* Strip timing bits */ -+ mode &= 0xCFC3FFFF; /* Leave DMA bits alone */ -+ reg &= ~0xCFC3FFFF; /* Strip timing bits */ - pci_write_config_dword(pdev, addr1, reg | mode); - } - -@@ -527,8 +525,7 @@ static void hpt372_set_dmamode(struct ata_port *ap, struct ata_device *adev) - { - struct pci_dev *pdev = to_pci_dev(ap->host->dev); - u32 addr1, addr2; -- u32 reg; -- u32 mode; -+ u32 reg, mode, mask; - u8 fast; - - addr1 = 0x40 + 4 * (adev->devno + 2 * ap->port_no); -@@ -539,12 +536,13 @@ static void hpt372_set_dmamode(struct ata_port *ap, struct ata_device *adev) - fast &= ~0x07; - pci_write_config_byte(pdev, addr2, fast); - -+ mask = adev->dma_mode < XFER_UDMA_0 ? 0x31C001FF : 0x303C0000; -+ - pci_read_config_dword(pdev, addr1, ®); - mode = hpt37x_find_mode(ap, adev->dma_mode); - printk("Find mode for DMA %d reports %X\n", adev->dma_mode, mode); -- mode &= ~0xC0000000; /* Leave config bits alone */ -- mode |= 0x80000000; /* FIFO in MWDMA or UDMA */ -- reg &= 0xC0000000; /* Strip timing bits */ -+ mode &= mask; -+ reg &= ~mask; - pci_write_config_dword(pdev, addr1, reg | mode); - } - -diff --git a/drivers/ata/pata_hpt3x2n.c b/drivers/ata/pata_hpt3x2n.c -index 3d59fe0..21c5bd6 100644 ---- a/drivers/ata/pata_hpt3x2n.c -+++ b/drivers/ata/pata_hpt3x2n.c -@@ -25,7 +25,7 @@ - #include - - #define DRV_NAME "pata_hpt3x2n" --#define DRV_VERSION "0.3.4" -+#define DRV_VERSION "0.3.7" - - enum { - HPT_PCI_FAST = (1 << 31), -@@ -185,9 +185,8 @@ static void hpt3x2n_set_piomode(struct ata_port *ap, struct ata_device *adev) - - pci_read_config_dword(pdev, addr1, ®); - mode = hpt3x2n_find_mode(ap, adev->pio_mode); -- mode &= ~0x8000000; /* No FIFO in PIO */ -- mode &= ~0x30070000; /* Leave config bits alone */ -- reg &= 0x30070000; /* Strip timing bits */ -+ mode &= 0xCFC3FFFF; /* Leave DMA bits alone */ -+ reg &= ~0xCFC3FFFF; /* Strip timing bits */ - pci_write_config_dword(pdev, addr1, reg | mode); - } - -@@ -204,8 +203,7 @@ static void hpt3x2n_set_dmamode(struct ata_port *ap, struct ata_device *adev) - { - struct pci_dev *pdev = to_pci_dev(ap->host->dev); - u32 addr1, addr2; -- u32 reg; -- u32 mode; -+ u32 reg, mode, mask; - u8 fast; - - addr1 = 0x40 + 4 * (adev->devno + 2 * ap->port_no); -@@ -216,11 +214,12 @@ static void hpt3x2n_set_dmamode(struct ata_port *ap, struct ata_device *adev) - fast &= ~0x07; - pci_write_config_byte(pdev, addr2, fast); - -+ mask = adev->dma_mode < XFER_UDMA_0 ? 0x31C001FF : 0x303C0000; -+ - pci_read_config_dword(pdev, addr1, ®); - mode = hpt3x2n_find_mode(ap, adev->dma_mode); -- mode |= 0x8000000; /* FIFO in MWDMA or UDMA */ -- mode &= ~0xC0000000; /* Leave config bits alone */ -- reg &= 0xC0000000; /* Strip timing bits */ -+ mode &= mask; -+ reg &= ~mask; - pci_write_config_dword(pdev, addr1, reg | mode); - } - -diff --git a/drivers/base/core.c b/drivers/base/core.c -index 6bee6af..1093179 100644 ---- a/drivers/base/core.c -+++ b/drivers/base/core.c -@@ -56,7 +56,14 @@ static inline int device_is_not_partition(struct device *dev) - */ - const char *dev_driver_string(const struct device *dev) - { -- return dev->driver ? dev->driver->name : -+ struct device_driver *drv; -+ -+ /* dev->driver can change to NULL underneath us because of unbinding, -+ * so be careful about accessing it. dev->bus and dev->class should -+ * never change once they are set, so they don't need special care. -+ */ -+ drv = ACCESS_ONCE(dev->driver); -+ return drv ? drv->name : - (dev->bus ? dev->bus->name : - (dev->class ? dev->class->name : "")); - } -diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c -index 846d89e..0a4b75f 100644 ---- a/drivers/base/power/runtime.c -+++ b/drivers/base/power/runtime.c -@@ -777,7 +777,7 @@ int __pm_runtime_set_status(struct device *dev, unsigned int status) - } - - if (parent) { -- spin_lock(&parent->power.lock); -+ spin_lock_nested(&parent->power.lock, SINGLE_DEPTH_NESTING); - - /* - * It is invalid to put an active child under a parent that is -diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c -index 94260aa..1e504de 100644 ---- a/drivers/firewire/ohci.c -+++ b/drivers/firewire/ohci.c -@@ -2209,6 +2209,13 @@ static int ohci_queue_iso_receive_dualbuffer(struct fw_iso_context *base, - page = payload >> PAGE_SHIFT; - offset = payload & ~PAGE_MASK; - rest = p->payload_length; -+ /* -+ * The controllers I've tested have not worked correctly when -+ * second_req_count is zero. Rather than do something we know won't -+ * work, return an error -+ */ -+ if (rest == 0) -+ return -EINVAL; - - /* FIXME: make packet-per-buffer/dual-buffer a context option */ - while (rest > 0) { -@@ -2262,7 +2269,7 @@ static int ohci_queue_iso_receive_packet_per_buffer(struct fw_iso_context *base, - unsigned long payload) - { - struct iso_context *ctx = container_of(base, struct iso_context, base); -- struct descriptor *d = NULL, *pd = NULL; -+ struct descriptor *d, *pd; - struct fw_iso_packet *p = packet; - dma_addr_t d_bus, page_bus; - u32 z, header_z, rest; -@@ -2300,8 +2307,9 @@ static int ohci_queue_iso_receive_packet_per_buffer(struct fw_iso_context *base, - d->data_address = cpu_to_le32(d_bus + (z * sizeof(*d))); - - rest = payload_per_buffer; -+ pd = d; - for (j = 1; j < z; j++) { -- pd = d + j; -+ pd++; - pd->control = cpu_to_le16(DESCRIPTOR_STATUS | - DESCRIPTOR_INPUT_MORE); - -diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c -index 0a6f0b3..332d743 100644 ---- a/drivers/gpu/drm/drm_irq.c -+++ b/drivers/gpu/drm/drm_irq.c -@@ -429,15 +429,21 @@ int drm_vblank_get(struct drm_device *dev, int crtc) - - spin_lock_irqsave(&dev->vbl_lock, irqflags); - /* Going from 0->1 means we have to enable interrupts again */ -- if (atomic_add_return(1, &dev->vblank_refcount[crtc]) == 1 && -- !dev->vblank_enabled[crtc]) { -- ret = dev->driver->enable_vblank(dev, crtc); -- DRM_DEBUG("enabling vblank on crtc %d, ret: %d\n", crtc, ret); -- if (ret) -+ if (atomic_add_return(1, &dev->vblank_refcount[crtc]) == 1) { -+ if (!dev->vblank_enabled[crtc]) { -+ ret = dev->driver->enable_vblank(dev, crtc); -+ DRM_DEBUG("enabling vblank on crtc %d, ret: %d\n", crtc, ret); -+ if (ret) -+ atomic_dec(&dev->vblank_refcount[crtc]); -+ else { -+ dev->vblank_enabled[crtc] = 1; -+ drm_update_vblank_count(dev, crtc); -+ } -+ } -+ } else { -+ if (!dev->vblank_enabled[crtc]) { - atomic_dec(&dev->vblank_refcount[crtc]); -- else { -- dev->vblank_enabled[crtc] = 1; -- drm_update_vblank_count(dev, crtc); -+ ret = -EINVAL; - } - } - spin_unlock_irqrestore(&dev->vbl_lock, irqflags); -@@ -464,6 +470,18 @@ void drm_vblank_put(struct drm_device *dev, int crtc) - } - EXPORT_SYMBOL(drm_vblank_put); - -+void drm_vblank_off(struct drm_device *dev, int crtc) -+{ -+ unsigned long irqflags; -+ -+ spin_lock_irqsave(&dev->vbl_lock, irqflags); -+ DRM_WAKEUP(&dev->vbl_queue[crtc]); -+ dev->vblank_enabled[crtc] = 0; -+ dev->last_vblank[crtc] = dev->driver->get_vblank_counter(dev, crtc); -+ spin_unlock_irqrestore(&dev->vbl_lock, irqflags); -+} -+EXPORT_SYMBOL(drm_vblank_off); -+ - /** - * drm_vblank_pre_modeset - account for vblanks across mode sets - * @dev: DRM device -diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h -index a725f65..ecbafd0 100644 ---- a/drivers/gpu/drm/i915/i915_drv.h -+++ b/drivers/gpu/drm/i915/i915_drv.h -@@ -957,6 +957,7 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); - #define IS_I85X(dev) ((dev)->pci_device == 0x3582) - #define IS_I855(dev) ((dev)->pci_device == 0x3582) - #define IS_I865G(dev) ((dev)->pci_device == 0x2572) -+#define IS_I8XX(dev) (IS_I830(dev) || IS_845G(dev) || IS_I85X(dev) || IS_I865G(dev)) - - #define IS_I915G(dev) ((dev)->pci_device == 0x2582 || (dev)->pci_device == 0x258a) - #define IS_I915GM(dev) ((dev)->pci_device == 0x2592) -@@ -1018,9 +1019,12 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); - */ - #define HAS_128_BYTE_Y_TILING(dev) (IS_I9XX(dev) && !(IS_I915G(dev) || \ - IS_I915GM(dev))) -+#define SUPPORTS_DIGITAL_OUTPUTS(dev) (IS_I9XX(dev) && !IS_IGD(dev)) - #define SUPPORTS_INTEGRATED_HDMI(dev) (IS_G4X(dev) || IS_IGDNG(dev)) - #define SUPPORTS_INTEGRATED_DP(dev) (IS_G4X(dev) || IS_IGDNG(dev)) - #define SUPPORTS_EDP(dev) (IS_IGDNG_M(dev)) -+#define SUPPORTS_TV(dev) (IS_I9XX(dev) && IS_MOBILE(dev) && \ -+ !IS_IGDNG(dev) && !IS_IGD(dev)) - #define I915_HAS_HOTPLUG(dev) (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev) || IS_I965G(dev)) - /* dsparb controlled by hw only */ - #define DSPARB_HWCONTROL(dev) (IS_G4X(dev) || IS_IGDNG(dev)) -diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c -index abfc27b..5ddbd38 100644 ---- a/drivers/gpu/drm/i915/i915_gem.c -+++ b/drivers/gpu/drm/i915/i915_gem.c -@@ -1288,6 +1288,7 @@ i915_gem_create_mmap_offset(struct drm_gem_object *obj) - list->hash.key = list->file_offset_node->start; - if (drm_ht_insert_item(&mm->offset_hash, &list->hash)) { - DRM_ERROR("failed to add to map hash\n"); -+ ret = -ENOMEM; - goto out_free_mm; - } - -diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c -index 099f420..f1de53b 100644 ---- a/drivers/gpu/drm/i915/intel_display.c -+++ b/drivers/gpu/drm/i915/intel_display.c -@@ -1482,6 +1482,15 @@ static void igdng_crtc_dpms(struct drm_crtc *crtc, int mode) - case DRM_MODE_DPMS_STANDBY: - case DRM_MODE_DPMS_SUSPEND: - DRM_DEBUG("crtc %d dpms on\n", pipe); -+ -+ if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) { -+ temp = I915_READ(PCH_LVDS); -+ if ((temp & LVDS_PORT_EN) == 0) { -+ I915_WRITE(PCH_LVDS, temp | LVDS_PORT_EN); -+ POSTING_READ(PCH_LVDS); -+ } -+ } -+ - if (HAS_eDP) { - /* enable eDP PLL */ - igdng_enable_pll_edp(crtc); -@@ -1666,8 +1675,6 @@ static void igdng_crtc_dpms(struct drm_crtc *crtc, int mode) - case DRM_MODE_DPMS_OFF: - DRM_DEBUG("crtc %d dpms off\n", pipe); - -- i915_disable_vga(dev); -- - /* Disable display plane */ - temp = I915_READ(dspcntr_reg); - if ((temp & DISPLAY_PLANE_ENABLE) != 0) { -@@ -1677,6 +1684,8 @@ static void igdng_crtc_dpms(struct drm_crtc *crtc, int mode) - I915_READ(dspbase_reg); - } - -+ i915_disable_vga(dev); -+ - /* disable cpu pipe, disable after all planes disabled */ - temp = I915_READ(pipeconf_reg); - if ((temp & PIPEACONF_ENABLE) != 0) { -@@ -1697,9 +1706,15 @@ static void igdng_crtc_dpms(struct drm_crtc *crtc, int mode) - } else - DRM_DEBUG("crtc %d is disabled\n", pipe); - -- if (HAS_eDP) { -- igdng_disable_pll_edp(crtc); -+ udelay(100); -+ -+ /* Disable PF */ -+ temp = I915_READ(pf_ctl_reg); -+ if ((temp & PF_ENABLE) != 0) { -+ I915_WRITE(pf_ctl_reg, temp & ~PF_ENABLE); -+ I915_READ(pf_ctl_reg); - } -+ I915_WRITE(pf_win_size, 0); - - /* disable CPU FDI tx and PCH FDI rx */ - temp = I915_READ(fdi_tx_reg); -@@ -1725,6 +1740,13 @@ static void igdng_crtc_dpms(struct drm_crtc *crtc, int mode) - - udelay(100); - -+ if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) { -+ temp = I915_READ(PCH_LVDS); -+ I915_WRITE(PCH_LVDS, temp & ~LVDS_PORT_EN); -+ I915_READ(PCH_LVDS); -+ udelay(100); -+ } -+ - /* disable PCH transcoder */ - temp = I915_READ(transconf_reg); - if ((temp & TRANS_ENABLE) != 0) { -@@ -1744,6 +1766,8 @@ static void igdng_crtc_dpms(struct drm_crtc *crtc, int mode) - } - } - -+ udelay(100); -+ - /* disable PCH DPLL */ - temp = I915_READ(pch_dpll_reg); - if ((temp & DPLL_VCO_ENABLE) != 0) { -@@ -1751,14 +1775,20 @@ static void igdng_crtc_dpms(struct drm_crtc *crtc, int mode) - I915_READ(pch_dpll_reg); - } - -- temp = I915_READ(fdi_rx_reg); -- if ((temp & FDI_RX_PLL_ENABLE) != 0) { -- temp &= ~FDI_SEL_PCDCLK; -- temp &= ~FDI_RX_PLL_ENABLE; -- I915_WRITE(fdi_rx_reg, temp); -- I915_READ(fdi_rx_reg); -+ if (HAS_eDP) { -+ igdng_disable_pll_edp(crtc); - } - -+ temp = I915_READ(fdi_rx_reg); -+ temp &= ~FDI_SEL_PCDCLK; -+ I915_WRITE(fdi_rx_reg, temp); -+ I915_READ(fdi_rx_reg); -+ -+ temp = I915_READ(fdi_rx_reg); -+ temp &= ~FDI_RX_PLL_ENABLE; -+ I915_WRITE(fdi_rx_reg, temp); -+ I915_READ(fdi_rx_reg); -+ - /* Disable CPU FDI TX PLL */ - temp = I915_READ(fdi_tx_reg); - if ((temp & FDI_TX_PLL_ENABLE) != 0) { -@@ -1767,16 +1797,8 @@ static void igdng_crtc_dpms(struct drm_crtc *crtc, int mode) - udelay(100); - } - -- /* Disable PF */ -- temp = I915_READ(pf_ctl_reg); -- if ((temp & PF_ENABLE) != 0) { -- I915_WRITE(pf_ctl_reg, temp & ~PF_ENABLE); -- I915_READ(pf_ctl_reg); -- } -- I915_WRITE(pf_win_size, 0); -- - /* Wait for the clocks to turn off. */ -- udelay(150); -+ udelay(100); - break; - } - } -@@ -1845,6 +1867,7 @@ static void i9xx_crtc_dpms(struct drm_crtc *crtc, int mode) - intel_update_watermarks(dev); - /* Give the overlay scaler a chance to disable if it's on this pipe */ - //intel_crtc_dpms_video(crtc, FALSE); TODO -+ drm_vblank_off(dev, pipe); - - if (dev_priv->cfb_plane == plane && - dev_priv->display.disable_fbc) -@@ -4118,7 +4141,7 @@ static void intel_setup_outputs(struct drm_device *dev) - if (I915_READ(PCH_DP_D) & DP_DETECTED) - intel_dp_init(dev, PCH_DP_D); - -- } else if (IS_I9XX(dev)) { -+ } else if (SUPPORTS_DIGITAL_OUTPUTS(dev)) { - bool found = false; - - if (I915_READ(SDVOB) & SDVO_DETECTED) { -@@ -4145,10 +4168,10 @@ static void intel_setup_outputs(struct drm_device *dev) - - if (SUPPORTS_INTEGRATED_DP(dev) && (I915_READ(DP_D) & DP_DETECTED)) - intel_dp_init(dev, DP_D); -- } else -+ } else if (IS_I8XX(dev)) - intel_dvo_init(dev); - -- if (IS_I9XX(dev) && IS_MOBILE(dev) && !IS_IGDNG(dev)) -+ if (SUPPORTS_TV(dev)) - intel_tv_init(dev); - - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { -diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c -index d834475..92a3d7b 100644 ---- a/drivers/gpu/drm/i915/intel_dp.c -+++ b/drivers/gpu/drm/i915/intel_dp.c -@@ -1254,11 +1254,11 @@ intel_dp_init(struct drm_device *dev, int output_reg) - else - intel_output->type = INTEL_OUTPUT_DISPLAYPORT; - -- if (output_reg == DP_B) -+ if (output_reg == DP_B || output_reg == PCH_DP_B) - intel_output->clone_mask = (1 << INTEL_DP_B_CLONE_BIT); -- else if (output_reg == DP_C) -+ else if (output_reg == DP_C || output_reg == PCH_DP_C) - intel_output->clone_mask = (1 << INTEL_DP_C_CLONE_BIT); -- else if (output_reg == DP_D) -+ else if (output_reg == DP_D || output_reg == PCH_DP_D) - intel_output->clone_mask = (1 << INTEL_DP_D_CLONE_BIT); - - if (IS_eDP(intel_output)) { -diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c -index 9ca9179..5b28b4e 100644 ---- a/drivers/gpu/drm/i915/intel_tv.c -+++ b/drivers/gpu/drm/i915/intel_tv.c -@@ -1213,20 +1213,17 @@ intel_tv_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, - tv_ctl |= TV_TRILEVEL_SYNC; - if (tv_mode->pal_burst) - tv_ctl |= TV_PAL_BURST; -+ - scctl1 = 0; -- /* dda1 implies valid video levels */ -- if (tv_mode->dda1_inc) { -+ if (tv_mode->dda1_inc) - scctl1 |= TV_SC_DDA1_EN; -- } -- - if (tv_mode->dda2_inc) - scctl1 |= TV_SC_DDA2_EN; -- - if (tv_mode->dda3_inc) - scctl1 |= TV_SC_DDA3_EN; -- - scctl1 |= tv_mode->sc_reset; -- scctl1 |= video_levels->burst << TV_BURST_LEVEL_SHIFT; -+ if (video_levels) -+ scctl1 |= video_levels->burst << TV_BURST_LEVEL_SHIFT; - scctl1 |= tv_mode->dda1_inc << TV_SCDDA1_INC_SHIFT; - - scctl2 = tv_mode->dda2_size << TV_SCDDA2_SIZE_SHIFT | -diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c -index c15287a..c6777cb 100644 ---- a/drivers/gpu/drm/radeon/atombios_crtc.c -+++ b/drivers/gpu/drm/radeon/atombios_crtc.c -@@ -241,6 +241,7 @@ void atombios_crtc_dpms(struct drm_crtc *crtc, int mode) - { - struct drm_device *dev = crtc->dev; - struct radeon_device *rdev = dev->dev_private; -+ struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); - - switch (mode) { - case DRM_MODE_DPMS_ON: -@@ -248,20 +249,19 @@ void atombios_crtc_dpms(struct drm_crtc *crtc, int mode) - if (ASIC_IS_DCE3(rdev)) - atombios_enable_crtc_memreq(crtc, 1); - atombios_blank_crtc(crtc, 0); -+ drm_vblank_post_modeset(dev, radeon_crtc->crtc_id); -+ radeon_crtc_load_lut(crtc); - break; - case DRM_MODE_DPMS_STANDBY: - case DRM_MODE_DPMS_SUSPEND: - case DRM_MODE_DPMS_OFF: -+ drm_vblank_pre_modeset(dev, radeon_crtc->crtc_id); - atombios_blank_crtc(crtc, 1); - if (ASIC_IS_DCE3(rdev)) - atombios_enable_crtc_memreq(crtc, 0); - atombios_enable_crtc(crtc, 0); - break; - } -- -- if (mode != DRM_MODE_DPMS_OFF) { -- radeon_crtc_load_lut(crtc); -- } - } - - static void -diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c -index 2ed88a8..969502a 100644 ---- a/drivers/gpu/drm/radeon/radeon_atombios.c -+++ b/drivers/gpu/drm/radeon/radeon_atombios.c -@@ -135,6 +135,14 @@ static bool radeon_atom_apply_quirks(struct drm_device *dev, - } - } - -+ /* HIS X1300 is DVI+VGA, not DVI+DVI */ -+ if ((dev->pdev->device == 0x7146) && -+ (dev->pdev->subsystem_vendor == 0x17af) && -+ (dev->pdev->subsystem_device == 0x2058)) { -+ if (supported_device == ATOM_DEVICE_DFP1_SUPPORT) -+ return false; -+ } -+ - /* Funky macbooks */ - if ((dev->pdev->device == 0x71C5) && - (dev->pdev->subsystem_vendor == 0x106b) && -diff --git a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c -index 8d0b7aa..22ce4d6 100644 ---- a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c -+++ b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c -@@ -292,8 +292,7 @@ void radeon_crtc_dpms(struct drm_crtc *crtc, int mode) - uint32_t mask; - - if (radeon_crtc->crtc_id) -- mask = (RADEON_CRTC2_EN | -- RADEON_CRTC2_DISP_DIS | -+ mask = (RADEON_CRTC2_DISP_DIS | - RADEON_CRTC2_VSYNC_DIS | - RADEON_CRTC2_HSYNC_DIS | - RADEON_CRTC2_DISP_REQ_EN_B); -@@ -305,7 +304,7 @@ void radeon_crtc_dpms(struct drm_crtc *crtc, int mode) - switch (mode) { - case DRM_MODE_DPMS_ON: - if (radeon_crtc->crtc_id) -- WREG32_P(RADEON_CRTC2_GEN_CNTL, RADEON_CRTC2_EN, ~mask); -+ WREG32_P(RADEON_CRTC2_GEN_CNTL, RADEON_CRTC2_EN, ~(RADEON_CRTC2_EN | mask)); - else { - WREG32_P(RADEON_CRTC_GEN_CNTL, RADEON_CRTC_EN, ~(RADEON_CRTC_EN | - RADEON_CRTC_DISP_REQ_EN_B)); -@@ -319,7 +318,7 @@ void radeon_crtc_dpms(struct drm_crtc *crtc, int mode) - case DRM_MODE_DPMS_OFF: - drm_vblank_pre_modeset(dev, radeon_crtc->crtc_id); - if (radeon_crtc->crtc_id) -- WREG32_P(RADEON_CRTC2_GEN_CNTL, mask, ~mask); -+ WREG32_P(RADEON_CRTC2_GEN_CNTL, mask, ~(RADEON_CRTC2_EN | mask)); - else { - WREG32_P(RADEON_CRTC_GEN_CNTL, RADEON_CRTC_DISP_REQ_EN_B, ~(RADEON_CRTC_EN | - RADEON_CRTC_DISP_REQ_EN_B)); -diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c -index 5f117cd..4444f48 100644 ---- a/drivers/gpu/drm/radeon/rs600.c -+++ b/drivers/gpu/drm/radeon/rs600.c -@@ -301,9 +301,7 @@ int rs600_mc_wait_for_idle(struct radeon_device *rdev) - - void rs600_gpu_init(struct radeon_device *rdev) - { -- /* FIXME: HDP same place on rs600 ? */ - r100_hdp_reset(rdev); -- /* FIXME: is this correct ? */ - r420_pipes_init(rdev); - /* Wait for mc idle */ - if (rs600_mc_wait_for_idle(rdev)) -@@ -312,9 +310,20 @@ void rs600_gpu_init(struct radeon_device *rdev) - - void rs600_vram_info(struct radeon_device *rdev) - { -- /* FIXME: to do or is these values sane ? */ - rdev->mc.vram_is_ddr = true; - rdev->mc.vram_width = 128; -+ -+ rdev->mc.real_vram_size = RREG32(RADEON_CONFIG_MEMSIZE); -+ rdev->mc.mc_vram_size = rdev->mc.real_vram_size; -+ -+ rdev->mc.aper_base = drm_get_resource_start(rdev->ddev, 0); -+ rdev->mc.aper_size = drm_get_resource_len(rdev->ddev, 0); -+ -+ if (rdev->mc.mc_vram_size > rdev->mc.aper_size) -+ rdev->mc.mc_vram_size = rdev->mc.aper_size; -+ -+ if (rdev->mc.real_vram_size > rdev->mc.aper_size) -+ rdev->mc.real_vram_size = rdev->mc.aper_size; - } - - void rs600_bandwidth_update(struct radeon_device *rdev) -diff --git a/drivers/gpu/drm/radeon/rs690.c b/drivers/gpu/drm/radeon/rs690.c -index 2754717..b12ff76 100644 ---- a/drivers/gpu/drm/radeon/rs690.c -+++ b/drivers/gpu/drm/radeon/rs690.c -@@ -131,24 +131,25 @@ void rs690_pm_info(struct radeon_device *rdev) - - void rs690_vram_info(struct radeon_device *rdev) - { -- uint32_t tmp; - fixed20_12 a; - - rs400_gart_adjust_size(rdev); -- /* DDR for all card after R300 & IGP */ -+ - rdev->mc.vram_is_ddr = true; -- /* FIXME: is this correct for RS690/RS740 ? */ -- tmp = RREG32(RADEON_MEM_CNTL); -- if (tmp & R300_MEM_NUM_CHANNELS_MASK) { -- rdev->mc.vram_width = 128; -- } else { -- rdev->mc.vram_width = 64; -- } -+ rdev->mc.vram_width = 128; -+ - rdev->mc.real_vram_size = RREG32(RADEON_CONFIG_MEMSIZE); - rdev->mc.mc_vram_size = rdev->mc.real_vram_size; - - rdev->mc.aper_base = drm_get_resource_start(rdev->ddev, 0); - rdev->mc.aper_size = drm_get_resource_len(rdev->ddev, 0); -+ -+ if (rdev->mc.mc_vram_size > rdev->mc.aper_size) -+ rdev->mc.mc_vram_size = rdev->mc.aper_size; -+ -+ if (rdev->mc.real_vram_size > rdev->mc.aper_size) -+ rdev->mc.real_vram_size = rdev->mc.aper_size; -+ - rs690_pm_info(rdev); - /* FIXME: we should enforce default clock in case GPU is not in - * default setup -diff --git a/drivers/ide/slc90e66.c b/drivers/ide/slc90e66.c -index 9aec78d..1ccfb40 100644 ---- a/drivers/ide/slc90e66.c -+++ b/drivers/ide/slc90e66.c -@@ -91,8 +91,7 @@ static void slc90e66_set_dma_mode(ide_drive_t *drive, const u8 speed) - - if (!(reg48 & u_flag)) - pci_write_config_word(dev, 0x48, reg48|u_flag); -- /* FIXME: (reg4a & a_speed) ? */ -- if ((reg4a & u_speed) != u_speed) { -+ if ((reg4a & a_speed) != u_speed) { - pci_write_config_word(dev, 0x4a, reg4a & ~a_speed); - pci_read_config_word(dev, 0x4a, ®4a); - pci_write_config_word(dev, 0x4a, reg4a|u_speed); -diff --git a/drivers/macintosh/therm_adt746x.c b/drivers/macintosh/therm_adt746x.c -index 556f0fe..386a797 100644 ---- a/drivers/macintosh/therm_adt746x.c -+++ b/drivers/macintosh/therm_adt746x.c -@@ -79,6 +79,7 @@ struct thermostat { - u8 limits[3]; - int last_speed[2]; - int last_var[2]; -+ int pwm_inv[2]; - }; - - static enum {ADT7460, ADT7467} therm_type; -@@ -229,19 +230,23 @@ static void write_fan_speed(struct thermostat *th, int speed, int fan) - - if (speed >= 0) { - manual = read_reg(th, MANUAL_MODE[fan]); -+ manual &= ~INVERT_MASK; - write_reg(th, MANUAL_MODE[fan], -- (manual|MANUAL_MASK) & (~INVERT_MASK)); -+ manual | MANUAL_MASK | th->pwm_inv[fan]); - write_reg(th, FAN_SPD_SET[fan], speed); - } else { - /* back to automatic */ - if(therm_type == ADT7460) { - manual = read_reg(th, - MANUAL_MODE[fan]) & (~MANUAL_MASK); -- -+ manual &= ~INVERT_MASK; -+ manual |= th->pwm_inv[fan]; - write_reg(th, - MANUAL_MODE[fan], manual|REM_CONTROL[fan]); - } else { - manual = read_reg(th, MANUAL_MODE[fan]); -+ manual &= ~INVERT_MASK; -+ manual |= th->pwm_inv[fan]; - write_reg(th, MANUAL_MODE[fan], manual&(~AUTO_MASK)); - } - } -@@ -418,6 +423,10 @@ static int probe_thermostat(struct i2c_client *client, - - thermostat = th; - -+ /* record invert bit status because fw can corrupt it after suspend */ -+ th->pwm_inv[0] = read_reg(th, MANUAL_MODE[0]) & INVERT_MASK; -+ th->pwm_inv[1] = read_reg(th, MANUAL_MODE[1]) & INVERT_MASK; -+ - /* be sure to really write fan speed the first time */ - th->last_speed[0] = -2; - th->last_speed[1] = -2; -diff --git a/drivers/macintosh/windfarm_smu_controls.c b/drivers/macintosh/windfarm_smu_controls.c -index 961fa0e..6c68b9e 100644 ---- a/drivers/macintosh/windfarm_smu_controls.c -+++ b/drivers/macintosh/windfarm_smu_controls.c -@@ -202,6 +202,8 @@ static struct smu_fan_control *smu_fan_create(struct device_node *node, - fct->ctrl.name = "cpu-front-fan-1"; - else if (!strcmp(l, "CPU A PUMP")) - fct->ctrl.name = "cpu-pump-0"; -+ else if (!strcmp(l, "CPU B PUMP")) -+ fct->ctrl.name = "cpu-pump-1"; - else if (!strcmp(l, "Slots Fan") || !strcmp(l, "Slots fan") || - !strcmp(l, "EXPANSION SLOTS INTAKE")) - fct->ctrl.name = "slots-fan"; -diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c -index 60e2b32..a5e5f2f 100644 ---- a/drivers/md/bitmap.c -+++ b/drivers/md/bitmap.c -@@ -1078,23 +1078,31 @@ static bitmap_counter_t *bitmap_get_counter(struct bitmap *bitmap, - * out to disk - */ - --void bitmap_daemon_work(struct bitmap *bitmap) -+void bitmap_daemon_work(mddev_t *mddev) - { -+ struct bitmap *bitmap; - unsigned long j; - unsigned long flags; - struct page *page = NULL, *lastpage = NULL; - int blocks; - void *paddr; - -- if (bitmap == NULL) -+ /* Use a mutex to guard daemon_work against -+ * bitmap_destroy. -+ */ -+ mutex_lock(&mddev->bitmap_mutex); -+ bitmap = mddev->bitmap; -+ if (bitmap == NULL) { -+ mutex_unlock(&mddev->bitmap_mutex); - return; -+ } - if (time_before(jiffies, bitmap->daemon_lastrun + bitmap->daemon_sleep*HZ)) - goto done; - - bitmap->daemon_lastrun = jiffies; - if (bitmap->allclean) { - bitmap->mddev->thread->timeout = MAX_SCHEDULE_TIMEOUT; -- return; -+ goto done; - } - bitmap->allclean = 1; - -@@ -1203,6 +1211,7 @@ void bitmap_daemon_work(struct bitmap *bitmap) - done: - if (bitmap->allclean == 0) - bitmap->mddev->thread->timeout = bitmap->daemon_sleep * HZ; -+ mutex_unlock(&mddev->bitmap_mutex); - } - - static bitmap_counter_t *bitmap_get_counter(struct bitmap *bitmap, -@@ -1541,9 +1550,9 @@ void bitmap_flush(mddev_t *mddev) - */ - sleep = bitmap->daemon_sleep; - bitmap->daemon_sleep = 0; -- bitmap_daemon_work(bitmap); -- bitmap_daemon_work(bitmap); -- bitmap_daemon_work(bitmap); -+ bitmap_daemon_work(mddev); -+ bitmap_daemon_work(mddev); -+ bitmap_daemon_work(mddev); - bitmap->daemon_sleep = sleep; - bitmap_update_sb(bitmap); - } -@@ -1574,6 +1583,7 @@ static void bitmap_free(struct bitmap *bitmap) - kfree(bp); - kfree(bitmap); - } -+ - void bitmap_destroy(mddev_t *mddev) - { - struct bitmap *bitmap = mddev->bitmap; -@@ -1581,7 +1591,9 @@ void bitmap_destroy(mddev_t *mddev) - if (!bitmap) /* there was no bitmap */ - return; - -+ mutex_lock(&mddev->bitmap_mutex); - mddev->bitmap = NULL; /* disconnect from the md device */ -+ mutex_unlock(&mddev->bitmap_mutex); - if (mddev->thread) - mddev->thread->timeout = MAX_SCHEDULE_TIMEOUT; - -diff --git a/drivers/md/bitmap.h b/drivers/md/bitmap.h -index e989006..7e38d13 100644 ---- a/drivers/md/bitmap.h -+++ b/drivers/md/bitmap.h -@@ -282,7 +282,7 @@ void bitmap_close_sync(struct bitmap *bitmap); - void bitmap_cond_end_sync(struct bitmap *bitmap, sector_t sector); - - void bitmap_unplug(struct bitmap *bitmap); --void bitmap_daemon_work(struct bitmap *bitmap); -+void bitmap_daemon_work(mddev_t *mddev); - #endif - - #endif -diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c -index ed10381..959d6d1 100644 ---- a/drivers/md/dm-crypt.c -+++ b/drivers/md/dm-crypt.c -@@ -1,7 +1,7 @@ - /* - * Copyright (C) 2003 Christophe Saout - * Copyright (C) 2004 Clemens Fruhwirth -- * Copyright (C) 2006-2008 Red Hat, Inc. All rights reserved. -+ * Copyright (C) 2006-2009 Red Hat, Inc. All rights reserved. - * - * This file is released under the GPL. - */ -@@ -71,10 +71,21 @@ struct crypt_iv_operations { - int (*ctr)(struct crypt_config *cc, struct dm_target *ti, - const char *opts); - void (*dtr)(struct crypt_config *cc); -- const char *(*status)(struct crypt_config *cc); -+ int (*init)(struct crypt_config *cc); -+ int (*wipe)(struct crypt_config *cc); - int (*generator)(struct crypt_config *cc, u8 *iv, sector_t sector); - }; - -+struct iv_essiv_private { -+ struct crypto_cipher *tfm; -+ struct crypto_hash *hash_tfm; -+ u8 *salt; -+}; -+ -+struct iv_benbi_private { -+ int shift; -+}; -+ - /* - * Crypt: maps a linear range of a block device - * and encrypts / decrypts at the same time. -@@ -102,8 +113,8 @@ struct crypt_config { - struct crypt_iv_operations *iv_gen_ops; - char *iv_mode; - union { -- struct crypto_cipher *essiv_tfm; -- int benbi_shift; -+ struct iv_essiv_private essiv; -+ struct iv_benbi_private benbi; - } iv_gen_private; - sector_t iv_offset; - unsigned int iv_size; -@@ -169,88 +180,114 @@ static int crypt_iv_plain_gen(struct crypt_config *cc, u8 *iv, sector_t sector) - return 0; - } - --static int crypt_iv_essiv_ctr(struct crypt_config *cc, struct dm_target *ti, -- const char *opts) -+/* Initialise ESSIV - compute salt but no local memory allocations */ -+static int crypt_iv_essiv_init(struct crypt_config *cc) - { -- struct crypto_cipher *essiv_tfm; -- struct crypto_hash *hash_tfm; -+ struct iv_essiv_private *essiv = &cc->iv_gen_private.essiv; - struct hash_desc desc; - struct scatterlist sg; -- unsigned int saltsize; -- u8 *salt; - int err; - -- if (opts == NULL) { -+ sg_init_one(&sg, cc->key, cc->key_size); -+ desc.tfm = essiv->hash_tfm; -+ desc.flags = CRYPTO_TFM_REQ_MAY_SLEEP; -+ -+ err = crypto_hash_digest(&desc, &sg, cc->key_size, essiv->salt); -+ if (err) -+ return err; -+ -+ return crypto_cipher_setkey(essiv->tfm, essiv->salt, -+ crypto_hash_digestsize(essiv->hash_tfm)); -+} -+ -+/* Wipe salt and reset key derived from volume key */ -+static int crypt_iv_essiv_wipe(struct crypt_config *cc) -+{ -+ struct iv_essiv_private *essiv = &cc->iv_gen_private.essiv; -+ unsigned salt_size = crypto_hash_digestsize(essiv->hash_tfm); -+ -+ memset(essiv->salt, 0, salt_size); -+ -+ return crypto_cipher_setkey(essiv->tfm, essiv->salt, salt_size); -+} -+ -+static void crypt_iv_essiv_dtr(struct crypt_config *cc) -+{ -+ struct iv_essiv_private *essiv = &cc->iv_gen_private.essiv; -+ -+ crypto_free_cipher(essiv->tfm); -+ essiv->tfm = NULL; -+ -+ crypto_free_hash(essiv->hash_tfm); -+ essiv->hash_tfm = NULL; -+ -+ kzfree(essiv->salt); -+ essiv->salt = NULL; -+} -+ -+static int crypt_iv_essiv_ctr(struct crypt_config *cc, struct dm_target *ti, -+ const char *opts) -+{ -+ struct crypto_cipher *essiv_tfm = NULL; -+ struct crypto_hash *hash_tfm = NULL; -+ u8 *salt = NULL; -+ int err; -+ -+ if (!opts) { - ti->error = "Digest algorithm missing for ESSIV mode"; - return -EINVAL; - } - -- /* Hash the cipher key with the given hash algorithm */ -+ /* Allocate hash algorithm */ - hash_tfm = crypto_alloc_hash(opts, 0, CRYPTO_ALG_ASYNC); - if (IS_ERR(hash_tfm)) { - ti->error = "Error initializing ESSIV hash"; -- return PTR_ERR(hash_tfm); -+ err = PTR_ERR(hash_tfm); -+ goto bad; - } - -- saltsize = crypto_hash_digestsize(hash_tfm); -- salt = kmalloc(saltsize, GFP_KERNEL); -- if (salt == NULL) { -+ salt = kzalloc(crypto_hash_digestsize(hash_tfm), GFP_KERNEL); -+ if (!salt) { - ti->error = "Error kmallocing salt storage in ESSIV"; -- crypto_free_hash(hash_tfm); -- return -ENOMEM; -+ err = -ENOMEM; -+ goto bad; - } - -- sg_init_one(&sg, cc->key, cc->key_size); -- desc.tfm = hash_tfm; -- desc.flags = CRYPTO_TFM_REQ_MAY_SLEEP; -- err = crypto_hash_digest(&desc, &sg, cc->key_size, salt); -- crypto_free_hash(hash_tfm); -- -- if (err) { -- ti->error = "Error calculating hash in ESSIV"; -- kfree(salt); -- return err; -- } -- -- /* Setup the essiv_tfm with the given salt */ -+ /* Allocate essiv_tfm */ - essiv_tfm = crypto_alloc_cipher(cc->cipher, 0, CRYPTO_ALG_ASYNC); - if (IS_ERR(essiv_tfm)) { - ti->error = "Error allocating crypto tfm for ESSIV"; -- kfree(salt); -- return PTR_ERR(essiv_tfm); -+ err = PTR_ERR(essiv_tfm); -+ goto bad; - } - if (crypto_cipher_blocksize(essiv_tfm) != - crypto_ablkcipher_ivsize(cc->tfm)) { - ti->error = "Block size of ESSIV cipher does " - "not match IV size of block cipher"; -- crypto_free_cipher(essiv_tfm); -- kfree(salt); -- return -EINVAL; -- } -- err = crypto_cipher_setkey(essiv_tfm, salt, saltsize); -- if (err) { -- ti->error = "Failed to set key for ESSIV cipher"; -- crypto_free_cipher(essiv_tfm); -- kfree(salt); -- return err; -+ err = -EINVAL; -+ goto bad; - } -- kfree(salt); - -- cc->iv_gen_private.essiv_tfm = essiv_tfm; -+ cc->iv_gen_private.essiv.salt = salt; -+ cc->iv_gen_private.essiv.tfm = essiv_tfm; -+ cc->iv_gen_private.essiv.hash_tfm = hash_tfm; -+ - return 0; --} - --static void crypt_iv_essiv_dtr(struct crypt_config *cc) --{ -- crypto_free_cipher(cc->iv_gen_private.essiv_tfm); -- cc->iv_gen_private.essiv_tfm = NULL; -+bad: -+ if (essiv_tfm && !IS_ERR(essiv_tfm)) -+ crypto_free_cipher(essiv_tfm); -+ if (hash_tfm && !IS_ERR(hash_tfm)) -+ crypto_free_hash(hash_tfm); -+ kfree(salt); -+ return err; - } - - static int crypt_iv_essiv_gen(struct crypt_config *cc, u8 *iv, sector_t sector) - { - memset(iv, 0, cc->iv_size); - *(u64 *)iv = cpu_to_le64(sector); -- crypto_cipher_encrypt_one(cc->iv_gen_private.essiv_tfm, iv, iv); -+ crypto_cipher_encrypt_one(cc->iv_gen_private.essiv.tfm, iv, iv); - return 0; - } - -@@ -273,7 +310,7 @@ static int crypt_iv_benbi_ctr(struct crypt_config *cc, struct dm_target *ti, - return -EINVAL; - } - -- cc->iv_gen_private.benbi_shift = 9 - log; -+ cc->iv_gen_private.benbi.shift = 9 - log; - - return 0; - } -@@ -288,7 +325,7 @@ static int crypt_iv_benbi_gen(struct crypt_config *cc, u8 *iv, sector_t sector) - - memset(iv, 0, cc->iv_size - sizeof(u64)); /* rest is cleared below */ - -- val = cpu_to_be64(((u64)sector << cc->iv_gen_private.benbi_shift) + 1); -+ val = cpu_to_be64(((u64)sector << cc->iv_gen_private.benbi.shift) + 1); - put_unaligned(val, (__be64 *)(iv + cc->iv_size - sizeof(u64))); - - return 0; -@@ -308,6 +345,8 @@ static struct crypt_iv_operations crypt_iv_plain_ops = { - static struct crypt_iv_operations crypt_iv_essiv_ops = { - .ctr = crypt_iv_essiv_ctr, - .dtr = crypt_iv_essiv_dtr, -+ .init = crypt_iv_essiv_init, -+ .wipe = crypt_iv_essiv_wipe, - .generator = crypt_iv_essiv_gen - }; - -@@ -1039,6 +1078,12 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv) - cc->iv_gen_ops->ctr(cc, ti, ivopts) < 0) - goto bad_ivmode; - -+ if (cc->iv_gen_ops && cc->iv_gen_ops->init && -+ cc->iv_gen_ops->init(cc) < 0) { -+ ti->error = "Error initialising IV"; -+ goto bad_slab_pool; -+ } -+ - cc->iv_size = crypto_ablkcipher_ivsize(tfm); - if (cc->iv_size) - /* at least a 64 bit sector number should fit in our buffer */ -@@ -1278,6 +1323,7 @@ static void crypt_resume(struct dm_target *ti) - static int crypt_message(struct dm_target *ti, unsigned argc, char **argv) - { - struct crypt_config *cc = ti->private; -+ int ret = -EINVAL; - - if (argc < 2) - goto error; -@@ -1287,10 +1333,22 @@ static int crypt_message(struct dm_target *ti, unsigned argc, char **argv) - DMWARN("not suspended during key manipulation."); - return -EINVAL; - } -- if (argc == 3 && !strnicmp(argv[1], MESG_STR("set"))) -- return crypt_set_key(cc, argv[2]); -- if (argc == 2 && !strnicmp(argv[1], MESG_STR("wipe"))) -+ if (argc == 3 && !strnicmp(argv[1], MESG_STR("set"))) { -+ ret = crypt_set_key(cc, argv[2]); -+ if (ret) -+ return ret; -+ if (cc->iv_gen_ops && cc->iv_gen_ops->init) -+ ret = cc->iv_gen_ops->init(cc); -+ return ret; -+ } -+ if (argc == 2 && !strnicmp(argv[1], MESG_STR("wipe"))) { -+ if (cc->iv_gen_ops && cc->iv_gen_ops->wipe) { -+ ret = cc->iv_gen_ops->wipe(cc); -+ if (ret) -+ return ret; -+ } - return crypt_wipe_key(cc); -+ } - } - - error: -diff --git a/drivers/md/dm-exception-store.c b/drivers/md/dm-exception-store.c -index 7dbe652..2052159 100644 ---- a/drivers/md/dm-exception-store.c -+++ b/drivers/md/dm-exception-store.c -@@ -216,7 +216,8 @@ int dm_exception_store_create(struct dm_target *ti, int argc, char **argv, - type = get_type("N"); - else { - ti->error = "Persistent flag is not P or N"; -- return -EINVAL; -+ r = -EINVAL; -+ goto bad_type; - } - - if (!type) { -diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c -index a679429..d19854c 100644 ---- a/drivers/md/dm-ioctl.c -+++ b/drivers/md/dm-ioctl.c -@@ -56,6 +56,11 @@ static void dm_hash_remove_all(int keep_open_devices); - */ - static DECLARE_RWSEM(_hash_lock); - -+/* -+ * Protects use of mdptr to obtain hash cell name and uuid from mapped device. -+ */ -+static DEFINE_MUTEX(dm_hash_cells_mutex); -+ - static void init_buckets(struct list_head *buckets) - { - unsigned int i; -@@ -206,7 +211,9 @@ static int dm_hash_insert(const char *name, const char *uuid, struct mapped_devi - list_add(&cell->uuid_list, _uuid_buckets + hash_str(uuid)); - } - dm_get(md); -+ mutex_lock(&dm_hash_cells_mutex); - dm_set_mdptr(md, cell); -+ mutex_unlock(&dm_hash_cells_mutex); - up_write(&_hash_lock); - - return 0; -@@ -224,7 +231,9 @@ static void __hash_remove(struct hash_cell *hc) - /* remove from the dev hash */ - list_del(&hc->uuid_list); - list_del(&hc->name_list); -+ mutex_lock(&dm_hash_cells_mutex); - dm_set_mdptr(hc->md, NULL); -+ mutex_unlock(&dm_hash_cells_mutex); - - table = dm_get_table(hc->md); - if (table) { -@@ -321,7 +330,9 @@ static int dm_hash_rename(uint32_t cookie, const char *old, const char *new) - */ - list_del(&hc->name_list); - old_name = hc->name; -+ mutex_lock(&dm_hash_cells_mutex); - hc->name = new_name; -+ mutex_unlock(&dm_hash_cells_mutex); - list_add(&hc->name_list, _name_buckets + hash_str(new_name)); - - /* -@@ -1582,8 +1593,7 @@ int dm_copy_name_and_uuid(struct mapped_device *md, char *name, char *uuid) - if (!md) - return -ENXIO; - -- dm_get(md); -- down_read(&_hash_lock); -+ mutex_lock(&dm_hash_cells_mutex); - hc = dm_get_mdptr(md); - if (!hc || hc->md != md) { - r = -ENXIO; -@@ -1596,8 +1606,7 @@ int dm_copy_name_and_uuid(struct mapped_device *md, char *name, char *uuid) - strcpy(uuid, hc->uuid ? : ""); - - out: -- up_read(&_hash_lock); -- dm_put(md); -+ mutex_unlock(&dm_hash_cells_mutex); - - return r; - } -diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c -index 3a3ba46..8a4a9c8 100644 ---- a/drivers/md/dm-snap.c -+++ b/drivers/md/dm-snap.c -@@ -553,6 +553,8 @@ static int init_hash_tables(struct dm_snapshot *s) - hash_size = min(origin_dev_size, cow_dev_size) >> s->store->chunk_shift; - hash_size = min(hash_size, max_buckets); - -+ if (hash_size < 64) -+ hash_size = 64; - hash_size = rounddown_pow_of_two(hash_size); - if (init_exception_table(&s->complete, hash_size, - DM_CHUNK_CONSECUTIVE_BITS)) -@@ -1152,10 +1154,11 @@ static int snapshot_status(struct dm_target *ti, status_type_t type, - unsigned sz = 0; - struct dm_snapshot *snap = ti->private; - -- down_write(&snap->lock); -- - switch (type) { - case STATUSTYPE_INFO: -+ -+ down_write(&snap->lock); -+ - if (!snap->valid) - DMEMIT("Invalid"); - else { -@@ -1171,6 +1174,9 @@ static int snapshot_status(struct dm_target *ti, status_type_t type, - else - DMEMIT("Unknown"); - } -+ -+ up_write(&snap->lock); -+ - break; - - case STATUSTYPE_TABLE: -@@ -1185,8 +1191,6 @@ static int snapshot_status(struct dm_target *ti, status_type_t type, - break; - } - -- up_write(&snap->lock); -- - return 0; - } - -diff --git a/drivers/md/dm-uevent.c b/drivers/md/dm-uevent.c -index 6f65883..c7c555a 100644 ---- a/drivers/md/dm-uevent.c -+++ b/drivers/md/dm-uevent.c -@@ -139,14 +139,13 @@ void dm_send_uevents(struct list_head *events, struct kobject *kobj) - list_del_init(&event->elist); - - /* -- * Need to call dm_copy_name_and_uuid from here for now. -- * Context of previous var adds and locking used for -- * hash_cell not compatable. -+ * When a device is being removed this copy fails and we -+ * discard these unsent events. - */ - if (dm_copy_name_and_uuid(event->md, event->name, - event->uuid)) { -- DMERR("%s: dm_copy_name_and_uuid() failed", -- __func__); -+ DMINFO("%s: skipping sending uevent for lost device", -+ __func__); - goto uevent_free; - } - -diff --git a/drivers/md/md.c b/drivers/md/md.c -index b182f86..02e4551 100644 ---- a/drivers/md/md.c -+++ b/drivers/md/md.c -@@ -367,6 +367,7 @@ static mddev_t * mddev_find(dev_t unit) - - mutex_init(&new->open_mutex); - mutex_init(&new->reconfig_mutex); -+ mutex_init(&new->bitmap_mutex); - INIT_LIST_HEAD(&new->disks); - INIT_LIST_HEAD(&new->all_mddevs); - init_timer(&new->safemode_timer); -@@ -6629,7 +6630,7 @@ void md_check_recovery(mddev_t *mddev) - - - if (mddev->bitmap) -- bitmap_daemon_work(mddev->bitmap); -+ bitmap_daemon_work(mddev); - - if (mddev->ro) - return; -diff --git a/drivers/md/md.h b/drivers/md/md.h -index f184b69..87430fe 100644 ---- a/drivers/md/md.h -+++ b/drivers/md/md.h -@@ -289,6 +289,7 @@ struct mddev_s - * hot-adding a bitmap. It should - * eventually be settable by sysfs. - */ -+ struct mutex bitmap_mutex; - - struct list_head all_mddevs; - }; -diff --git a/drivers/media/common/tuners/mxl5007t.c b/drivers/media/common/tuners/mxl5007t.c -index 2d02698..7eb1bf7 100644 ---- a/drivers/media/common/tuners/mxl5007t.c -+++ b/drivers/media/common/tuners/mxl5007t.c -@@ -196,7 +196,7 @@ static void copy_reg_bits(struct reg_pair_t *reg_pair1, - i = j = 0; - - while (reg_pair1[i].reg || reg_pair1[i].val) { -- while (reg_pair2[j].reg || reg_pair2[j].reg) { -+ while (reg_pair2[j].reg || reg_pair2[j].val) { - if (reg_pair1[i].reg != reg_pair2[j].reg) { - j++; - continue; -diff --git a/drivers/media/video/gspca/ov519.c b/drivers/media/video/gspca/ov519.c -index a5c190e..e165578 100644 ---- a/drivers/media/video/gspca/ov519.c -+++ b/drivers/media/video/gspca/ov519.c -@@ -3364,6 +3364,7 @@ static const __devinitdata struct usb_device_id device_table[] = { - {USB_DEVICE(0x041e, 0x4061), .driver_info = BRIDGE_OV519 }, - {USB_DEVICE(0x041e, 0x4064), - .driver_info = BRIDGE_OV519 | BRIDGE_INVERT_LED }, -+ {USB_DEVICE(0x041e, 0x4067), .driver_info = BRIDGE_OV519 }, - {USB_DEVICE(0x041e, 0x4068), - .driver_info = BRIDGE_OV519 | BRIDGE_INVERT_LED }, - {USB_DEVICE(0x045e, 0x028c), .driver_info = BRIDGE_OV519 }, -diff --git a/drivers/mtd/ubi/upd.c b/drivers/mtd/ubi/upd.c -index 74fdc40..c1d7b88 100644 ---- a/drivers/mtd/ubi/upd.c -+++ b/drivers/mtd/ubi/upd.c -@@ -147,12 +147,14 @@ int ubi_start_update(struct ubi_device *ubi, struct ubi_volume *vol, - } - - if (bytes == 0) { -+ err = ubi_wl_flush(ubi); -+ if (err) -+ return err; -+ - err = clear_update_marker(ubi, vol, 0); - if (err) - return err; -- err = ubi_wl_flush(ubi); -- if (!err) -- vol->updating = 0; -+ vol->updating = 0; - } - - vol->upd_buf = vmalloc(ubi->leb_size); -@@ -362,16 +364,16 @@ int ubi_more_update_data(struct ubi_device *ubi, struct ubi_volume *vol, - - ubi_assert(vol->upd_received <= vol->upd_bytes); - if (vol->upd_received == vol->upd_bytes) { -+ err = ubi_wl_flush(ubi); -+ if (err) -+ return err; - /* The update is finished, clear the update marker */ - err = clear_update_marker(ubi, vol, vol->upd_bytes); - if (err) - return err; -- err = ubi_wl_flush(ubi); -- if (err == 0) { -- vol->updating = 0; -- err = to_write; -- vfree(vol->upd_buf); -- } -+ vol->updating = 0; -+ err = to_write; -+ vfree(vol->upd_buf); - } - - return err; -diff --git a/drivers/net/b44.c b/drivers/net/b44.c -index 2a91323..4869adb 100644 ---- a/drivers/net/b44.c -+++ b/drivers/net/b44.c -@@ -1505,8 +1505,7 @@ static int b44_magic_pattern(u8 *macaddr, u8 *ppattern, u8 *pmask, int offset) - for (k = 0; k< ethaddr_bytes; k++) { - ppattern[offset + magicsync + - (j * ETH_ALEN) + k] = macaddr[k]; -- len++; -- set_bit(len, (unsigned long *) pmask); -+ set_bit(len++, (unsigned long *) pmask); - } - } - return len - 1; -diff --git a/drivers/net/bcm63xx_enet.c b/drivers/net/bcm63xx_enet.c -index ba29dc3..d110c1b 100644 ---- a/drivers/net/bcm63xx_enet.c -+++ b/drivers/net/bcm63xx_enet.c -@@ -1248,9 +1248,15 @@ static void bcm_enet_get_drvinfo(struct net_device *netdev, - drvinfo->n_stats = BCM_ENET_STATS_LEN; - } - --static int bcm_enet_get_stats_count(struct net_device *netdev) -+static int bcm_enet_get_sset_count(struct net_device *netdev, -+ int string_set) - { -- return BCM_ENET_STATS_LEN; -+ switch (string_set) { -+ case ETH_SS_STATS: -+ return BCM_ENET_STATS_LEN; -+ default: -+ return -EINVAL; -+ } - } - - static void bcm_enet_get_strings(struct net_device *netdev, -@@ -1476,7 +1482,7 @@ static int bcm_enet_set_pauseparam(struct net_device *dev, - - static struct ethtool_ops bcm_enet_ethtool_ops = { - .get_strings = bcm_enet_get_strings, -- .get_stats_count = bcm_enet_get_stats_count, -+ .get_sset_count = bcm_enet_get_sset_count, - .get_ethtool_stats = bcm_enet_get_ethtool_stats, - .get_settings = bcm_enet_get_settings, - .set_settings = bcm_enet_set_settings, -diff --git a/drivers/net/wireless/ath/ath5k/eeprom.c b/drivers/net/wireless/ath/ath5k/eeprom.c -index 644962a..7918852 100644 ---- a/drivers/net/wireless/ath/ath5k/eeprom.c -+++ b/drivers/net/wireless/ath/ath5k/eeprom.c -@@ -97,6 +97,7 @@ ath5k_eeprom_init_header(struct ath5k_hw *ah) - struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; - int ret; - u16 val; -+ u32 cksum, offset; - - /* - * Read values from EEPROM and store them in the capability structure -@@ -111,7 +112,6 @@ ath5k_eeprom_init_header(struct ath5k_hw *ah) - if (ah->ah_ee_version < AR5K_EEPROM_VERSION_3_0) - return 0; - --#ifdef notyet - /* - * Validate the checksum of the EEPROM date. There are some - * devices with invalid EEPROMs. -@@ -124,7 +124,6 @@ ath5k_eeprom_init_header(struct ath5k_hw *ah) - ATH5K_ERR(ah->ah_sc, "Invalid EEPROM checksum 0x%04x\n", cksum); - return -EIO; - } --#endif - - AR5K_EEPROM_READ_HDR(AR5K_EEPROM_ANT_GAIN(ah->ah_ee_version), - ee_ant_gain); -diff --git a/drivers/net/wireless/ath/ath5k/phy.c b/drivers/net/wireless/ath/ath5k/phy.c -index 1a039f2..9d67647 100644 ---- a/drivers/net/wireless/ath/ath5k/phy.c -+++ b/drivers/net/wireless/ath/ath5k/phy.c -@@ -2954,8 +2954,6 @@ ath5k_hw_txpower(struct ath5k_hw *ah, struct ieee80211_channel *channel, - ATH5K_ERR(ah->ah_sc, "invalid tx power: %u\n", txpower); - return -EINVAL; - } -- if (txpower == 0) -- txpower = AR5K_TUNE_DEFAULT_TXPOWER; - - /* Reset TX power values */ - memset(&ah->ah_txpower, 0, sizeof(ah->ah_txpower)); -diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h -index 1d59f10..cdb90c5 100644 ---- a/drivers/net/wireless/ath/ath9k/ath9k.h -+++ b/drivers/net/wireless/ath/ath9k/ath9k.h -@@ -139,6 +139,7 @@ struct ath_buf { - dma_addr_t bf_daddr; /* physical addr of desc */ - dma_addr_t bf_buf_addr; /* physical addr of data buffer */ - bool bf_stale; -+ bool bf_isnullfunc; - u16 bf_flags; - struct ath_buf_state bf_state; - dma_addr_t bf_dmacontext; -@@ -524,6 +525,8 @@ struct ath_led { - #define SC_OP_BEACON_SYNC BIT(19) - #define SC_OP_BTCOEX_ENABLED BIT(20) - #define SC_OP_BT_PRIORITY_DETECTED BIT(21) -+#define SC_OP_NULLFUNC_COMPLETED BIT(22) -+#define SC_OP_PS_ENABLED BIT(23) - - struct ath_bus_ops { - void (*read_cachesize)(struct ath_softc *sc, int *csz); -diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c -index ca7694c..c7aa05a 100644 ---- a/drivers/net/wireless/ath/ath9k/hw.c -+++ b/drivers/net/wireless/ath/ath9k/hw.c -@@ -937,6 +937,11 @@ int ath9k_hw_init(struct ath_hw *ah) - DPRINTF(ah->ah_sc, ATH_DBG_RESET, "serialize_regmode is %d\n", - ah->config.serialize_regmode); - -+ if (AR_SREV_9285(ah) || AR_SREV_9271(ah)) -+ ah->config.max_txtrig_level = MAX_TX_FIFO_THRESHOLD >> 1; -+ else -+ ah->config.max_txtrig_level = MAX_TX_FIFO_THRESHOLD; -+ - if (!ath9k_hw_macversion_supported(ah->hw_version.macVersion)) { - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, - "Mac Chip Rev 0x%02x.%x is not supported by " -@@ -3670,7 +3675,11 @@ void ath9k_hw_fill_cap_info(struct ath_hw *ah) - pCap->keycache_size = AR_KEYTABLE_SIZE; - - pCap->hw_caps |= ATH9K_HW_CAP_FASTCC; -- pCap->tx_triglevel_max = MAX_TX_FIFO_THRESHOLD; -+ -+ if (AR_SREV_9285(ah) || AR_SREV_9271(ah)) -+ pCap->tx_triglevel_max = MAX_TX_FIFO_THRESHOLD >> 1; -+ else -+ pCap->tx_triglevel_max = MAX_TX_FIFO_THRESHOLD; - - if (AR_SREV_9285_10_OR_LATER(ah)) - pCap->num_gpio_pins = AR9285_NUM_GPIO; -diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h -index b892345..57f1463 100644 ---- a/drivers/net/wireless/ath/ath9k/hw.h -+++ b/drivers/net/wireless/ath/ath9k/hw.h -@@ -218,6 +218,7 @@ struct ath9k_ops_config { - #define AR_SPUR_FEEQ_BOUND_HT20 10 - int spurmode; - u16 spurchans[AR_EEPROM_MODAL_SPURS][2]; -+ u8 max_txtrig_level; - }; - - enum ath9k_int { -diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c -index 800bfab..d4d9d82 100644 ---- a/drivers/net/wireless/ath/ath9k/mac.c -+++ b/drivers/net/wireless/ath/ath9k/mac.c -@@ -70,7 +70,7 @@ bool ath9k_hw_updatetxtriglevel(struct ath_hw *ah, bool bIncTrigLevel) - u32 txcfg, curLevel, newLevel; - enum ath9k_int omask; - -- if (ah->tx_trig_level >= MAX_TX_FIFO_THRESHOLD) -+ if (ah->tx_trig_level >= ah->config.max_txtrig_level) - return false; - - omask = ath9k_hw_set_interrupts(ah, ah->mask_reg & ~ATH9K_INT_GLOBAL); -@@ -79,7 +79,7 @@ bool ath9k_hw_updatetxtriglevel(struct ath_hw *ah, bool bIncTrigLevel) - curLevel = MS(txcfg, AR_FTRIG); - newLevel = curLevel; - if (bIncTrigLevel) { -- if (curLevel < MAX_TX_FIFO_THRESHOLD) -+ if (curLevel < ah->config.max_txtrig_level) - newLevel++; - } else if (curLevel > MIN_TX_FIFO_THRESHOLD) - newLevel--; -@@ -222,6 +222,8 @@ int ath9k_hw_txprocdesc(struct ath_hw *ah, struct ath_desc *ds) - ds->ds_txstat.ts_status = 0; - ds->ds_txstat.ts_flags = 0; - -+ if (ads->ds_txstatus1 & AR_FrmXmitOK) -+ ds->ds_txstat.ts_status |= ATH9K_TX_ACKED; - if (ads->ds_txstatus1 & AR_ExcessiveRetries) - ds->ds_txstat.ts_status |= ATH9K_TXERR_XRETRY; - if (ads->ds_txstatus1 & AR_Filtered) -diff --git a/drivers/net/wireless/ath/ath9k/mac.h b/drivers/net/wireless/ath/ath9k/mac.h -index f56e77d..ff65f85 100644 ---- a/drivers/net/wireless/ath/ath9k/mac.h -+++ b/drivers/net/wireless/ath/ath9k/mac.h -@@ -76,6 +76,7 @@ - #define ATH9K_TXERR_FIFO 0x04 - #define ATH9K_TXERR_XTXOP 0x08 - #define ATH9K_TXERR_TIMER_EXPIRED 0x10 -+#define ATH9K_TX_ACKED 0x20 - - #define ATH9K_TX_BA 0x01 - #define ATH9K_TX_PWRMGMT 0x02 -diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c -index 43d2be9..59359e3 100644 ---- a/drivers/net/wireless/ath/ath9k/main.c -+++ b/drivers/net/wireless/ath/ath9k/main.c -@@ -2327,6 +2327,7 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) - - if (changed & IEEE80211_CONF_CHANGE_PS) { - if (conf->flags & IEEE80211_CONF_PS) { -+ sc->sc_flags |= SC_OP_PS_ENABLED; - if (!(ah->caps.hw_caps & - ATH9K_HW_CAP_AUTOSLEEP)) { - if ((sc->imask & ATH9K_INT_TIM_TIMER) == 0) { -@@ -2334,11 +2335,17 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) - ath9k_hw_set_interrupts(sc->sc_ah, - sc->imask); - } -- ath9k_hw_setrxabort(sc->sc_ah, 1); - } - sc->ps_enabled = true; -+ if ((sc->sc_flags & SC_OP_NULLFUNC_COMPLETED)) { -+ sc->sc_flags &= ~SC_OP_NULLFUNC_COMPLETED; -+ sc->ps_enabled = true; -+ ath9k_hw_setrxabort(sc->sc_ah, 1); -+ } - } else { - sc->ps_enabled = false; -+ sc->sc_flags &= ~(SC_OP_PS_ENABLED | -+ SC_OP_NULLFUNC_COMPLETED); - ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE); - if (!(ah->caps.hw_caps & - ATH9K_HW_CAP_AUTOSLEEP)) { -diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c -index 42551a4..4753909 100644 ---- a/drivers/net/wireless/ath/ath9k/xmit.c -+++ b/drivers/net/wireless/ath/ath9k/xmit.c -@@ -1592,6 +1592,13 @@ static int ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_buf *bf, - } - - bf->bf_buf_addr = bf->bf_dmacontext; -+ -+ if (ieee80211_is_nullfunc(fc) && ieee80211_has_pm(fc)) { -+ bf->bf_isnullfunc = true; -+ sc->sc_flags &= ~SC_OP_NULLFUNC_COMPLETED; -+ } else -+ bf->bf_isnullfunc = false; -+ - return 0; - } - -@@ -1989,6 +1996,15 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) - if (ds == txq->axq_gatingds) - txq->axq_gatingds = NULL; - -+ if (bf->bf_isnullfunc && -+ (ds->ds_txstat.ts_status & ATH9K_TX_ACKED)) { -+ if ((sc->sc_flags & SC_OP_PS_ENABLED)) { -+ sc->ps_enabled = true; -+ ath9k_hw_setrxabort(sc->sc_ah, 1); -+ } else -+ sc->sc_flags |= SC_OP_NULLFUNC_COMPLETED; -+ } -+ - /* - * Remove ath_buf's of the same transmit unit from txq, - * however leave the last descriptor back as the holding -@@ -2004,7 +2020,7 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) - if (bf_isaggr(bf)) - txq->axq_aggr_depth--; - -- txok = (ds->ds_txstat.ts_status == 0); -+ txok = !(ds->ds_txstat.ts_status & ATH9K_TXERR_FILT); - txq->axq_tx_inprogress = false; - spin_unlock_bh(&txq->axq_lock); - -@@ -2065,7 +2081,9 @@ static void ath_tx_complete_poll_work(struct work_struct *work) - - if (needreset) { - DPRINTF(sc, ATH_DBG_RESET, "tx hung, resetting the chip\n"); -+ ath9k_ps_wakeup(sc); - ath_reset(sc, false); -+ ath9k_ps_restore(sc); - } - - ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, -diff --git a/drivers/net/wireless/b43legacy/rfkill.c b/drivers/net/wireless/b43legacy/rfkill.c -index 8783022..d579df7 100644 ---- a/drivers/net/wireless/b43legacy/rfkill.c -+++ b/drivers/net/wireless/b43legacy/rfkill.c -@@ -34,6 +34,13 @@ bool b43legacy_is_hw_radio_enabled(struct b43legacy_wldev *dev) - & B43legacy_MMIO_RADIO_HWENABLED_HI_MASK)) - return 1; - } else { -+ /* To prevent CPU fault on PPC, do not read a register -+ * unless the interface is started; however, on resume -+ * for hibernation, this routine is entered early. When -+ * that happens, unconditionally return TRUE. -+ */ -+ if (b43legacy_status(dev) < B43legacy_STAT_STARTED) -+ return 1; - if (b43legacy_read16(dev, B43legacy_MMIO_RADIO_HWENABLED_LO) - & B43legacy_MMIO_RADIO_HWENABLED_LO_MASK) - return 1; -diff --git a/drivers/net/wireless/ipw2x00/ipw2100.c b/drivers/net/wireless/ipw2x00/ipw2100.c -index 6e2fc0c..43102bf 100644 ---- a/drivers/net/wireless/ipw2x00/ipw2100.c -+++ b/drivers/net/wireless/ipw2x00/ipw2100.c -@@ -6487,6 +6487,16 @@ static int ipw2100_resume(struct pci_dev *pci_dev) - } - #endif - -+static void ipw2100_shutdown(struct pci_dev *pci_dev) -+{ -+ struct ipw2100_priv *priv = pci_get_drvdata(pci_dev); -+ -+ /* Take down the device; powers it off, etc. */ -+ ipw2100_down(priv); -+ -+ pci_disable_device(pci_dev); -+} -+ - #define IPW2100_DEV_ID(x) { PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, x } - - static struct pci_device_id ipw2100_pci_id_table[] __devinitdata = { -@@ -6550,6 +6560,7 @@ static struct pci_driver ipw2100_pci_driver = { - .suspend = ipw2100_suspend, - .resume = ipw2100_resume, - #endif -+ .shutdown = ipw2100_shutdown, - }; - - /** -diff --git a/drivers/net/wireless/rtl818x/rtl8187.h b/drivers/net/wireless/rtl818x/rtl8187.h -index bf9175a..99406bf 100644 ---- a/drivers/net/wireless/rtl818x/rtl8187.h -+++ b/drivers/net/wireless/rtl818x/rtl8187.h -@@ -23,6 +23,7 @@ - #define RTL8187_EEPROM_TXPWR_CHAN_1 0x16 /* 3 channels */ - #define RTL8187_EEPROM_TXPWR_CHAN_6 0x1B /* 2 channels */ - #define RTL8187_EEPROM_TXPWR_CHAN_4 0x3D /* 2 channels */ -+#define RTL8187_EEPROM_SELECT_GPIO 0x3B - - #define RTL8187_REQT_READ 0xC0 - #define RTL8187_REQT_WRITE 0x40 -@@ -31,6 +32,9 @@ - - #define RTL8187_MAX_RX 0x9C4 - -+#define RFKILL_MASK_8187_89_97 0x2 -+#define RFKILL_MASK_8198 0x4 -+ - struct rtl8187_rx_info { - struct urb *urb; - struct ieee80211_hw *dev; -@@ -123,6 +127,7 @@ struct rtl8187_priv { - u8 noise; - u8 slot_time; - u8 aifsn[4]; -+ u8 rfkill_mask; - struct { - __le64 buf; - struct sk_buff_head queue; -diff --git a/drivers/net/wireless/rtl818x/rtl8187_dev.c b/drivers/net/wireless/rtl818x/rtl8187_dev.c -index 2017ccc..ea49918 100644 ---- a/drivers/net/wireless/rtl818x/rtl8187_dev.c -+++ b/drivers/net/wireless/rtl818x/rtl8187_dev.c -@@ -1329,6 +1329,7 @@ static int __devinit rtl8187_probe(struct usb_interface *intf, - struct ieee80211_channel *channel; - const char *chip_name; - u16 txpwr, reg; -+ u16 product_id = le16_to_cpu(udev->descriptor.idProduct); - int err, i; - - dev = ieee80211_alloc_hw(sizeof(*priv), &rtl8187_ops); -@@ -1488,6 +1489,13 @@ static int __devinit rtl8187_probe(struct usb_interface *intf, - (*channel++).hw_value = txpwr & 0xFF; - (*channel++).hw_value = txpwr >> 8; - } -+ /* Handle the differing rfkill GPIO bit in different models */ -+ priv->rfkill_mask = RFKILL_MASK_8187_89_97; -+ if (product_id == 0x8197 || product_id == 0x8198) { -+ eeprom_93cx6_read(&eeprom, RTL8187_EEPROM_SELECT_GPIO, ®); -+ if (reg & 0xFF00) -+ priv->rfkill_mask = RFKILL_MASK_8198; -+ } - - /* - * XXX: Once this driver supports anything that requires -@@ -1516,9 +1524,9 @@ static int __devinit rtl8187_probe(struct usb_interface *intf, - mutex_init(&priv->conf_mutex); - skb_queue_head_init(&priv->b_tx_status.queue); - -- printk(KERN_INFO "%s: hwaddr %pM, %s V%d + %s\n", -+ printk(KERN_INFO "%s: hwaddr %pM, %s V%d + %s, rfkill mask %d\n", - wiphy_name(dev->wiphy), dev->wiphy->perm_addr, -- chip_name, priv->asic_rev, priv->rf->name); -+ chip_name, priv->asic_rev, priv->rf->name, priv->rfkill_mask); - - #ifdef CONFIG_RTL8187_LEDS - eeprom_93cx6_read(&eeprom, 0x3F, ®); -diff --git a/drivers/net/wireless/rtl818x/rtl8187_rfkill.c b/drivers/net/wireless/rtl818x/rtl8187_rfkill.c -index cad8037..03555e1 100644 ---- a/drivers/net/wireless/rtl818x/rtl8187_rfkill.c -+++ b/drivers/net/wireless/rtl818x/rtl8187_rfkill.c -@@ -25,10 +25,10 @@ static bool rtl8187_is_radio_enabled(struct rtl8187_priv *priv) - u8 gpio; - - gpio = rtl818x_ioread8(priv, &priv->map->GPIO0); -- rtl818x_iowrite8(priv, &priv->map->GPIO0, gpio & ~0x02); -+ rtl818x_iowrite8(priv, &priv->map->GPIO0, gpio & ~priv->rfkill_mask); - gpio = rtl818x_ioread8(priv, &priv->map->GPIO1); - -- return gpio & 0x02; -+ return gpio & priv->rfkill_mask; - } - - void rtl8187_rfkill_init(struct ieee80211_hw *hw) -diff --git a/drivers/pci/dmar.c b/drivers/pci/dmar.c -index b952ebc..5753036 100644 ---- a/drivers/pci/dmar.c -+++ b/drivers/pci/dmar.c -@@ -582,6 +582,8 @@ int __init dmar_table_init(void) - return 0; - } - -+static int bios_warned; -+ - int __init check_zero_address(void) - { - struct acpi_table_dmar *dmar; -@@ -601,6 +603,9 @@ int __init check_zero_address(void) - } - - if (entry_header->type == ACPI_DMAR_TYPE_HARDWARE_UNIT) { -+ void __iomem *addr; -+ u64 cap, ecap; -+ - drhd = (void *)entry_header; - if (!drhd->address) { - /* Promote an attitude of violence to a BIOS engineer today */ -@@ -609,17 +614,40 @@ int __init check_zero_address(void) - dmi_get_system_info(DMI_BIOS_VENDOR), - dmi_get_system_info(DMI_BIOS_VERSION), - dmi_get_system_info(DMI_PRODUCT_VERSION)); --#ifdef CONFIG_DMAR -- dmar_disabled = 1; --#endif -- return 0; -+ bios_warned = 1; -+ goto failed; -+ } -+ -+ addr = early_ioremap(drhd->address, VTD_PAGE_SIZE); -+ if (!addr ) { -+ printk("IOMMU: can't validate: %llx\n", drhd->address); -+ goto failed; -+ } -+ cap = dmar_readq(addr + DMAR_CAP_REG); -+ ecap = dmar_readq(addr + DMAR_ECAP_REG); -+ early_iounmap(addr, VTD_PAGE_SIZE); -+ if (cap == (uint64_t)-1 && ecap == (uint64_t)-1) { -+ /* Promote an attitude of violence to a BIOS engineer today */ -+ WARN(1, "Your BIOS is broken; DMAR reported at address %llx returns all ones!\n" -+ "BIOS vendor: %s; Ver: %s; Product Version: %s\n", -+ drhd->address, -+ dmi_get_system_info(DMI_BIOS_VENDOR), -+ dmi_get_system_info(DMI_BIOS_VERSION), -+ dmi_get_system_info(DMI_PRODUCT_VERSION)); -+ bios_warned = 1; -+ goto failed; - } -- break; - } - - entry_header = ((void *)entry_header + entry_header->length); - } - return 1; -+ -+failed: -+#ifdef CONFIG_DMAR -+ dmar_disabled = 1; -+#endif -+ return 0; - } - - void __init detect_intel_iommu(void) -@@ -664,6 +692,18 @@ int alloc_iommu(struct dmar_drhd_unit *drhd) - int agaw = 0; - int msagaw = 0; - -+ if (!drhd->reg_base_addr) { -+ if (!bios_warned) { -+ WARN(1, "Your BIOS is broken; DMAR reported at address zero!\n" -+ "BIOS vendor: %s; Ver: %s; Product Version: %s\n", -+ dmi_get_system_info(DMI_BIOS_VENDOR), -+ dmi_get_system_info(DMI_BIOS_VERSION), -+ dmi_get_system_info(DMI_PRODUCT_VERSION)); -+ bios_warned = 1; -+ } -+ return -EINVAL; -+ } -+ - iommu = kzalloc(sizeof(*iommu), GFP_KERNEL); - if (!iommu) - return -ENOMEM; -@@ -680,13 +720,16 @@ int alloc_iommu(struct dmar_drhd_unit *drhd) - iommu->ecap = dmar_readq(iommu->reg + DMAR_ECAP_REG); - - if (iommu->cap == (uint64_t)-1 && iommu->ecap == (uint64_t)-1) { -- /* Promote an attitude of violence to a BIOS engineer today */ -- WARN(1, "Your BIOS is broken; DMAR reported at address %llx returns all ones!\n" -- "BIOS vendor: %s; Ver: %s; Product Version: %s\n", -- drhd->reg_base_addr, -- dmi_get_system_info(DMI_BIOS_VENDOR), -- dmi_get_system_info(DMI_BIOS_VERSION), -- dmi_get_system_info(DMI_PRODUCT_VERSION)); -+ if (!bios_warned) { -+ /* Promote an attitude of violence to a BIOS engineer today */ -+ WARN(1, "Your BIOS is broken; DMAR reported at address %llx returns all ones!\n" -+ "BIOS vendor: %s; Ver: %s; Product Version: %s\n", -+ drhd->reg_base_addr, -+ dmi_get_system_info(DMI_BIOS_VENDOR), -+ dmi_get_system_info(DMI_BIOS_VERSION), -+ dmi_get_system_info(DMI_PRODUCT_VERSION)); -+ bios_warned = 1; -+ } - goto err_unmap; - } - -diff --git a/drivers/pci/intel-iommu.c b/drivers/pci/intel-iommu.c -index 1840a05..2498602 100644 ---- a/drivers/pci/intel-iommu.c -+++ b/drivers/pci/intel-iommu.c -@@ -1523,12 +1523,15 @@ static int domain_context_mapping_one(struct dmar_domain *domain, int segment, - - /* Skip top levels of page tables for - * iommu which has less agaw than default. -+ * Unnecessary for PT mode. - */ -- for (agaw = domain->agaw; agaw != iommu->agaw; agaw--) { -- pgd = phys_to_virt(dma_pte_addr(pgd)); -- if (!dma_pte_present(pgd)) { -- spin_unlock_irqrestore(&iommu->lock, flags); -- return -ENOMEM; -+ if (translation != CONTEXT_TT_PASS_THROUGH) { -+ for (agaw = domain->agaw; agaw != iommu->agaw; agaw--) { -+ pgd = phys_to_virt(dma_pte_addr(pgd)); -+ if (!dma_pte_present(pgd)) { -+ spin_unlock_irqrestore(&iommu->lock, flags); -+ return -ENOMEM; -+ } - } - } - } -@@ -1991,6 +1994,16 @@ static int iommu_prepare_identity_map(struct pci_dev *pdev, - "IOMMU: Setting identity map for device %s [0x%Lx - 0x%Lx]\n", - pci_name(pdev), start, end); - -+ if (end < start) { -+ WARN(1, "Your BIOS is broken; RMRR ends before it starts!\n" -+ "BIOS vendor: %s; Ver: %s; Product Version: %s\n", -+ dmi_get_system_info(DMI_BIOS_VENDOR), -+ dmi_get_system_info(DMI_BIOS_VERSION), -+ dmi_get_system_info(DMI_PRODUCT_VERSION)); -+ ret = -EIO; -+ goto error; -+ } -+ - if (end >> agaw_to_width(domain->agaw)) { - WARN(1, "Your BIOS is broken; RMRR exceeds permitted address width (%d bits)\n" - "BIOS vendor: %s; Ver: %s; Product Version: %s\n", -@@ -3228,6 +3241,9 @@ static int device_notifier(struct notifier_block *nb, - struct pci_dev *pdev = to_pci_dev(dev); - struct dmar_domain *domain; - -+ if (iommu_no_mapping(dev)) -+ return 0; -+ - domain = find_domain(pdev); - if (!domain) - return 0; -diff --git a/drivers/platform/x86/acerhdf.c b/drivers/platform/x86/acerhdf.c -index ab64522..d8b4229 100644 ---- a/drivers/platform/x86/acerhdf.c -+++ b/drivers/platform/x86/acerhdf.c -@@ -52,7 +52,7 @@ - */ - #undef START_IN_KERNEL_MODE - --#define DRV_VER "0.5.18" -+#define DRV_VER "0.5.20" - - /* - * According to the Atom N270 datasheet, -@@ -112,12 +112,14 @@ module_param_string(force_product, force_product, 16, 0); - MODULE_PARM_DESC(force_product, "Force BIOS product and omit BIOS check"); - - /* -- * cmd_off: to switch the fan completely off / to check if the fan is off -+ * cmd_off: to switch the fan completely off -+ * chk_off: to check if the fan is off - * cmd_auto: to set the BIOS in control of the fan. The BIOS regulates then - * the fan speed depending on the temperature - */ - struct fancmd { - u8 cmd_off; -+ u8 chk_off; - u8 cmd_auto; - }; - -@@ -134,32 +136,41 @@ struct bios_settings_t { - /* Register addresses and values for different BIOS versions */ - static const struct bios_settings_t bios_tbl[] = { - /* AOA110 */ -- {"Acer", "AOA110", "v0.3109", 0x55, 0x58, {0x1f, 0x00} }, -- {"Acer", "AOA110", "v0.3114", 0x55, 0x58, {0x1f, 0x00} }, -- {"Acer", "AOA110", "v0.3301", 0x55, 0x58, {0xaf, 0x00} }, -- {"Acer", "AOA110", "v0.3304", 0x55, 0x58, {0xaf, 0x00} }, -- {"Acer", "AOA110", "v0.3305", 0x55, 0x58, {0xaf, 0x00} }, -- {"Acer", "AOA110", "v0.3307", 0x55, 0x58, {0xaf, 0x00} }, -- {"Acer", "AOA110", "v0.3308", 0x55, 0x58, {0x21, 0x00} }, -- {"Acer", "AOA110", "v0.3309", 0x55, 0x58, {0x21, 0x00} }, -- {"Acer", "AOA110", "v0.3310", 0x55, 0x58, {0x21, 0x00} }, -+ {"Acer", "AOA110", "v0.3109", 0x55, 0x58, {0x1f, 0x1f, 0x00} }, -+ {"Acer", "AOA110", "v0.3114", 0x55, 0x58, {0x1f, 0x1f, 0x00} }, -+ {"Acer", "AOA110", "v0.3301", 0x55, 0x58, {0xaf, 0xaf, 0x00} }, -+ {"Acer", "AOA110", "v0.3304", 0x55, 0x58, {0xaf, 0xaf, 0x00} }, -+ {"Acer", "AOA110", "v0.3305", 0x55, 0x58, {0xaf, 0xaf, 0x00} }, -+ {"Acer", "AOA110", "v0.3307", 0x55, 0x58, {0xaf, 0xaf, 0x00} }, -+ {"Acer", "AOA110", "v0.3308", 0x55, 0x58, {0x21, 0x21, 0x00} }, -+ {"Acer", "AOA110", "v0.3309", 0x55, 0x58, {0x21, 0x21, 0x00} }, -+ {"Acer", "AOA110", "v0.3310", 0x55, 0x58, {0x21, 0x21, 0x00} }, - /* AOA150 */ -- {"Acer", "AOA150", "v0.3114", 0x55, 0x58, {0x20, 0x00} }, -- {"Acer", "AOA150", "v0.3301", 0x55, 0x58, {0x20, 0x00} }, -- {"Acer", "AOA150", "v0.3304", 0x55, 0x58, {0x20, 0x00} }, -- {"Acer", "AOA150", "v0.3305", 0x55, 0x58, {0x20, 0x00} }, -- {"Acer", "AOA150", "v0.3307", 0x55, 0x58, {0x20, 0x00} }, -- {"Acer", "AOA150", "v0.3308", 0x55, 0x58, {0x20, 0x00} }, -- {"Acer", "AOA150", "v0.3309", 0x55, 0x58, {0x20, 0x00} }, -- {"Acer", "AOA150", "v0.3310", 0x55, 0x58, {0x20, 0x00} }, -+ {"Acer", "AOA150", "v0.3114", 0x55, 0x58, {0x20, 0x20, 0x00} }, -+ {"Acer", "AOA150", "v0.3301", 0x55, 0x58, {0x20, 0x20, 0x00} }, -+ {"Acer", "AOA150", "v0.3304", 0x55, 0x58, {0x20, 0x20, 0x00} }, -+ {"Acer", "AOA150", "v0.3305", 0x55, 0x58, {0x20, 0x20, 0x00} }, -+ {"Acer", "AOA150", "v0.3307", 0x55, 0x58, {0x20, 0x20, 0x00} }, -+ {"Acer", "AOA150", "v0.3308", 0x55, 0x58, {0x20, 0x20, 0x00} }, -+ {"Acer", "AOA150", "v0.3309", 0x55, 0x58, {0x20, 0x20, 0x00} }, -+ {"Acer", "AOA150", "v0.3310", 0x55, 0x58, {0x20, 0x20, 0x00} }, -+ /* Acer 1410 */ -+ {"Acer", "Aspire 1410", "v0.3120", 0x55, 0x58, {0x9e, 0x9e, 0x00} }, - /* special BIOS / other */ -- {"Gateway", "AOA110", "v0.3103", 0x55, 0x58, {0x21, 0x00} }, -- {"Gateway", "AOA150", "v0.3103", 0x55, 0x58, {0x20, 0x00} }, -- {"Packard Bell", "DOA150", "v0.3104", 0x55, 0x58, {0x21, 0x00} }, -- {"Packard Bell", "AOA110", "v0.3105", 0x55, 0x58, {0x21, 0x00} }, -- {"Packard Bell", "AOA150", "v0.3105", 0x55, 0x58, {0x20, 0x00} }, -+ {"Gateway", "AOA110", "v0.3103", 0x55, 0x58, {0x21, 0x21, 0x00} }, -+ {"Gateway", "AOA150", "v0.3103", 0x55, 0x58, {0x20, 0x20, 0x00} }, -+ {"Gateway ", "LT31 ", "v1.3103 ", 0x55, 0x58, -+ {0x10, 0x0f, 0x00} }, -+ {"Gateway ", "LT31 ", "v1.3201 ", 0x55, 0x58, -+ {0x10, 0x0f, 0x00} }, -+ {"Gateway ", "LT31 ", "v1.3302 ", 0x55, 0x58, -+ {0x10, 0x0f, 0x00} }, -+ {"Packard Bell", "DOA150", "v0.3104", 0x55, 0x58, {0x21, 0x21, 0x00} }, -+ {"Packard Bell", "DOA150", "v0.3105", 0x55, 0x58, {0x20, 0x20, 0x00} }, -+ {"Packard Bell", "AOA110", "v0.3105", 0x55, 0x58, {0x21, 0x21, 0x00} }, -+ {"Packard Bell", "AOA150", "v0.3105", 0x55, 0x58, {0x20, 0x20, 0x00} }, - /* pewpew-terminator */ -- {"", "", "", 0, 0, {0, 0} } -+ {"", "", "", 0, 0, {0, 0, 0} } - }; - - static const struct bios_settings_t *bios_cfg __read_mostly; -@@ -183,7 +194,7 @@ static int acerhdf_get_fanstate(int *state) - if (ec_read(bios_cfg->fanreg, &fan)) - return -EINVAL; - -- if (fan != bios_cfg->cmd.cmd_off) -+ if (fan != bios_cfg->cmd.chk_off) - *state = ACERHDF_FAN_AUTO; - else - *state = ACERHDF_FAN_OFF; -diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c -index b39d2bb..849359a 100644 ---- a/drivers/platform/x86/asus-laptop.c -+++ b/drivers/platform/x86/asus-laptop.c -@@ -1283,8 +1283,8 @@ static int asus_hotk_add(struct acpi_device *device) - hotk->ledd_status = 0xFFF; - - /* Set initial values of light sensor and level */ -- hotk->light_switch = 1; /* Default to light sensor disabled */ -- hotk->light_level = 0; /* level 5 for sensor sensitivity */ -+ hotk->light_switch = 0; /* Default to light sensor disabled */ -+ hotk->light_level = 5; /* level 5 for sensor sensitivity */ - - if (ls_switch_handle) - set_light_sens_switch(hotk->light_switch); -diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c -index a848c7e..1ee734c 100644 ---- a/drivers/platform/x86/thinkpad_acpi.c -+++ b/drivers/platform/x86/thinkpad_acpi.c -@@ -3866,15 +3866,6 @@ enum { - - #define TPACPI_RFK_BLUETOOTH_SW_NAME "tpacpi_bluetooth_sw" - --static void bluetooth_suspend(pm_message_t state) --{ -- /* Try to make sure radio will resume powered off */ -- if (!acpi_evalf(NULL, NULL, "\\BLTH", "vd", -- TP_ACPI_BLTH_PWR_OFF_ON_RESUME)) -- vdbg_printk(TPACPI_DBG_RFKILL, -- "bluetooth power down on resume request failed\n"); --} -- - static int bluetooth_get_status(void) - { - int status; -@@ -3908,10 +3899,9 @@ static int bluetooth_set_status(enum tpacpi_rfkill_state state) - #endif - - /* We make sure to keep TP_ACPI_BLUETOOTH_RESUMECTRL off */ -+ status = TP_ACPI_BLUETOOTH_RESUMECTRL; - if (state == TPACPI_RFK_RADIO_ON) -- status = TP_ACPI_BLUETOOTH_RADIOSSW; -- else -- status = 0; -+ status |= TP_ACPI_BLUETOOTH_RADIOSSW; - - if (!acpi_evalf(hkey_handle, NULL, "SBDC", "vd", status)) - return -EIO; -@@ -4050,7 +4040,6 @@ static struct ibm_struct bluetooth_driver_data = { - .read = bluetooth_read, - .write = bluetooth_write, - .exit = bluetooth_exit, -- .suspend = bluetooth_suspend, - .shutdown = bluetooth_shutdown, - }; - -@@ -4068,15 +4057,6 @@ enum { - - #define TPACPI_RFK_WWAN_SW_NAME "tpacpi_wwan_sw" - --static void wan_suspend(pm_message_t state) --{ -- /* Try to make sure radio will resume powered off */ -- if (!acpi_evalf(NULL, NULL, "\\WGSV", "qvd", -- TP_ACPI_WGSV_PWR_OFF_ON_RESUME)) -- vdbg_printk(TPACPI_DBG_RFKILL, -- "WWAN power down on resume request failed\n"); --} -- - static int wan_get_status(void) - { - int status; -@@ -4109,11 +4089,10 @@ static int wan_set_status(enum tpacpi_rfkill_state state) - } - #endif - -- /* We make sure to keep TP_ACPI_WANCARD_RESUMECTRL off */ -+ /* We make sure to set TP_ACPI_WANCARD_RESUMECTRL */ -+ status = TP_ACPI_WANCARD_RESUMECTRL; - if (state == TPACPI_RFK_RADIO_ON) -- status = TP_ACPI_WANCARD_RADIOSSW; -- else -- status = 0; -+ status |= TP_ACPI_WANCARD_RADIOSSW; - - if (!acpi_evalf(hkey_handle, NULL, "SWAN", "vd", status)) - return -EIO; -@@ -4251,7 +4230,6 @@ static struct ibm_struct wan_driver_data = { - .read = wan_read, - .write = wan_write, - .exit = wan_exit, -- .suspend = wan_suspend, - .shutdown = wan_shutdown, - }; - -@@ -6123,8 +6101,8 @@ static const struct tpacpi_quirk brightness_quirk_table[] __initconst = { - - /* Models with Intel Extreme Graphics 2 */ - TPACPI_Q_IBM('1', 'U', TPACPI_BRGHT_Q_NOEC), -- TPACPI_Q_IBM('1', 'V', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_NOEC), -- TPACPI_Q_IBM('1', 'W', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_NOEC), -+ TPACPI_Q_IBM('1', 'V', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_EC), -+ TPACPI_Q_IBM('1', 'W', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_EC), - - /* Models with Intel GMA900 */ - TPACPI_Q_IBM('7', '0', TPACPI_BRGHT_Q_NOEC), /* T43, R52 */ -diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c -index 737b4c9..807042b 100644 ---- a/drivers/serial/8250.c -+++ b/drivers/serial/8250.c -@@ -1339,14 +1339,12 @@ static void serial8250_start_tx(struct uart_port *port) - serial_out(up, UART_IER, up->ier); - - if (up->bugs & UART_BUG_TXEN) { -- unsigned char lsr, iir; -+ unsigned char lsr; - lsr = serial_in(up, UART_LSR); - up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS; -- iir = serial_in(up, UART_IIR) & 0x0f; - if ((up->port.type == PORT_RM9000) ? -- (lsr & UART_LSR_THRE && -- (iir == UART_IIR_NO_INT || iir == UART_IIR_THRI)) : -- (lsr & UART_LSR_TEMT && iir & UART_IIR_NO_INT)) -+ (lsr & UART_LSR_THRE) : -+ (lsr & UART_LSR_TEMT)) - transmit_chars(up); - } - } -diff --git a/drivers/ssb/sprom.c b/drivers/ssb/sprom.c -index 8943015..eb70843 100644 ---- a/drivers/ssb/sprom.c -+++ b/drivers/ssb/sprom.c -@@ -13,6 +13,8 @@ - - #include "ssb_private.h" - -+#include -+ - - static const struct ssb_sprom *fallback_sprom; - -@@ -33,17 +35,27 @@ static int sprom2hex(const u16 *sprom, char *buf, size_t buf_len, - static int hex2sprom(u16 *sprom, const char *dump, size_t len, - size_t sprom_size_words) - { -- char tmp[5] = { 0 }; -- int cnt = 0; -+ char c, tmp[5] = { 0 }; -+ int err, cnt = 0; - unsigned long parsed; - -- if (len < sprom_size_words * 2) -+ /* Strip whitespace at the end. */ -+ while (len) { -+ c = dump[len - 1]; -+ if (!isspace(c) && c != '\0') -+ break; -+ len--; -+ } -+ /* Length must match exactly. */ -+ if (len != sprom_size_words * 4) - return -EINVAL; - - while (cnt < sprom_size_words) { - memcpy(tmp, dump, 4); - dump += 4; -- parsed = simple_strtoul(tmp, NULL, 16); -+ err = strict_strtoul(tmp, 16, &parsed); -+ if (err) -+ return err; - sprom[cnt++] = swab16((u16)parsed); - } - -diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c -index 2473cf0..d9461c9 100644 ---- a/drivers/usb/class/usbtmc.c -+++ b/drivers/usb/class/usbtmc.c -@@ -562,10 +562,16 @@ static ssize_t usbtmc_write(struct file *filp, const char __user *buf, - n_bytes = roundup(12 + this_part, 4); - memset(buffer + 12 + this_part, 0, n_bytes - (12 + this_part)); - -- retval = usb_bulk_msg(data->usb_dev, -- usb_sndbulkpipe(data->usb_dev, -- data->bulk_out), -- buffer, n_bytes, &actual, USBTMC_TIMEOUT); -+ do { -+ retval = usb_bulk_msg(data->usb_dev, -+ usb_sndbulkpipe(data->usb_dev, -+ data->bulk_out), -+ buffer, n_bytes, -+ &actual, USBTMC_TIMEOUT); -+ if (retval != 0) -+ break; -+ n_bytes -= actual; -+ } while (n_bytes); - - data->bTag_last_write = data->bTag; - data->bTag++; -diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c -index b1b85ab..52e5e31 100644 ---- a/drivers/usb/core/usb.c -+++ b/drivers/usb/core/usb.c -@@ -132,7 +132,7 @@ EXPORT_SYMBOL_GPL(usb_altnum_to_altsetting); - - struct find_interface_arg { - int minor; -- struct usb_interface *interface; -+ struct device_driver *drv; - }; - - static int __find_interface(struct device *dev, void *data) -@@ -143,12 +143,10 @@ static int __find_interface(struct device *dev, void *data) - if (!is_usb_interface(dev)) - return 0; - -+ if (dev->driver != arg->drv) -+ return 0; - intf = to_usb_interface(dev); -- if (intf->minor != -1 && intf->minor == arg->minor) { -- arg->interface = intf; -- return 1; -- } -- return 0; -+ return intf->minor == arg->minor; - } - - /** -@@ -156,21 +154,24 @@ static int __find_interface(struct device *dev, void *data) - * @drv: the driver whose current configuration is considered - * @minor: the minor number of the desired device - * -- * This walks the driver device list and returns a pointer to the interface -- * with the matching minor. Note, this only works for devices that share the -- * USB major number. -+ * This walks the bus device list and returns a pointer to the interface -+ * with the matching minor and driver. Note, this only works for devices -+ * that share the USB major number. - */ - struct usb_interface *usb_find_interface(struct usb_driver *drv, int minor) - { - struct find_interface_arg argb; -- int retval; -+ struct device *dev; - - argb.minor = minor; -- argb.interface = NULL; -- /* eat the error, it will be in argb.interface */ -- retval = driver_for_each_device(&drv->drvwrap.driver, NULL, &argb, -- __find_interface); -- return argb.interface; -+ argb.drv = &drv->drvwrap.driver; -+ -+ dev = bus_find_device(&usb_bus_type, NULL, &argb, __find_interface); -+ -+ /* Drop reference count from bus_find_device */ -+ put_device(dev); -+ -+ return dev ? to_usb_interface(dev) : NULL; - } - EXPORT_SYMBOL_GPL(usb_find_interface); - -diff --git a/drivers/usb/musb/musb_gadget_ep0.c b/drivers/usb/musb/musb_gadget_ep0.c -index 522efb3..1c44b97 100644 ---- a/drivers/usb/musb/musb_gadget_ep0.c -+++ b/drivers/usb/musb/musb_gadget_ep0.c -@@ -199,7 +199,6 @@ service_in_request(struct musb *musb, const struct usb_ctrlrequest *ctrlrequest) - static void musb_g_ep0_giveback(struct musb *musb, struct usb_request *req) - { - musb_g_giveback(&musb->endpoints[0].ep_in, req, 0); -- musb->ep0_state = MUSB_EP0_STAGE_SETUP; - } - - /* -diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c -index 0577e4b..dffc8a1 100644 ---- a/drivers/usb/serial/option.c -+++ b/drivers/usb/serial/option.c -@@ -580,12 +580,48 @@ static struct usb_device_id option_ids[] = { - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0086, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x2002, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x2003, 0xff, 0xff, 0xff) }, -+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0104, 0xff, 0xff, 0xff) }, -+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0106, 0xff, 0xff, 0xff) }, -+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0108, 0xff, 0xff, 0xff) }, -+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0113, 0xff, 0xff, 0xff) }, -+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0117, 0xff, 0xff, 0xff) }, -+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0118, 0xff, 0xff, 0xff) }, -+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0121, 0xff, 0xff, 0xff) }, -+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0122, 0xff, 0xff, 0xff) }, -+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0123, 0xff, 0xff, 0xff) }, -+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0124, 0xff, 0xff, 0xff) }, -+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0125, 0xff, 0xff, 0xff) }, -+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0126, 0xff, 0xff, 0xff) }, -+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0128, 0xff, 0xff, 0xff) }, -+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0142, 0xff, 0xff, 0xff) }, -+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0143, 0xff, 0xff, 0xff) }, -+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0144, 0xff, 0xff, 0xff) }, -+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0145, 0xff, 0xff, 0xff) }, -+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0146, 0xff, 0xff, 0xff) }, -+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0147, 0xff, 0xff, 0xff) }, -+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0148, 0xff, 0xff, 0xff) }, -+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0149, 0xff, 0xff, 0xff) }, -+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0150, 0xff, 0xff, 0xff) }, -+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0151, 0xff, 0xff, 0xff) }, -+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0152, 0xff, 0xff, 0xff) }, -+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0153, 0xff, 0xff, 0xff) }, -+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0154, 0xff, 0xff, 0xff) }, -+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0155, 0xff, 0xff, 0xff) }, -+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0156, 0xff, 0xff, 0xff) }, -+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0157, 0xff, 0xff, 0xff) }, -+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0158, 0xff, 0xff, 0xff) }, -+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0159, 0xff, 0xff, 0xff) }, -+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0160, 0xff, 0xff, 0xff) }, -+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0161, 0xff, 0xff, 0xff) }, -+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0162, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0014, 0xff, 0xff, 0xff) }, /* ZTE CDMA products */ - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0027, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0059, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0060, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0070, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0073, 0xff, 0xff, 0xff) }, -+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0130, 0xff, 0xff, 0xff) }, -+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0141, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_CDMA_TECH, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_AC8710, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_AC2726, 0xff, 0xff, 0xff) }, -@@ -599,6 +635,7 @@ static struct usb_device_id option_ids[] = { - { USB_DEVICE(TOSHIBA_VENDOR_ID, TOSHIBA_PRODUCT_G450) }, - { USB_DEVICE(TOSHIBA_VENDOR_ID, TOSHIBA_PRODUCT_HSDPA_MINICARD ) }, /* Toshiba 3G HSDPA == Novatel Expedite EU870D MiniCard */ - { USB_DEVICE(ALINK_VENDOR_ID, 0x9000) }, -+ { USB_DEVICE(ALINK_VENDOR_ID, 0xce16) }, - { USB_DEVICE_AND_INTERFACE_INFO(ALINK_VENDOR_ID, ALINK_PRODUCT_3GU, 0xff, 0xff, 0xff) }, - { USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_X060S) }, - { USB_DEVICE(AIRPLUS_VENDOR_ID, AIRPLUS_PRODUCT_MCD650) }, -diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c -index 589f6b4..cc313d1 100644 ---- a/drivers/usb/storage/transport.c -+++ b/drivers/usb/storage/transport.c -@@ -666,10 +666,11 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us) - * to wait for at least one CHECK_CONDITION to determine - * SANE_SENSE support - */ -- if ((srb->cmnd[0] == ATA_16 || srb->cmnd[0] == ATA_12) && -+ if (unlikely((srb->cmnd[0] == ATA_16 || srb->cmnd[0] == ATA_12) && - result == USB_STOR_TRANSPORT_GOOD && - !(us->fflags & US_FL_SANE_SENSE) && -- !(srb->cmnd[2] & 0x20)) { -+ !(us->fflags & US_FL_BAD_SENSE) && -+ !(srb->cmnd[2] & 0x20))) { - US_DEBUGP("-- SAT supported, increasing auto-sense\n"); - us->fflags |= US_FL_SANE_SENSE; - } -@@ -718,6 +719,12 @@ Retry_Sense: - if (test_bit(US_FLIDX_TIMED_OUT, &us->dflags)) { - US_DEBUGP("-- auto-sense aborted\n"); - srb->result = DID_ABORT << 16; -+ -+ /* If SANE_SENSE caused this problem, disable it */ -+ if (sense_size != US_SENSE_SIZE) { -+ us->fflags &= ~US_FL_SANE_SENSE; -+ us->fflags |= US_FL_BAD_SENSE; -+ } - goto Handle_Errors; - } - -@@ -727,10 +734,11 @@ Retry_Sense: - * (small) sense request. This fixes some USB GSM modems - */ - if (temp_result == USB_STOR_TRANSPORT_FAILED && -- (us->fflags & US_FL_SANE_SENSE) && -- sense_size != US_SENSE_SIZE) { -+ sense_size != US_SENSE_SIZE) { - US_DEBUGP("-- auto-sense failure, retry small sense\n"); - sense_size = US_SENSE_SIZE; -+ us->fflags &= ~US_FL_SANE_SENSE; -+ us->fflags |= US_FL_BAD_SENSE; - goto Retry_Sense; - } - -@@ -754,6 +762,7 @@ Retry_Sense: - */ - if (srb->sense_buffer[7] > (US_SENSE_SIZE - 8) && - !(us->fflags & US_FL_SANE_SENSE) && -+ !(us->fflags & US_FL_BAD_SENSE) && - (srb->sense_buffer[0] & 0x7C) == 0x70) { - US_DEBUGP("-- SANE_SENSE support enabled\n"); - us->fflags |= US_FL_SANE_SENSE; -diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h -index d4f034e..64a0a2c 100644 ---- a/drivers/usb/storage/unusual_devs.h -+++ b/drivers/usb/storage/unusual_devs.h -@@ -818,6 +818,13 @@ UNUSUAL_DEV( 0x066f, 0x8000, 0x0001, 0x0001, - US_SC_DEVICE, US_PR_DEVICE, NULL, - US_FL_FIX_CAPACITY ), - -+/* Reported by Daniel Kukula */ -+UNUSUAL_DEV( 0x067b, 0x1063, 0x0100, 0x0100, -+ "Prolific Technology, Inc.", -+ "Prolific Storage Gadget", -+ US_SC_DEVICE, US_PR_DEVICE, NULL, -+ US_FL_BAD_SENSE ), -+ - /* Reported by Rogerio Brito */ - UNUSUAL_DEV( 0x067b, 0x2317, 0x0001, 0x001, - "Prolific Technology, Inc.", -diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c -index 8060b85..716c8d7 100644 ---- a/drivers/usb/storage/usb.c -+++ b/drivers/usb/storage/usb.c -@@ -228,6 +228,7 @@ void fill_inquiry_response(struct us_data *us, unsigned char *data, - if (data_len<36) // You lose. - return; - -+ memset(data+8, ' ', 28); - if(data[0]&0x20) { /* USB device currently not connected. Return - peripheral qualifier 001b ("...however, the - physical device is not currently connected -@@ -237,15 +238,15 @@ void fill_inquiry_response(struct us_data *us, unsigned char *data, - device, it may return zeros or ASCII spaces - (20h) in those fields until the data is - available from the device."). */ -- memset(data+8,0,28); - } else { - u16 bcdDevice = le16_to_cpu(us->pusb_dev->descriptor.bcdDevice); -- memcpy(data+8, us->unusual_dev->vendorName, -- strlen(us->unusual_dev->vendorName) > 8 ? 8 : -- strlen(us->unusual_dev->vendorName)); -- memcpy(data+16, us->unusual_dev->productName, -- strlen(us->unusual_dev->productName) > 16 ? 16 : -- strlen(us->unusual_dev->productName)); -+ int n; -+ -+ n = strlen(us->unusual_dev->vendorName); -+ memcpy(data+8, us->unusual_dev->vendorName, min(8, n)); -+ n = strlen(us->unusual_dev->productName); -+ memcpy(data+16, us->unusual_dev->productName, min(16, n)); -+ - data[32] = 0x30 + ((bcdDevice>>12) & 0x0F); - data[33] = 0x30 + ((bcdDevice>>8) & 0x0F); - data[34] = 0x30 + ((bcdDevice>>4) & 0x0F); -@@ -459,6 +460,9 @@ static void adjust_quirks(struct us_data *us) - case 'a': - f |= US_FL_SANE_SENSE; - break; -+ case 'b': -+ f |= US_FL_BAD_SENSE; -+ break; - case 'c': - f |= US_FL_FIX_CAPACITY; - break; -diff --git a/drivers/video/matrox/g450_pll.c b/drivers/video/matrox/g450_pll.c -index 09f6e04..c15f8a5 100644 ---- a/drivers/video/matrox/g450_pll.c -+++ b/drivers/video/matrox/g450_pll.c -@@ -368,7 +368,8 @@ static int __g450_setclk(struct matrox_fb_info *minfo, unsigned int fout, - M1064_XDVICLKCTRL_C1DVICLKEN | - M1064_XDVICLKCTRL_DVILOOPCTL | - M1064_XDVICLKCTRL_P1LOOPBWDTCTL; -- matroxfb_DAC_out(minfo, M1064_XDVICLKCTRL, tmp); -+ /* Setting this breaks PC systems so don't do it */ -+ /* matroxfb_DAC_out(minfo, M1064_XDVICLKCTRL, tmp); */ - matroxfb_DAC_out(minfo, M1064_XPWRCTRL, - xpwrctrl); - -diff --git a/drivers/xen/balloon.c b/drivers/xen/balloon.c -index d31505b..4204336 100644 ---- a/drivers/xen/balloon.c -+++ b/drivers/xen/balloon.c -@@ -66,8 +66,6 @@ struct balloon_stats { - /* We aim for 'current allocation' == 'target allocation'. */ - unsigned long current_pages; - unsigned long target_pages; -- /* We may hit the hard limit in Xen. If we do then we remember it. */ -- unsigned long hard_limit; - /* - * Drivers may alter the memory reservation independently, but they - * must inform the balloon driver so we avoid hitting the hard limit. -@@ -136,6 +134,8 @@ static void balloon_append(struct page *page) - list_add(&page->lru, &ballooned_pages); - balloon_stats.balloon_low++; - } -+ -+ totalram_pages--; - } - - /* balloon_retrieve: rescue a page from the balloon, if it is not empty. */ -@@ -156,6 +156,8 @@ static struct page *balloon_retrieve(void) - else - balloon_stats.balloon_low--; - -+ totalram_pages++; -+ - return page; - } - -@@ -181,7 +183,7 @@ static void balloon_alarm(unsigned long unused) - - static unsigned long current_target(void) - { -- unsigned long target = min(balloon_stats.target_pages, balloon_stats.hard_limit); -+ unsigned long target = balloon_stats.target_pages; - - target = min(target, - balloon_stats.current_pages + -@@ -217,23 +219,10 @@ static int increase_reservation(unsigned long nr_pages) - set_xen_guest_handle(reservation.extent_start, frame_list); - reservation.nr_extents = nr_pages; - rc = HYPERVISOR_memory_op(XENMEM_populate_physmap, &reservation); -- if (rc < nr_pages) { -- if (rc > 0) { -- int ret; -- -- /* We hit the Xen hard limit: reprobe. */ -- reservation.nr_extents = rc; -- ret = HYPERVISOR_memory_op(XENMEM_decrease_reservation, -- &reservation); -- BUG_ON(ret != rc); -- } -- if (rc >= 0) -- balloon_stats.hard_limit = (balloon_stats.current_pages + rc - -- balloon_stats.driver_pages); -+ if (rc < 0) - goto out; -- } - -- for (i = 0; i < nr_pages; i++) { -+ for (i = 0; i < rc; i++) { - page = balloon_retrieve(); - BUG_ON(page == NULL); - -@@ -259,13 +248,12 @@ static int increase_reservation(unsigned long nr_pages) - __free_page(page); - } - -- balloon_stats.current_pages += nr_pages; -- totalram_pages = balloon_stats.current_pages; -+ balloon_stats.current_pages += rc; - - out: - spin_unlock_irqrestore(&balloon_lock, flags); - -- return 0; -+ return rc < 0 ? rc : rc != nr_pages; - } - - static int decrease_reservation(unsigned long nr_pages) -@@ -323,7 +311,6 @@ static int decrease_reservation(unsigned long nr_pages) - BUG_ON(ret != nr_pages); - - balloon_stats.current_pages -= nr_pages; -- totalram_pages = balloon_stats.current_pages; - - spin_unlock_irqrestore(&balloon_lock, flags); - -@@ -367,7 +354,6 @@ static void balloon_process(struct work_struct *work) - static void balloon_set_new_target(unsigned long target) - { - /* No need for lock. Not read-modify-write updates. */ -- balloon_stats.hard_limit = ~0UL; - balloon_stats.target_pages = target; - schedule_work(&balloon_worker); - } -@@ -422,12 +408,10 @@ static int __init balloon_init(void) - pr_info("xen_balloon: Initialising balloon driver.\n"); - - balloon_stats.current_pages = min(xen_start_info->nr_pages, max_pfn); -- totalram_pages = balloon_stats.current_pages; - balloon_stats.target_pages = balloon_stats.current_pages; - balloon_stats.balloon_low = 0; - balloon_stats.balloon_high = 0; - balloon_stats.driver_pages = 0UL; -- balloon_stats.hard_limit = ~0UL; - - init_timer(&balloon_timer); - balloon_timer.data = 0; -@@ -472,9 +456,6 @@ module_exit(balloon_exit); - BALLOON_SHOW(current_kb, "%lu\n", PAGES2KB(balloon_stats.current_pages)); - BALLOON_SHOW(low_kb, "%lu\n", PAGES2KB(balloon_stats.balloon_low)); - BALLOON_SHOW(high_kb, "%lu\n", PAGES2KB(balloon_stats.balloon_high)); --BALLOON_SHOW(hard_limit_kb, -- (balloon_stats.hard_limit!=~0UL) ? "%lu\n" : "???\n", -- (balloon_stats.hard_limit!=~0UL) ? PAGES2KB(balloon_stats.hard_limit) : 0); - BALLOON_SHOW(driver_kb, "%lu\n", PAGES2KB(balloon_stats.driver_pages)); - - static ssize_t show_target_kb(struct sys_device *dev, struct sysdev_attribute *attr, -@@ -544,7 +525,6 @@ static struct attribute *balloon_info_attrs[] = { - &attr_current_kb.attr, - &attr_low_kb.attr, - &attr_high_kb.attr, -- &attr_hard_limit_kb.attr, - &attr_driver_kb.attr, - NULL - }; -diff --git a/drivers/xen/events.c b/drivers/xen/events.c -index 2f57276..ce602dd 100644 ---- a/drivers/xen/events.c -+++ b/drivers/xen/events.c -@@ -474,6 +474,9 @@ static void unbind_from_irq(unsigned int irq) - bind_evtchn_to_cpu(evtchn, 0); - - evtchn_to_irq[evtchn] = -1; -+ } -+ -+ if (irq_info[irq].type != IRQT_UNBOUND) { - irq_info[irq] = mk_unbound_info(); - - dynamic_irq_cleanup(irq); -diff --git a/drivers/xen/manage.c b/drivers/xen/manage.c -index 10d03d7..c499793 100644 ---- a/drivers/xen/manage.c -+++ b/drivers/xen/manage.c -@@ -43,7 +43,6 @@ static int xen_suspend(void *data) - if (err) { - printk(KERN_ERR "xen_suspend: sysdev_suspend failed: %d\n", - err); -- dpm_resume_noirq(PMSG_RESUME); - return err; - } - -@@ -69,7 +68,6 @@ static int xen_suspend(void *data) - } - - sysdev_resume(); -- dpm_resume_noirq(PMSG_RESUME); - - return 0; - } -@@ -81,6 +79,12 @@ static void do_suspend(void) - - shutting_down = SHUTDOWN_SUSPEND; - -+ err = stop_machine_create(); -+ if (err) { -+ printk(KERN_ERR "xen suspend: failed to setup stop_machine %d\n", err); -+ goto out; -+ } -+ - #ifdef CONFIG_PREEMPT - /* If the kernel is preemptible, we need to freeze all the processes - to prevent them from being in the middle of a pagetable update -@@ -88,29 +92,32 @@ static void do_suspend(void) - err = freeze_processes(); - if (err) { - printk(KERN_ERR "xen suspend: freeze failed %d\n", err); -- return; -+ goto out_destroy_sm; - } - #endif - - err = dpm_suspend_start(PMSG_SUSPEND); - if (err) { - printk(KERN_ERR "xen suspend: dpm_suspend_start %d\n", err); -- goto out; -+ goto out_thaw; - } - -- printk(KERN_DEBUG "suspending xenstore...\n"); -- xs_suspend(); -- - err = dpm_suspend_noirq(PMSG_SUSPEND); - if (err) { - printk(KERN_ERR "dpm_suspend_noirq failed: %d\n", err); -- goto resume_devices; -+ goto out_resume; - } - -+ printk(KERN_DEBUG "suspending xenstore...\n"); -+ xs_suspend(); -+ - err = stop_machine(xen_suspend, &cancelled, cpumask_of(0)); -+ -+ dpm_resume_noirq(PMSG_RESUME); -+ - if (err) { - printk(KERN_ERR "failed to start xen_suspend: %d\n", err); -- goto out; -+ cancelled = 1; - } - - if (!cancelled) { -@@ -119,17 +126,21 @@ static void do_suspend(void) - } else - xs_suspend_cancel(); - -- dpm_resume_noirq(PMSG_RESUME); -- --resume_devices: -+out_resume: - dpm_resume_end(PMSG_RESUME); - - /* Make sure timer events get retriggered on all CPUs */ - clock_was_set(); --out: -+ -+out_thaw: - #ifdef CONFIG_PREEMPT - thaw_processes(); -+ -+out_destroy_sm: - #endif -+ stop_machine_destroy(); -+ -+out: - shutting_down = SHUTDOWN_INVALID; - } - #endif /* CONFIG_PM_SLEEP */ -diff --git a/drivers/xen/xenbus/xenbus_probe.c b/drivers/xen/xenbus/xenbus_probe.c -index d42e25d..3800da7 100644 ---- a/drivers/xen/xenbus/xenbus_probe.c -+++ b/drivers/xen/xenbus/xenbus_probe.c -@@ -454,21 +454,21 @@ static ssize_t xendev_show_nodename(struct device *dev, - { - return sprintf(buf, "%s\n", to_xenbus_device(dev)->nodename); - } --DEVICE_ATTR(nodename, S_IRUSR | S_IRGRP | S_IROTH, xendev_show_nodename, NULL); -+static DEVICE_ATTR(nodename, S_IRUSR | S_IRGRP | S_IROTH, xendev_show_nodename, NULL); - - static ssize_t xendev_show_devtype(struct device *dev, - struct device_attribute *attr, char *buf) - { - return sprintf(buf, "%s\n", to_xenbus_device(dev)->devicetype); - } --DEVICE_ATTR(devtype, S_IRUSR | S_IRGRP | S_IROTH, xendev_show_devtype, NULL); -+static DEVICE_ATTR(devtype, S_IRUSR | S_IRGRP | S_IROTH, xendev_show_devtype, NULL); - - static ssize_t xendev_show_modalias(struct device *dev, - struct device_attribute *attr, char *buf) - { - return sprintf(buf, "xen:%s\n", to_xenbus_device(dev)->devicetype); - } --DEVICE_ATTR(modalias, S_IRUSR | S_IRGRP | S_IROTH, xendev_show_modalias, NULL); -+static DEVICE_ATTR(modalias, S_IRUSR | S_IRGRP | S_IROTH, xendev_show_modalias, NULL); - - int xenbus_probe_node(struct xen_bus_type *bus, - const char *type, -diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c -index d22438e..39c6ee8 100644 ---- a/fs/debugfs/inode.c -+++ b/fs/debugfs/inode.c -@@ -32,7 +32,9 @@ static struct vfsmount *debugfs_mount; - static int debugfs_mount_count; - static bool debugfs_registered; - --static struct inode *debugfs_get_inode(struct super_block *sb, int mode, dev_t dev) -+static struct inode *debugfs_get_inode(struct super_block *sb, int mode, dev_t dev, -+ void *data, const struct file_operations *fops) -+ - { - struct inode *inode = new_inode(sb); - -@@ -44,14 +46,18 @@ static struct inode *debugfs_get_inode(struct super_block *sb, int mode, dev_t d - init_special_inode(inode, mode, dev); - break; - case S_IFREG: -- inode->i_fop = &debugfs_file_operations; -+ inode->i_fop = fops ? fops : &debugfs_file_operations; -+ inode->i_private = data; - break; - case S_IFLNK: - inode->i_op = &debugfs_link_operations; -+ inode->i_fop = fops; -+ inode->i_private = data; - break; - case S_IFDIR: - inode->i_op = &simple_dir_inode_operations; -- inode->i_fop = &simple_dir_operations; -+ inode->i_fop = fops ? fops : &simple_dir_operations; -+ inode->i_private = data; - - /* directory inodes start off with i_nlink == 2 - * (for "." entry) */ -@@ -64,7 +70,8 @@ static struct inode *debugfs_get_inode(struct super_block *sb, int mode, dev_t d - - /* SMP-safe */ - static int debugfs_mknod(struct inode *dir, struct dentry *dentry, -- int mode, dev_t dev) -+ int mode, dev_t dev, void *data, -+ const struct file_operations *fops) - { - struct inode *inode; - int error = -EPERM; -@@ -72,7 +79,7 @@ static int debugfs_mknod(struct inode *dir, struct dentry *dentry, - if (dentry->d_inode) - return -EEXIST; - -- inode = debugfs_get_inode(dir->i_sb, mode, dev); -+ inode = debugfs_get_inode(dir->i_sb, mode, dev, data, fops); - if (inode) { - d_instantiate(dentry, inode); - dget(dentry); -@@ -81,12 +88,13 @@ static int debugfs_mknod(struct inode *dir, struct dentry *dentry, - return error; - } - --static int debugfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) -+static int debugfs_mkdir(struct inode *dir, struct dentry *dentry, int mode, -+ void *data, const struct file_operations *fops) - { - int res; - - mode = (mode & (S_IRWXUGO | S_ISVTX)) | S_IFDIR; -- res = debugfs_mknod(dir, dentry, mode, 0); -+ res = debugfs_mknod(dir, dentry, mode, 0, data, fops); - if (!res) { - inc_nlink(dir); - fsnotify_mkdir(dir, dentry); -@@ -94,18 +102,20 @@ static int debugfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) - return res; - } - --static int debugfs_link(struct inode *dir, struct dentry *dentry, int mode) -+static int debugfs_link(struct inode *dir, struct dentry *dentry, int mode, -+ void *data, const struct file_operations *fops) - { - mode = (mode & S_IALLUGO) | S_IFLNK; -- return debugfs_mknod(dir, dentry, mode, 0); -+ return debugfs_mknod(dir, dentry, mode, 0, data, fops); - } - --static int debugfs_create(struct inode *dir, struct dentry *dentry, int mode) -+static int debugfs_create(struct inode *dir, struct dentry *dentry, int mode, -+ void *data, const struct file_operations *fops) - { - int res; - - mode = (mode & S_IALLUGO) | S_IFREG; -- res = debugfs_mknod(dir, dentry, mode, 0); -+ res = debugfs_mknod(dir, dentry, mode, 0, data, fops); - if (!res) - fsnotify_create(dir, dentry); - return res; -@@ -139,7 +149,9 @@ static struct file_system_type debug_fs_type = { - - static int debugfs_create_by_name(const char *name, mode_t mode, - struct dentry *parent, -- struct dentry **dentry) -+ struct dentry **dentry, -+ void *data, -+ const struct file_operations *fops) - { - int error = 0; - -@@ -164,13 +176,16 @@ static int debugfs_create_by_name(const char *name, mode_t mode, - if (!IS_ERR(*dentry)) { - switch (mode & S_IFMT) { - case S_IFDIR: -- error = debugfs_mkdir(parent->d_inode, *dentry, mode); -+ error = debugfs_mkdir(parent->d_inode, *dentry, mode, -+ data, fops); - break; - case S_IFLNK: -- error = debugfs_link(parent->d_inode, *dentry, mode); -+ error = debugfs_link(parent->d_inode, *dentry, mode, -+ data, fops); - break; - default: -- error = debugfs_create(parent->d_inode, *dentry, mode); -+ error = debugfs_create(parent->d_inode, *dentry, mode, -+ data, fops); - break; - } - dput(*dentry); -@@ -221,19 +236,13 @@ struct dentry *debugfs_create_file(const char *name, mode_t mode, - if (error) - goto exit; - -- error = debugfs_create_by_name(name, mode, parent, &dentry); -+ error = debugfs_create_by_name(name, mode, parent, &dentry, -+ data, fops); - if (error) { - dentry = NULL; - simple_release_fs(&debugfs_mount, &debugfs_mount_count); - goto exit; - } -- -- if (dentry->d_inode) { -- if (data) -- dentry->d_inode->i_private = data; -- if (fops) -- dentry->d_inode->i_fop = fops; -- } - exit: - return dentry; - } -diff --git a/fs/devpts/inode.c b/fs/devpts/inode.c -index d5f8c96..8882ecc 100644 ---- a/fs/devpts/inode.c -+++ b/fs/devpts/inode.c -@@ -517,11 +517,23 @@ int devpts_pty_new(struct inode *ptmx_inode, struct tty_struct *tty) - - struct tty_struct *devpts_get_tty(struct inode *pts_inode, int number) - { -+ struct dentry *dentry; -+ struct tty_struct *tty; -+ - BUG_ON(pts_inode->i_rdev == MKDEV(TTYAUX_MAJOR, PTMX_MINOR)); - -+ /* Ensure dentry has not been deleted by devpts_pty_kill() */ -+ dentry = d_find_alias(pts_inode); -+ if (!dentry) -+ return NULL; -+ -+ tty = NULL; - if (pts_inode->i_sb->s_magic == DEVPTS_SUPER_MAGIC) -- return (struct tty_struct *)pts_inode->i_private; -- return NULL; -+ tty = (struct tty_struct *)pts_inode->i_private; -+ -+ dput(dentry); -+ -+ return tty; - } - - void devpts_pty_kill(struct tty_struct *tty) -diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c -index 354ed3b..f9d6937 100644 ---- a/fs/ext3/inode.c -+++ b/fs/ext3/inode.c -@@ -1151,6 +1151,16 @@ static int do_journal_get_write_access(handle_t *handle, - return ext3_journal_get_write_access(handle, bh); - } - -+/* -+ * Truncate blocks that were not used by write. We have to truncate the -+ * pagecache as well so that corresponding buffers get properly unmapped. -+ */ -+static void ext3_truncate_failed_write(struct inode *inode) -+{ -+ truncate_inode_pages(inode->i_mapping, inode->i_size); -+ ext3_truncate(inode); -+} -+ - static int ext3_write_begin(struct file *file, struct address_space *mapping, - loff_t pos, unsigned len, unsigned flags, - struct page **pagep, void **fsdata) -@@ -1209,7 +1219,7 @@ write_begin_failed: - unlock_page(page); - page_cache_release(page); - if (pos + len > inode->i_size) -- ext3_truncate(inode); -+ ext3_truncate_failed_write(inode); - } - if (ret == -ENOSPC && ext3_should_retry_alloc(inode->i_sb, &retries)) - goto retry; -@@ -1304,7 +1314,7 @@ static int ext3_ordered_write_end(struct file *file, - page_cache_release(page); - - if (pos + len > inode->i_size) -- ext3_truncate(inode); -+ ext3_truncate_failed_write(inode); - return ret ? ret : copied; - } - -@@ -1330,7 +1340,7 @@ static int ext3_writeback_write_end(struct file *file, - page_cache_release(page); - - if (pos + len > inode->i_size) -- ext3_truncate(inode); -+ ext3_truncate_failed_write(inode); - return ret ? ret : copied; - } - -@@ -1383,7 +1393,7 @@ static int ext3_journalled_write_end(struct file *file, - page_cache_release(page); - - if (pos + len > inode->i_size) -- ext3_truncate(inode); -+ ext3_truncate_failed_write(inode); - return ret ? ret : copied; - } - -diff --git a/fs/hfs/catalog.c b/fs/hfs/catalog.c -index 6d98f11..424b033 100644 ---- a/fs/hfs/catalog.c -+++ b/fs/hfs/catalog.c -@@ -289,6 +289,10 @@ int hfs_cat_move(u32 cnid, struct inode *src_dir, struct qstr *src_name, - err = hfs_brec_find(&src_fd); - if (err) - goto out; -+ if (src_fd.entrylength > sizeof(entry) || src_fd.entrylength < 0) { -+ err = -EIO; -+ goto out; -+ } - - hfs_bnode_read(src_fd.bnode, &entry, src_fd.entryoffset, - src_fd.entrylength); -diff --git a/fs/hfs/dir.c b/fs/hfs/dir.c -index 7c69b98..2b3b861 100644 ---- a/fs/hfs/dir.c -+++ b/fs/hfs/dir.c -@@ -79,6 +79,11 @@ static int hfs_readdir(struct file *filp, void *dirent, filldir_t filldir) - filp->f_pos++; - /* fall through */ - case 1: -+ if (fd.entrylength > sizeof(entry) || fd.entrylength < 0) { -+ err = -EIO; -+ goto out; -+ } -+ - hfs_bnode_read(fd.bnode, &entry, fd.entryoffset, fd.entrylength); - if (entry.type != HFS_CDR_THD) { - printk(KERN_ERR "hfs: bad catalog folder thread\n"); -@@ -109,6 +114,12 @@ static int hfs_readdir(struct file *filp, void *dirent, filldir_t filldir) - err = -EIO; - goto out; - } -+ -+ if (fd.entrylength > sizeof(entry) || fd.entrylength < 0) { -+ err = -EIO; -+ goto out; -+ } -+ - hfs_bnode_read(fd.bnode, &entry, fd.entryoffset, fd.entrylength); - type = entry.type; - len = hfs_mac2asc(sb, strbuf, &fd.key->cat.CName); -diff --git a/fs/hfs/super.c b/fs/hfs/super.c -index f7fcbe4..5ed7252 100644 ---- a/fs/hfs/super.c -+++ b/fs/hfs/super.c -@@ -409,8 +409,13 @@ static int hfs_fill_super(struct super_block *sb, void *data, int silent) - /* try to get the root inode */ - hfs_find_init(HFS_SB(sb)->cat_tree, &fd); - res = hfs_cat_find_brec(sb, HFS_ROOT_CNID, &fd); -- if (!res) -+ if (!res) { -+ if (fd.entrylength > sizeof(rec) || fd.entrylength < 0) { -+ res = -EIO; -+ goto bail; -+ } - hfs_bnode_read(fd.bnode, &rec, fd.entryoffset, fd.entrylength); -+ } - if (res) { - hfs_find_exit(&fd); - goto bail_no_root; -diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c -index 82c295d..b7ca3a9 100644 ---- a/fs/jbd2/journal.c -+++ b/fs/jbd2/journal.c -@@ -1253,6 +1253,13 @@ int jbd2_journal_load(journal_t *journal) - if (jbd2_journal_recover(journal)) - goto recovery_error; - -+ if (journal->j_failed_commit) { -+ printk(KERN_ERR "JBD2: journal transaction %u on %s " -+ "is corrupt.\n", journal->j_failed_commit, -+ journal->j_devname); -+ return -EIO; -+ } -+ - /* OK, we've finished with the dynamic journal bits: - * reinitialise the dynamic contents of the superblock in memory - * and reset them on disk. */ -diff --git a/fs/jffs2/gc.c b/fs/jffs2/gc.c -index 090c556..3b6f2fa 100644 ---- a/fs/jffs2/gc.c -+++ b/fs/jffs2/gc.c -@@ -700,7 +700,8 @@ static int jffs2_garbage_collect_metadata(struct jffs2_sb_info *c, struct jffs2_ - struct jffs2_raw_inode ri; - struct jffs2_node_frag *last_frag; - union jffs2_device_node dev; -- char *mdata = NULL, mdatalen = 0; -+ char *mdata = NULL; -+ int mdatalen = 0; - uint32_t alloclen, ilen; - int ret; - -diff --git a/fs/nfs/write.c b/fs/nfs/write.c -index 53eb26c..6fc3776 100644 ---- a/fs/nfs/write.c -+++ b/fs/nfs/write.c -@@ -1612,15 +1612,16 @@ int nfs_migrate_page(struct address_space *mapping, struct page *newpage, - if (ret) - goto out_unlock; - page_cache_get(newpage); -+ spin_lock(&mapping->host->i_lock); - req->wb_page = newpage; - SetPagePrivate(newpage); -- set_page_private(newpage, page_private(page)); -+ set_page_private(newpage, (unsigned long)req); - ClearPagePrivate(page); - set_page_private(page, 0); -+ spin_unlock(&mapping->host->i_lock); - page_cache_release(page); - out_unlock: - nfs_clear_page_tag_locked(req); -- nfs_release_request(req); - out: - return ret; - } -diff --git a/include/drm/drmP.h b/include/drm/drmP.h -index c8e64bb..9d3d684 100644 ---- a/include/drm/drmP.h -+++ b/include/drm/drmP.h -@@ -1295,6 +1295,7 @@ extern u32 drm_vblank_count(struct drm_device *dev, int crtc); - extern void drm_handle_vblank(struct drm_device *dev, int crtc); - extern int drm_vblank_get(struct drm_device *dev, int crtc); - extern void drm_vblank_put(struct drm_device *dev, int crtc); -+extern void drm_vblank_off(struct drm_device *dev, int crtc); - extern void drm_vblank_cleanup(struct drm_device *dev); - /* Modesetting support */ - extern void drm_vblank_pre_modeset(struct drm_device *dev, int crtc); -diff --git a/include/drm/ttm/ttm_memory.h b/include/drm/ttm/ttm_memory.h -index 6983a7c..b199170 100644 ---- a/include/drm/ttm/ttm_memory.h -+++ b/include/drm/ttm/ttm_memory.h -@@ -33,6 +33,7 @@ - #include - #include - #include -+#include - - /** - * struct ttm_mem_shrink - callback to shrink TTM memory usage. -diff --git a/include/linux/hrtimer.h b/include/linux/hrtimer.h -index ff037f0..9bace4b 100644 ---- a/include/linux/hrtimer.h -+++ b/include/linux/hrtimer.h -@@ -446,7 +446,7 @@ extern void timer_stats_update_stats(void *timer, pid_t pid, void *startf, - - static inline void timer_stats_account_hrtimer(struct hrtimer *timer) - { -- if (likely(!timer->start_site)) -+ if (likely(!timer_stats_active)) - return; - timer_stats_update_stats(timer, timer->start_pid, timer->start_site, - timer->function, timer->start_comm, 0); -@@ -457,8 +457,6 @@ extern void __timer_stats_hrtimer_set_start_info(struct hrtimer *timer, - - static inline void timer_stats_hrtimer_set_start_info(struct hrtimer *timer) - { -- if (likely(!timer_stats_active)) -- return; - __timer_stats_hrtimer_set_start_info(timer, __builtin_return_address(0)); - } - -diff --git a/include/linux/kvm.h b/include/linux/kvm.h -index f8f8900..8908dd6 100644 ---- a/include/linux/kvm.h -+++ b/include/linux/kvm.h -@@ -116,6 +116,11 @@ struct kvm_run { - __u64 cr8; - __u64 apic_base; - -+#ifdef __KVM_S390 -+ /* the processor status word for s390 */ -+ __u64 psw_mask; /* psw upper half */ -+ __u64 psw_addr; /* psw lower half */ -+#endif - union { - /* KVM_EXIT_UNKNOWN */ - struct { -@@ -167,8 +172,6 @@ struct kvm_run { - /* KVM_EXIT_S390_SIEIC */ - struct { - __u8 icptcode; -- __u64 mask; /* psw upper half */ -- __u64 addr; /* psw lower half */ - __u16 ipa; - __u32 ipb; - } s390_sieic; -@@ -474,6 +477,7 @@ struct kvm_irq_routing { - }; - - #endif -+#define KVM_CAP_S390_PSW 42 - - #ifdef KVM_CAP_MCE - /* x86 MCE */ -diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h -index 9e70126..81c9689 100644 ---- a/include/linux/perf_event.h -+++ b/include/linux/perf_event.h -@@ -219,7 +219,7 @@ struct perf_event_attr { - #define PERF_EVENT_IOC_DISABLE _IO ('$', 1) - #define PERF_EVENT_IOC_REFRESH _IO ('$', 2) - #define PERF_EVENT_IOC_RESET _IO ('$', 3) --#define PERF_EVENT_IOC_PERIOD _IOW('$', 4, u64) -+#define PERF_EVENT_IOC_PERIOD _IOW('$', 4, __u64) - #define PERF_EVENT_IOC_SET_OUTPUT _IO ('$', 5) - - enum perf_event_ioc_flags { -diff --git a/include/linux/usb_usual.h b/include/linux/usb_usual.h -index 3d15fb9..a4b947e 100644 ---- a/include/linux/usb_usual.h -+++ b/include/linux/usb_usual.h -@@ -56,7 +56,9 @@ - US_FLAG(SANE_SENSE, 0x00008000) \ - /* Sane Sense (> 18 bytes) */ \ - US_FLAG(CAPACITY_OK, 0x00010000) \ -- /* READ CAPACITY response is correct */ -+ /* READ CAPACITY response is correct */ \ -+ US_FLAG(BAD_SENSE, 0x00020000) \ -+ /* Bad Sense (never more than 18 bytes) */ - - #define US_FLAG(name, value) US_FL_##name = value , - enum { US_DO_ALL_FLAGS }; -diff --git a/include/linux/vmalloc.h b/include/linux/vmalloc.h -index 227c2a5..3c123c3 100644 ---- a/include/linux/vmalloc.h -+++ b/include/linux/vmalloc.h -@@ -115,9 +115,11 @@ extern rwlock_t vmlist_lock; - extern struct vm_struct *vmlist; - extern __init void vm_area_register_early(struct vm_struct *vm, size_t align); - -+#ifndef CONFIG_HAVE_LEGACY_PER_CPU_AREA - struct vm_struct **pcpu_get_vm_areas(const unsigned long *offsets, - const size_t *sizes, int nr_vms, - size_t align, gfp_t gfp_mask); -+#endif - - void pcpu_free_vm_areas(struct vm_struct **vms, int nr_vms); - -diff --git a/include/net/tcp.h b/include/net/tcp.h -index 03a49c7..842ac4d 100644 ---- a/include/net/tcp.h -+++ b/include/net/tcp.h -@@ -1263,14 +1263,20 @@ static inline struct sk_buff *tcp_write_queue_prev(struct sock *sk, struct sk_bu - * TCP connection after "boundary" unsucessful, exponentially backed-off - * retransmissions with an initial RTO of TCP_RTO_MIN. - */ --static inline bool retransmits_timed_out(const struct sock *sk, -+static inline bool retransmits_timed_out(struct sock *sk, - unsigned int boundary) - { - unsigned int timeout, linear_backoff_thresh; -+ unsigned int start_ts; - - if (!inet_csk(sk)->icsk_retransmits) - return false; - -+ if (unlikely(!tcp_sk(sk)->retrans_stamp)) -+ start_ts = TCP_SKB_CB(tcp_write_queue_head(sk))->when; -+ else -+ start_ts = tcp_sk(sk)->retrans_stamp; -+ - linear_backoff_thresh = ilog2(TCP_RTO_MAX/TCP_RTO_MIN); - - if (boundary <= linear_backoff_thresh) -@@ -1279,7 +1285,7 @@ static inline bool retransmits_timed_out(const struct sock *sk, - timeout = ((2 << linear_backoff_thresh) - 1) * TCP_RTO_MIN + - (boundary - linear_backoff_thresh) * TCP_RTO_MAX; - -- return (tcp_time_stamp - tcp_sk(sk)->retrans_stamp) >= timeout; -+ return (tcp_time_stamp - start_ts) >= timeout; - } - - static inline struct sk_buff *tcp_send_head(struct sock *sk) -diff --git a/include/trace/ftrace.h b/include/trace/ftrace.h -index cc0d966..dacb8ef 100644 ---- a/include/trace/ftrace.h -+++ b/include/trace/ftrace.h -@@ -159,7 +159,7 @@ - #undef __get_str - - #undef TP_printk --#define TP_printk(fmt, args...) "%s, %s\n", #fmt, __stringify(args) -+#define TP_printk(fmt, args...) "\"%s\", %s\n", fmt, __stringify(args) - - #undef TP_fast_assign - #define TP_fast_assign(args...) args -diff --git a/kernel/acct.c b/kernel/acct.c -index 9a4715a..a6605ca 100644 ---- a/kernel/acct.c -+++ b/kernel/acct.c -@@ -536,7 +536,8 @@ static void do_acct_process(struct bsd_acct_struct *acct, - do_div(elapsed, AHZ); - ac.ac_btime = get_seconds() - elapsed; - /* we really need to bite the bullet and change layout */ -- current_uid_gid(&ac.ac_uid, &ac.ac_gid); -+ ac.ac_uid = orig_cred->uid; -+ ac.ac_gid = orig_cred->gid; - #if ACCT_VERSION==2 - ac.ac_ahz = AHZ; - #endif -diff --git a/kernel/futex.c b/kernel/futex.c -index fb65e82..d73ef1f 100644 ---- a/kernel/futex.c -+++ b/kernel/futex.c -@@ -304,8 +304,14 @@ void put_futex_key(int fshared, union futex_key *key) - */ - static int fault_in_user_writeable(u32 __user *uaddr) - { -- int ret = get_user_pages(current, current->mm, (unsigned long)uaddr, -- 1, 1, 0, NULL, NULL); -+ struct mm_struct *mm = current->mm; -+ int ret; -+ -+ down_read(&mm->mmap_sem); -+ ret = get_user_pages(current, mm, (unsigned long)uaddr, -+ 1, 1, 0, NULL, NULL); -+ up_read(&mm->mmap_sem); -+ - return ret < 0 ? ret : 0; - } - -diff --git a/kernel/perf_event.c b/kernel/perf_event.c -index 7f29643..6eee915 100644 ---- a/kernel/perf_event.c -+++ b/kernel/perf_event.c -@@ -1583,7 +1583,7 @@ static struct perf_event_context *find_get_context(pid_t pid, int cpu) - if (perf_paranoid_cpu() && !capable(CAP_SYS_ADMIN)) - return ERR_PTR(-EACCES); - -- if (cpu < 0 || cpu > num_possible_cpus()) -+ if (cpu < 0 || cpu >= nr_cpumask_bits) - return ERR_PTR(-EINVAL); - - /* -@@ -2174,6 +2174,7 @@ static void perf_mmap_data_free(struct perf_mmap_data *data) - perf_mmap_free_page((unsigned long)data->user_page); - for (i = 0; i < data->nr_pages; i++) - perf_mmap_free_page((unsigned long)data->data_pages[i]); -+ kfree(data); - } - - #else -@@ -2214,6 +2215,7 @@ static void perf_mmap_data_free_work(struct work_struct *work) - perf_mmap_unmark_page(base + (i * PAGE_SIZE)); - - vfree(base); -+ kfree(data); - } - - static void perf_mmap_data_free(struct perf_mmap_data *data) -@@ -2319,7 +2321,6 @@ static void perf_mmap_data_free_rcu(struct rcu_head *rcu_head) - - data = container_of(rcu_head, struct perf_mmap_data, rcu_head); - perf_mmap_data_free(data); -- kfree(data); - } - - static void perf_mmap_data_release(struct perf_event *event) -@@ -3949,6 +3950,7 @@ static enum hrtimer_restart perf_swevent_hrtimer(struct hrtimer *hrtimer) - event->pmu->read(event); - - data.addr = 0; -+ data.period = event->hw.last_period; - regs = get_irq_regs(); - /* - * In case we exclude kernel IPs or are somehow not in interrupt -diff --git a/kernel/rcutree.c b/kernel/rcutree.c -index f3077c0..683c4f3 100644 ---- a/kernel/rcutree.c -+++ b/kernel/rcutree.c -@@ -176,9 +176,29 @@ static struct rcu_node *rcu_get_root(struct rcu_state *rsp) - return &rsp->node[0]; - } - -+/* -+ * Record the specified "completed" value, which is later used to validate -+ * dynticks counter manipulations and CPU-offline checks. Specify -+ * "rsp->completed - 1" to unconditionally invalidate any future dynticks -+ * manipulations and CPU-offline checks. Such invalidation is useful at -+ * the beginning of a grace period. -+ */ -+static void dyntick_record_completed(struct rcu_state *rsp, long comp) -+{ -+ rsp->dynticks_completed = comp; -+} -+ - #ifdef CONFIG_SMP - - /* -+ * Recall the previously recorded value of the completion for dynticks. -+ */ -+static long dyntick_recall_completed(struct rcu_state *rsp) -+{ -+ return rsp->dynticks_completed; -+} -+ -+/* - * If the specified CPU is offline, tell the caller that it is in - * a quiescent state. Otherwise, whack it with a reschedule IPI. - * Grace periods can end up waiting on an offline CPU when that -@@ -335,28 +355,9 @@ void rcu_irq_exit(void) - set_need_resched(); - } - --/* -- * Record the specified "completed" value, which is later used to validate -- * dynticks counter manipulations. Specify "rsp->completed - 1" to -- * unconditionally invalidate any future dynticks manipulations (which is -- * useful at the beginning of a grace period). -- */ --static void dyntick_record_completed(struct rcu_state *rsp, long comp) --{ -- rsp->dynticks_completed = comp; --} -- - #ifdef CONFIG_SMP - - /* -- * Recall the previously recorded value of the completion for dynticks. -- */ --static long dyntick_recall_completed(struct rcu_state *rsp) --{ -- return rsp->dynticks_completed; --} -- --/* - * Snapshot the specified CPU's dynticks counter so that we can later - * credit them with an implicit quiescent state. Return 1 if this CPU - * is in dynticks idle mode, which is an extended quiescent state. -@@ -419,24 +420,8 @@ static int rcu_implicit_dynticks_qs(struct rcu_data *rdp) - - #else /* #ifdef CONFIG_NO_HZ */ - --static void dyntick_record_completed(struct rcu_state *rsp, long comp) --{ --} -- - #ifdef CONFIG_SMP - --/* -- * If there are no dynticks, then the only way that a CPU can passively -- * be in a quiescent state is to be offline. Unlike dynticks idle, which -- * is a point in time during the prior (already finished) grace period, -- * an offline CPU is always in a quiescent state, and thus can be -- * unconditionally applied. So just return the current value of completed. -- */ --static long dyntick_recall_completed(struct rcu_state *rsp) --{ -- return rsp->completed; --} -- - static int dyntick_save_progress_counter(struct rcu_data *rdp) - { - return 0; -@@ -553,13 +538,33 @@ static void check_cpu_stall(struct rcu_state *rsp, struct rcu_data *rdp) - /* - * Update CPU-local rcu_data state to record the newly noticed grace period. - * This is used both when we started the grace period and when we notice -- * that someone else started the grace period. -+ * that someone else started the grace period. The caller must hold the -+ * ->lock of the leaf rcu_node structure corresponding to the current CPU, -+ * and must have irqs disabled. - */ -+static void __note_new_gpnum(struct rcu_state *rsp, struct rcu_node *rnp, struct rcu_data *rdp) -+{ -+ if (rdp->gpnum != rnp->gpnum) { -+ rdp->qs_pending = 1; -+ rdp->passed_quiesc = 0; -+ rdp->gpnum = rnp->gpnum; -+ } -+} -+ - static void note_new_gpnum(struct rcu_state *rsp, struct rcu_data *rdp) - { -- rdp->qs_pending = 1; -- rdp->passed_quiesc = 0; -- rdp->gpnum = rsp->gpnum; -+ unsigned long flags; -+ struct rcu_node *rnp; -+ -+ local_irq_save(flags); -+ rnp = rdp->mynode; -+ if (rdp->gpnum == ACCESS_ONCE(rnp->gpnum) || /* outside lock. */ -+ !spin_trylock(&rnp->lock)) { /* irqs already off, retry later. */ -+ local_irq_restore(flags); -+ return; -+ } -+ __note_new_gpnum(rsp, rnp, rdp); -+ spin_unlock_irqrestore(&rnp->lock, flags); - } - - /* -@@ -583,6 +588,79 @@ check_for_new_grace_period(struct rcu_state *rsp, struct rcu_data *rdp) - } - - /* -+ * Advance this CPU's callbacks, but only if the current grace period -+ * has ended. This may be called only from the CPU to whom the rdp -+ * belongs. In addition, the corresponding leaf rcu_node structure's -+ * ->lock must be held by the caller, with irqs disabled. -+ */ -+static void -+__rcu_process_gp_end(struct rcu_state *rsp, struct rcu_node *rnp, struct rcu_data *rdp) -+{ -+ /* Did another grace period end? */ -+ if (rdp->completed != rnp->completed) { -+ -+ /* Advance callbacks. No harm if list empty. */ -+ rdp->nxttail[RCU_DONE_TAIL] = rdp->nxttail[RCU_WAIT_TAIL]; -+ rdp->nxttail[RCU_WAIT_TAIL] = rdp->nxttail[RCU_NEXT_READY_TAIL]; -+ rdp->nxttail[RCU_NEXT_READY_TAIL] = rdp->nxttail[RCU_NEXT_TAIL]; -+ -+ /* Remember that we saw this grace-period completion. */ -+ rdp->completed = rnp->completed; -+ } -+} -+ -+/* -+ * Advance this CPU's callbacks, but only if the current grace period -+ * has ended. This may be called only from the CPU to whom the rdp -+ * belongs. -+ */ -+static void -+rcu_process_gp_end(struct rcu_state *rsp, struct rcu_data *rdp) -+{ -+ unsigned long flags; -+ struct rcu_node *rnp; -+ -+ local_irq_save(flags); -+ rnp = rdp->mynode; -+ if (rdp->completed == ACCESS_ONCE(rnp->completed) || /* outside lock. */ -+ !spin_trylock(&rnp->lock)) { /* irqs already off, retry later. */ -+ local_irq_restore(flags); -+ return; -+ } -+ __rcu_process_gp_end(rsp, rnp, rdp); -+ spin_unlock_irqrestore(&rnp->lock, flags); -+} -+ -+/* -+ * Do per-CPU grace-period initialization for running CPU. The caller -+ * must hold the lock of the leaf rcu_node structure corresponding to -+ * this CPU. -+ */ -+static void -+rcu_start_gp_per_cpu(struct rcu_state *rsp, struct rcu_node *rnp, struct rcu_data *rdp) -+{ -+ /* Prior grace period ended, so advance callbacks for current CPU. */ -+ __rcu_process_gp_end(rsp, rnp, rdp); -+ -+ /* -+ * Because this CPU just now started the new grace period, we know -+ * that all of its callbacks will be covered by this upcoming grace -+ * period, even the ones that were registered arbitrarily recently. -+ * Therefore, advance all outstanding callbacks to RCU_WAIT_TAIL. -+ * -+ * Other CPUs cannot be sure exactly when the grace period started. -+ * Therefore, their recently registered callbacks must pass through -+ * an additional RCU_NEXT_READY stage, so that they will be handled -+ * by the next RCU grace period. -+ */ -+ rdp->nxttail[RCU_NEXT_READY_TAIL] = rdp->nxttail[RCU_NEXT_TAIL]; -+ rdp->nxttail[RCU_WAIT_TAIL] = rdp->nxttail[RCU_NEXT_TAIL]; -+ -+ /* Set state so that this CPU will detect the next quiescent state. */ -+ __note_new_gpnum(rsp, rnp, rdp); -+} -+ -+/* - * Start a new RCU grace period if warranted, re-initializing the hierarchy - * in preparation for detecting the next grace period. The caller must hold - * the root node's ->lock, which is released before return. Hard irqs must -@@ -607,28 +685,15 @@ rcu_start_gp(struct rcu_state *rsp, unsigned long flags) - rsp->jiffies_force_qs = jiffies + RCU_JIFFIES_TILL_FORCE_QS; - record_gp_stall_check_time(rsp); - dyntick_record_completed(rsp, rsp->completed - 1); -- note_new_gpnum(rsp, rdp); -- -- /* -- * Because this CPU just now started the new grace period, we know -- * that all of its callbacks will be covered by this upcoming grace -- * period, even the ones that were registered arbitrarily recently. -- * Therefore, advance all outstanding callbacks to RCU_WAIT_TAIL. -- * -- * Other CPUs cannot be sure exactly when the grace period started. -- * Therefore, their recently registered callbacks must pass through -- * an additional RCU_NEXT_READY stage, so that they will be handled -- * by the next RCU grace period. -- */ -- rdp->nxttail[RCU_NEXT_READY_TAIL] = rdp->nxttail[RCU_NEXT_TAIL]; -- rdp->nxttail[RCU_WAIT_TAIL] = rdp->nxttail[RCU_NEXT_TAIL]; - - /* Special-case the common single-level case. */ - if (NUM_RCU_NODES == 1) { - rcu_preempt_check_blocked_tasks(rnp); - rnp->qsmask = rnp->qsmaskinit; - rnp->gpnum = rsp->gpnum; -+ rnp->completed = rsp->completed; - rsp->signaled = RCU_SIGNAL_INIT; /* force_quiescent_state OK. */ -+ rcu_start_gp_per_cpu(rsp, rnp, rdp); - spin_unlock_irqrestore(&rnp->lock, flags); - return; - } -@@ -661,6 +726,9 @@ rcu_start_gp(struct rcu_state *rsp, unsigned long flags) - rcu_preempt_check_blocked_tasks(rnp); - rnp->qsmask = rnp->qsmaskinit; - rnp->gpnum = rsp->gpnum; -+ rnp->completed = rsp->completed; -+ if (rnp == rdp->mynode) -+ rcu_start_gp_per_cpu(rsp, rnp, rdp); - spin_unlock(&rnp->lock); /* irqs remain disabled. */ - } - -@@ -672,34 +740,6 @@ rcu_start_gp(struct rcu_state *rsp, unsigned long flags) - } - - /* -- * Advance this CPU's callbacks, but only if the current grace period -- * has ended. This may be called only from the CPU to whom the rdp -- * belongs. -- */ --static void --rcu_process_gp_end(struct rcu_state *rsp, struct rcu_data *rdp) --{ -- long completed_snap; -- unsigned long flags; -- -- local_irq_save(flags); -- completed_snap = ACCESS_ONCE(rsp->completed); /* outside of lock. */ -- -- /* Did another grace period end? */ -- if (rdp->completed != completed_snap) { -- -- /* Advance callbacks. No harm if list empty. */ -- rdp->nxttail[RCU_DONE_TAIL] = rdp->nxttail[RCU_WAIT_TAIL]; -- rdp->nxttail[RCU_WAIT_TAIL] = rdp->nxttail[RCU_NEXT_READY_TAIL]; -- rdp->nxttail[RCU_NEXT_READY_TAIL] = rdp->nxttail[RCU_NEXT_TAIL]; -- -- /* Remember that we saw this grace-period completion. */ -- rdp->completed = completed_snap; -- } -- local_irq_restore(flags); --} -- --/* - * Clean up after the prior grace period and let rcu_start_gp() start up - * the next grace period if one is needed. Note that the caller must - * hold rnp->lock, as required by rcu_start_gp(), which will release it. -@@ -710,7 +750,6 @@ static void cpu_quiet_msk_finish(struct rcu_state *rsp, unsigned long flags) - WARN_ON_ONCE(!rcu_gp_in_progress(rsp)); - rsp->completed = rsp->gpnum; - rsp->signaled = RCU_GP_IDLE; -- rcu_process_gp_end(rsp, rsp->rda[smp_processor_id()]); - rcu_start_gp(rsp, flags); /* releases root node's rnp->lock. */ - } - -@@ -1144,6 +1183,7 @@ static void force_quiescent_state(struct rcu_state *rsp, int relaxed) - long lastcomp; - struct rcu_node *rnp = rcu_get_root(rsp); - u8 signaled; -+ u8 forcenow; - - if (!rcu_gp_in_progress(rsp)) - return; /* No grace period in progress, nothing to force. */ -@@ -1180,16 +1220,23 @@ static void force_quiescent_state(struct rcu_state *rsp, int relaxed) - if (rcu_process_dyntick(rsp, lastcomp, - dyntick_save_progress_counter)) - goto unlock_ret; -+ /* fall into next case. */ -+ -+ case RCU_SAVE_COMPLETED: - - /* Update state, record completion counter. */ -+ forcenow = 0; - spin_lock(&rnp->lock); - if (lastcomp == rsp->completed && -- rsp->signaled == RCU_SAVE_DYNTICK) { -+ rsp->signaled == signaled) { - rsp->signaled = RCU_FORCE_QS; - dyntick_record_completed(rsp, lastcomp); -+ forcenow = signaled == RCU_SAVE_COMPLETED; - } - spin_unlock(&rnp->lock); -- break; -+ if (!forcenow) -+ break; -+ /* fall into next case. */ - - case RCU_FORCE_QS: - -@@ -1544,21 +1591,16 @@ static void __cpuinit - rcu_init_percpu_data(int cpu, struct rcu_state *rsp, int preemptable) - { - unsigned long flags; -- long lastcomp; - unsigned long mask; - struct rcu_data *rdp = rsp->rda[cpu]; - struct rcu_node *rnp = rcu_get_root(rsp); - - /* Set up local state, ensuring consistent view of global state. */ - spin_lock_irqsave(&rnp->lock, flags); -- lastcomp = rsp->completed; -- rdp->completed = lastcomp; -- rdp->gpnum = lastcomp; - rdp->passed_quiesc = 0; /* We could be racing with new GP, */ - rdp->qs_pending = 1; /* so set up to respond to current GP. */ - rdp->beenonline = 1; /* We have now been online. */ - rdp->preemptable = preemptable; -- rdp->passed_quiesc_completed = lastcomp - 1; - rdp->qlen_last_fqs_check = 0; - rdp->n_force_qs_snap = rsp->n_force_qs; - rdp->blimit = blimit; -@@ -1580,6 +1622,11 @@ rcu_init_percpu_data(int cpu, struct rcu_state *rsp, int preemptable) - spin_lock(&rnp->lock); /* irqs already disabled. */ - rnp->qsmaskinit |= mask; - mask = rnp->grpmask; -+ if (rnp == rdp->mynode) { -+ rdp->gpnum = rnp->completed; /* if GP in progress... */ -+ rdp->completed = rnp->completed; -+ rdp->passed_quiesc_completed = rnp->completed - 1; -+ } - spin_unlock(&rnp->lock); /* irqs already disabled. */ - rnp = rnp->parent; - } while (rnp != NULL && !(rnp->qsmaskinit & mask)); -diff --git a/kernel/rcutree.h b/kernel/rcutree.h -index 1899023..ddb79ec 100644 ---- a/kernel/rcutree.h -+++ b/kernel/rcutree.h -@@ -84,6 +84,9 @@ struct rcu_node { - long gpnum; /* Current grace period for this node. */ - /* This will either be equal to or one */ - /* behind the root rcu_node's gpnum. */ -+ long completed; /* Last grace period completed for this node. */ -+ /* This will either be equal to or one */ -+ /* behind the root rcu_node's gpnum. */ - unsigned long qsmask; /* CPUs or groups that need to switch in */ - /* order for current grace period to proceed.*/ - /* In leaf rcu_node, each bit corresponds to */ -@@ -204,11 +207,12 @@ struct rcu_data { - #define RCU_GP_IDLE 0 /* No grace period in progress. */ - #define RCU_GP_INIT 1 /* Grace period being initialized. */ - #define RCU_SAVE_DYNTICK 2 /* Need to scan dyntick state. */ --#define RCU_FORCE_QS 3 /* Need to force quiescent state. */ -+#define RCU_SAVE_COMPLETED 3 /* Need to save rsp->completed. */ -+#define RCU_FORCE_QS 4 /* Need to force quiescent state. */ - #ifdef CONFIG_NO_HZ - #define RCU_SIGNAL_INIT RCU_SAVE_DYNTICK - #else /* #ifdef CONFIG_NO_HZ */ --#define RCU_SIGNAL_INIT RCU_FORCE_QS -+#define RCU_SIGNAL_INIT RCU_SAVE_COMPLETED - #endif /* #else #ifdef CONFIG_NO_HZ */ - - #define RCU_JIFFIES_TILL_FORCE_QS 3 /* for rsp->jiffies_force_qs */ -@@ -274,9 +278,8 @@ struct rcu_state { - unsigned long jiffies_stall; /* Time at which to check */ - /* for CPU stalls. */ - #endif /* #ifdef CONFIG_RCU_CPU_STALL_DETECTOR */ --#ifdef CONFIG_NO_HZ - long dynticks_completed; /* Value of completed @ snap. */ --#endif /* #ifdef CONFIG_NO_HZ */ -+ /* Protected by fqslock. */ - }; - - #ifdef RCU_TREE_NONCORE -@@ -298,7 +301,7 @@ DECLARE_PER_CPU(struct rcu_data, rcu_preempt_data); - #else /* #ifdef RCU_TREE_NONCORE */ - - /* Forward declarations for rcutree_plugin.h */ --static inline void rcu_bootup_announce(void); -+static void rcu_bootup_announce(void); - long rcu_batches_completed(void); - static void rcu_preempt_note_context_switch(int cpu); - static int rcu_preempted_readers(struct rcu_node *rnp); -diff --git a/kernel/rcutree_plugin.h b/kernel/rcutree_plugin.h -index ef2a58c..c03edf7 100644 ---- a/kernel/rcutree_plugin.h -+++ b/kernel/rcutree_plugin.h -@@ -33,7 +33,7 @@ DEFINE_PER_CPU(struct rcu_data, rcu_preempt_data); - /* - * Tell them what RCU they are running. - */ --static inline void rcu_bootup_announce(void) -+static void rcu_bootup_announce(void) - { - printk(KERN_INFO - "Experimental preemptable hierarchical RCU implementation.\n"); -@@ -481,7 +481,7 @@ void exit_rcu(void) - /* - * Tell them what RCU they are running. - */ --static inline void rcu_bootup_announce(void) -+static void rcu_bootup_announce(void) - { - printk(KERN_INFO "Hierarchical RCU implementation.\n"); - } -diff --git a/kernel/sched.c b/kernel/sched.c -index 3c11ae0..d079a9f 100644 ---- a/kernel/sched.c -+++ b/kernel/sched.c -@@ -591,6 +591,8 @@ struct rq { - - u64 rt_avg; - u64 age_stamp; -+ u64 idle_stamp; -+ u64 avg_idle; - #endif - - /* calc_load related fields */ -@@ -2440,6 +2442,17 @@ out_running: - #ifdef CONFIG_SMP - if (p->sched_class->task_wake_up) - p->sched_class->task_wake_up(rq, p); -+ -+ if (unlikely(rq->idle_stamp)) { -+ u64 delta = rq->clock - rq->idle_stamp; -+ u64 max = 2*sysctl_sched_migration_cost; -+ -+ if (delta > max) -+ rq->avg_idle = max; -+ else -+ update_avg(&rq->avg_idle, delta); -+ rq->idle_stamp = 0; -+ } - #endif - out: - task_rq_unlock(rq, &flags); -@@ -4126,7 +4139,7 @@ static int load_balance(int this_cpu, struct rq *this_rq, - unsigned long flags; - struct cpumask *cpus = __get_cpu_var(load_balance_tmpmask); - -- cpumask_setall(cpus); -+ cpumask_copy(cpus, cpu_online_mask); - - /* - * When power savings policy is enabled for the parent domain, idle -@@ -4289,7 +4302,7 @@ load_balance_newidle(int this_cpu, struct rq *this_rq, struct sched_domain *sd) - int all_pinned = 0; - struct cpumask *cpus = __get_cpu_var(load_balance_tmpmask); - -- cpumask_setall(cpus); -+ cpumask_copy(cpus, cpu_online_mask); - - /* - * When power savings policy is enabled for the parent domain, idle -@@ -4429,6 +4442,11 @@ static void idle_balance(int this_cpu, struct rq *this_rq) - int pulled_task = 0; - unsigned long next_balance = jiffies + HZ; - -+ this_rq->idle_stamp = this_rq->clock; -+ -+ if (this_rq->avg_idle < sysctl_sched_migration_cost) -+ return; -+ - for_each_domain(this_cpu, sd) { - unsigned long interval; - -@@ -4443,8 +4461,10 @@ static void idle_balance(int this_cpu, struct rq *this_rq) - interval = msecs_to_jiffies(sd->balance_interval); - if (time_after(next_balance, sd->last_balance + interval)) - next_balance = sd->last_balance + interval; -- if (pulled_task) -+ if (pulled_task) { -+ this_rq->idle_stamp = 0; - break; -+ } - } - if (pulled_task || time_after(jiffies, this_rq->next_balance)) { - /* -@@ -9522,6 +9542,8 @@ void __init sched_init(void) - rq->cpu = i; - rq->online = 0; - rq->migration_thread = NULL; -+ rq->idle_stamp = 0; -+ rq->avg_idle = 2*sysctl_sched_migration_cost; - INIT_LIST_HEAD(&rq->migration_queue); - rq_attach_root(rq, &def_root_domain); - #endif -diff --git a/kernel/sched_debug.c b/kernel/sched_debug.c -index efb8440..6988cf0 100644 ---- a/kernel/sched_debug.c -+++ b/kernel/sched_debug.c -@@ -285,12 +285,16 @@ static void print_cpu(struct seq_file *m, int cpu) - - #ifdef CONFIG_SCHEDSTATS - #define P(n) SEQ_printf(m, " .%-30s: %d\n", #n, rq->n); -+#define P64(n) SEQ_printf(m, " .%-30s: %Ld\n", #n, rq->n); - - P(yld_count); - - P(sched_switch); - P(sched_count); - P(sched_goidle); -+#ifdef CONFIG_SMP -+ P64(avg_idle); -+#endif - - P(ttwu_count); - P(ttwu_local); -diff --git a/kernel/sched_fair.c b/kernel/sched_fair.c -index 37087a7..5488a5d 100644 ---- a/kernel/sched_fair.c -+++ b/kernel/sched_fair.c -@@ -1398,11 +1398,38 @@ static int select_task_rq_fair(struct task_struct *p, int sd_flag, int wake_flag - want_sd = 0; - } - -- if (want_affine && (tmp->flags & SD_WAKE_AFFINE) && -- cpumask_test_cpu(prev_cpu, sched_domain_span(tmp))) { -+ if (want_affine && (tmp->flags & SD_WAKE_AFFINE)) { -+ int candidate = -1, i; - -- affine_sd = tmp; -- want_affine = 0; -+ if (cpumask_test_cpu(prev_cpu, sched_domain_span(tmp))) -+ candidate = cpu; -+ -+ /* -+ * Check for an idle shared cache. -+ */ -+ if (tmp->flags & SD_PREFER_SIBLING) { -+ if (candidate == cpu) { -+ if (!cpu_rq(prev_cpu)->cfs.nr_running) -+ candidate = prev_cpu; -+ } -+ -+ if (candidate == -1 || candidate == cpu) { -+ for_each_cpu(i, sched_domain_span(tmp)) { -+ if (!cpumask_test_cpu(i, &p->cpus_allowed)) -+ continue; -+ if (!cpu_rq(i)->cfs.nr_running) { -+ candidate = i; -+ break; -+ } -+ } -+ } -+ } -+ -+ if (candidate >= 0) { -+ affine_sd = tmp; -+ want_affine = 0; -+ cpu = candidate; -+ } - } - - if (!want_sd && !want_affine) -diff --git a/mm/memcontrol.c b/mm/memcontrol.c -index f99f599..6314015 100644 ---- a/mm/memcontrol.c -+++ b/mm/memcontrol.c -@@ -2541,6 +2541,7 @@ static u64 mem_cgroup_read(struct cgroup *cont, struct cftype *cft) - val += idx_val; - mem_cgroup_get_recursive_idx_stat(mem, - MEM_CGROUP_STAT_SWAPOUT, &idx_val); -+ val += idx_val; - val <<= PAGE_SHIFT; - } else - val = res_counter_read_u64(&mem->memsw, name); -diff --git a/mm/memory.c b/mm/memory.c -index 6ab19dd..4e59455 100644 ---- a/mm/memory.c -+++ b/mm/memory.c -@@ -2514,7 +2514,7 @@ static int do_swap_page(struct mm_struct *mm, struct vm_area_struct *vma, - ret = VM_FAULT_HWPOISON; - } else { - print_bad_pte(vma, address, orig_pte, NULL); -- ret = VM_FAULT_OOM; -+ ret = VM_FAULT_SIGBUS; - } - goto out; - } -@@ -2910,7 +2910,7 @@ static int do_nonlinear_fault(struct mm_struct *mm, struct vm_area_struct *vma, - * Page table corrupted: show pte and kill process. - */ - print_bad_pte(vma, address, orig_pte, NULL); -- return VM_FAULT_OOM; -+ return VM_FAULT_SIGBUS; - } - - pgoff = pte_to_pgoff(orig_pte); -diff --git a/mm/mincore.c b/mm/mincore.c -index 8cb508f..7a3436e 100644 ---- a/mm/mincore.c -+++ b/mm/mincore.c -@@ -14,6 +14,7 @@ - #include - #include - #include -+#include - - #include - #include -@@ -72,6 +73,42 @@ static long do_mincore(unsigned long addr, unsigned char *vec, unsigned long pag - if (!vma || addr < vma->vm_start) - return -ENOMEM; - -+#ifdef CONFIG_HUGETLB_PAGE -+ if (is_vm_hugetlb_page(vma)) { -+ struct hstate *h; -+ unsigned long nr_huge; -+ unsigned char present; -+ -+ i = 0; -+ nr = min(pages, (vma->vm_end - addr) >> PAGE_SHIFT); -+ h = hstate_vma(vma); -+ nr_huge = ((addr + pages * PAGE_SIZE - 1) >> huge_page_shift(h)) -+ - (addr >> huge_page_shift(h)) + 1; -+ nr_huge = min(nr_huge, -+ (vma->vm_end - addr) >> huge_page_shift(h)); -+ while (1) { -+ /* hugepage always in RAM for now, -+ * but generally it needs to be check */ -+ ptep = huge_pte_offset(current->mm, -+ addr & huge_page_mask(h)); -+ present = !!(ptep && -+ !huge_pte_none(huge_ptep_get(ptep))); -+ while (1) { -+ vec[i++] = present; -+ addr += PAGE_SIZE; -+ /* reach buffer limit */ -+ if (i == nr) -+ return nr; -+ /* check hugepage border */ -+ if (!((addr & ~huge_page_mask(h)) -+ >> PAGE_SHIFT)) -+ break; -+ } -+ } -+ return nr; -+ } -+#endif -+ - /* - * Calculate how many pages there are left in the last level of the - * PTE array for our address. -diff --git a/mm/pagewalk.c b/mm/pagewalk.c -index d5878be..a286915 100644 ---- a/mm/pagewalk.c -+++ b/mm/pagewalk.c -@@ -1,6 +1,7 @@ - #include - #include - #include -+#include - - static int walk_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end, - struct mm_walk *walk) -@@ -107,6 +108,7 @@ int walk_page_range(unsigned long addr, unsigned long end, - pgd_t *pgd; - unsigned long next; - int err = 0; -+ struct vm_area_struct *vma; - - if (addr >= end) - return err; -@@ -117,11 +119,22 @@ int walk_page_range(unsigned long addr, unsigned long end, - pgd = pgd_offset(walk->mm, addr); - do { - next = pgd_addr_end(addr, end); -+ -+ /* skip hugetlb vma to avoid hugepage PMD being cleared -+ * in pmd_none_or_clear_bad(). */ -+ vma = find_vma(walk->mm, addr); -+ if (vma && is_vm_hugetlb_page(vma)) { -+ if (vma->vm_end < next) -+ next = vma->vm_end; -+ continue; -+ } -+ - if (pgd_none_or_clear_bad(pgd)) { - if (walk->pte_hole) - err = walk->pte_hole(addr, next, walk); - if (err) - break; -+ pgd++; - continue; - } - if (walk->pgd_entry) -@@ -131,7 +144,8 @@ int walk_page_range(unsigned long addr, unsigned long end, - err = walk_pud_range(pgd, addr, next, walk); - if (err) - break; -- } while (pgd++, addr = next, addr != end); -+ pgd++; -+ } while (addr = next, addr != end); - - return err; - } -diff --git a/mm/vmalloc.c b/mm/vmalloc.c -index 0f551a4..7758726 100644 ---- a/mm/vmalloc.c -+++ b/mm/vmalloc.c -@@ -1993,6 +1993,7 @@ void free_vm_area(struct vm_struct *area) - } - EXPORT_SYMBOL_GPL(free_vm_area); - -+#ifndef CONFIG_HAVE_LEGACY_PER_CPU_AREA - static struct vmap_area *node_to_va(struct rb_node *n) - { - return n ? rb_entry(n, struct vmap_area, rb_node) : NULL; -@@ -2257,6 +2258,7 @@ err_free: - kfree(vms); - return NULL; - } -+#endif - - /** - * pcpu_free_vm_areas - free vmalloc areas for percpu allocator -diff --git a/net/core/dev.c b/net/core/dev.c -index fe10551..584046e 100644 ---- a/net/core/dev.c -+++ b/net/core/dev.c -@@ -4860,6 +4860,11 @@ int register_netdevice(struct net_device *dev) - rollback_registered(dev); - dev->reg_state = NETREG_UNREGISTERED; - } -+ /* -+ * Prevent userspace races by waiting until the network -+ * device is fully setup before sending notifications. -+ */ -+ rtmsg_ifinfo(RTM_NEWLINK, dev, ~0U); - - out: - return ret; -@@ -5398,6 +5403,12 @@ int dev_change_net_namespace(struct net_device *dev, struct net *net, const char - /* Notify protocols, that a new device appeared. */ - call_netdevice_notifiers(NETDEV_REGISTER, dev); - -+ /* -+ * Prevent userspace races by waiting until the network -+ * device is fully setup before sending notifications. -+ */ -+ rtmsg_ifinfo(RTM_NEWLINK, dev, ~0U); -+ - synchronize_net(); - err = 0; - out: -diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c -index eb42873..d4fd895 100644 ---- a/net/core/rtnetlink.c -+++ b/net/core/rtnetlink.c -@@ -1334,13 +1334,11 @@ static int rtnetlink_event(struct notifier_block *this, unsigned long event, voi - case NETDEV_UNREGISTER: - rtmsg_ifinfo(RTM_DELLINK, dev, ~0U); - break; -- case NETDEV_REGISTER: -- rtmsg_ifinfo(RTM_NEWLINK, dev, ~0U); -- break; - case NETDEV_UP: - case NETDEV_DOWN: - rtmsg_ifinfo(RTM_NEWLINK, dev, IFF_UP|IFF_RUNNING); - break; -+ case NETDEV_REGISTER: - case NETDEV_CHANGE: - case NETDEV_GOING_DOWN: - break; -diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c -index f989518..4d50daa 100644 ---- a/net/ipv4/ip_output.c -+++ b/net/ipv4/ip_output.c -@@ -501,8 +501,8 @@ int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) - if (skb->sk) { - frag->sk = skb->sk; - frag->destructor = sock_wfree; -- truesizes += frag->truesize; - } -+ truesizes += frag->truesize; - } - - /* Everything is OK. Generate! */ -diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c -index 7b5131b..cca675e 100644 ---- a/net/mac80211/cfg.c -+++ b/net/mac80211/cfg.c -@@ -338,7 +338,8 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) - sinfo->rx_packets = sta->rx_packets; - sinfo->tx_packets = sta->tx_packets; - -- if (sta->local->hw.flags & IEEE80211_HW_SIGNAL_DBM) { -+ if ((sta->local->hw.flags & IEEE80211_HW_SIGNAL_DBM) || -+ (sta->local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC)) { - sinfo->filled |= STATION_INFO_SIGNAL; - sinfo->signal = (s8)sta->last_signal; - } -diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h -index 10d316e..5a46164 100644 ---- a/net/mac80211/ieee80211_i.h -+++ b/net/mac80211/ieee80211_i.h -@@ -808,6 +808,7 @@ struct ieee80211_local { - unsigned int wmm_acm; /* bit field of ACM bits (BIT(802.1D tag)) */ - - bool pspolling; -+ bool scan_ps_enabled; - /* - * PS can only be enabled when we have exactly one managed - * interface (and monitors) in PS, this then points there. -diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h -index dd1c193..010ff2f 100644 ---- a/net/mac80211/mesh.h -+++ b/net/mac80211/mesh.h -@@ -186,8 +186,9 @@ struct mesh_rmc { - */ - #define MESH_PREQ_MIN_INT 10 - #define MESH_DIAM_TRAVERSAL_TIME 50 --/* Paths will be refreshed if they are closer than PATH_REFRESH_TIME to their -- * expiration -+/* A path will be refreshed if it is used PATH_REFRESH_TIME milliseconds before -+ * timing out. This way it will remain ACTIVE and no data frames will be -+ * unnecesarily held in the pending queue. - */ - #define MESH_PATH_REFRESH_TIME 1000 - #define MESH_MIN_DISCOVERY_TIMEOUT (2 * MESH_DIAM_TRAVERSAL_TIME) -diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c -index 29b82e9..93c49fc 100644 ---- a/net/mac80211/mesh_hwmp.c -+++ b/net/mac80211/mesh_hwmp.c -@@ -813,7 +813,7 @@ int mesh_nexthop_lookup(struct sk_buff *skb, - } - - if (mpath->flags & MESH_PATH_ACTIVE) { -- if (time_after(jiffies, mpath->exp_time + -+ if (time_after(jiffies, mpath->exp_time - - msecs_to_jiffies(sdata->u.mesh.mshcfg.path_refresh_time)) - && !memcmp(sdata->dev->dev_addr, hdr->addr4, - ETH_ALEN) -diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c -index 7170bf4..4e14754 100644 ---- a/net/mac80211/rx.c -+++ b/net/mac80211/rx.c -@@ -1514,7 +1514,6 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) - mpp_path_add(mesh_hdr->eaddr2, hdr->addr4, sdata); - } else { - spin_lock_bh(&mppath->state_lock); -- mppath->exp_time = jiffies; - if (compare_ether_addr(mppath->mpp, hdr->addr4) != 0) - memcpy(mppath->mpp, hdr->addr4, ETH_ALEN); - spin_unlock_bh(&mppath->state_lock); -diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c -index 71e10ca..1a41909 100644 ---- a/net/mac80211/scan.c -+++ b/net/mac80211/scan.c -@@ -196,7 +196,8 @@ ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) - static void ieee80211_scan_ps_enable(struct ieee80211_sub_if_data *sdata) - { - struct ieee80211_local *local = sdata->local; -- bool ps = false; -+ -+ local->scan_ps_enabled = false; - - /* FIXME: what to do when local->pspolling is true? */ - -@@ -204,12 +205,13 @@ static void ieee80211_scan_ps_enable(struct ieee80211_sub_if_data *sdata) - cancel_work_sync(&local->dynamic_ps_enable_work); - - if (local->hw.conf.flags & IEEE80211_CONF_PS) { -- ps = true; -+ local->scan_ps_enabled = true; - local->hw.conf.flags &= ~IEEE80211_CONF_PS; - ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); - } - -- if (!ps || !(local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK)) -+ if (!(local->scan_ps_enabled) || -+ !(local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK)) - /* - * If power save was enabled, no need to send a nullfunc - * frame because AP knows that we are sleeping. But if the -@@ -230,7 +232,7 @@ static void ieee80211_scan_ps_disable(struct ieee80211_sub_if_data *sdata) - - if (!local->ps_sdata) - ieee80211_send_nullfunc(local, sdata, 0); -- else { -+ else if (local->scan_ps_enabled) { - /* - * In !IEEE80211_HW_PS_NULLFUNC_STACK case the hardware - * will send a nullfunc frame with the powersave bit set -@@ -246,6 +248,16 @@ static void ieee80211_scan_ps_disable(struct ieee80211_sub_if_data *sdata) - */ - local->hw.conf.flags |= IEEE80211_CONF_PS; - ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); -+ } else if (local->hw.conf.dynamic_ps_timeout > 0) { -+ /* -+ * If IEEE80211_CONF_PS was not set and the dynamic_ps_timer -+ * had been running before leaving the operating channel, -+ * restart the timer now and send a nullfunc frame to inform -+ * the AP that we are awake. -+ */ -+ ieee80211_send_nullfunc(local, sdata, 0); -+ mod_timer(&local->dynamic_ps_timer, jiffies + -+ msecs_to_jiffies(local->hw.conf.dynamic_ps_timeout)); - } - } - -@@ -264,10 +276,14 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) - - mutex_lock(&local->scan_mtx); - -- if (WARN_ON(!local->scanning)) { -- mutex_unlock(&local->scan_mtx); -- return; -- } -+ /* -+ * It's ok to abort a not-yet-running scan (that -+ * we have one at all will be verified by checking -+ * local->scan_req next), but not to complete it -+ * successfully. -+ */ -+ if (WARN_ON(!local->scanning && !aborted)) -+ aborted = true; - - if (WARN_ON(!local->scan_req)) { - mutex_unlock(&local->scan_mtx); -diff --git a/net/mac80211/util.c b/net/mac80211/util.c -index e6c08da..cbc5d20 100644 ---- a/net/mac80211/util.c -+++ b/net/mac80211/util.c -@@ -579,7 +579,7 @@ u32 ieee802_11_parse_elems_crc(u8 *start, size_t len, - if (elen > left) - break; - -- if (calc_crc && id < 64 && (filter & BIT(id))) -+ if (calc_crc && id < 64 && (filter & (1ULL << id))) - crc = crc32_be(crc, pos - 2, elen + 2); - - switch (id) { -diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c -index 446e9bd..02b2610 100644 ---- a/net/netfilter/ipvs/ip_vs_ctl.c -+++ b/net/netfilter/ipvs/ip_vs_ctl.c -@@ -2714,6 +2714,8 @@ static int ip_vs_genl_parse_service(struct ip_vs_service_user_kern *usvc, - if (!(nla_af && (nla_fwmark || (nla_port && nla_protocol && nla_addr)))) - return -EINVAL; - -+ memset(usvc, 0, sizeof(*usvc)); -+ - usvc->af = nla_get_u16(nla_af); - #ifdef CONFIG_IP_VS_IPV6 - if (usvc->af != AF_INET && usvc->af != AF_INET6) -@@ -2901,6 +2903,8 @@ static int ip_vs_genl_parse_dest(struct ip_vs_dest_user_kern *udest, - if (!(nla_addr && nla_port)) - return -EINVAL; - -+ memset(udest, 0, sizeof(*udest)); -+ - nla_memcpy(&udest->addr, nla_addr, sizeof(udest->addr)); - udest->port = nla_get_u16(nla_port); - -diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c -index fc6a43c..129d75e 100644 ---- a/net/sunrpc/auth_gss/auth_gss.c -+++ b/net/sunrpc/auth_gss/auth_gss.c -@@ -485,7 +485,7 @@ gss_refresh_upcall(struct rpc_task *task) - dprintk("RPC: %5u gss_refresh_upcall for uid %u\n", task->tk_pid, - cred->cr_uid); - gss_msg = gss_setup_upcall(task->tk_client, gss_auth, cred); -- if (IS_ERR(gss_msg) == -EAGAIN) { -+ if (PTR_ERR(gss_msg) == -EAGAIN) { - /* XXX: warning on the first, under the assumption we - * shouldn't normally hit this case on a refresh. */ - warn_gssd(); -diff --git a/sound/core/hrtimer.c b/sound/core/hrtimer.c -index 34c7d48..7f4d744 100644 ---- a/sound/core/hrtimer.c -+++ b/sound/core/hrtimer.c -@@ -37,14 +37,22 @@ static unsigned int resolution; - struct snd_hrtimer { - struct snd_timer *timer; - struct hrtimer hrt; -+ atomic_t running; - }; - - static enum hrtimer_restart snd_hrtimer_callback(struct hrtimer *hrt) - { - struct snd_hrtimer *stime = container_of(hrt, struct snd_hrtimer, hrt); - struct snd_timer *t = stime->timer; -+ -+ if (!atomic_read(&stime->running)) -+ return HRTIMER_NORESTART; -+ - hrtimer_forward_now(hrt, ns_to_ktime(t->sticks * resolution)); - snd_timer_interrupt(stime->timer, t->sticks); -+ -+ if (!atomic_read(&stime->running)) -+ return HRTIMER_NORESTART; - return HRTIMER_RESTART; - } - -@@ -58,6 +66,7 @@ static int snd_hrtimer_open(struct snd_timer *t) - hrtimer_init(&stime->hrt, CLOCK_MONOTONIC, HRTIMER_MODE_REL); - stime->timer = t; - stime->hrt.function = snd_hrtimer_callback; -+ atomic_set(&stime->running, 0); - t->private_data = stime; - return 0; - } -@@ -78,16 +87,18 @@ static int snd_hrtimer_start(struct snd_timer *t) - { - struct snd_hrtimer *stime = t->private_data; - -+ atomic_set(&stime->running, 0); -+ hrtimer_cancel(&stime->hrt); - hrtimer_start(&stime->hrt, ns_to_ktime(t->sticks * resolution), - HRTIMER_MODE_REL); -+ atomic_set(&stime->running, 1); - return 0; - } - - static int snd_hrtimer_stop(struct snd_timer *t) - { - struct snd_hrtimer *stime = t->private_data; -- -- hrtimer_cancel(&stime->hrt); -+ atomic_set(&stime->running, 0); - return 0; - } - -diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c -index 6517f58..7e4ee4e 100644 ---- a/sound/pci/hda/hda_intel.c -+++ b/sound/pci/hda/hda_intel.c -@@ -2436,6 +2436,11 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, - } - } - -+ /* disable 64bit DMA address for Teradici */ -+ /* it does not work with device 6549:1200 subsys e4a2:040b */ -+ if (chip->driver_type == AZX_DRIVER_TERA) -+ gcap &= ~ICH6_GCAP_64OK; -+ - /* allow 64bit DMA address if supported by H/W */ - if ((gcap & ICH6_GCAP_64OK) && !pci_set_dma_mask(pci, DMA_BIT_MASK(64))) - pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(64)); -diff --git a/virt/kvm/irq_comm.c b/virt/kvm/irq_comm.c -index 001663f..03e5b21 100644 ---- a/virt/kvm/irq_comm.c -+++ b/virt/kvm/irq_comm.c -@@ -205,10 +205,9 @@ int kvm_request_irq_source_id(struct kvm *kvm) - int irq_source_id; - - mutex_lock(&kvm->irq_lock); -- irq_source_id = find_first_zero_bit(bitmap, -- sizeof(kvm->arch.irq_sources_bitmap)); -+ irq_source_id = find_first_zero_bit(bitmap, BITS_PER_LONG); - -- if (irq_source_id >= sizeof(kvm->arch.irq_sources_bitmap)) { -+ if (irq_source_id >= BITS_PER_LONG) { - printk(KERN_WARNING "kvm: exhaust allocatable IRQ sources!\n"); - return -EFAULT; - } -@@ -228,7 +227,7 @@ void kvm_free_irq_source_id(struct kvm *kvm, int irq_source_id) - - mutex_lock(&kvm->irq_lock); - if (irq_source_id < 0 || -- irq_source_id >= sizeof(kvm->arch.irq_sources_bitmap)) { -+ irq_source_id >= BITS_PER_LONG) { - printk(KERN_ERR "kvm: IRQ source ID out of range!\n"); - return; - } diff --git a/debian/patches/bugfix/all/stable/2.6.32.3.patch b/debian/patches/bugfix/all/stable/2.6.32.3.patch deleted file mode 100644 index d07a891cd..000000000 --- a/debian/patches/bugfix/all/stable/2.6.32.3.patch +++ /dev/null @@ -1,4878 +0,0 @@ -diff --git a/Documentation/filesystems/ext4.txt b/Documentation/filesystems/ext4.txt -index af6885c..e1def17 100644 ---- a/Documentation/filesystems/ext4.txt -+++ b/Documentation/filesystems/ext4.txt -@@ -196,7 +196,7 @@ nobarrier This also requires an IO stack which can support - also be used to enable or disable barriers, for - consistency with other ext4 mount options. - --inode_readahead=n This tuning parameter controls the maximum -+inode_readahead_blks=n This tuning parameter controls the maximum - number of inode table blocks that ext4's inode - table readahead algorithm will pre-read into - the buffer cache. The default value is 32 blocks. -diff --git a/Makefile b/Makefile -index 23803ce..482dcdd 100644 -diff --git a/arch/powerpc/kernel/align.c b/arch/powerpc/kernel/align.c -index a5b632e..f0c624f 100644 ---- a/arch/powerpc/kernel/align.c -+++ b/arch/powerpc/kernel/align.c -@@ -642,10 +642,14 @@ static int emulate_spe(struct pt_regs *regs, unsigned int reg, - */ - static int emulate_vsx(unsigned char __user *addr, unsigned int reg, - unsigned int areg, struct pt_regs *regs, -- unsigned int flags, unsigned int length) -+ unsigned int flags, unsigned int length, -+ unsigned int elsize) - { - char *ptr; -+ unsigned long *lptr; - int ret = 0; -+ int sw = 0; -+ int i, j; - - flush_vsx_to_thread(current); - -@@ -654,19 +658,35 @@ static int emulate_vsx(unsigned char __user *addr, unsigned int reg, - else - ptr = (char *) ¤t->thread.vr[reg - 32]; - -- if (flags & ST) -- ret = __copy_to_user(addr, ptr, length); -- else { -- if (flags & SPLT){ -- ret = __copy_from_user(ptr, addr, length); -- ptr += length; -+ lptr = (unsigned long *) ptr; -+ -+ if (flags & SW) -+ sw = elsize-1; -+ -+ for (j = 0; j < length; j += elsize) { -+ for (i = 0; i < elsize; ++i) { -+ if (flags & ST) -+ ret |= __put_user(ptr[i^sw], addr + i); -+ else -+ ret |= __get_user(ptr[i^sw], addr + i); - } -- ret |= __copy_from_user(ptr, addr, length); -+ ptr += elsize; -+ addr += elsize; - } -- if (flags & U) -- regs->gpr[areg] = regs->dar; -- if (ret) -+ -+ if (!ret) { -+ if (flags & U) -+ regs->gpr[areg] = regs->dar; -+ -+ /* Splat load copies the same data to top and bottom 8 bytes */ -+ if (flags & SPLT) -+ lptr[1] = lptr[0]; -+ /* For 8 byte loads, zero the top 8 bytes */ -+ else if (!(flags & ST) && (8 == length)) -+ lptr[1] = 0; -+ } else - return -EFAULT; -+ - return 1; - } - #endif -@@ -767,16 +787,25 @@ int fix_alignment(struct pt_regs *regs) - - #ifdef CONFIG_VSX - if ((instruction & 0xfc00003e) == 0x7c000018) { -- /* Additional register addressing bit (64 VSX vs 32 FPR/GPR */ -+ unsigned int elsize; -+ -+ /* Additional register addressing bit (64 VSX vs 32 FPR/GPR) */ - reg |= (instruction & 0x1) << 5; - /* Simple inline decoder instead of a table */ -+ /* VSX has only 8 and 16 byte memory accesses */ -+ nb = 8; - if (instruction & 0x200) - nb = 16; -- else if (instruction & 0x080) -- nb = 8; -- else -- nb = 4; -+ -+ /* Vector stores in little-endian mode swap individual -+ elements, so process them separately */ -+ elsize = 4; -+ if (instruction & 0x80) -+ elsize = 8; -+ - flags = 0; -+ if (regs->msr & MSR_LE) -+ flags |= SW; - if (instruction & 0x100) - flags |= ST; - if (instruction & 0x040) -@@ -787,7 +816,7 @@ int fix_alignment(struct pt_regs *regs) - nb = 8; - } - PPC_WARN_EMULATED(vsx); -- return emulate_vsx(addr, reg, areg, regs, flags, nb); -+ return emulate_vsx(addr, reg, areg, regs, flags, nb, elsize); - } - #endif - /* A size of 0 indicates an instruction we don't support, with -diff --git a/arch/x86/include/asm/msr.h b/arch/x86/include/asm/msr.h -index 7e2b6ba..0e3e728 100644 ---- a/arch/x86/include/asm/msr.h -+++ b/arch/x86/include/asm/msr.h -@@ -27,6 +27,18 @@ struct msr { - }; - }; - -+struct msr_info { -+ u32 msr_no; -+ struct msr reg; -+ struct msr *msrs; -+ int err; -+}; -+ -+struct msr_regs_info { -+ u32 *regs; -+ int err; -+}; -+ - static inline unsigned long long native_read_tscp(unsigned int *aux) - { - unsigned long low, high; -@@ -244,11 +256,14 @@ do { \ - - #define write_rdtscp_aux(val) wrmsr(0xc0000103, (val), 0) - -+struct msr *msrs_alloc(void); -+void msrs_free(struct msr *msrs); -+ - #ifdef CONFIG_SMP - int rdmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h); - int wrmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h); --void rdmsr_on_cpus(const cpumask_t *mask, u32 msr_no, struct msr *msrs); --void wrmsr_on_cpus(const cpumask_t *mask, u32 msr_no, struct msr *msrs); -+void rdmsr_on_cpus(const struct cpumask *mask, u32 msr_no, struct msr *msrs); -+void wrmsr_on_cpus(const struct cpumask *mask, u32 msr_no, struct msr *msrs); - int rdmsr_safe_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h); - int wrmsr_safe_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h); - int rdmsr_safe_regs_on_cpu(unsigned int cpu, u32 regs[8]); -diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h -index c978648..13b1885 100644 ---- a/arch/x86/include/asm/processor.h -+++ b/arch/x86/include/asm/processor.h -@@ -180,7 +180,7 @@ static inline void native_cpuid(unsigned int *eax, unsigned int *ebx, - unsigned int *ecx, unsigned int *edx) - { - /* ecx is often an input as well as an output. */ -- asm("cpuid" -+ asm volatile("cpuid" - : "=a" (*eax), - "=b" (*ebx), - "=c" (*ecx), -diff --git a/arch/x86/include/asm/uv/uv_hub.h b/arch/x86/include/asm/uv/uv_hub.h -index d1414af..e90a8a9 100644 ---- a/arch/x86/include/asm/uv/uv_hub.h -+++ b/arch/x86/include/asm/uv/uv_hub.h -@@ -31,20 +31,20 @@ - * contiguous (although various IO spaces may punch holes in - * it).. - * -- * N - Number of bits in the node portion of a socket physical -- * address. -+ * N - Number of bits in the node portion of a socket physical -+ * address. - * -- * NASID - network ID of a router, Mbrick or Cbrick. Nasid values of -- * routers always have low bit of 1, C/MBricks have low bit -- * equal to 0. Most addressing macros that target UV hub chips -- * right shift the NASID by 1 to exclude the always-zero bit. -- * NASIDs contain up to 15 bits. -+ * NASID - network ID of a router, Mbrick or Cbrick. Nasid values of -+ * routers always have low bit of 1, C/MBricks have low bit -+ * equal to 0. Most addressing macros that target UV hub chips -+ * right shift the NASID by 1 to exclude the always-zero bit. -+ * NASIDs contain up to 15 bits. - * - * GNODE - NASID right shifted by 1 bit. Most mmrs contain gnodes instead - * of nasids. - * -- * PNODE - the low N bits of the GNODE. The PNODE is the most useful variant -- * of the nasid for socket usage. -+ * PNODE - the low N bits of the GNODE. The PNODE is the most useful variant -+ * of the nasid for socket usage. - * - * - * NumaLink Global Physical Address Format: -@@ -71,12 +71,12 @@ - * - * - * APICID format -- * NOTE!!!!!! This is the current format of the APICID. However, code -- * should assume that this will change in the future. Use functions -- * in this file for all APICID bit manipulations and conversion. -+ * NOTE!!!!!! This is the current format of the APICID. However, code -+ * should assume that this will change in the future. Use functions -+ * in this file for all APICID bit manipulations and conversion. - * -- * 1111110000000000 -- * 5432109876543210 -+ * 1111110000000000 -+ * 5432109876543210 - * pppppppppplc0cch - * sssssssssss - * -@@ -89,9 +89,9 @@ - * Note: Processor only supports 12 bits in the APICID register. The ACPI - * tables hold all 16 bits. Software needs to be aware of this. - * -- * Unless otherwise specified, all references to APICID refer to -- * the FULL value contained in ACPI tables, not the subset in the -- * processor APICID register. -+ * Unless otherwise specified, all references to APICID refer to -+ * the FULL value contained in ACPI tables, not the subset in the -+ * processor APICID register. - */ - - -@@ -151,16 +151,16 @@ struct uv_hub_info_s { - }; - - DECLARE_PER_CPU(struct uv_hub_info_s, __uv_hub_info); --#define uv_hub_info (&__get_cpu_var(__uv_hub_info)) -+#define uv_hub_info (&__get_cpu_var(__uv_hub_info)) - #define uv_cpu_hub_info(cpu) (&per_cpu(__uv_hub_info, cpu)) - - /* - * Local & Global MMR space macros. -- * Note: macros are intended to be used ONLY by inline functions -- * in this file - not by other kernel code. -- * n - NASID (full 15-bit global nasid) -- * g - GNODE (full 15-bit global nasid, right shifted 1) -- * p - PNODE (local part of nsids, right shifted 1) -+ * Note: macros are intended to be used ONLY by inline functions -+ * in this file - not by other kernel code. -+ * n - NASID (full 15-bit global nasid) -+ * g - GNODE (full 15-bit global nasid, right shifted 1) -+ * p - PNODE (local part of nsids, right shifted 1) - */ - #define UV_NASID_TO_PNODE(n) (((n) >> 1) & uv_hub_info->pnode_mask) - #define UV_PNODE_TO_GNODE(p) ((p) |uv_hub_info->gnode_extra) -@@ -213,8 +213,8 @@ DECLARE_PER_CPU(struct uv_hub_info_s, __uv_hub_info); - /* - * Macros for converting between kernel virtual addresses, socket local physical - * addresses, and UV global physical addresses. -- * Note: use the standard __pa() & __va() macros for converting -- * between socket virtual and socket physical addresses. -+ * Note: use the standard __pa() & __va() macros for converting -+ * between socket virtual and socket physical addresses. - */ - - /* socket phys RAM --> UV global physical address */ -@@ -265,21 +265,18 @@ static inline int uv_apicid_to_pnode(int apicid) - * Access global MMRs using the low memory MMR32 space. This region supports - * faster MMR access but not all MMRs are accessible in this space. - */ --static inline unsigned long *uv_global_mmr32_address(int pnode, -- unsigned long offset) -+static inline unsigned long *uv_global_mmr32_address(int pnode, unsigned long offset) - { - return __va(UV_GLOBAL_MMR32_BASE | - UV_GLOBAL_MMR32_PNODE_BITS(pnode) | offset); - } - --static inline void uv_write_global_mmr32(int pnode, unsigned long offset, -- unsigned long val) -+static inline void uv_write_global_mmr32(int pnode, unsigned long offset, unsigned long val) - { - writeq(val, uv_global_mmr32_address(pnode, offset)); - } - --static inline unsigned long uv_read_global_mmr32(int pnode, -- unsigned long offset) -+static inline unsigned long uv_read_global_mmr32(int pnode, unsigned long offset) - { - return readq(uv_global_mmr32_address(pnode, offset)); - } -@@ -288,25 +285,32 @@ static inline unsigned long uv_read_global_mmr32(int pnode, - * Access Global MMR space using the MMR space located at the top of physical - * memory. - */ --static inline unsigned long *uv_global_mmr64_address(int pnode, -- unsigned long offset) -+static inline unsigned long *uv_global_mmr64_address(int pnode, unsigned long offset) - { - return __va(UV_GLOBAL_MMR64_BASE | - UV_GLOBAL_MMR64_PNODE_BITS(pnode) | offset); - } - --static inline void uv_write_global_mmr64(int pnode, unsigned long offset, -- unsigned long val) -+static inline void uv_write_global_mmr64(int pnode, unsigned long offset, unsigned long val) - { - writeq(val, uv_global_mmr64_address(pnode, offset)); - } - --static inline unsigned long uv_read_global_mmr64(int pnode, -- unsigned long offset) -+static inline unsigned long uv_read_global_mmr64(int pnode, unsigned long offset) - { - return readq(uv_global_mmr64_address(pnode, offset)); - } - -+static inline void uv_write_global_mmr8(int pnode, unsigned long offset, unsigned char val) -+{ -+ writeb(val, uv_global_mmr64_address(pnode, offset)); -+} -+ -+static inline unsigned char uv_read_global_mmr8(int pnode, unsigned long offset) -+{ -+ return readb(uv_global_mmr64_address(pnode, offset)); -+} -+ - /* - * Access hub local MMRs. Faster than using global space but only local MMRs - * are accessible. -@@ -426,11 +430,17 @@ static inline void uv_set_scir_bits(unsigned char value) - } - } - -+static inline unsigned long uv_scir_offset(int apicid) -+{ -+ return SCIR_LOCAL_MMR_BASE | (apicid & 0x3f); -+} -+ - static inline void uv_set_cpu_scir_bits(int cpu, unsigned char value) - { - if (uv_cpu_hub_info(cpu)->scir.state != value) { -+ uv_write_global_mmr8(uv_cpu_to_pnode(cpu), -+ uv_cpu_hub_info(cpu)->scir.offset, value); - uv_cpu_hub_info(cpu)->scir.state = value; -- uv_write_local_mmr8(uv_cpu_hub_info(cpu)->scir.offset, value); - } - } - -diff --git a/arch/x86/kernel/amd_iommu_init.c b/arch/x86/kernel/amd_iommu_init.c -index e0b3130..c8243f0 100644 ---- a/arch/x86/kernel/amd_iommu_init.c -+++ b/arch/x86/kernel/amd_iommu_init.c -@@ -136,6 +136,11 @@ LIST_HEAD(amd_iommu_list); /* list of all AMD IOMMUs in the - system */ - - /* -+ * Set to true if ACPI table parsing and hardware intialization went properly -+ */ -+static bool amd_iommu_initialized; -+ -+/* - * Pointer to the device table which is shared by all AMD IOMMUs - * it is indexed by the PCI device id or the HT unit id and contains - * information about the domain the device belongs to as well as the -@@ -913,6 +918,8 @@ static int __init init_iommu_all(struct acpi_table_header *table) - } - WARN_ON(p != end); - -+ amd_iommu_initialized = true; -+ - return 0; - } - -@@ -1263,6 +1270,9 @@ int __init amd_iommu_init(void) - if (acpi_table_parse("IVRS", init_iommu_all) != 0) - goto free; - -+ if (!amd_iommu_initialized) -+ goto free; -+ - if (acpi_table_parse("IVRS", init_memory_definitions) != 0) - goto free; - -diff --git a/arch/x86/kernel/apic/x2apic_uv_x.c b/arch/x86/kernel/apic/x2apic_uv_x.c -index 326c254..2ab3535 100644 ---- a/arch/x86/kernel/apic/x2apic_uv_x.c -+++ b/arch/x86/kernel/apic/x2apic_uv_x.c -@@ -607,8 +607,10 @@ void __init uv_system_init(void) - uv_rtc_init(); - - for_each_present_cpu(cpu) { -+ int apicid = per_cpu(x86_cpu_to_apicid, cpu); -+ - nid = cpu_to_node(cpu); -- pnode = uv_apicid_to_pnode(per_cpu(x86_cpu_to_apicid, cpu)); -+ pnode = uv_apicid_to_pnode(apicid); - blade = boot_pnode_to_blade(pnode); - lcpu = uv_blade_info[blade].nr_possible_cpus; - uv_blade_info[blade].nr_possible_cpus++; -@@ -629,15 +631,13 @@ void __init uv_system_init(void) - uv_cpu_hub_info(cpu)->gnode_extra = gnode_extra; - uv_cpu_hub_info(cpu)->global_mmr_base = mmr_base; - uv_cpu_hub_info(cpu)->coherency_domain_number = sn_coherency_id; -- uv_cpu_hub_info(cpu)->scir.offset = SCIR_LOCAL_MMR_BASE + lcpu; -+ uv_cpu_hub_info(cpu)->scir.offset = uv_scir_offset(apicid); - uv_node_to_blade[nid] = blade; - uv_cpu_to_blade[cpu] = blade; - max_pnode = max(pnode, max_pnode); - -- printk(KERN_DEBUG "UV: cpu %d, apicid 0x%x, pnode %d, nid %d, " -- "lcpu %d, blade %d\n", -- cpu, per_cpu(x86_cpu_to_apicid, cpu), pnode, nid, -- lcpu, blade); -+ printk(KERN_DEBUG "UV: cpu %d, apicid 0x%x, pnode %d, nid %d, lcpu %d, blade %d\n", -+ cpu, apicid, pnode, nid, lcpu, blade); - } - - /* Add blade/pnode info for nodes without cpus */ -diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c -index 7b058a2..c06acdd 100644 ---- a/arch/x86/kernel/ptrace.c -+++ b/arch/x86/kernel/ptrace.c -@@ -408,14 +408,14 @@ static int genregs_get(struct task_struct *target, - { - if (kbuf) { - unsigned long *k = kbuf; -- while (count > 0) { -+ while (count >= sizeof(*k)) { - *k++ = getreg(target, pos); - count -= sizeof(*k); - pos += sizeof(*k); - } - } else { - unsigned long __user *u = ubuf; -- while (count > 0) { -+ while (count >= sizeof(*u)) { - if (__put_user(getreg(target, pos), u++)) - return -EFAULT; - count -= sizeof(*u); -@@ -434,14 +434,14 @@ static int genregs_set(struct task_struct *target, - int ret = 0; - if (kbuf) { - const unsigned long *k = kbuf; -- while (count > 0 && !ret) { -+ while (count >= sizeof(*k) && !ret) { - ret = putreg(target, pos, *k++); - count -= sizeof(*k); - pos += sizeof(*k); - } - } else { - const unsigned long __user *u = ubuf; -- while (count > 0 && !ret) { -+ while (count >= sizeof(*u) && !ret) { - unsigned long word; - ret = __get_user(word, u++); - if (ret) -@@ -1219,14 +1219,14 @@ static int genregs32_get(struct task_struct *target, - { - if (kbuf) { - compat_ulong_t *k = kbuf; -- while (count > 0) { -+ while (count >= sizeof(*k)) { - getreg32(target, pos, k++); - count -= sizeof(*k); - pos += sizeof(*k); - } - } else { - compat_ulong_t __user *u = ubuf; -- while (count > 0) { -+ while (count >= sizeof(*u)) { - compat_ulong_t word; - getreg32(target, pos, &word); - if (__put_user(word, u++)) -@@ -1247,14 +1247,14 @@ static int genregs32_set(struct task_struct *target, - int ret = 0; - if (kbuf) { - const compat_ulong_t *k = kbuf; -- while (count > 0 && !ret) { -+ while (count >= sizeof(*k) && !ret) { - ret = putreg32(target, pos, *k++); - count -= sizeof(*k); - pos += sizeof(*k); - } - } else { - const compat_ulong_t __user *u = ubuf; -- while (count > 0 && !ret) { -+ while (count >= sizeof(*u) && !ret) { - compat_ulong_t word; - ret = __get_user(word, u++); - if (ret) -diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c -index 23c2176..41659fb 100644 ---- a/arch/x86/kvm/lapic.c -+++ b/arch/x86/kvm/lapic.c -@@ -1156,6 +1156,7 @@ void kvm_apic_post_state_restore(struct kvm_vcpu *vcpu) - hrtimer_cancel(&apic->lapic_timer.timer); - update_divide_count(apic); - start_apic_timer(apic); -+ apic->irr_pending = true; - } - - void __kvm_migrate_apic_timer(struct kvm_vcpu *vcpu) -diff --git a/arch/x86/kvm/paging_tmpl.h b/arch/x86/kvm/paging_tmpl.h -index 72558f8..85e12cd 100644 ---- a/arch/x86/kvm/paging_tmpl.h -+++ b/arch/x86/kvm/paging_tmpl.h -@@ -455,8 +455,6 @@ out_unlock: - static void FNAME(invlpg)(struct kvm_vcpu *vcpu, gva_t gva) - { - struct kvm_shadow_walk_iterator iterator; -- pt_element_t gpte; -- gpa_t pte_gpa = -1; - int level; - u64 *sptep; - int need_flush = 0; -@@ -471,10 +469,6 @@ static void FNAME(invlpg)(struct kvm_vcpu *vcpu, gva_t gva) - if (level == PT_PAGE_TABLE_LEVEL || - ((level == PT_DIRECTORY_LEVEL && is_large_pte(*sptep))) || - ((level == PT_PDPE_LEVEL && is_large_pte(*sptep)))) { -- struct kvm_mmu_page *sp = page_header(__pa(sptep)); -- -- pte_gpa = (sp->gfn << PAGE_SHIFT); -- pte_gpa += (sptep - sp->spt) * sizeof(pt_element_t); - - if (is_shadow_present_pte(*sptep)) { - rmap_remove(vcpu->kvm, sptep); -@@ -493,18 +487,6 @@ static void FNAME(invlpg)(struct kvm_vcpu *vcpu, gva_t gva) - if (need_flush) - kvm_flush_remote_tlbs(vcpu->kvm); - spin_unlock(&vcpu->kvm->mmu_lock); -- -- if (pte_gpa == -1) -- return; -- if (kvm_read_guest_atomic(vcpu->kvm, pte_gpa, &gpte, -- sizeof(pt_element_t))) -- return; -- if (is_present_gpte(gpte) && (gpte & PT_ACCESSED_MASK)) { -- if (mmu_topup_memory_caches(vcpu)) -- return; -- kvm_mmu_pte_write(vcpu, pte_gpa, (const u8 *)&gpte, -- sizeof(pt_element_t), 0); -- } - } - - static gpa_t FNAME(gva_to_gpa)(struct kvm_vcpu *vcpu, gva_t vaddr) -diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile -index 85f5db9..c2b6f39 100644 ---- a/arch/x86/lib/Makefile -+++ b/arch/x86/lib/Makefile -@@ -2,14 +2,14 @@ - # Makefile for x86 specific library files. - # - --obj-$(CONFIG_SMP) := msr.o -+obj-$(CONFIG_SMP) += msr-smp.o - - lib-y := delay.o - lib-y += thunk_$(BITS).o - lib-y += usercopy_$(BITS).o getuser.o putuser.o - lib-y += memcpy_$(BITS).o - --obj-y += msr-reg.o msr-reg-export.o -+obj-y += msr.o msr-reg.o msr-reg-export.o - - ifeq ($(CONFIG_X86_32),y) - obj-y += atomic64_32.o -diff --git a/arch/x86/lib/msr-smp.c b/arch/x86/lib/msr-smp.c -new file mode 100644 -index 0000000..a6b1b86 ---- /dev/null -+++ b/arch/x86/lib/msr-smp.c -@@ -0,0 +1,204 @@ -+#include -+#include -+#include -+#include -+ -+static void __rdmsr_on_cpu(void *info) -+{ -+ struct msr_info *rv = info; -+ struct msr *reg; -+ int this_cpu = raw_smp_processor_id(); -+ -+ if (rv->msrs) -+ reg = per_cpu_ptr(rv->msrs, this_cpu); -+ else -+ reg = &rv->reg; -+ -+ rdmsr(rv->msr_no, reg->l, reg->h); -+} -+ -+static void __wrmsr_on_cpu(void *info) -+{ -+ struct msr_info *rv = info; -+ struct msr *reg; -+ int this_cpu = raw_smp_processor_id(); -+ -+ if (rv->msrs) -+ reg = per_cpu_ptr(rv->msrs, this_cpu); -+ else -+ reg = &rv->reg; -+ -+ wrmsr(rv->msr_no, reg->l, reg->h); -+} -+ -+int rdmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h) -+{ -+ int err; -+ struct msr_info rv; -+ -+ memset(&rv, 0, sizeof(rv)); -+ -+ rv.msr_no = msr_no; -+ err = smp_call_function_single(cpu, __rdmsr_on_cpu, &rv, 1); -+ *l = rv.reg.l; -+ *h = rv.reg.h; -+ -+ return err; -+} -+EXPORT_SYMBOL(rdmsr_on_cpu); -+ -+int wrmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h) -+{ -+ int err; -+ struct msr_info rv; -+ -+ memset(&rv, 0, sizeof(rv)); -+ -+ rv.msr_no = msr_no; -+ rv.reg.l = l; -+ rv.reg.h = h; -+ err = smp_call_function_single(cpu, __wrmsr_on_cpu, &rv, 1); -+ -+ return err; -+} -+EXPORT_SYMBOL(wrmsr_on_cpu); -+ -+static void __rwmsr_on_cpus(const struct cpumask *mask, u32 msr_no, -+ struct msr *msrs, -+ void (*msr_func) (void *info)) -+{ -+ struct msr_info rv; -+ int this_cpu; -+ -+ memset(&rv, 0, sizeof(rv)); -+ -+ rv.msrs = msrs; -+ rv.msr_no = msr_no; -+ -+ this_cpu = get_cpu(); -+ -+ if (cpumask_test_cpu(this_cpu, mask)) -+ msr_func(&rv); -+ -+ smp_call_function_many(mask, msr_func, &rv, 1); -+ put_cpu(); -+} -+ -+/* rdmsr on a bunch of CPUs -+ * -+ * @mask: which CPUs -+ * @msr_no: which MSR -+ * @msrs: array of MSR values -+ * -+ */ -+void rdmsr_on_cpus(const struct cpumask *mask, u32 msr_no, struct msr *msrs) -+{ -+ __rwmsr_on_cpus(mask, msr_no, msrs, __rdmsr_on_cpu); -+} -+EXPORT_SYMBOL(rdmsr_on_cpus); -+ -+/* -+ * wrmsr on a bunch of CPUs -+ * -+ * @mask: which CPUs -+ * @msr_no: which MSR -+ * @msrs: array of MSR values -+ * -+ */ -+void wrmsr_on_cpus(const struct cpumask *mask, u32 msr_no, struct msr *msrs) -+{ -+ __rwmsr_on_cpus(mask, msr_no, msrs, __wrmsr_on_cpu); -+} -+EXPORT_SYMBOL(wrmsr_on_cpus); -+ -+/* These "safe" variants are slower and should be used when the target MSR -+ may not actually exist. */ -+static void __rdmsr_safe_on_cpu(void *info) -+{ -+ struct msr_info *rv = info; -+ -+ rv->err = rdmsr_safe(rv->msr_no, &rv->reg.l, &rv->reg.h); -+} -+ -+static void __wrmsr_safe_on_cpu(void *info) -+{ -+ struct msr_info *rv = info; -+ -+ rv->err = wrmsr_safe(rv->msr_no, rv->reg.l, rv->reg.h); -+} -+ -+int rdmsr_safe_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h) -+{ -+ int err; -+ struct msr_info rv; -+ -+ memset(&rv, 0, sizeof(rv)); -+ -+ rv.msr_no = msr_no; -+ err = smp_call_function_single(cpu, __rdmsr_safe_on_cpu, &rv, 1); -+ *l = rv.reg.l; -+ *h = rv.reg.h; -+ -+ return err ? err : rv.err; -+} -+EXPORT_SYMBOL(rdmsr_safe_on_cpu); -+ -+int wrmsr_safe_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h) -+{ -+ int err; -+ struct msr_info rv; -+ -+ memset(&rv, 0, sizeof(rv)); -+ -+ rv.msr_no = msr_no; -+ rv.reg.l = l; -+ rv.reg.h = h; -+ err = smp_call_function_single(cpu, __wrmsr_safe_on_cpu, &rv, 1); -+ -+ return err ? err : rv.err; -+} -+EXPORT_SYMBOL(wrmsr_safe_on_cpu); -+ -+/* -+ * These variants are significantly slower, but allows control over -+ * the entire 32-bit GPR set. -+ */ -+static void __rdmsr_safe_regs_on_cpu(void *info) -+{ -+ struct msr_regs_info *rv = info; -+ -+ rv->err = rdmsr_safe_regs(rv->regs); -+} -+ -+static void __wrmsr_safe_regs_on_cpu(void *info) -+{ -+ struct msr_regs_info *rv = info; -+ -+ rv->err = wrmsr_safe_regs(rv->regs); -+} -+ -+int rdmsr_safe_regs_on_cpu(unsigned int cpu, u32 *regs) -+{ -+ int err; -+ struct msr_regs_info rv; -+ -+ rv.regs = regs; -+ rv.err = -EIO; -+ err = smp_call_function_single(cpu, __rdmsr_safe_regs_on_cpu, &rv, 1); -+ -+ return err ? err : rv.err; -+} -+EXPORT_SYMBOL(rdmsr_safe_regs_on_cpu); -+ -+int wrmsr_safe_regs_on_cpu(unsigned int cpu, u32 *regs) -+{ -+ int err; -+ struct msr_regs_info rv; -+ -+ rv.regs = regs; -+ rv.err = -EIO; -+ err = smp_call_function_single(cpu, __wrmsr_safe_regs_on_cpu, &rv, 1); -+ -+ return err ? err : rv.err; -+} -+EXPORT_SYMBOL(wrmsr_safe_regs_on_cpu); -diff --git a/arch/x86/lib/msr.c b/arch/x86/lib/msr.c -index 33a1e3c..8f8eebd 100644 ---- a/arch/x86/lib/msr.c -+++ b/arch/x86/lib/msr.c -@@ -1,226 +1,23 @@ - #include - #include --#include - #include - --struct msr_info { -- u32 msr_no; -- struct msr reg; -- struct msr *msrs; -- int off; -- int err; --}; -- --static void __rdmsr_on_cpu(void *info) --{ -- struct msr_info *rv = info; -- struct msr *reg; -- int this_cpu = raw_smp_processor_id(); -- -- if (rv->msrs) -- reg = &rv->msrs[this_cpu - rv->off]; -- else -- reg = &rv->reg; -- -- rdmsr(rv->msr_no, reg->l, reg->h); --} -- --static void __wrmsr_on_cpu(void *info) --{ -- struct msr_info *rv = info; -- struct msr *reg; -- int this_cpu = raw_smp_processor_id(); -- -- if (rv->msrs) -- reg = &rv->msrs[this_cpu - rv->off]; -- else -- reg = &rv->reg; -- -- wrmsr(rv->msr_no, reg->l, reg->h); --} -- --int rdmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h) --{ -- int err; -- struct msr_info rv; -- -- memset(&rv, 0, sizeof(rv)); -- -- rv.msr_no = msr_no; -- err = smp_call_function_single(cpu, __rdmsr_on_cpu, &rv, 1); -- *l = rv.reg.l; -- *h = rv.reg.h; -- -- return err; --} --EXPORT_SYMBOL(rdmsr_on_cpu); -- --int wrmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h) --{ -- int err; -- struct msr_info rv; -- -- memset(&rv, 0, sizeof(rv)); -- -- rv.msr_no = msr_no; -- rv.reg.l = l; -- rv.reg.h = h; -- err = smp_call_function_single(cpu, __wrmsr_on_cpu, &rv, 1); -- -- return err; --} --EXPORT_SYMBOL(wrmsr_on_cpu); -- --/* rdmsr on a bunch of CPUs -- * -- * @mask: which CPUs -- * @msr_no: which MSR -- * @msrs: array of MSR values -- * -- */ --void rdmsr_on_cpus(const cpumask_t *mask, u32 msr_no, struct msr *msrs) --{ -- struct msr_info rv; -- int this_cpu; -- -- memset(&rv, 0, sizeof(rv)); -- -- rv.off = cpumask_first(mask); -- rv.msrs = msrs; -- rv.msr_no = msr_no; -- -- this_cpu = get_cpu(); -- -- if (cpumask_test_cpu(this_cpu, mask)) -- __rdmsr_on_cpu(&rv); -- -- smp_call_function_many(mask, __rdmsr_on_cpu, &rv, 1); -- put_cpu(); --} --EXPORT_SYMBOL(rdmsr_on_cpus); -- --/* -- * wrmsr on a bunch of CPUs -- * -- * @mask: which CPUs -- * @msr_no: which MSR -- * @msrs: array of MSR values -- * -- */ --void wrmsr_on_cpus(const cpumask_t *mask, u32 msr_no, struct msr *msrs) --{ -- struct msr_info rv; -- int this_cpu; -- -- memset(&rv, 0, sizeof(rv)); -- -- rv.off = cpumask_first(mask); -- rv.msrs = msrs; -- rv.msr_no = msr_no; -- -- this_cpu = get_cpu(); -- -- if (cpumask_test_cpu(this_cpu, mask)) -- __wrmsr_on_cpu(&rv); -- -- smp_call_function_many(mask, __wrmsr_on_cpu, &rv, 1); -- put_cpu(); --} --EXPORT_SYMBOL(wrmsr_on_cpus); -- --/* These "safe" variants are slower and should be used when the target MSR -- may not actually exist. */ --static void __rdmsr_safe_on_cpu(void *info) --{ -- struct msr_info *rv = info; -- -- rv->err = rdmsr_safe(rv->msr_no, &rv->reg.l, &rv->reg.h); --} -- --static void __wrmsr_safe_on_cpu(void *info) --{ -- struct msr_info *rv = info; -- -- rv->err = wrmsr_safe(rv->msr_no, rv->reg.l, rv->reg.h); --} -- --int rdmsr_safe_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h) -+struct msr *msrs_alloc(void) - { -- int err; -- struct msr_info rv; -+ struct msr *msrs = NULL; - -- memset(&rv, 0, sizeof(rv)); -+ msrs = alloc_percpu(struct msr); -+ if (!msrs) { -+ pr_warning("%s: error allocating msrs\n", __func__); -+ return NULL; -+ } - -- rv.msr_no = msr_no; -- err = smp_call_function_single(cpu, __rdmsr_safe_on_cpu, &rv, 1); -- *l = rv.reg.l; -- *h = rv.reg.h; -- -- return err ? err : rv.err; -+ return msrs; - } --EXPORT_SYMBOL(rdmsr_safe_on_cpu); -+EXPORT_SYMBOL(msrs_alloc); - --int wrmsr_safe_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h) -+void msrs_free(struct msr *msrs) - { -- int err; -- struct msr_info rv; -- -- memset(&rv, 0, sizeof(rv)); -- -- rv.msr_no = msr_no; -- rv.reg.l = l; -- rv.reg.h = h; -- err = smp_call_function_single(cpu, __wrmsr_safe_on_cpu, &rv, 1); -- -- return err ? err : rv.err; --} --EXPORT_SYMBOL(wrmsr_safe_on_cpu); -- --/* -- * These variants are significantly slower, but allows control over -- * the entire 32-bit GPR set. -- */ --struct msr_regs_info { -- u32 *regs; -- int err; --}; -- --static void __rdmsr_safe_regs_on_cpu(void *info) --{ -- struct msr_regs_info *rv = info; -- -- rv->err = rdmsr_safe_regs(rv->regs); --} -- --static void __wrmsr_safe_regs_on_cpu(void *info) --{ -- struct msr_regs_info *rv = info; -- -- rv->err = wrmsr_safe_regs(rv->regs); --} -- --int rdmsr_safe_regs_on_cpu(unsigned int cpu, u32 *regs) --{ -- int err; -- struct msr_regs_info rv; -- -- rv.regs = regs; -- rv.err = -EIO; -- err = smp_call_function_single(cpu, __rdmsr_safe_regs_on_cpu, &rv, 1); -- -- return err ? err : rv.err; --} --EXPORT_SYMBOL(rdmsr_safe_regs_on_cpu); -- --int wrmsr_safe_regs_on_cpu(unsigned int cpu, u32 *regs) --{ -- int err; -- struct msr_regs_info rv; -- -- rv.regs = regs; -- rv.err = -EIO; -- err = smp_call_function_single(cpu, __wrmsr_safe_regs_on_cpu, &rv, 1); -- -- return err ? err : rv.err; -+ free_percpu(msrs); - } --EXPORT_SYMBOL(wrmsr_safe_regs_on_cpu); -+EXPORT_SYMBOL(msrs_free); -diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c -index 0c9c6a9..8a95e83 100644 ---- a/drivers/acpi/button.c -+++ b/drivers/acpi/button.c -@@ -282,6 +282,13 @@ static int acpi_lid_send_state(struct acpi_device *device) - if (ret == NOTIFY_DONE) - ret = blocking_notifier_call_chain(&acpi_lid_notifier, state, - device); -+ if (ret == NOTIFY_DONE || ret == NOTIFY_OK) { -+ /* -+ * It is also regarded as success if the notifier_chain -+ * returns NOTIFY_OK or NOTIFY_DONE. -+ */ -+ ret = 0; -+ } - return ret; - } - -diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c -index baef28c..7511029 100644 ---- a/drivers/acpi/ec.c -+++ b/drivers/acpi/ec.c -@@ -916,6 +916,7 @@ static int ec_validate_ecdt(const struct dmi_system_id *id) - /* MSI EC needs special treatment, enable it */ - static int ec_flag_msi(const struct dmi_system_id *id) - { -+ printk(KERN_DEBUG PREFIX "Detected MSI hardware, enabling workarounds.\n"); - EC_FLAGS_MSI = 1; - EC_FLAGS_VALIDATE_ECDT = 1; - return 0; -@@ -928,8 +929,13 @@ static struct dmi_system_id __initdata ec_dmi_table[] = { - DMI_MATCH(DMI_BOARD_NAME, "JFL92") }, NULL}, - { - ec_flag_msi, "MSI hardware", { -- DMI_MATCH(DMI_BIOS_VENDOR, "Micro-Star"), -- DMI_MATCH(DMI_CHASSIS_VENDOR, "MICRO-Star") }, NULL}, -+ DMI_MATCH(DMI_BIOS_VENDOR, "Micro-Star")}, NULL}, -+ { -+ ec_flag_msi, "MSI hardware", { -+ DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star")}, NULL}, -+ { -+ ec_flag_msi, "MSI hardware", { -+ DMI_MATCH(DMI_CHASSIS_VENDOR, "MICRO-Star")}, NULL}, - { - ec_validate_ecdt, "ASUS hardware", { - DMI_MATCH(DMI_BIOS_VENDOR, "ASUS") }, NULL}, -diff --git a/drivers/ata/pata_cmd64x.c b/drivers/ata/pata_cmd64x.c -index f98dffe..f0bad9b 100644 ---- a/drivers/ata/pata_cmd64x.c -+++ b/drivers/ata/pata_cmd64x.c -@@ -219,7 +219,7 @@ static void cmd64x_set_dmamode(struct ata_port *ap, struct ata_device *adev) - regU |= udma_data[adev->dma_mode - XFER_UDMA_0] << shift; - /* Merge the control bits */ - regU |= 1 << adev->devno; /* UDMA on */ -- if (adev->dma_mode > 2) /* 15nS timing */ -+ if (adev->dma_mode > XFER_UDMA_2) /* 15nS timing */ - regU |= 4 << adev->devno; - } else { - regU &= ~ (1 << adev->devno); /* UDMA off */ -diff --git a/drivers/ata/pata_hpt3x2n.c b/drivers/ata/pata_hpt3x2n.c -index 21c5bd6..d16e87e 100644 ---- a/drivers/ata/pata_hpt3x2n.c -+++ b/drivers/ata/pata_hpt3x2n.c -@@ -8,7 +8,7 @@ - * Copyright (C) 1999-2003 Andre Hedrick - * Portions Copyright (C) 2001 Sun Microsystems, Inc. - * Portions Copyright (C) 2003 Red Hat Inc -- * Portions Copyright (C) 2005-2007 MontaVista Software, Inc. -+ * Portions Copyright (C) 2005-2009 MontaVista Software, Inc. - * - * - * TODO -@@ -25,7 +25,7 @@ - #include - - #define DRV_NAME "pata_hpt3x2n" --#define DRV_VERSION "0.3.7" -+#define DRV_VERSION "0.3.8" - - enum { - HPT_PCI_FAST = (1 << 31), -@@ -262,7 +262,7 @@ static void hpt3x2n_bmdma_stop(struct ata_queued_cmd *qc) - - static void hpt3x2n_set_clock(struct ata_port *ap, int source) - { -- void __iomem *bmdma = ap->ioaddr.bmdma_addr; -+ void __iomem *bmdma = ap->ioaddr.bmdma_addr - ap->port_no * 8; - - /* Tristate the bus */ - iowrite8(0x80, bmdma+0x73); -@@ -272,9 +272,9 @@ static void hpt3x2n_set_clock(struct ata_port *ap, int source) - iowrite8(source, bmdma+0x7B); - iowrite8(0xC0, bmdma+0x79); - -- /* Reset state machines */ -- iowrite8(0x37, bmdma+0x70); -- iowrite8(0x37, bmdma+0x74); -+ /* Reset state machines, avoid enabling the disabled channels */ -+ iowrite8(ioread8(bmdma+0x70) | 0x32, bmdma+0x70); -+ iowrite8(ioread8(bmdma+0x74) | 0x32, bmdma+0x74); - - /* Complete reset */ - iowrite8(0x00, bmdma+0x79); -@@ -284,21 +284,10 @@ static void hpt3x2n_set_clock(struct ata_port *ap, int source) - iowrite8(0x00, bmdma+0x77); - } - --/* Check if our partner interface is busy */ -- --static int hpt3x2n_pair_idle(struct ata_port *ap) --{ -- struct ata_host *host = ap->host; -- struct ata_port *pair = host->ports[ap->port_no ^ 1]; -- -- if (pair->hsm_task_state == HSM_ST_IDLE) -- return 1; -- return 0; --} -- - static int hpt3x2n_use_dpll(struct ata_port *ap, int writing) - { - long flags = (long)ap->host->private_data; -+ - /* See if we should use the DPLL */ - if (writing) - return USE_DPLL; /* Needed for write */ -@@ -307,20 +296,35 @@ static int hpt3x2n_use_dpll(struct ata_port *ap, int writing) - return 0; - } - -+static int hpt3x2n_qc_defer(struct ata_queued_cmd *qc) -+{ -+ struct ata_port *ap = qc->ap; -+ struct ata_port *alt = ap->host->ports[ap->port_no ^ 1]; -+ int rc, flags = (long)ap->host->private_data; -+ int dpll = hpt3x2n_use_dpll(ap, qc->tf.flags & ATA_TFLAG_WRITE); -+ -+ /* First apply the usual rules */ -+ rc = ata_std_qc_defer(qc); -+ if (rc != 0) -+ return rc; -+ -+ if ((flags & USE_DPLL) != dpll && alt->qc_active) -+ return ATA_DEFER_PORT; -+ return 0; -+} -+ - static unsigned int hpt3x2n_qc_issue(struct ata_queued_cmd *qc) - { -- struct ata_taskfile *tf = &qc->tf; - struct ata_port *ap = qc->ap; - int flags = (long)ap->host->private_data; -+ int dpll = hpt3x2n_use_dpll(ap, qc->tf.flags & ATA_TFLAG_WRITE); - -- if (hpt3x2n_pair_idle(ap)) { -- int dpll = hpt3x2n_use_dpll(ap, (tf->flags & ATA_TFLAG_WRITE)); -- if ((flags & USE_DPLL) != dpll) { -- if (dpll == 1) -- hpt3x2n_set_clock(ap, 0x21); -- else -- hpt3x2n_set_clock(ap, 0x23); -- } -+ if ((flags & USE_DPLL) != dpll) { -+ flags &= ~USE_DPLL; -+ flags |= dpll; -+ ap->host->private_data = (void *)(long)flags; -+ -+ hpt3x2n_set_clock(ap, dpll ? 0x21 : 0x23); - } - return ata_sff_qc_issue(qc); - } -@@ -337,6 +341,8 @@ static struct ata_port_operations hpt3x2n_port_ops = { - .inherits = &ata_bmdma_port_ops, - - .bmdma_stop = hpt3x2n_bmdma_stop, -+ -+ .qc_defer = hpt3x2n_qc_defer, - .qc_issue = hpt3x2n_qc_issue, - - .cable_detect = hpt3x2n_cable_detect, -@@ -454,7 +460,7 @@ static int hpt3x2n_init_one(struct pci_dev *dev, const struct pci_device_id *id) - unsigned int f_low, f_high; - int adjust; - unsigned long iobase = pci_resource_start(dev, 4); -- void *hpriv = NULL; -+ void *hpriv = (void *)USE_DPLL; - int rc; - - rc = pcim_enable_device(dev); -@@ -542,7 +548,7 @@ static int hpt3x2n_init_one(struct pci_dev *dev, const struct pci_device_id *id) - /* Set our private data up. We only need a few flags so we use - it directly */ - if (pci_mhz > 60) { -- hpriv = (void *)PCI66; -+ hpriv = (void *)(PCI66 | USE_DPLL); - /* - * On HPT371N, if ATA clock is 66 MHz we must set bit 2 in - * the MISC. register to stretch the UltraDMA Tss timing. -diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c -index 44bc8bb..1be7631 100644 ---- a/drivers/bluetooth/btusb.c -+++ b/drivers/bluetooth/btusb.c -@@ -307,6 +307,7 @@ static void btusb_bulk_complete(struct urb *urb) - return; - - usb_anchor_urb(urb, &data->bulk_anchor); -+ usb_mark_last_busy(data->udev); - - err = usb_submit_urb(urb, GFP_ATOMIC); - if (err < 0) { -diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c -index 7585c41..c558fa1 100644 ---- a/drivers/dma/at_hdmac.c -+++ b/drivers/dma/at_hdmac.c -@@ -815,7 +815,7 @@ atc_is_tx_complete(struct dma_chan *chan, - dev_vdbg(chan2dev(chan), "is_tx_complete: %d (d%d, u%d)\n", - cookie, done ? *done : 0, used ? *used : 0); - -- spin_lock_bh(atchan->lock); -+ spin_lock_bh(&atchan->lock); - - last_complete = atchan->completed_cookie; - last_used = chan->cookie; -@@ -830,7 +830,7 @@ atc_is_tx_complete(struct dma_chan *chan, - ret = dma_async_is_complete(cookie, last_complete, last_used); - } - -- spin_unlock_bh(atchan->lock); -+ spin_unlock_bh(&atchan->lock); - - if (done) - *done = last_complete; -diff --git a/drivers/dma/ioat/dma.c b/drivers/dma/ioat/dma.c -index c524d36..dcc4ab7 100644 ---- a/drivers/dma/ioat/dma.c -+++ b/drivers/dma/ioat/dma.c -@@ -1032,7 +1032,7 @@ int __devinit ioat_probe(struct ioatdma_device *device) - dma->dev = &pdev->dev; - - if (!dma->chancnt) { -- dev_err(dev, "zero channels detected\n"); -+ dev_err(dev, "channel enumeration error\n"); - goto err_setup_interrupts; - } - -diff --git a/drivers/dma/ioat/dma.h b/drivers/dma/ioat/dma.h -index 45edde9..bbc3e78 100644 ---- a/drivers/dma/ioat/dma.h -+++ b/drivers/dma/ioat/dma.h -@@ -60,6 +60,7 @@ - * @dca: direct cache access context - * @intr_quirk: interrupt setup quirk (for ioat_v1 devices) - * @enumerate_channels: hw version specific channel enumeration -+ * @reset_hw: hw version specific channel (re)initialization - * @cleanup_tasklet: select between the v2 and v3 cleanup routines - * @timer_fn: select between the v2 and v3 timer watchdog routines - * @self_test: hardware version specific self test for each supported op type -@@ -78,6 +79,7 @@ struct ioatdma_device { - struct dca_provider *dca; - void (*intr_quirk)(struct ioatdma_device *device); - int (*enumerate_channels)(struct ioatdma_device *device); -+ int (*reset_hw)(struct ioat_chan_common *chan); - void (*cleanup_tasklet)(unsigned long data); - void (*timer_fn)(unsigned long data); - int (*self_test)(struct ioatdma_device *device); -@@ -264,6 +266,22 @@ static inline void ioat_suspend(struct ioat_chan_common *chan) - writeb(IOAT_CHANCMD_SUSPEND, chan->reg_base + IOAT_CHANCMD_OFFSET(ver)); - } - -+static inline void ioat_reset(struct ioat_chan_common *chan) -+{ -+ u8 ver = chan->device->version; -+ -+ writeb(IOAT_CHANCMD_RESET, chan->reg_base + IOAT_CHANCMD_OFFSET(ver)); -+} -+ -+static inline bool ioat_reset_pending(struct ioat_chan_common *chan) -+{ -+ u8 ver = chan->device->version; -+ u8 cmd; -+ -+ cmd = readb(chan->reg_base + IOAT_CHANCMD_OFFSET(ver)); -+ return (cmd & IOAT_CHANCMD_RESET) == IOAT_CHANCMD_RESET; -+} -+ - static inline void ioat_set_chainaddr(struct ioat_dma_chan *ioat, u64 addr) - { - struct ioat_chan_common *chan = &ioat->base; -diff --git a/drivers/dma/ioat/dma_v2.c b/drivers/dma/ioat/dma_v2.c -index 8f1f7f0..5f7a500 100644 ---- a/drivers/dma/ioat/dma_v2.c -+++ b/drivers/dma/ioat/dma_v2.c -@@ -239,20 +239,50 @@ void __ioat2_restart_chan(struct ioat2_dma_chan *ioat) - __ioat2_start_null_desc(ioat); - } - --static void ioat2_restart_channel(struct ioat2_dma_chan *ioat) -+int ioat2_quiesce(struct ioat_chan_common *chan, unsigned long tmo) - { -- struct ioat_chan_common *chan = &ioat->base; -- unsigned long phys_complete; -+ unsigned long end = jiffies + tmo; -+ int err = 0; - u32 status; - - status = ioat_chansts(chan); - if (is_ioat_active(status) || is_ioat_idle(status)) - ioat_suspend(chan); - while (is_ioat_active(status) || is_ioat_idle(status)) { -+ if (end && time_after(jiffies, end)) { -+ err = -ETIMEDOUT; -+ break; -+ } - status = ioat_chansts(chan); - cpu_relax(); - } - -+ return err; -+} -+ -+int ioat2_reset_sync(struct ioat_chan_common *chan, unsigned long tmo) -+{ -+ unsigned long end = jiffies + tmo; -+ int err = 0; -+ -+ ioat_reset(chan); -+ while (ioat_reset_pending(chan)) { -+ if (end && time_after(jiffies, end)) { -+ err = -ETIMEDOUT; -+ break; -+ } -+ cpu_relax(); -+ } -+ -+ return err; -+} -+ -+static void ioat2_restart_channel(struct ioat2_dma_chan *ioat) -+{ -+ struct ioat_chan_common *chan = &ioat->base; -+ unsigned long phys_complete; -+ -+ ioat2_quiesce(chan, 0); - if (ioat_cleanup_preamble(chan, &phys_complete)) - __cleanup(ioat, phys_complete); - -@@ -318,6 +348,19 @@ void ioat2_timer_event(unsigned long data) - spin_unlock_bh(&chan->cleanup_lock); - } - -+static int ioat2_reset_hw(struct ioat_chan_common *chan) -+{ -+ /* throw away whatever the channel was doing and get it initialized */ -+ u32 chanerr; -+ -+ ioat2_quiesce(chan, msecs_to_jiffies(100)); -+ -+ chanerr = readl(chan->reg_base + IOAT_CHANERR_OFFSET); -+ writel(chanerr, chan->reg_base + IOAT_CHANERR_OFFSET); -+ -+ return ioat2_reset_sync(chan, msecs_to_jiffies(200)); -+} -+ - /** - * ioat2_enumerate_channels - find and initialize the device's channels - * @device: the device to be enumerated -@@ -360,6 +403,10 @@ int ioat2_enumerate_channels(struct ioatdma_device *device) - (unsigned long) ioat); - ioat->xfercap_log = xfercap_log; - spin_lock_init(&ioat->ring_lock); -+ if (device->reset_hw(&ioat->base)) { -+ i = 0; -+ break; -+ } - } - dma->chancnt = i; - return i; -@@ -467,7 +514,6 @@ int ioat2_alloc_chan_resources(struct dma_chan *c) - struct ioat2_dma_chan *ioat = to_ioat2_chan(c); - struct ioat_chan_common *chan = &ioat->base; - struct ioat_ring_ent **ring; -- u32 chanerr; - int order; - - /* have we already been set up? */ -@@ -477,12 +523,6 @@ int ioat2_alloc_chan_resources(struct dma_chan *c) - /* Setup register to interrupt and write completion status on error */ - writew(IOAT_CHANCTRL_RUN, chan->reg_base + IOAT_CHANCTRL_OFFSET); - -- chanerr = readl(chan->reg_base + IOAT_CHANERR_OFFSET); -- if (chanerr) { -- dev_err(to_dev(chan), "CHANERR = %x, clearing\n", chanerr); -- writel(chanerr, chan->reg_base + IOAT_CHANERR_OFFSET); -- } -- - /* allocate a completion writeback area */ - /* doing 2 32bit writes to mmio since 1 64b write doesn't work */ - chan->completion = pci_pool_alloc(chan->device->completion_pool, -@@ -746,13 +786,7 @@ void ioat2_free_chan_resources(struct dma_chan *c) - tasklet_disable(&chan->cleanup_task); - del_timer_sync(&chan->timer); - device->cleanup_tasklet((unsigned long) ioat); -- -- /* Delay 100ms after reset to allow internal DMA logic to quiesce -- * before removing DMA descriptor resources. -- */ -- writeb(IOAT_CHANCMD_RESET, -- chan->reg_base + IOAT_CHANCMD_OFFSET(chan->device->version)); -- mdelay(100); -+ device->reset_hw(chan); - - spin_lock_bh(&ioat->ring_lock); - descs = ioat2_ring_space(ioat); -@@ -839,6 +873,7 @@ int __devinit ioat2_dma_probe(struct ioatdma_device *device, int dca) - int err; - - device->enumerate_channels = ioat2_enumerate_channels; -+ device->reset_hw = ioat2_reset_hw; - device->cleanup_tasklet = ioat2_cleanup_tasklet; - device->timer_fn = ioat2_timer_event; - device->self_test = ioat_dma_self_test; -diff --git a/drivers/dma/ioat/dma_v2.h b/drivers/dma/ioat/dma_v2.h -index 1d849ef..3afad8d 100644 ---- a/drivers/dma/ioat/dma_v2.h -+++ b/drivers/dma/ioat/dma_v2.h -@@ -185,6 +185,8 @@ bool reshape_ring(struct ioat2_dma_chan *ioat, int order); - void __ioat2_issue_pending(struct ioat2_dma_chan *ioat); - void ioat2_cleanup_tasklet(unsigned long data); - void ioat2_timer_event(unsigned long data); -+int ioat2_quiesce(struct ioat_chan_common *chan, unsigned long tmo); -+int ioat2_reset_sync(struct ioat_chan_common *chan, unsigned long tmo); - extern struct kobj_type ioat2_ktype; - extern struct kmem_cache *ioat2_cache; - #endif /* IOATDMA_V2_H */ -diff --git a/drivers/dma/ioat/dma_v3.c b/drivers/dma/ioat/dma_v3.c -index 42f6f10..9908c9e 100644 ---- a/drivers/dma/ioat/dma_v3.c -+++ b/drivers/dma/ioat/dma_v3.c -@@ -650,9 +650,11 @@ __ioat3_prep_pq_lock(struct dma_chan *c, enum sum_check_flags *result, - - num_descs = ioat2_xferlen_to_descs(ioat, len); - /* we need 2x the number of descriptors to cover greater than 3 -- * sources -+ * sources (we need 1 extra source in the q-only continuation -+ * case and 3 extra sources in the p+q continuation case. - */ -- if (src_cnt > 3 || flags & DMA_PREP_CONTINUE) { -+ if (src_cnt + dmaf_p_disabled_continue(flags) > 3 || -+ (dmaf_continue(flags) && !dmaf_p_disabled_continue(flags))) { - with_ext = 1; - num_descs *= 2; - } else -@@ -1128,6 +1130,45 @@ static int __devinit ioat3_dma_self_test(struct ioatdma_device *device) - return 0; - } - -+static int ioat3_reset_hw(struct ioat_chan_common *chan) -+{ -+ /* throw away whatever the channel was doing and get it -+ * initialized, with ioat3 specific workarounds -+ */ -+ struct ioatdma_device *device = chan->device; -+ struct pci_dev *pdev = device->pdev; -+ u32 chanerr; -+ u16 dev_id; -+ int err; -+ -+ ioat2_quiesce(chan, msecs_to_jiffies(100)); -+ -+ chanerr = readl(chan->reg_base + IOAT_CHANERR_OFFSET); -+ writel(chanerr, chan->reg_base + IOAT_CHANERR_OFFSET); -+ -+ /* -= IOAT ver.3 workarounds =- */ -+ /* Write CHANERRMSK_INT with 3E07h to mask out the errors -+ * that can cause stability issues for IOAT ver.3, and clear any -+ * pending errors -+ */ -+ pci_write_config_dword(pdev, IOAT_PCI_CHANERRMASK_INT_OFFSET, 0x3e07); -+ err = pci_read_config_dword(pdev, IOAT_PCI_CHANERR_INT_OFFSET, &chanerr); -+ if (err) { -+ dev_err(&pdev->dev, "channel error register unreachable\n"); -+ return err; -+ } -+ pci_write_config_dword(pdev, IOAT_PCI_CHANERR_INT_OFFSET, chanerr); -+ -+ /* Clear DMAUNCERRSTS Cfg-Reg Parity Error status bit -+ * (workaround for spurious config parity error after restart) -+ */ -+ pci_read_config_word(pdev, IOAT_PCI_DEVICE_ID_OFFSET, &dev_id); -+ if (dev_id == PCI_DEVICE_ID_INTEL_IOAT_TBG0) -+ pci_write_config_dword(pdev, IOAT_PCI_DMAUNCERRSTS_OFFSET, 0x10); -+ -+ return ioat2_reset_sync(chan, msecs_to_jiffies(200)); -+} -+ - int __devinit ioat3_dma_probe(struct ioatdma_device *device, int dca) - { - struct pci_dev *pdev = device->pdev; -@@ -1137,10 +1178,10 @@ int __devinit ioat3_dma_probe(struct ioatdma_device *device, int dca) - struct ioat_chan_common *chan; - bool is_raid_device = false; - int err; -- u16 dev_id; - u32 cap; - - device->enumerate_channels = ioat2_enumerate_channels; -+ device->reset_hw = ioat3_reset_hw; - device->self_test = ioat3_dma_self_test; - dma = &device->common; - dma->device_prep_dma_memcpy = ioat2_dma_prep_memcpy_lock; -@@ -1216,19 +1257,6 @@ int __devinit ioat3_dma_probe(struct ioatdma_device *device, int dca) - dma->device_prep_dma_xor_val = NULL; - #endif - -- /* -= IOAT ver.3 workarounds =- */ -- /* Write CHANERRMSK_INT with 3E07h to mask out the errors -- * that can cause stability issues for IOAT ver.3 -- */ -- pci_write_config_dword(pdev, IOAT_PCI_CHANERRMASK_INT_OFFSET, 0x3e07); -- -- /* Clear DMAUNCERRSTS Cfg-Reg Parity Error status bit -- * (workaround for spurious config parity error after restart) -- */ -- pci_read_config_word(pdev, IOAT_PCI_DEVICE_ID_OFFSET, &dev_id); -- if (dev_id == PCI_DEVICE_ID_INTEL_IOAT_TBG0) -- pci_write_config_dword(pdev, IOAT_PCI_DMAUNCERRSTS_OFFSET, 0x10); -- - err = ioat_probe(device); - if (err) - return err; -diff --git a/drivers/dma/ioat/registers.h b/drivers/dma/ioat/registers.h -index f015ec1..e8ae63b 100644 ---- a/drivers/dma/ioat/registers.h -+++ b/drivers/dma/ioat/registers.h -@@ -27,6 +27,7 @@ - - #define IOAT_PCI_DEVICE_ID_OFFSET 0x02 - #define IOAT_PCI_DMAUNCERRSTS_OFFSET 0x148 -+#define IOAT_PCI_CHANERR_INT_OFFSET 0x180 - #define IOAT_PCI_CHANERRMASK_INT_OFFSET 0x184 - - /* MMIO Device Registers */ -diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c -index a38831c..a0bcfba 100644 ---- a/drivers/edac/amd64_edac.c -+++ b/drivers/edac/amd64_edac.c -@@ -13,6 +13,8 @@ module_param(report_gart_errors, int, 0644); - static int ecc_enable_override; - module_param(ecc_enable_override, int, 0644); - -+static struct msr *msrs; -+ - /* Lookup table for all possible MC control instances */ - struct amd64_pvt; - static struct mem_ctl_info *mci_lookup[EDAC_MAX_NUMNODES]; -@@ -2618,6 +2620,90 @@ static int amd64_init_csrows(struct mem_ctl_info *mci) - return empty; - } - -+/* get all cores on this DCT */ -+static void get_cpus_on_this_dct_cpumask(struct cpumask *mask, int nid) -+{ -+ int cpu; -+ -+ for_each_online_cpu(cpu) -+ if (amd_get_nb_id(cpu) == nid) -+ cpumask_set_cpu(cpu, mask); -+} -+ -+/* check MCG_CTL on all the cpus on this node */ -+static bool amd64_nb_mce_bank_enabled_on_node(int nid) -+{ -+ cpumask_var_t mask; -+ int cpu, nbe; -+ bool ret = false; -+ -+ if (!zalloc_cpumask_var(&mask, GFP_KERNEL)) { -+ amd64_printk(KERN_WARNING, "%s: error allocating mask\n", -+ __func__); -+ return false; -+ } -+ -+ get_cpus_on_this_dct_cpumask(mask, nid); -+ -+ rdmsr_on_cpus(mask, MSR_IA32_MCG_CTL, msrs); -+ -+ for_each_cpu(cpu, mask) { -+ struct msr *reg = per_cpu_ptr(msrs, cpu); -+ nbe = reg->l & K8_MSR_MCGCTL_NBE; -+ -+ debugf0("core: %u, MCG_CTL: 0x%llx, NB MSR is %s\n", -+ cpu, reg->q, -+ (nbe ? "enabled" : "disabled")); -+ -+ if (!nbe) -+ goto out; -+ } -+ ret = true; -+ -+out: -+ free_cpumask_var(mask); -+ return ret; -+} -+ -+static int amd64_toggle_ecc_err_reporting(struct amd64_pvt *pvt, bool on) -+{ -+ cpumask_var_t cmask; -+ int cpu; -+ -+ if (!zalloc_cpumask_var(&cmask, GFP_KERNEL)) { -+ amd64_printk(KERN_WARNING, "%s: error allocating mask\n", -+ __func__); -+ return false; -+ } -+ -+ get_cpus_on_this_dct_cpumask(cmask, pvt->mc_node_id); -+ -+ rdmsr_on_cpus(cmask, MSR_IA32_MCG_CTL, msrs); -+ -+ for_each_cpu(cpu, cmask) { -+ -+ struct msr *reg = per_cpu_ptr(msrs, cpu); -+ -+ if (on) { -+ if (reg->l & K8_MSR_MCGCTL_NBE) -+ pvt->flags.ecc_report = 1; -+ -+ reg->l |= K8_MSR_MCGCTL_NBE; -+ } else { -+ /* -+ * Turn off ECC reporting only when it was off before -+ */ -+ if (!pvt->flags.ecc_report) -+ reg->l &= ~K8_MSR_MCGCTL_NBE; -+ } -+ } -+ wrmsr_on_cpus(cmask, MSR_IA32_MCG_CTL, msrs); -+ -+ free_cpumask_var(cmask); -+ -+ return 0; -+} -+ - /* - * Only if 'ecc_enable_override' is set AND BIOS had ECC disabled, do "we" - * enable it. -@@ -2625,17 +2711,12 @@ static int amd64_init_csrows(struct mem_ctl_info *mci) - static void amd64_enable_ecc_error_reporting(struct mem_ctl_info *mci) - { - struct amd64_pvt *pvt = mci->pvt_info; -- const cpumask_t *cpumask = cpumask_of_node(pvt->mc_node_id); -- int cpu, idx = 0, err = 0; -- struct msr msrs[cpumask_weight(cpumask)]; -- u32 value; -- u32 mask = K8_NBCTL_CECCEn | K8_NBCTL_UECCEn; -+ int err = 0; -+ u32 value, mask = K8_NBCTL_CECCEn | K8_NBCTL_UECCEn; - - if (!ecc_enable_override) - return; - -- memset(msrs, 0, sizeof(msrs)); -- - amd64_printk(KERN_WARNING, - "'ecc_enable_override' parameter is active, " - "Enabling AMD ECC hardware now: CAUTION\n"); -@@ -2651,16 +2732,9 @@ static void amd64_enable_ecc_error_reporting(struct mem_ctl_info *mci) - value |= mask; - pci_write_config_dword(pvt->misc_f3_ctl, K8_NBCTL, value); - -- rdmsr_on_cpus(cpumask, K8_MSR_MCGCTL, msrs); -- -- for_each_cpu(cpu, cpumask) { -- if (msrs[idx].l & K8_MSR_MCGCTL_NBE) -- set_bit(idx, &pvt->old_mcgctl); -- -- msrs[idx].l |= K8_MSR_MCGCTL_NBE; -- idx++; -- } -- wrmsr_on_cpus(cpumask, K8_MSR_MCGCTL, msrs); -+ if (amd64_toggle_ecc_err_reporting(pvt, ON)) -+ amd64_printk(KERN_WARNING, "Error enabling ECC reporting over " -+ "MCGCTL!\n"); - - err = pci_read_config_dword(pvt->misc_f3_ctl, K8_NBCFG, &value); - if (err) -@@ -2701,17 +2775,12 @@ static void amd64_enable_ecc_error_reporting(struct mem_ctl_info *mci) - - static void amd64_restore_ecc_error_reporting(struct amd64_pvt *pvt) - { -- const cpumask_t *cpumask = cpumask_of_node(pvt->mc_node_id); -- int cpu, idx = 0, err = 0; -- struct msr msrs[cpumask_weight(cpumask)]; -- u32 value; -- u32 mask = K8_NBCTL_CECCEn | K8_NBCTL_UECCEn; -+ int err = 0; -+ u32 value, mask = K8_NBCTL_CECCEn | K8_NBCTL_UECCEn; - - if (!pvt->nbctl_mcgctl_saved) - return; - -- memset(msrs, 0, sizeof(msrs)); -- - err = pci_read_config_dword(pvt->misc_f3_ctl, K8_NBCTL, &value); - if (err) - debugf0("Reading K8_NBCTL failed\n"); -@@ -2721,66 +2790,9 @@ static void amd64_restore_ecc_error_reporting(struct amd64_pvt *pvt) - /* restore the NB Enable MCGCTL bit */ - pci_write_config_dword(pvt->misc_f3_ctl, K8_NBCTL, value); - -- rdmsr_on_cpus(cpumask, K8_MSR_MCGCTL, msrs); -- -- for_each_cpu(cpu, cpumask) { -- msrs[idx].l &= ~K8_MSR_MCGCTL_NBE; -- msrs[idx].l |= -- test_bit(idx, &pvt->old_mcgctl) << K8_MSR_MCGCTL_NBE; -- idx++; -- } -- -- wrmsr_on_cpus(cpumask, K8_MSR_MCGCTL, msrs); --} -- --/* get all cores on this DCT */ --static void get_cpus_on_this_dct_cpumask(cpumask_t *mask, int nid) --{ -- int cpu; -- -- for_each_online_cpu(cpu) -- if (amd_get_nb_id(cpu) == nid) -- cpumask_set_cpu(cpu, mask); --} -- --/* check MCG_CTL on all the cpus on this node */ --static bool amd64_nb_mce_bank_enabled_on_node(int nid) --{ -- cpumask_t mask; -- struct msr *msrs; -- int cpu, nbe, idx = 0; -- bool ret = false; -- -- cpumask_clear(&mask); -- -- get_cpus_on_this_dct_cpumask(&mask, nid); -- -- msrs = kzalloc(sizeof(struct msr) * cpumask_weight(&mask), GFP_KERNEL); -- if (!msrs) { -- amd64_printk(KERN_WARNING, "%s: error allocating msrs\n", -- __func__); -- return false; -- } -- -- rdmsr_on_cpus(&mask, MSR_IA32_MCG_CTL, msrs); -- -- for_each_cpu(cpu, &mask) { -- nbe = msrs[idx].l & K8_MSR_MCGCTL_NBE; -- -- debugf0("core: %u, MCG_CTL: 0x%llx, NB MSR is %s\n", -- cpu, msrs[idx].q, -- (nbe ? "enabled" : "disabled")); -- -- if (!nbe) -- goto out; -- -- idx++; -- } -- ret = true; -- --out: -- kfree(msrs); -- return ret; -+ if (amd64_toggle_ecc_err_reporting(pvt, OFF)) -+ amd64_printk(KERN_WARNING, "Error restoring ECC reporting over " -+ "MCGCTL!\n"); - } - - /* -@@ -2824,9 +2836,8 @@ static int amd64_check_ecc_enabled(struct amd64_pvt *pvt) - amd64_printk(KERN_WARNING, "%s", ecc_warning); - return -ENODEV; - } -- } else -- /* CLEAR the override, since BIOS controlled it */ - ecc_enable_override = 0; -+ } - - return 0; - } -@@ -2909,7 +2920,6 @@ static int amd64_probe_one_instance(struct pci_dev *dram_f2_ctl, - pvt->ext_model = boot_cpu_data.x86_model >> 4; - pvt->mc_type_index = mc_type_index; - pvt->ops = family_ops(mc_type_index); -- pvt->old_mcgctl = 0; - - /* - * We have the dram_f2_ctl device as an argument, now go reserve its -@@ -3071,16 +3081,15 @@ static void __devexit amd64_remove_one_instance(struct pci_dev *pdev) - - amd64_free_mc_sibling_devices(pvt); - -- kfree(pvt); -- mci->pvt_info = NULL; -- -- mci_lookup[pvt->mc_node_id] = NULL; -- - /* unregister from EDAC MCE */ - amd_report_gart_errors(false); - amd_unregister_ecc_decoder(amd64_decode_bus_error); - - /* Free the EDAC CORE resources */ -+ mci->pvt_info = NULL; -+ mci_lookup[pvt->mc_node_id] = NULL; -+ -+ kfree(pvt); - edac_mc_free(mci); - } - -@@ -3157,23 +3166,29 @@ static void amd64_setup_pci_device(void) - static int __init amd64_edac_init(void) - { - int nb, err = -ENODEV; -+ bool load_ok = false; - - edac_printk(KERN_INFO, EDAC_MOD_STR, EDAC_AMD64_VERSION "\n"); - - opstate_init(); - - if (cache_k8_northbridges() < 0) -- return err; -+ goto err_ret; -+ -+ msrs = msrs_alloc(); -+ if (!msrs) -+ goto err_ret; - - err = pci_register_driver(&amd64_pci_driver); - if (err) -- return err; -+ goto err_pci; - - /* - * At this point, the array 'pvt_lookup[]' contains pointers to alloc'd - * amd64_pvt structs. These will be used in the 2nd stage init function - * to finish initialization of the MC instances. - */ -+ err = -ENODEV; - for (nb = 0; nb < num_k8_northbridges; nb++) { - if (!pvt_lookup[nb]) - continue; -@@ -3181,16 +3196,21 @@ static int __init amd64_edac_init(void) - err = amd64_init_2nd_stage(pvt_lookup[nb]); - if (err) - goto err_2nd_stage; -- } - -- amd64_setup_pci_device(); -+ load_ok = true; -+ } - -- return 0; -+ if (load_ok) { -+ amd64_setup_pci_device(); -+ return 0; -+ } - - err_2nd_stage: -- debugf0("2nd stage failed\n"); - pci_unregister_driver(&amd64_pci_driver); -- -+err_pci: -+ msrs_free(msrs); -+ msrs = NULL; -+err_ret: - return err; - } - -@@ -3200,6 +3220,9 @@ static void __exit amd64_edac_exit(void) - edac_pci_release_generic_ctl(amd64_ctl_pci); - - pci_unregister_driver(&amd64_pci_driver); -+ -+ msrs_free(msrs); -+ msrs = NULL; - } - - module_init(amd64_edac_init); -diff --git a/drivers/edac/amd64_edac.h b/drivers/edac/amd64_edac.h -index c6f359a..bba6c94 100644 ---- a/drivers/edac/amd64_edac.h -+++ b/drivers/edac/amd64_edac.h -@@ -147,6 +147,8 @@ - #define MAX_CS_COUNT 8 - #define DRAM_REG_COUNT 8 - -+#define ON true -+#define OFF false - - /* - * PCI-defined configuration space registers -@@ -386,10 +388,7 @@ enum { - #define K8_NBCAP_DUAL_NODE BIT(1) - #define K8_NBCAP_DCT_DUAL BIT(0) - --/* -- * MSR Regs -- */ --#define K8_MSR_MCGCTL 0x017b -+/* MSRs */ - #define K8_MSR_MCGCTL_NBE BIT(4) - - #define K8_MSR_MC4CTL 0x0410 -@@ -487,7 +486,6 @@ struct amd64_pvt { - /* Save old hw registers' values before we modified them */ - u32 nbctl_mcgctl_saved; /* When true, following 2 are valid */ - u32 old_nbctl; -- unsigned long old_mcgctl; /* per core on this node */ - - /* MC Type Index value: socket F vs Family 10h */ - u32 mc_type_index; -@@ -495,6 +493,7 @@ struct amd64_pvt { - /* misc settings */ - struct flags { - unsigned long cf8_extcfg:1; -+ unsigned long ecc_report:1; - } flags; - }; - -diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c -index bbfd110..afed886 100644 ---- a/drivers/gpu/drm/drm_crtc_helper.c -+++ b/drivers/gpu/drm/drm_crtc_helper.c -@@ -1020,6 +1020,9 @@ bool drm_helper_initial_config(struct drm_device *dev) - { - int count = 0; - -+ /* disable all the possible outputs/crtcs before entering KMS mode */ -+ drm_helper_disable_unused_functions(dev); -+ - drm_fb_helper_parse_command_line(dev); - - count = drm_helper_probe_connector_modes(dev, -diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c -index c6777cb..19f93f2 100644 ---- a/drivers/gpu/drm/radeon/atombios_crtc.c -+++ b/drivers/gpu/drm/radeon/atombios_crtc.c -@@ -249,13 +249,15 @@ void atombios_crtc_dpms(struct drm_crtc *crtc, int mode) - if (ASIC_IS_DCE3(rdev)) - atombios_enable_crtc_memreq(crtc, 1); - atombios_blank_crtc(crtc, 0); -- drm_vblank_post_modeset(dev, radeon_crtc->crtc_id); -+ if (rdev->family < CHIP_R600) -+ drm_vblank_post_modeset(dev, radeon_crtc->crtc_id); - radeon_crtc_load_lut(crtc); - break; - case DRM_MODE_DPMS_STANDBY: - case DRM_MODE_DPMS_SUSPEND: - case DRM_MODE_DPMS_OFF: -- drm_vblank_pre_modeset(dev, radeon_crtc->crtc_id); -+ if (rdev->family < CHIP_R600) -+ drm_vblank_pre_modeset(dev, radeon_crtc->crtc_id); - atombios_blank_crtc(crtc, 1); - if (ASIC_IS_DCE3(rdev)) - atombios_enable_crtc_memreq(crtc, 0); -diff --git a/drivers/gpu/drm/radeon/radeon_test.c b/drivers/gpu/drm/radeon/radeon_test.c -index f8a465d..c8942ca 100644 ---- a/drivers/gpu/drm/radeon/radeon_test.c -+++ b/drivers/gpu/drm/radeon/radeon_test.c -@@ -42,8 +42,8 @@ void radeon_test_moves(struct radeon_device *rdev) - /* Number of tests = - * (Total GTT - IB pool - writeback page - ring buffer) / test size - */ -- n = (rdev->mc.gtt_size - RADEON_IB_POOL_SIZE*64*1024 - RADEON_GPU_PAGE_SIZE - -- rdev->cp.ring_size) / size; -+ n = ((u32)(rdev->mc.gtt_size - RADEON_IB_POOL_SIZE*64*1024 - RADEON_GPU_PAGE_SIZE - -+ rdev->cp.ring_size)) / size; - - gtt_obj = kzalloc(n * sizeof(*gtt_obj), GFP_KERNEL); - if (!gtt_obj) { -diff --git a/drivers/hwmon/sht15.c b/drivers/hwmon/sht15.c -index ebe38b6..864a371 100644 ---- a/drivers/hwmon/sht15.c -+++ b/drivers/hwmon/sht15.c -@@ -305,7 +305,7 @@ static inline int sht15_calc_temp(struct sht15_data *data) - int d1 = 0; - int i; - -- for (i = 1; i < ARRAY_SIZE(temppoints) - 1; i++) -+ for (i = 1; i < ARRAY_SIZE(temppoints); i++) - /* Find pointer to interpolate */ - if (data->supply_uV > temppoints[i - 1].vdd) { - d1 = (data->supply_uV/1000 - temppoints[i - 1].vdd) -@@ -332,12 +332,12 @@ static inline int sht15_calc_humid(struct sht15_data *data) - - const int c1 = -4; - const int c2 = 40500; /* x 10 ^ -6 */ -- const int c3 = 2800; /* x10 ^ -9 */ -+ const int c3 = -2800; /* x10 ^ -9 */ - - RHlinear = c1*1000 - + c2 * data->val_humid/1000 - + (data->val_humid * data->val_humid * c3)/1000000; -- return (temp - 25000) * (10000 + 800 * data->val_humid) -+ return (temp - 25000) * (10000 + 80 * data->val_humid) - / 1000000 + RHlinear; - } - -diff --git a/drivers/lguest/segments.c b/drivers/lguest/segments.c -index 951c57b..ede4658 100644 ---- a/drivers/lguest/segments.c -+++ b/drivers/lguest/segments.c -@@ -179,8 +179,10 @@ void load_guest_gdt_entry(struct lg_cpu *cpu, u32 num, u32 lo, u32 hi) - * We assume the Guest has the same number of GDT entries as the - * Host, otherwise we'd have to dynamically allocate the Guest GDT. - */ -- if (num >= ARRAY_SIZE(cpu->arch.gdt)) -+ if (num >= ARRAY_SIZE(cpu->arch.gdt)) { - kill_guest(cpu, "too many gdt entries %i", num); -+ return; -+ } - - /* Set it up, then fix it. */ - cpu->arch.gdt[num].a = lo; -diff --git a/drivers/md/md.c b/drivers/md/md.c -index 02e4551..c6a6685 100644 ---- a/drivers/md/md.c -+++ b/drivers/md/md.c -@@ -282,7 +282,9 @@ static void mddev_put(mddev_t *mddev) - if (!atomic_dec_and_lock(&mddev->active, &all_mddevs_lock)) - return; - if (!mddev->raid_disks && list_empty(&mddev->disks) && -- !mddev->hold_active) { -+ mddev->ctime == 0 && !mddev->hold_active) { -+ /* Array is not configured at all, and not held active, -+ * so destroy it */ - list_del(&mddev->all_mddevs); - if (mddev->gendisk) { - /* we did a probe so need to clean up. -@@ -5071,6 +5073,10 @@ static int set_array_info(mddev_t * mddev, mdu_array_info_t *info) - mddev->minor_version = info->minor_version; - mddev->patch_version = info->patch_version; - mddev->persistent = !info->not_persistent; -+ /* ensure mddev_put doesn't delete this now that there -+ * is some minimal configuration. -+ */ -+ mddev->ctime = get_seconds(); - return 0; - } - mddev->major_version = MD_MAJOR_VERSION; -diff --git a/drivers/media/video/ov511.c b/drivers/media/video/ov511.c -index 0bc2cf5..2bed9e2 100644 ---- a/drivers/media/video/ov511.c -+++ b/drivers/media/video/ov511.c -@@ -5878,7 +5878,7 @@ ov51x_probe(struct usb_interface *intf, const struct usb_device_id *id) - goto error; - } - -- mutex_lock(&ov->lock); -+ mutex_unlock(&ov->lock); - - return 0; - -diff --git a/drivers/net/e100.c b/drivers/net/e100.c -index d269a68..0c53c92 100644 ---- a/drivers/net/e100.c -+++ b/drivers/net/e100.c -@@ -1817,6 +1817,7 @@ static int e100_alloc_cbs(struct nic *nic) - &nic->cbs_dma_addr); - if (!nic->cbs) - return -ENOMEM; -+ memset(nic->cbs, 0, count * sizeof(struct cb)); - - for (cb = nic->cbs, i = 0; i < count; cb++, i++) { - cb->next = (i + 1 < count) ? cb + 1 : nic->cbs; -@@ -1825,7 +1826,6 @@ static int e100_alloc_cbs(struct nic *nic) - cb->dma_addr = nic->cbs_dma_addr + i * sizeof(struct cb); - cb->link = cpu_to_le32(nic->cbs_dma_addr + - ((i+1) % count) * sizeof(struct cb)); -- cb->skb = NULL; - } - - nic->cb_to_use = nic->cb_to_send = nic->cb_to_clean = nic->cbs; -diff --git a/drivers/net/usb/rtl8150.c b/drivers/net/usb/rtl8150.c -index b091e20..f14d225 100644 ---- a/drivers/net/usb/rtl8150.c -+++ b/drivers/net/usb/rtl8150.c -@@ -324,7 +324,7 @@ static int rtl8150_set_mac_address(struct net_device *netdev, void *p) - dbg("%02X:", netdev->dev_addr[i]); - dbg("%02X\n", netdev->dev_addr[i]); - /* Set the IDR registers. */ -- set_registers(dev, IDR, sizeof(netdev->dev_addr), netdev->dev_addr); -+ set_registers(dev, IDR, netdev->addr_len, netdev->dev_addr); - #ifdef EEPROM_WRITE - { - u8 cr; -diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c -index 95a8e23..8a82c75 100644 ---- a/drivers/net/wireless/ath/ath5k/base.c -+++ b/drivers/net/wireless/ath/ath5k/base.c -@@ -2349,6 +2349,9 @@ ath5k_init(struct ath5k_softc *sc) - */ - ath5k_stop_locked(sc); - -+ /* Set PHY calibration interval */ -+ ah->ah_cal_intval = ath5k_calinterval; -+ - /* - * The basic interface to setting the hardware in a good - * state is ``reset''. On return the hardware is known to -@@ -2376,10 +2379,6 @@ ath5k_init(struct ath5k_softc *sc) - - /* Set ack to be sent at low bit-rates */ - ath5k_hw_set_ack_bitrate_high(ah, false); -- -- /* Set PHY calibration inteval */ -- ah->ah_cal_intval = ath5k_calinterval; -- - ret = 0; - done: - mmiowb(); -diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h -index 57f1463..ff4383b 100644 ---- a/drivers/net/wireless/ath/ath9k/hw.h -+++ b/drivers/net/wireless/ath/ath9k/hw.h -@@ -408,7 +408,7 @@ struct ath9k_hw_version { - * Using de Bruijin sequence to to look up 1's index in a 32 bit number - * debruijn32 = 0000 0111 0111 1100 1011 0101 0011 0001 - */ --#define debruijn32 0x077CB531UL -+#define debruijn32 0x077CB531U - - struct ath_gen_timer_configuration { - u32 next_addr; -diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c -index d4d9d82..110c16d 100644 ---- a/drivers/net/wireless/ath/ath9k/mac.c -+++ b/drivers/net/wireless/ath/ath9k/mac.c -@@ -155,7 +155,7 @@ bool ath9k_hw_stoptxdma(struct ath_hw *ah, u32 q) - wait = wait_time; - while (ath9k_hw_numtxpending(ah, q)) { - if ((--wait) == 0) { -- DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, -+ DPRINTF(ah->ah_sc, ATH_DBG_FATAL, - "Failed to stop TX DMA in 100 " - "msec after killing last frame\n"); - break; -diff --git a/drivers/net/wireless/ath/ath9k/mac.h b/drivers/net/wireless/ath/ath9k/mac.h -index ff65f85..9720c4d 100644 ---- a/drivers/net/wireless/ath/ath9k/mac.h -+++ b/drivers/net/wireless/ath/ath9k/mac.h -@@ -77,6 +77,9 @@ - #define ATH9K_TXERR_XTXOP 0x08 - #define ATH9K_TXERR_TIMER_EXPIRED 0x10 - #define ATH9K_TX_ACKED 0x20 -+#define ATH9K_TXERR_MASK \ -+ (ATH9K_TXERR_XRETRY | ATH9K_TXERR_FILT | ATH9K_TXERR_FIFO | \ -+ ATH9K_TXERR_XTXOP | ATH9K_TXERR_TIMER_EXPIRED) - - #define ATH9K_TX_BA 0x01 - #define ATH9K_TX_PWRMGMT 0x02 -diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c -index 59359e3..80df8f3 100644 ---- a/drivers/net/wireless/ath/ath9k/main.c -+++ b/drivers/net/wireless/ath/ath9k/main.c -@@ -2147,6 +2147,9 @@ static void ath9k_stop(struct ieee80211_hw *hw) - return; /* another wiphy still in use */ - } - -+ /* Ensure HW is awake when we try to shut it down. */ -+ ath9k_ps_wakeup(sc); -+ - if (sc->sc_flags & SC_OP_BTCOEX_ENABLED) { - ath9k_hw_btcoex_disable(sc->sc_ah); - if (sc->btcoex_info.btcoex_scheme == ATH_BTCOEX_CFG_3WIRE) -@@ -2167,6 +2170,9 @@ static void ath9k_stop(struct ieee80211_hw *hw) - /* disable HAL and put h/w to sleep */ - ath9k_hw_disable(sc->sc_ah); - ath9k_hw_configpcipowersave(sc->sc_ah, 1, 1); -+ ath9k_ps_restore(sc); -+ -+ /* Finally, put the chip in FULL SLEEP mode */ - ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_FULL_SLEEP); - - sc->sc_flags |= SC_OP_INVALID; -@@ -2277,8 +2283,10 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw, - if ((sc->sc_ah->opmode == NL80211_IFTYPE_AP) || - (sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC) || - (sc->sc_ah->opmode == NL80211_IFTYPE_MESH_POINT)) { -+ ath9k_ps_wakeup(sc); - ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq); - ath_beacon_return(sc, avp); -+ ath9k_ps_restore(sc); - } - - sc->sc_flags &= ~SC_OP_BEACONS; -@@ -2724,15 +2732,21 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw, - case IEEE80211_AMPDU_RX_STOP: - break; - case IEEE80211_AMPDU_TX_START: -+ ath9k_ps_wakeup(sc); - ath_tx_aggr_start(sc, sta, tid, ssn); - ieee80211_start_tx_ba_cb_irqsafe(hw, sta->addr, tid); -+ ath9k_ps_restore(sc); - break; - case IEEE80211_AMPDU_TX_STOP: -+ ath9k_ps_wakeup(sc); - ath_tx_aggr_stop(sc, sta, tid); - ieee80211_stop_tx_ba_cb_irqsafe(hw, sta->addr, tid); -+ ath9k_ps_restore(sc); - break; - case IEEE80211_AMPDU_TX_OPERATIONAL: -+ ath9k_ps_wakeup(sc); - ath_tx_aggr_resume(sc, sta, tid); -+ ath9k_ps_restore(sc); - break; - default: - DPRINTF(sc, ATH_DBG_FATAL, "Unknown AMPDU action\n"); -diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h -index d83b77f..c0d7e65 100644 ---- a/drivers/net/wireless/ath/ath9k/reg.h -+++ b/drivers/net/wireless/ath/ath9k/reg.h -@@ -969,10 +969,10 @@ enum { - #define AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_S 4 - #define AR_GPIO_INPUT_EN_VAL_RFSILENT_DEF 0x00000080 - #define AR_GPIO_INPUT_EN_VAL_RFSILENT_DEF_S 7 -+#define AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_BB 0x00000400 -+#define AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_BB_S 10 - #define AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB 0x00001000 - #define AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB_S 12 --#define AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_BB 0x00001000 --#define AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_BB_S 1 - #define AR_GPIO_INPUT_EN_VAL_RFSILENT_BB 0x00008000 - #define AR_GPIO_INPUT_EN_VAL_RFSILENT_BB_S 15 - #define AR_GPIO_RTC_RESET_OVERRIDE_ENABLE 0x00010000 -diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c -index 4753909..2c6b063 100644 ---- a/drivers/net/wireless/ath/ath9k/xmit.c -+++ b/drivers/net/wireless/ath/ath9k/xmit.c -@@ -1076,10 +1076,10 @@ void ath_drain_all_txq(struct ath_softc *sc, bool retry_tx) - if (npend) { - int r; - -- DPRINTF(sc, ATH_DBG_XMIT, "Unable to stop TxDMA. Reset HAL!\n"); -+ DPRINTF(sc, ATH_DBG_FATAL, "Unable to stop TxDMA. Reset HAL!\n"); - - spin_lock_bh(&sc->sc_resetlock); -- r = ath9k_hw_reset(ah, sc->sc_ah->curchan, true); -+ r = ath9k_hw_reset(ah, sc->sc_ah->curchan, false); - if (r) - DPRINTF(sc, ATH_DBG_FATAL, - "Unable to reset hardware; reset status %d\n", -@@ -2020,7 +2020,7 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) - if (bf_isaggr(bf)) - txq->axq_aggr_depth--; - -- txok = !(ds->ds_txstat.ts_status & ATH9K_TXERR_FILT); -+ txok = !(ds->ds_txstat.ts_status & ATH9K_TXERR_MASK); - txq->axq_tx_inprogress = false; - spin_unlock_bh(&txq->axq_lock); - -diff --git a/drivers/net/wireless/b43/rfkill.c b/drivers/net/wireless/b43/rfkill.c -index ffdce6f..78016ae 100644 ---- a/drivers/net/wireless/b43/rfkill.c -+++ b/drivers/net/wireless/b43/rfkill.c -@@ -33,8 +33,14 @@ bool b43_is_hw_radio_enabled(struct b43_wldev *dev) - & B43_MMIO_RADIO_HWENABLED_HI_MASK)) - return 1; - } else { -- if (b43_status(dev) >= B43_STAT_STARTED && -- b43_read16(dev, B43_MMIO_RADIO_HWENABLED_LO) -+ /* To prevent CPU fault on PPC, do not read a register -+ * unless the interface is started; however, on resume -+ * for hibernation, this routine is entered early. When -+ * that happens, unconditionally return TRUE. -+ */ -+ if (b43_status(dev) < B43_STAT_STARTED) -+ return 1; -+ if (b43_read16(dev, B43_MMIO_RADIO_HWENABLED_LO) - & B43_MMIO_RADIO_HWENABLED_LO_MASK) - return 1; - } -diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c -index f059b49..9d60f6c 100644 ---- a/drivers/net/wireless/iwlwifi/iwl-3945.c -+++ b/drivers/net/wireless/iwlwifi/iwl-3945.c -@@ -2895,6 +2895,7 @@ static struct iwl_cfg iwl3945_bg_cfg = { - .mod_params = &iwl3945_mod_params, - .use_isr_legacy = true, - .ht_greenfield_support = false, -+ .broken_powersave = true, - }; - - static struct iwl_cfg iwl3945_abg_cfg = { -@@ -2909,6 +2910,7 @@ static struct iwl_cfg iwl3945_abg_cfg = { - .mod_params = &iwl3945_mod_params, - .use_isr_legacy = true, - .ht_greenfield_support = false, -+ .broken_powersave = true, - }; - - struct pci_device_id iwl3945_hw_card_ids[] = { -diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c -index 6f703a0..f4e2e84 100644 ---- a/drivers/net/wireless/iwlwifi/iwl-4965.c -+++ b/drivers/net/wireless/iwlwifi/iwl-4965.c -@@ -1337,7 +1337,7 @@ static int iwl4965_fill_txpower_tbl(struct iwl_priv *priv, u8 band, u16 channel, - iwl4965_interpolate_chan(priv, channel, &ch_eeprom_info); - - /* calculate tx gain adjustment based on power supply voltage */ -- voltage = priv->calib_info->voltage; -+ voltage = le16_to_cpu(priv->calib_info->voltage); - init_voltage = (s32)le32_to_cpu(priv->card_alive_init.voltage); - voltage_compensation = - iwl4965_get_voltage_compensation(voltage, init_voltage); -diff --git a/drivers/net/wireless/iwlwifi/iwl-5000-hw.h b/drivers/net/wireless/iwlwifi/iwl-5000-hw.h -index 4ef6804..bc056e9 100644 ---- a/drivers/net/wireless/iwlwifi/iwl-5000-hw.h -+++ b/drivers/net/wireless/iwlwifi/iwl-5000-hw.h -@@ -92,11 +92,15 @@ - - static inline s32 iwl_temp_calib_to_offset(struct iwl_priv *priv) - { -- u16 *temp_calib = (u16 *)iwl_eeprom_query_addr(priv, -- EEPROM_5000_TEMPERATURE); -- /* offset = temperature - voltage / coef */ -- s32 offset = (s32)(temp_calib[0] - temp_calib[1] / IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF); -- return offset; -+ u16 temperature, voltage; -+ __le16 *temp_calib = -+ (__le16 *)iwl_eeprom_query_addr(priv, EEPROM_5000_TEMPERATURE); -+ -+ temperature = le16_to_cpu(temp_calib[0]); -+ voltage = le16_to_cpu(temp_calib[1]); -+ -+ /* offset = temp - volt / coeff */ -+ return (s32)(temperature - voltage / IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF); - } - - /* Fixed (non-configurable) rx data from phy */ -diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c -index 6e6f516..94a1225 100644 ---- a/drivers/net/wireless/iwlwifi/iwl-5000.c -+++ b/drivers/net/wireless/iwlwifi/iwl-5000.c -@@ -460,14 +460,15 @@ static void iwl5000_set_ct_threshold(struct iwl_priv *priv) - static int iwl5000_set_Xtal_calib(struct iwl_priv *priv) - { - struct iwl_calib_xtal_freq_cmd cmd; -- u16 *xtal_calib = (u16 *)iwl_eeprom_query_addr(priv, EEPROM_5000_XTAL); -+ __le16 *xtal_calib = -+ (__le16 *)iwl_eeprom_query_addr(priv, EEPROM_5000_XTAL); - - cmd.hdr.op_code = IWL_PHY_CALIBRATE_CRYSTAL_FRQ_CMD; - cmd.hdr.first_group = 0; - cmd.hdr.groups_num = 1; - cmd.hdr.data_valid = 1; -- cmd.cap_pin1 = (u8)xtal_calib[0]; -- cmd.cap_pin2 = (u8)xtal_calib[1]; -+ cmd.cap_pin1 = le16_to_cpu(xtal_calib[0]); -+ cmd.cap_pin2 = le16_to_cpu(xtal_calib[1]); - return iwl_calib_set(&priv->calib_results[IWL_CALIB_XTAL], - (u8 *)&cmd, sizeof(cmd)); - } -diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h -index 028d505..c2d9b7a 100644 ---- a/drivers/net/wireless/iwlwifi/iwl-dev.h -+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h -@@ -1149,7 +1149,7 @@ struct iwl_priv { - u32 last_beacon_time; - u64 last_tsf; - -- /* eeprom */ -+ /* eeprom -- this is in the card's little endian byte order */ - u8 *eeprom; - int nvm_device_type; - struct iwl_eeprom_calib_info *calib_info; -diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c -index e14c995..18dc3a4 100644 ---- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c -+++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c -@@ -337,7 +337,7 @@ static int iwl_init_otp_access(struct iwl_priv *priv) - return ret; - } - --static int iwl_read_otp_word(struct iwl_priv *priv, u16 addr, u16 *eeprom_data) -+static int iwl_read_otp_word(struct iwl_priv *priv, u16 addr, __le16 *eeprom_data) - { - int ret = 0; - u32 r; -@@ -370,7 +370,7 @@ static int iwl_read_otp_word(struct iwl_priv *priv, u16 addr, u16 *eeprom_data) - CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK); - IWL_ERR(priv, "Correctable OTP ECC error, continue read\n"); - } -- *eeprom_data = le16_to_cpu((__force __le16)(r >> 16)); -+ *eeprom_data = cpu_to_le16(r >> 16); - return 0; - } - -@@ -379,7 +379,8 @@ static int iwl_read_otp_word(struct iwl_priv *priv, u16 addr, u16 *eeprom_data) - */ - static bool iwl_is_otp_empty(struct iwl_priv *priv) - { -- u16 next_link_addr = 0, link_value; -+ u16 next_link_addr = 0; -+ __le16 link_value; - bool is_empty = false; - - /* locate the beginning of OTP link list */ -@@ -409,7 +410,8 @@ static bool iwl_is_otp_empty(struct iwl_priv *priv) - static int iwl_find_otp_image(struct iwl_priv *priv, - u16 *validblockaddr) - { -- u16 next_link_addr = 0, link_value = 0, valid_addr; -+ u16 next_link_addr = 0, valid_addr; -+ __le16 link_value = 0; - int usedblocks = 0; - - /* set addressing mode to absolute to traverse the link list */ -@@ -429,7 +431,7 @@ static int iwl_find_otp_image(struct iwl_priv *priv, - * check for more block on the link list - */ - valid_addr = next_link_addr; -- next_link_addr = link_value * sizeof(u16); -+ next_link_addr = le16_to_cpu(link_value) * sizeof(u16); - IWL_DEBUG_INFO(priv, "OTP blocks %d addr 0x%x\n", - usedblocks, next_link_addr); - if (iwl_read_otp_word(priv, next_link_addr, &link_value)) -@@ -463,7 +465,7 @@ static int iwl_find_otp_image(struct iwl_priv *priv, - */ - int iwl_eeprom_init(struct iwl_priv *priv) - { -- u16 *e; -+ __le16 *e; - u32 gp = iwl_read32(priv, CSR_EEPROM_GP); - int sz; - int ret; -@@ -482,7 +484,7 @@ int iwl_eeprom_init(struct iwl_priv *priv) - ret = -ENOMEM; - goto alloc_err; - } -- e = (u16 *)priv->eeprom; -+ e = (__le16 *)priv->eeprom; - - ret = priv->cfg->ops->lib->eeprom_ops.verify_signature(priv); - if (ret < 0) { -@@ -521,7 +523,7 @@ int iwl_eeprom_init(struct iwl_priv *priv) - } - for (addr = validblockaddr; addr < validblockaddr + sz; - addr += sizeof(u16)) { -- u16 eeprom_data; -+ __le16 eeprom_data; - - ret = iwl_read_otp_word(priv, addr, &eeprom_data); - if (ret) -@@ -545,7 +547,7 @@ int iwl_eeprom_init(struct iwl_priv *priv) - goto done; - } - r = _iwl_read_direct32(priv, CSR_EEPROM_REG); -- e[addr / 2] = le16_to_cpu((__force __le16)(r >> 16)); -+ e[addr / 2] = cpu_to_le16(r >> 16); - } - } - ret = 0; -@@ -709,7 +711,8 @@ static int iwl_mod_ht40_chan_info(struct iwl_priv *priv, - ch_info->ht40_min_power = 0; - ch_info->ht40_scan_power = eeprom_ch->max_power_avg; - ch_info->ht40_flags = eeprom_ch->flags; -- ch_info->ht40_extension_channel &= ~clear_ht40_extension_channel; -+ if (eeprom_ch->flags & EEPROM_CHANNEL_VALID) -+ ch_info->ht40_extension_channel &= ~clear_ht40_extension_channel; - - return 0; - } -diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h -index 80b9e45..fc93f12 100644 ---- a/drivers/net/wireless/iwlwifi/iwl-eeprom.h -+++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h -@@ -133,7 +133,7 @@ struct iwl_eeprom_channel { - * - */ - struct iwl_eeprom_enhanced_txpwr { -- u16 reserved; -+ __le16 common; - s8 chain_a_max; - s8 chain_b_max; - s8 chain_c_max; -@@ -347,7 +347,7 @@ struct iwl_eeprom_calib_subband_info { - struct iwl_eeprom_calib_info { - u8 saturation_power24; /* half-dBm (e.g. "34" = 17 dBm) */ - u8 saturation_power52; /* half-dBm */ -- s16 voltage; /* signed */ -+ __le16 voltage; /* signed */ - struct iwl_eeprom_calib_subband_info - band_info[EEPROM_TX_POWER_BANDS]; - } __attribute__ ((packed)); -diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c -index d00a803..5f26c93 100644 ---- a/drivers/net/wireless/iwlwifi/iwl3945-base.c -+++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c -@@ -562,6 +562,9 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) - txq = &priv->txq[txq_id]; - q = &txq->q; - -+ if ((iwl_queue_space(q) < q->high_mark)) -+ goto drop; -+ - spin_lock_irqsave(&priv->lock, flags); - - idx = get_cmd_index(q, q->write_ptr, 0); -@@ -3854,9 +3857,11 @@ static int iwl3945_setup_mac(struct iwl_priv *priv) - /* Tell mac80211 our characteristics */ - hw->flags = IEEE80211_HW_SIGNAL_DBM | - IEEE80211_HW_NOISE_DBM | -- IEEE80211_HW_SPECTRUM_MGMT | -- IEEE80211_HW_SUPPORTS_PS | -- IEEE80211_HW_SUPPORTS_DYNAMIC_PS; -+ IEEE80211_HW_SPECTRUM_MGMT; -+ -+ if (!priv->cfg->broken_powersave) -+ hw->flags |= IEEE80211_HW_SUPPORTS_PS | -+ IEEE80211_HW_SUPPORTS_DYNAMIC_PS; - - hw->wiphy->interface_modes = - BIT(NL80211_IFTYPE_STATION) | -diff --git a/drivers/net/wireless/iwmc3200wifi/iwm.h b/drivers/net/wireless/iwmc3200wifi/iwm.h -index 1b02a4e..93c8989 100644 ---- a/drivers/net/wireless/iwmc3200wifi/iwm.h -+++ b/drivers/net/wireless/iwmc3200wifi/iwm.h -@@ -258,7 +258,7 @@ struct iwm_priv { - - struct sk_buff_head rx_list; - struct list_head rx_tickets; -- struct list_head rx_packets[IWM_RX_ID_HASH]; -+ struct list_head rx_packets[IWM_RX_ID_HASH + 1]; - struct workqueue_struct *rx_wq; - struct work_struct rx_worker; - -diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c -index be837a0..01c738b 100644 ---- a/drivers/net/wireless/libertas/wext.c -+++ b/drivers/net/wireless/libertas/wext.c -@@ -1953,10 +1953,8 @@ static int lbs_get_essid(struct net_device *dev, struct iw_request_info *info, - if (priv->connect_status == LBS_CONNECTED) { - memcpy(extra, priv->curbssparams.ssid, - priv->curbssparams.ssid_len); -- extra[priv->curbssparams.ssid_len] = '\0'; - } else { - memset(extra, 0, 32); -- extra[priv->curbssparams.ssid_len] = '\0'; - } - /* - * If none, we may want to get the one that was set -diff --git a/drivers/net/wireless/orinoco/wext.c b/drivers/net/wireless/orinoco/wext.c -index 7698fdd..31ca241 100644 ---- a/drivers/net/wireless/orinoco/wext.c -+++ b/drivers/net/wireless/orinoco/wext.c -@@ -23,7 +23,7 @@ - #define MAX_RID_LEN 1024 - - /* Helper routine to record keys -- * Do not call from interrupt context */ -+ * It is called under orinoco_lock so it may not sleep */ - static int orinoco_set_key(struct orinoco_private *priv, int index, - enum orinoco_alg alg, const u8 *key, int key_len, - const u8 *seq, int seq_len) -@@ -32,14 +32,14 @@ static int orinoco_set_key(struct orinoco_private *priv, int index, - kzfree(priv->keys[index].seq); - - if (key_len) { -- priv->keys[index].key = kzalloc(key_len, GFP_KERNEL); -+ priv->keys[index].key = kzalloc(key_len, GFP_ATOMIC); - if (!priv->keys[index].key) - goto nomem; - } else - priv->keys[index].key = NULL; - - if (seq_len) { -- priv->keys[index].seq = kzalloc(seq_len, GFP_KERNEL); -+ priv->keys[index].seq = kzalloc(seq_len, GFP_ATOMIC); - if (!priv->keys[index].seq) - goto free_key; - } else -diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c -index b20e3ea..9a6ceb4 100644 ---- a/drivers/net/wireless/rt2x00/rt61pci.c -+++ b/drivers/net/wireless/rt2x00/rt61pci.c -@@ -2538,6 +2538,11 @@ static int rt61pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) - unsigned int i; - - /* -+ * Disable powersaving as default. -+ */ -+ rt2x00dev->hw->wiphy->ps_default = false; -+ -+ /* - * Initialize all hw fields. - */ - rt2x00dev->hw->flags = -diff --git a/drivers/platform/x86/acerhdf.c b/drivers/platform/x86/acerhdf.c -index d8b4229..4d922e4 100644 ---- a/drivers/platform/x86/acerhdf.c -+++ b/drivers/platform/x86/acerhdf.c -@@ -640,9 +640,10 @@ static void __exit acerhdf_exit(void) - MODULE_LICENSE("GPL"); - MODULE_AUTHOR("Peter Feuerer"); - MODULE_DESCRIPTION("Aspire One temperature and fan driver"); --MODULE_ALIAS("dmi:*:*Acer*:*:"); --MODULE_ALIAS("dmi:*:*Gateway*:*:"); --MODULE_ALIAS("dmi:*:*Packard Bell*:*:"); -+MODULE_ALIAS("dmi:*:*Acer*:pnAOA*:"); -+MODULE_ALIAS("dmi:*:*Gateway*:pnAOA*:"); -+MODULE_ALIAS("dmi:*:*Packard Bell*:pnAOA*:"); -+MODULE_ALIAS("dmi:*:*Packard Bell*:pnDOA*:"); - - module_init(acerhdf_init); - module_exit(acerhdf_exit); -diff --git a/drivers/s390/block/dasd_diag.c b/drivers/s390/block/dasd_diag.c -index 4e49b4a..8174ec9 100644 ---- a/drivers/s390/block/dasd_diag.c -+++ b/drivers/s390/block/dasd_diag.c -@@ -145,6 +145,15 @@ dasd_diag_erp(struct dasd_device *device) - - mdsk_term_io(device); - rc = mdsk_init_io(device, device->block->bp_block, 0, NULL); -+ if (rc == 4) { -+ if (!(device->features & DASD_FEATURE_READONLY)) { -+ dev_warn(&device->cdev->dev, -+ "The access mode of a DIAG device changed" -+ " to read-only"); -+ device->features |= DASD_FEATURE_READONLY; -+ } -+ rc = 0; -+ } - if (rc) - dev_warn(&device->cdev->dev, "DIAG ERP failed with " - "rc=%d\n", rc); -@@ -433,16 +442,20 @@ dasd_diag_check_device(struct dasd_device *device) - for (sb = 512; sb < bsize; sb = sb << 1) - block->s2b_shift++; - rc = mdsk_init_io(device, block->bp_block, 0, NULL); -- if (rc) { -+ if (rc && (rc != 4)) { - dev_warn(&device->cdev->dev, "DIAG initialization " - "failed with rc=%d\n", rc); - rc = -EIO; - } else { -+ if (rc == 4) -+ device->features |= DASD_FEATURE_READONLY; - dev_info(&device->cdev->dev, -- "New DASD with %ld byte/block, total size %ld KB\n", -+ "New DASD with %ld byte/block, total size %ld KB%s\n", - (unsigned long) block->bp_block, - (unsigned long) (block->blocks << -- block->s2b_shift) >> 1); -+ block->s2b_shift) >> 1, -+ (rc == 4) ? ", read-only device" : ""); -+ rc = 0; - } - out_label: - free_page((long) label); -diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c -index 76d294f..c3ff9a6 100644 ---- a/drivers/scsi/ipr.c -+++ b/drivers/scsi/ipr.c -@@ -6516,6 +6516,7 @@ static int ipr_reset_restore_cfg_space(struct ipr_cmnd *ipr_cmd) - int rc; - - ENTER; -+ ioa_cfg->pdev->state_saved = true; - rc = pci_restore_state(ioa_cfg->pdev); - - if (rc != PCIBIOS_SUCCESSFUL) { -diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c -index b79fca7..06bbe0d 100644 ---- a/drivers/scsi/qla2xxx/qla_os.c -+++ b/drivers/scsi/qla2xxx/qla_os.c -@@ -2016,13 +2016,13 @@ skip_dpc: - DEBUG2(printk("DEBUG: detect hba %ld at address = %p\n", - base_vha->host_no, ha)); - -- base_vha->flags.init_done = 1; -- base_vha->flags.online = 1; -- - ret = scsi_add_host(host, &pdev->dev); - if (ret) - goto probe_failed; - -+ base_vha->flags.init_done = 1; -+ base_vha->flags.online = 1; -+ - ha->isp_ops->enable_intrs(ha); - - scsi_scan_host(host); -diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c -index c6f70da..45be82f 100644 ---- a/drivers/scsi/scsi_transport_fc.c -+++ b/drivers/scsi/scsi_transport_fc.c -@@ -648,11 +648,22 @@ static __init int fc_transport_init(void) - return error; - error = transport_class_register(&fc_vport_class); - if (error) -- return error; -+ goto unreg_host_class; - error = transport_class_register(&fc_rport_class); - if (error) -- return error; -- return transport_class_register(&fc_transport_class); -+ goto unreg_vport_class; -+ error = transport_class_register(&fc_transport_class); -+ if (error) -+ goto unreg_rport_class; -+ return 0; -+ -+unreg_rport_class: -+ transport_class_unregister(&fc_rport_class); -+unreg_vport_class: -+ transport_class_unregister(&fc_vport_class); -+unreg_host_class: -+ transport_class_unregister(&fc_host_class); -+ return error; - } - - static void __exit fc_transport_exit(void) -diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c -index 12d58a7..5081f97 100644 ---- a/drivers/scsi/st.c -+++ b/drivers/scsi/st.c -@@ -552,13 +552,15 @@ st_do_scsi(struct st_request * SRpnt, struct scsi_tape * STp, unsigned char *cmd - SRpnt->waiting = waiting; - - if (STp->buffer->do_dio) { -+ mdata->page_order = 0; - mdata->nr_entries = STp->buffer->sg_segs; - mdata->pages = STp->buffer->mapped_pages; - } else { -+ mdata->page_order = STp->buffer->reserved_page_order; - mdata->nr_entries = - DIV_ROUND_UP(bytes, PAGE_SIZE << mdata->page_order); -- STp->buffer->map_data.pages = STp->buffer->reserved_pages; -- STp->buffer->map_data.offset = 0; -+ mdata->pages = STp->buffer->reserved_pages; -+ mdata->offset = 0; - } - - memcpy(SRpnt->cmd, cmd, sizeof(SRpnt->cmd)); -@@ -3718,7 +3720,7 @@ static int enlarge_buffer(struct st_buffer * STbuffer, int new_size, int need_dm - priority |= __GFP_ZERO; - - if (STbuffer->frp_segs) { -- order = STbuffer->map_data.page_order; -+ order = STbuffer->reserved_page_order; - b_size = PAGE_SIZE << order; - } else { - for (b_size = PAGE_SIZE, order = 0; -@@ -3751,7 +3753,7 @@ static int enlarge_buffer(struct st_buffer * STbuffer, int new_size, int need_dm - segs++; - } - STbuffer->b_data = page_address(STbuffer->reserved_pages[0]); -- STbuffer->map_data.page_order = order; -+ STbuffer->reserved_page_order = order; - - return 1; - } -@@ -3764,7 +3766,7 @@ static void clear_buffer(struct st_buffer * st_bp) - - for (i=0; i < st_bp->frp_segs; i++) - memset(page_address(st_bp->reserved_pages[i]), 0, -- PAGE_SIZE << st_bp->map_data.page_order); -+ PAGE_SIZE << st_bp->reserved_page_order); - st_bp->cleared = 1; - } - -@@ -3772,7 +3774,7 @@ static void clear_buffer(struct st_buffer * st_bp) - /* Release the extra buffer */ - static void normalize_buffer(struct st_buffer * STbuffer) - { -- int i, order = STbuffer->map_data.page_order; -+ int i, order = STbuffer->reserved_page_order; - - for (i = 0; i < STbuffer->frp_segs; i++) { - __free_pages(STbuffer->reserved_pages[i], order); -@@ -3780,7 +3782,7 @@ static void normalize_buffer(struct st_buffer * STbuffer) - } - STbuffer->frp_segs = 0; - STbuffer->sg_segs = 0; -- STbuffer->map_data.page_order = 0; -+ STbuffer->reserved_page_order = 0; - STbuffer->map_data.offset = 0; - } - -@@ -3790,7 +3792,7 @@ static void normalize_buffer(struct st_buffer * STbuffer) - static int append_to_buffer(const char __user *ubp, struct st_buffer * st_bp, int do_count) - { - int i, cnt, res, offset; -- int length = PAGE_SIZE << st_bp->map_data.page_order; -+ int length = PAGE_SIZE << st_bp->reserved_page_order; - - for (i = 0, offset = st_bp->buffer_bytes; - i < st_bp->frp_segs && offset >= length; i++) -@@ -3822,7 +3824,7 @@ static int append_to_buffer(const char __user *ubp, struct st_buffer * st_bp, in - static int from_buffer(struct st_buffer * st_bp, char __user *ubp, int do_count) - { - int i, cnt, res, offset; -- int length = PAGE_SIZE << st_bp->map_data.page_order; -+ int length = PAGE_SIZE << st_bp->reserved_page_order; - - for (i = 0, offset = st_bp->read_pointer; - i < st_bp->frp_segs && offset >= length; i++) -@@ -3855,7 +3857,7 @@ static void move_buffer_data(struct st_buffer * st_bp, int offset) - { - int src_seg, dst_seg, src_offset = 0, dst_offset; - int count, total; -- int length = PAGE_SIZE << st_bp->map_data.page_order; -+ int length = PAGE_SIZE << st_bp->reserved_page_order; - - if (offset == 0) - return; -@@ -4577,7 +4579,6 @@ static int sgl_map_user_pages(struct st_buffer *STbp, - } - - mdata->offset = uaddr & ~PAGE_MASK; -- mdata->page_order = 0; - STbp->mapped_pages = pages; - - return nr_pages; -diff --git a/drivers/scsi/st.h b/drivers/scsi/st.h -index 544dc6b..f91a67c 100644 ---- a/drivers/scsi/st.h -+++ b/drivers/scsi/st.h -@@ -46,6 +46,7 @@ struct st_buffer { - struct st_request *last_SRpnt; - struct st_cmdstatus cmdstat; - struct page **reserved_pages; -+ int reserved_page_order; - struct page **mapped_pages; - struct rq_map_data map_data; - unsigned char *b_data; -diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c -index 0f857e6..8b0c235 100644 ---- a/drivers/usb/core/hub.c -+++ b/drivers/usb/core/hub.c -@@ -1612,12 +1612,12 @@ static inline void announce_device(struct usb_device *udev) { } - #endif - - /** -- * usb_configure_device_otg - FIXME (usbcore-internal) -+ * usb_enumerate_device_otg - FIXME (usbcore-internal) - * @udev: newly addressed device (in ADDRESS state) - * -- * Do configuration for On-The-Go devices -+ * Finish enumeration for On-The-Go devices - */ --static int usb_configure_device_otg(struct usb_device *udev) -+static int usb_enumerate_device_otg(struct usb_device *udev) - { - int err = 0; - -@@ -1688,7 +1688,7 @@ fail: - - - /** -- * usb_configure_device - Detect and probe device intfs/otg (usbcore-internal) -+ * usb_enumerate_device - Read device configs/intfs/otg (usbcore-internal) - * @udev: newly addressed device (in ADDRESS state) - * - * This is only called by usb_new_device() and usb_authorize_device() -@@ -1699,7 +1699,7 @@ fail: - * the string descriptors, as they will be errored out by the device - * until it has been authorized. - */ --static int usb_configure_device(struct usb_device *udev) -+static int usb_enumerate_device(struct usb_device *udev) - { - int err; - -@@ -1723,7 +1723,7 @@ static int usb_configure_device(struct usb_device *udev) - udev->descriptor.iManufacturer); - udev->serial = usb_cache_string(udev, udev->descriptor.iSerialNumber); - } -- err = usb_configure_device_otg(udev); -+ err = usb_enumerate_device_otg(udev); - fail: - return err; - } -@@ -1733,8 +1733,8 @@ fail: - * usb_new_device - perform initial device setup (usbcore-internal) - * @udev: newly addressed device (in ADDRESS state) - * -- * This is called with devices which have been enumerated, but not yet -- * configured. The device descriptor is available, but not descriptors -+ * This is called with devices which have been detected but not fully -+ * enumerated. The device descriptor is available, but not descriptors - * for any device configuration. The caller must have locked either - * the parent hub (if udev is a normal device) or else the - * usb_bus_list_lock (if udev is a root hub). The parent's pointer to -@@ -1757,8 +1757,8 @@ int usb_new_device(struct usb_device *udev) - if (udev->parent) - usb_autoresume_device(udev->parent); - -- usb_detect_quirks(udev); /* Determine quirks */ -- err = usb_configure_device(udev); /* detect & probe dev/intfs */ -+ usb_detect_quirks(udev); -+ err = usb_enumerate_device(udev); /* Read descriptors */ - if (err < 0) - goto fail; - dev_dbg(&udev->dev, "udev %d, busnum %d, minor = %d\n", -@@ -1803,21 +1803,23 @@ fail: - */ - int usb_deauthorize_device(struct usb_device *usb_dev) - { -- unsigned cnt; - usb_lock_device(usb_dev); - if (usb_dev->authorized == 0) - goto out_unauthorized; -+ - usb_dev->authorized = 0; - usb_set_configuration(usb_dev, -1); -+ -+ kfree(usb_dev->product); - usb_dev->product = kstrdup("n/a (unauthorized)", GFP_KERNEL); -+ kfree(usb_dev->manufacturer); - usb_dev->manufacturer = kstrdup("n/a (unauthorized)", GFP_KERNEL); -+ kfree(usb_dev->serial); - usb_dev->serial = kstrdup("n/a (unauthorized)", GFP_KERNEL); -- kfree(usb_dev->config); -- usb_dev->config = NULL; -- for (cnt = 0; cnt < usb_dev->descriptor.bNumConfigurations; cnt++) -- kfree(usb_dev->rawdescriptors[cnt]); -+ -+ usb_destroy_configuration(usb_dev); - usb_dev->descriptor.bNumConfigurations = 0; -- kfree(usb_dev->rawdescriptors); -+ - out_unauthorized: - usb_unlock_device(usb_dev); - return 0; -@@ -1827,15 +1829,11 @@ out_unauthorized: - int usb_authorize_device(struct usb_device *usb_dev) - { - int result = 0, c; -+ - usb_lock_device(usb_dev); - if (usb_dev->authorized == 1) - goto out_authorized; -- kfree(usb_dev->product); -- usb_dev->product = NULL; -- kfree(usb_dev->manufacturer); -- usb_dev->manufacturer = NULL; -- kfree(usb_dev->serial); -- usb_dev->serial = NULL; -+ - result = usb_autoresume_device(usb_dev); - if (result < 0) { - dev_err(&usb_dev->dev, -@@ -1848,10 +1846,18 @@ int usb_authorize_device(struct usb_device *usb_dev) - "authorization: %d\n", result); - goto error_device_descriptor; - } -+ -+ kfree(usb_dev->product); -+ usb_dev->product = NULL; -+ kfree(usb_dev->manufacturer); -+ usb_dev->manufacturer = NULL; -+ kfree(usb_dev->serial); -+ usb_dev->serial = NULL; -+ - usb_dev->authorized = 1; -- result = usb_configure_device(usb_dev); -+ result = usb_enumerate_device(usb_dev); - if (result < 0) -- goto error_configure; -+ goto error_enumerate; - /* Choose and set the configuration. This registers the interfaces - * with the driver core and lets interface drivers bind to them. - */ -@@ -1866,8 +1872,10 @@ int usb_authorize_device(struct usb_device *usb_dev) - } - } - dev_info(&usb_dev->dev, "authorized to connect\n"); --error_configure: -+ -+error_enumerate: - error_device_descriptor: -+ usb_autosuspend_device(usb_dev); - error_autoresume: - out_authorized: - usb_unlock_device(usb_dev); // complements locktree -diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c -index 7ec3041..8752e55 100644 ---- a/drivers/usb/core/sysfs.c -+++ b/drivers/usb/core/sysfs.c -@@ -82,9 +82,13 @@ static ssize_t show_##name(struct device *dev, \ - struct device_attribute *attr, char *buf) \ - { \ - struct usb_device *udev; \ -+ int retval; \ - \ - udev = to_usb_device(dev); \ -- return sprintf(buf, "%s\n", udev->name); \ -+ usb_lock_device(udev); \ -+ retval = sprintf(buf, "%s\n", udev->name); \ -+ usb_unlock_device(udev); \ -+ return retval; \ - } \ - static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL); - -diff --git a/drivers/usb/misc/appledisplay.c b/drivers/usb/misc/appledisplay.c -index 1d8e39a..62ff5e7 100644 ---- a/drivers/usb/misc/appledisplay.c -+++ b/drivers/usb/misc/appledisplay.c -@@ -72,8 +72,8 @@ struct appledisplay { - struct usb_device *udev; /* usb device */ - struct urb *urb; /* usb request block */ - struct backlight_device *bd; /* backlight device */ -- char *urbdata; /* interrupt URB data buffer */ -- char *msgdata; /* control message data buffer */ -+ u8 *urbdata; /* interrupt URB data buffer */ -+ u8 *msgdata; /* control message data buffer */ - - struct delayed_work work; - int button_pressed; -diff --git a/drivers/usb/misc/emi62.c b/drivers/usb/misc/emi62.c -index 602ee05..59860b3 100644 ---- a/drivers/usb/misc/emi62.c -+++ b/drivers/usb/misc/emi62.c -@@ -167,7 +167,7 @@ static int emi62_load_firmware (struct usb_device *dev) - err("%s - error loading firmware: error = %d", __func__, err); - goto wraperr; - } -- } while (i > 0); -+ } while (rec); - - /* Assert reset (stop the CPU in the EMI) */ - err = emi62_set_reset(dev,1); -diff --git a/drivers/usb/musb/musb_gadget_ep0.c b/drivers/usb/musb/musb_gadget_ep0.c -index 1c44b97..067e5a9 100644 ---- a/drivers/usb/musb/musb_gadget_ep0.c -+++ b/drivers/usb/musb/musb_gadget_ep0.c -@@ -647,7 +647,7 @@ irqreturn_t musb_g_ep0_irq(struct musb *musb) - musb->ep0_state = MUSB_EP0_STAGE_STATUSIN; - break; - default: -- ERR("SetupEnd came in a wrong ep0stage %s", -+ ERR("SetupEnd came in a wrong ep0stage %s\n", - decode_ep0stage(musb->ep0_state)); - } - csr = musb_readw(regs, MUSB_CSR0); -@@ -770,12 +770,18 @@ setup: - handled = service_zero_data_request( - musb, &setup); - -+ /* -+ * We're expecting no data in any case, so -+ * always set the DATAEND bit -- doing this -+ * here helps avoid SetupEnd interrupt coming -+ * in the idle stage when we're stalling... -+ */ -+ musb->ackpend |= MUSB_CSR0_P_DATAEND; -+ - /* status stage might be immediate */ -- if (handled > 0) { -- musb->ackpend |= MUSB_CSR0_P_DATAEND; -+ if (handled > 0) - musb->ep0_state = - MUSB_EP0_STAGE_STATUSIN; -- } - break; - - /* sequence #1 (IN to host), includes GET_STATUS -diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c -index dffc8a1..be3dff1 100644 ---- a/drivers/usb/serial/option.c -+++ b/drivers/usb/serial/option.c -@@ -340,6 +340,10 @@ static int option_resume(struct usb_serial *serial); - #define FOUR_G_SYSTEMS_VENDOR_ID 0x1c9e - #define FOUR_G_SYSTEMS_PRODUCT_W14 0x9603 - -+/* Haier products */ -+#define HAIER_VENDOR_ID 0x201e -+#define HAIER_PRODUCT_CE100 0x2009 -+ - static struct usb_device_id option_ids[] = { - { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COLT) }, - { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA) }, -@@ -641,6 +645,7 @@ static struct usb_device_id option_ids[] = { - { USB_DEVICE(AIRPLUS_VENDOR_ID, AIRPLUS_PRODUCT_MCD650) }, - { USB_DEVICE(TLAYTECH_VENDOR_ID, TLAYTECH_PRODUCT_TEU800) }, - { USB_DEVICE(FOUR_G_SYSTEMS_VENDOR_ID, FOUR_G_SYSTEMS_PRODUCT_W14) }, -+ { USB_DEVICE(HAIER_VENDOR_ID, HAIER_PRODUCT_CE100) }, - { } /* Terminating entry */ - }; - MODULE_DEVICE_TABLE(usb, option_ids); -diff --git a/drivers/xen/xenbus/xenbus_probe.c b/drivers/xen/xenbus/xenbus_probe.c -index 3800da7..649fcdf 100644 ---- a/drivers/xen/xenbus/xenbus_probe.c -+++ b/drivers/xen/xenbus/xenbus_probe.c -@@ -843,7 +843,7 @@ postcore_initcall(xenbus_probe_init); - - MODULE_LICENSE("GPL"); - --static int is_disconnected_device(struct device *dev, void *data) -+static int is_device_connecting(struct device *dev, void *data) - { - struct xenbus_device *xendev = to_xenbus_device(dev); - struct device_driver *drv = data; -@@ -861,14 +861,15 @@ static int is_disconnected_device(struct device *dev, void *data) - return 0; - - xendrv = to_xenbus_driver(dev->driver); -- return (xendev->state != XenbusStateConnected || -- (xendrv->is_ready && !xendrv->is_ready(xendev))); -+ return (xendev->state < XenbusStateConnected || -+ (xendev->state == XenbusStateConnected && -+ xendrv->is_ready && !xendrv->is_ready(xendev))); - } - --static int exists_disconnected_device(struct device_driver *drv) -+static int exists_connecting_device(struct device_driver *drv) - { - return bus_for_each_dev(&xenbus_frontend.bus, NULL, drv, -- is_disconnected_device); -+ is_device_connecting); - } - - static int print_device_status(struct device *dev, void *data) -@@ -884,10 +885,13 @@ static int print_device_status(struct device *dev, void *data) - /* Information only: is this too noisy? */ - printk(KERN_INFO "XENBUS: Device with no driver: %s\n", - xendev->nodename); -- } else if (xendev->state != XenbusStateConnected) { -+ } else if (xendev->state < XenbusStateConnected) { -+ enum xenbus_state rstate = XenbusStateUnknown; -+ if (xendev->otherend) -+ rstate = xenbus_read_driver_state(xendev->otherend); - printk(KERN_WARNING "XENBUS: Timeout connecting " -- "to device: %s (state %d)\n", -- xendev->nodename, xendev->state); -+ "to device: %s (local state %d, remote state %d)\n", -+ xendev->nodename, xendev->state, rstate); - } - - return 0; -@@ -897,7 +901,7 @@ static int print_device_status(struct device *dev, void *data) - static int ready_to_wait_for_devices; - - /* -- * On a 10 second timeout, wait for all devices currently configured. We need -+ * On a 5-minute timeout, wait for all devices currently configured. We need - * to do this to guarantee that the filesystems and / or network devices - * needed for boot are available, before we can allow the boot to proceed. - * -@@ -912,18 +916,30 @@ static int ready_to_wait_for_devices; - */ - static void wait_for_devices(struct xenbus_driver *xendrv) - { -- unsigned long timeout = jiffies + 10*HZ; -+ unsigned long start = jiffies; - struct device_driver *drv = xendrv ? &xendrv->driver : NULL; -+ unsigned int seconds_waited = 0; - - if (!ready_to_wait_for_devices || !xen_domain()) - return; - -- while (exists_disconnected_device(drv)) { -- if (time_after(jiffies, timeout)) -- break; -+ while (exists_connecting_device(drv)) { -+ if (time_after(jiffies, start + (seconds_waited+5)*HZ)) { -+ if (!seconds_waited) -+ printk(KERN_WARNING "XENBUS: Waiting for " -+ "devices to initialise: "); -+ seconds_waited += 5; -+ printk("%us...", 300 - seconds_waited); -+ if (seconds_waited == 300) -+ break; -+ } -+ - schedule_timeout_interruptible(HZ/10); - } - -+ if (seconds_waited) -+ printk("\n"); -+ - bus_for_each_dev(&xenbus_frontend.bus, NULL, drv, - print_device_status); - } -diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c -index 63ea83f..3bbcaa7 100644 ---- a/fs/cifs/connect.c -+++ b/fs/cifs/connect.c -@@ -2287,12 +2287,12 @@ int - cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, - char *mount_data_global, const char *devname) - { -- int rc = 0; -+ int rc; - int xid; - struct smb_vol *volume_info; -- struct cifsSesInfo *pSesInfo = NULL; -- struct cifsTconInfo *tcon = NULL; -- struct TCP_Server_Info *srvTcp = NULL; -+ struct cifsSesInfo *pSesInfo; -+ struct cifsTconInfo *tcon; -+ struct TCP_Server_Info *srvTcp; - char *full_path; - char *mount_data = mount_data_global; - #ifdef CONFIG_CIFS_DFS_UPCALL -@@ -2301,6 +2301,10 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, - int referral_walks_count = 0; - try_mount_again: - #endif -+ rc = 0; -+ tcon = NULL; -+ pSesInfo = NULL; -+ srvTcp = NULL; - full_path = NULL; - - xid = GetXid(); -@@ -2597,6 +2601,7 @@ remote_path_check: - - cleanup_volume_info(&volume_info); - referral_walks_count++; -+ FreeXid(xid); - goto try_mount_again; - } - #else /* No DFS support, return error on mount */ -diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h -index bd2a9dd..d0a2afb 100644 ---- a/fs/ext4/ext4.h -+++ b/fs/ext4/ext4.h -@@ -698,6 +698,10 @@ struct ext4_inode_info { - __u16 i_extra_isize; - - spinlock_t i_block_reservation_lock; -+#ifdef CONFIG_QUOTA -+ /* quota space reservation, managed internally by quota code */ -+ qsize_t i_reserved_quota; -+#endif - - /* completed async DIOs that might need unwritten extents handling */ - struct list_head i_aio_dio_complete_list; -@@ -1432,7 +1436,7 @@ extern int ext4_chunk_trans_blocks(struct inode *, int nrblocks); - extern int ext4_block_truncate_page(handle_t *handle, - struct address_space *mapping, loff_t from); - extern int ext4_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf); --extern qsize_t ext4_get_reserved_space(struct inode *inode); -+extern qsize_t *ext4_get_reserved_space(struct inode *inode); - extern int flush_aio_dio_completed_IO(struct inode *inode); - /* ioctl.c */ - extern long ext4_ioctl(struct file *, unsigned int, unsigned long); -diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c -index 1dae9a4..e233879 100644 ---- a/fs/ext4/inode.c -+++ b/fs/ext4/inode.c -@@ -1045,17 +1045,12 @@ out: - return err; - } - --qsize_t ext4_get_reserved_space(struct inode *inode) -+#ifdef CONFIG_QUOTA -+qsize_t *ext4_get_reserved_space(struct inode *inode) - { -- unsigned long long total; -- -- spin_lock(&EXT4_I(inode)->i_block_reservation_lock); -- total = EXT4_I(inode)->i_reserved_data_blocks + -- EXT4_I(inode)->i_reserved_meta_blocks; -- spin_unlock(&EXT4_I(inode)->i_block_reservation_lock); -- -- return (total << inode->i_blkbits); -+ return &EXT4_I(inode)->i_reserved_quota; - } -+#endif - /* - * Calculate the number of metadata blocks need to reserve - * to allocate @blocks for non extent file based file -@@ -1858,19 +1853,17 @@ repeat: - - md_needed = mdblocks - EXT4_I(inode)->i_reserved_meta_blocks; - total = md_needed + nrblocks; -+ spin_unlock(&EXT4_I(inode)->i_block_reservation_lock); - - /* - * Make quota reservation here to prevent quota overflow - * later. Real quota accounting is done at pages writeout - * time. - */ -- if (vfs_dq_reserve_block(inode, total)) { -- spin_unlock(&EXT4_I(inode)->i_block_reservation_lock); -+ if (vfs_dq_reserve_block(inode, total)) - return -EDQUOT; -- } - - if (ext4_claim_free_blocks(sbi, total)) { -- spin_unlock(&EXT4_I(inode)->i_block_reservation_lock); - vfs_dq_release_reservation_block(inode, total); - if (ext4_should_retry_alloc(inode->i_sb, &retries)) { - yield(); -@@ -1878,10 +1871,11 @@ repeat: - } - return -ENOSPC; - } -+ spin_lock(&EXT4_I(inode)->i_block_reservation_lock); - EXT4_I(inode)->i_reserved_data_blocks += nrblocks; -- EXT4_I(inode)->i_reserved_meta_blocks = mdblocks; -- -+ EXT4_I(inode)->i_reserved_meta_blocks += md_needed; - spin_unlock(&EXT4_I(inode)->i_block_reservation_lock); -+ - return 0; /* success */ - } - -@@ -4850,6 +4844,9 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino) - ((__u64)le16_to_cpu(raw_inode->i_file_acl_high)) << 32; - inode->i_size = ext4_isize(raw_inode); - ei->i_disksize = inode->i_size; -+#ifdef CONFIG_QUOTA -+ ei->i_reserved_quota = 0; -+#endif - inode->i_generation = le32_to_cpu(raw_inode->i_generation); - ei->i_block_group = iloc.block_group; - ei->i_last_alloc_group = ~0; -diff --git a/fs/ext4/super.c b/fs/ext4/super.c -index 9ae5217..92943f2 100644 ---- a/fs/ext4/super.c -+++ b/fs/ext4/super.c -@@ -704,6 +704,9 @@ static struct inode *ext4_alloc_inode(struct super_block *sb) - ei->i_allocated_meta_blocks = 0; - ei->i_delalloc_reserved_flag = 0; - spin_lock_init(&(ei->i_block_reservation_lock)); -+#ifdef CONFIG_QUOTA -+ ei->i_reserved_quota = 0; -+#endif - INIT_LIST_HEAD(&ei->i_aio_dio_complete_list); - ei->cur_aio_dio = NULL; - ei->i_sync_tid = 0; -@@ -1001,7 +1004,9 @@ static const struct dquot_operations ext4_quota_operations = { - .reserve_space = dquot_reserve_space, - .claim_space = dquot_claim_space, - .release_rsv = dquot_release_reserved_space, -+#ifdef CONFIG_QUOTA - .get_reserved_space = ext4_get_reserved_space, -+#endif - .alloc_inode = dquot_alloc_inode, - .free_space = dquot_free_space, - .free_inode = dquot_free_inode, -diff --git a/fs/namei.c b/fs/namei.c -index d11f404..a2b3c28 100644 ---- a/fs/namei.c -+++ b/fs/namei.c -@@ -234,6 +234,7 @@ int generic_permission(struct inode *inode, int mask, - /* - * Searching includes executable on directories, else just read. - */ -+ mask &= MAY_READ | MAY_WRITE | MAY_EXEC; - if (mask == MAY_READ || (S_ISDIR(inode->i_mode) && !(mask & MAY_WRITE))) - if (capable(CAP_DAC_READ_SEARCH)) - return 0; -diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c -index 39b49c4..c4d07a8 100644 ---- a/fs/quota/dquot.c -+++ b/fs/quota/dquot.c -@@ -1388,6 +1388,67 @@ void vfs_dq_drop(struct inode *inode) - EXPORT_SYMBOL(vfs_dq_drop); - - /* -+ * inode_reserved_space is managed internally by quota, and protected by -+ * i_lock similar to i_blocks+i_bytes. -+ */ -+static qsize_t *inode_reserved_space(struct inode * inode) -+{ -+ /* Filesystem must explicitly define it's own method in order to use -+ * quota reservation interface */ -+ BUG_ON(!inode->i_sb->dq_op->get_reserved_space); -+ return inode->i_sb->dq_op->get_reserved_space(inode); -+} -+ -+static void inode_add_rsv_space(struct inode *inode, qsize_t number) -+{ -+ spin_lock(&inode->i_lock); -+ *inode_reserved_space(inode) += number; -+ spin_unlock(&inode->i_lock); -+} -+ -+ -+static void inode_claim_rsv_space(struct inode *inode, qsize_t number) -+{ -+ spin_lock(&inode->i_lock); -+ *inode_reserved_space(inode) -= number; -+ __inode_add_bytes(inode, number); -+ spin_unlock(&inode->i_lock); -+} -+ -+static void inode_sub_rsv_space(struct inode *inode, qsize_t number) -+{ -+ spin_lock(&inode->i_lock); -+ *inode_reserved_space(inode) -= number; -+ spin_unlock(&inode->i_lock); -+} -+ -+static qsize_t inode_get_rsv_space(struct inode *inode) -+{ -+ qsize_t ret; -+ spin_lock(&inode->i_lock); -+ ret = *inode_reserved_space(inode); -+ spin_unlock(&inode->i_lock); -+ return ret; -+} -+ -+static void inode_incr_space(struct inode *inode, qsize_t number, -+ int reserve) -+{ -+ if (reserve) -+ inode_add_rsv_space(inode, number); -+ else -+ inode_add_bytes(inode, number); -+} -+ -+static void inode_decr_space(struct inode *inode, qsize_t number, int reserve) -+{ -+ if (reserve) -+ inode_sub_rsv_space(inode, number); -+ else -+ inode_sub_bytes(inode, number); -+} -+ -+/* - * Following four functions update i_blocks+i_bytes fields and - * quota information (together with appropriate checks) - * NOTE: We absolutely rely on the fact that caller dirties -@@ -1405,6 +1466,21 @@ int __dquot_alloc_space(struct inode *inode, qsize_t number, - int cnt, ret = QUOTA_OK; - char warntype[MAXQUOTAS]; - -+ /* -+ * First test before acquiring mutex - solves deadlocks when we -+ * re-enter the quota code and are already holding the mutex -+ */ -+ if (IS_NOQUOTA(inode)) { -+ inode_incr_space(inode, number, reserve); -+ goto out; -+ } -+ -+ down_read(&sb_dqopt(inode->i_sb)->dqptr_sem); -+ if (IS_NOQUOTA(inode)) { -+ inode_incr_space(inode, number, reserve); -+ goto out_unlock; -+ } -+ - for (cnt = 0; cnt < MAXQUOTAS; cnt++) - warntype[cnt] = QUOTA_NL_NOWARN; - -@@ -1415,7 +1491,8 @@ int __dquot_alloc_space(struct inode *inode, qsize_t number, - if (check_bdq(inode->i_dquot[cnt], number, warn, warntype+cnt) - == NO_QUOTA) { - ret = NO_QUOTA; -- goto out_unlock; -+ spin_unlock(&dq_data_lock); -+ goto out_flush_warn; - } - } - for (cnt = 0; cnt < MAXQUOTAS; cnt++) { -@@ -1426,64 +1503,32 @@ int __dquot_alloc_space(struct inode *inode, qsize_t number, - else - dquot_incr_space(inode->i_dquot[cnt], number); - } -- if (!reserve) -- inode_add_bytes(inode, number); --out_unlock: -+ inode_incr_space(inode, number, reserve); - spin_unlock(&dq_data_lock); -- flush_warnings(inode->i_dquot, warntype); -- return ret; --} -- --int dquot_alloc_space(struct inode *inode, qsize_t number, int warn) --{ -- int cnt, ret = QUOTA_OK; -- -- /* -- * First test before acquiring mutex - solves deadlocks when we -- * re-enter the quota code and are already holding the mutex -- */ -- if (IS_NOQUOTA(inode)) { -- inode_add_bytes(inode, number); -- goto out; -- } -- -- down_read(&sb_dqopt(inode->i_sb)->dqptr_sem); -- if (IS_NOQUOTA(inode)) { -- inode_add_bytes(inode, number); -- goto out_unlock; -- } -- -- ret = __dquot_alloc_space(inode, number, warn, 0); -- if (ret == NO_QUOTA) -- goto out_unlock; - -+ if (reserve) -+ goto out_flush_warn; - /* Dirtify all the dquots - this can block when journalling */ - for (cnt = 0; cnt < MAXQUOTAS; cnt++) - if (inode->i_dquot[cnt]) - mark_dquot_dirty(inode->i_dquot[cnt]); -+out_flush_warn: -+ flush_warnings(inode->i_dquot, warntype); - out_unlock: - up_read(&sb_dqopt(inode->i_sb)->dqptr_sem); - out: - return ret; - } -+ -+int dquot_alloc_space(struct inode *inode, qsize_t number, int warn) -+{ -+ return __dquot_alloc_space(inode, number, warn, 0); -+} - EXPORT_SYMBOL(dquot_alloc_space); - - int dquot_reserve_space(struct inode *inode, qsize_t number, int warn) - { -- int ret = QUOTA_OK; -- -- if (IS_NOQUOTA(inode)) -- goto out; -- -- down_read(&sb_dqopt(inode->i_sb)->dqptr_sem); -- if (IS_NOQUOTA(inode)) -- goto out_unlock; -- -- ret = __dquot_alloc_space(inode, number, warn, 1); --out_unlock: -- up_read(&sb_dqopt(inode->i_sb)->dqptr_sem); --out: -- return ret; -+ return __dquot_alloc_space(inode, number, warn, 1); - } - EXPORT_SYMBOL(dquot_reserve_space); - -@@ -1540,14 +1585,14 @@ int dquot_claim_space(struct inode *inode, qsize_t number) - int ret = QUOTA_OK; - - if (IS_NOQUOTA(inode)) { -- inode_add_bytes(inode, number); -+ inode_claim_rsv_space(inode, number); - goto out; - } - - down_read(&sb_dqopt(inode->i_sb)->dqptr_sem); - if (IS_NOQUOTA(inode)) { - up_read(&sb_dqopt(inode->i_sb)->dqptr_sem); -- inode_add_bytes(inode, number); -+ inode_claim_rsv_space(inode, number); - goto out; - } - -@@ -1559,7 +1604,7 @@ int dquot_claim_space(struct inode *inode, qsize_t number) - number); - } - /* Update inode bytes */ -- inode_add_bytes(inode, number); -+ inode_claim_rsv_space(inode, number); - spin_unlock(&dq_data_lock); - /* Dirtify all the dquots - this can block when journalling */ - for (cnt = 0; cnt < MAXQUOTAS; cnt++) -@@ -1572,38 +1617,9 @@ out: - EXPORT_SYMBOL(dquot_claim_space); - - /* -- * Release reserved quota space -- */ --void dquot_release_reserved_space(struct inode *inode, qsize_t number) --{ -- int cnt; -- -- if (IS_NOQUOTA(inode)) -- goto out; -- -- down_read(&sb_dqopt(inode->i_sb)->dqptr_sem); -- if (IS_NOQUOTA(inode)) -- goto out_unlock; -- -- spin_lock(&dq_data_lock); -- /* Release reserved dquots */ -- for (cnt = 0; cnt < MAXQUOTAS; cnt++) { -- if (inode->i_dquot[cnt]) -- dquot_free_reserved_space(inode->i_dquot[cnt], number); -- } -- spin_unlock(&dq_data_lock); -- --out_unlock: -- up_read(&sb_dqopt(inode->i_sb)->dqptr_sem); --out: -- return; --} --EXPORT_SYMBOL(dquot_release_reserved_space); -- --/* - * This operation can block, but only after everything is updated - */ --int dquot_free_space(struct inode *inode, qsize_t number) -+int __dquot_free_space(struct inode *inode, qsize_t number, int reserve) - { - unsigned int cnt; - char warntype[MAXQUOTAS]; -@@ -1612,7 +1628,7 @@ int dquot_free_space(struct inode *inode, qsize_t number) - * re-enter the quota code and are already holding the mutex */ - if (IS_NOQUOTA(inode)) { - out_sub: -- inode_sub_bytes(inode, number); -+ inode_decr_space(inode, number, reserve); - return QUOTA_OK; - } - -@@ -1627,21 +1643,43 @@ out_sub: - if (!inode->i_dquot[cnt]) - continue; - warntype[cnt] = info_bdq_free(inode->i_dquot[cnt], number); -- dquot_decr_space(inode->i_dquot[cnt], number); -+ if (reserve) -+ dquot_free_reserved_space(inode->i_dquot[cnt], number); -+ else -+ dquot_decr_space(inode->i_dquot[cnt], number); - } -- inode_sub_bytes(inode, number); -+ inode_decr_space(inode, number, reserve); - spin_unlock(&dq_data_lock); -+ -+ if (reserve) -+ goto out_unlock; - /* Dirtify all the dquots - this can block when journalling */ - for (cnt = 0; cnt < MAXQUOTAS; cnt++) - if (inode->i_dquot[cnt]) - mark_dquot_dirty(inode->i_dquot[cnt]); -+out_unlock: - flush_warnings(inode->i_dquot, warntype); - up_read(&sb_dqopt(inode->i_sb)->dqptr_sem); - return QUOTA_OK; - } -+ -+int dquot_free_space(struct inode *inode, qsize_t number) -+{ -+ return __dquot_free_space(inode, number, 0); -+} - EXPORT_SYMBOL(dquot_free_space); - - /* -+ * Release reserved quota space -+ */ -+void dquot_release_reserved_space(struct inode *inode, qsize_t number) -+{ -+ __dquot_free_space(inode, number, 1); -+ -+} -+EXPORT_SYMBOL(dquot_release_reserved_space); -+ -+/* - * This operation can block, but only after everything is updated - */ - int dquot_free_inode(const struct inode *inode, qsize_t number) -@@ -1679,19 +1717,6 @@ int dquot_free_inode(const struct inode *inode, qsize_t number) - EXPORT_SYMBOL(dquot_free_inode); - - /* -- * call back function, get reserved quota space from underlying fs -- */ --qsize_t dquot_get_reserved_space(struct inode *inode) --{ -- qsize_t reserved_space = 0; -- -- if (sb_any_quota_active(inode->i_sb) && -- inode->i_sb->dq_op->get_reserved_space) -- reserved_space = inode->i_sb->dq_op->get_reserved_space(inode); -- return reserved_space; --} -- --/* - * Transfer the number of inode and blocks from one diskquota to an other. - * - * This operation can block, but only after everything is updated -@@ -1734,7 +1759,7 @@ int dquot_transfer(struct inode *inode, struct iattr *iattr) - } - spin_lock(&dq_data_lock); - cur_space = inode_get_bytes(inode); -- rsv_space = dquot_get_reserved_space(inode); -+ rsv_space = inode_get_rsv_space(inode); - space = cur_space + rsv_space; - /* Build the transfer_from list and check the limits */ - for (cnt = 0; cnt < MAXQUOTAS; cnt++) { -diff --git a/fs/stat.c b/fs/stat.c -index 075694e..c4ecd52 100644 ---- a/fs/stat.c -+++ b/fs/stat.c -@@ -401,9 +401,9 @@ SYSCALL_DEFINE4(fstatat64, int, dfd, char __user *, filename, - } - #endif /* __ARCH_WANT_STAT64 */ - --void inode_add_bytes(struct inode *inode, loff_t bytes) -+/* Caller is here responsible for sufficient locking (ie. inode->i_lock) */ -+void __inode_add_bytes(struct inode *inode, loff_t bytes) - { -- spin_lock(&inode->i_lock); - inode->i_blocks += bytes >> 9; - bytes &= 511; - inode->i_bytes += bytes; -@@ -411,6 +411,12 @@ void inode_add_bytes(struct inode *inode, loff_t bytes) - inode->i_blocks++; - inode->i_bytes -= 512; - } -+} -+ -+void inode_add_bytes(struct inode *inode, loff_t bytes) -+{ -+ spin_lock(&inode->i_lock); -+ __inode_add_bytes(inode, bytes); - spin_unlock(&inode->i_lock); - } - -diff --git a/fs/udf/super.c b/fs/udf/super.c -index 9d1b8c2..1e4543c 100644 ---- a/fs/udf/super.c -+++ b/fs/udf/super.c -@@ -1078,21 +1078,39 @@ static int udf_fill_partdesc_info(struct super_block *sb, - return 0; - } - --static int udf_load_vat(struct super_block *sb, int p_index, int type1_index) -+static void udf_find_vat_block(struct super_block *sb, int p_index, -+ int type1_index, sector_t start_block) - { - struct udf_sb_info *sbi = UDF_SB(sb); - struct udf_part_map *map = &sbi->s_partmaps[p_index]; -+ sector_t vat_block; - struct kernel_lb_addr ino; -+ -+ /* -+ * VAT file entry is in the last recorded block. Some broken disks have -+ * it a few blocks before so try a bit harder... -+ */ -+ ino.partitionReferenceNum = type1_index; -+ for (vat_block = start_block; -+ vat_block >= map->s_partition_root && -+ vat_block >= start_block - 3 && -+ !sbi->s_vat_inode; vat_block--) { -+ ino.logicalBlockNum = vat_block - map->s_partition_root; -+ sbi->s_vat_inode = udf_iget(sb, &ino); -+ } -+} -+ -+static int udf_load_vat(struct super_block *sb, int p_index, int type1_index) -+{ -+ struct udf_sb_info *sbi = UDF_SB(sb); -+ struct udf_part_map *map = &sbi->s_partmaps[p_index]; - struct buffer_head *bh = NULL; - struct udf_inode_info *vati; - uint32_t pos; - struct virtualAllocationTable20 *vat20; - sector_t blocks = sb->s_bdev->bd_inode->i_size >> sb->s_blocksize_bits; - -- /* VAT file entry is in the last recorded block */ -- ino.partitionReferenceNum = type1_index; -- ino.logicalBlockNum = sbi->s_last_block - map->s_partition_root; -- sbi->s_vat_inode = udf_iget(sb, &ino); -+ udf_find_vat_block(sb, p_index, type1_index, sbi->s_last_block); - if (!sbi->s_vat_inode && - sbi->s_last_block != blocks - 1) { - printk(KERN_NOTICE "UDF-fs: Failed to read VAT inode from the" -@@ -1100,9 +1118,7 @@ static int udf_load_vat(struct super_block *sb, int p_index, int type1_index) - "block of the device (%lu).\n", - (unsigned long)sbi->s_last_block, - (unsigned long)blocks - 1); -- ino.partitionReferenceNum = type1_index; -- ino.logicalBlockNum = blocks - 1 - map->s_partition_root; -- sbi->s_vat_inode = udf_iget(sb, &ino); -+ udf_find_vat_block(sb, p_index, type1_index, blocks - 1); - } - if (!sbi->s_vat_inode) - return 1; -diff --git a/include/linux/cpumask.h b/include/linux/cpumask.h -index 789cf5f..d77b547 100644 ---- a/include/linux/cpumask.h -+++ b/include/linux/cpumask.h -@@ -84,6 +84,7 @@ extern const struct cpumask *const cpu_active_mask; - #define num_online_cpus() cpumask_weight(cpu_online_mask) - #define num_possible_cpus() cpumask_weight(cpu_possible_mask) - #define num_present_cpus() cpumask_weight(cpu_present_mask) -+#define num_active_cpus() cpumask_weight(cpu_active_mask) - #define cpu_online(cpu) cpumask_test_cpu((cpu), cpu_online_mask) - #define cpu_possible(cpu) cpumask_test_cpu((cpu), cpu_possible_mask) - #define cpu_present(cpu) cpumask_test_cpu((cpu), cpu_present_mask) -@@ -92,6 +93,7 @@ extern const struct cpumask *const cpu_active_mask; - #define num_online_cpus() 1 - #define num_possible_cpus() 1 - #define num_present_cpus() 1 -+#define num_active_cpus() 1 - #define cpu_online(cpu) ((cpu) == 0) - #define cpu_possible(cpu) ((cpu) == 0) - #define cpu_present(cpu) ((cpu) == 0) -diff --git a/include/linux/fs.h b/include/linux/fs.h -index 2620a8c..98ea200 100644 ---- a/include/linux/fs.h -+++ b/include/linux/fs.h -@@ -2314,6 +2314,7 @@ extern const struct inode_operations page_symlink_inode_operations; - extern int generic_readlink(struct dentry *, char __user *, int); - extern void generic_fillattr(struct inode *, struct kstat *); - extern int vfs_getattr(struct vfsmount *, struct dentry *, struct kstat *); -+void __inode_add_bytes(struct inode *inode, loff_t bytes); - void inode_add_bytes(struct inode *inode, loff_t bytes); - void inode_sub_bytes(struct inode *inode, loff_t bytes); - loff_t inode_get_bytes(struct inode *inode); -diff --git a/include/linux/quota.h b/include/linux/quota.h -index 78c4889..8fd8efc 100644 ---- a/include/linux/quota.h -+++ b/include/linux/quota.h -@@ -313,8 +313,9 @@ struct dquot_operations { - int (*claim_space) (struct inode *, qsize_t); - /* release rsved quota for delayed alloc */ - void (*release_rsv) (struct inode *, qsize_t); -- /* get reserved quota for delayed alloc */ -- qsize_t (*get_reserved_space) (struct inode *); -+ /* get reserved quota for delayed alloc, value returned is managed by -+ * quota code only */ -+ qsize_t *(*get_reserved_space) (struct inode *); - }; - - /* Operations handling requests from userspace */ -diff --git a/include/linux/security.h b/include/linux/security.h -index 239e40d..d40d23f 100644 ---- a/include/linux/security.h -+++ b/include/linux/security.h -@@ -95,8 +95,13 @@ struct seq_file; - extern int cap_netlink_send(struct sock *sk, struct sk_buff *skb); - extern int cap_netlink_recv(struct sk_buff *skb, int cap); - -+#ifdef CONFIG_MMU - extern unsigned long mmap_min_addr; - extern unsigned long dac_mmap_min_addr; -+#else -+#define dac_mmap_min_addr 0UL -+#endif -+ - /* - * Values used in the task_security_ops calls - */ -@@ -121,6 +126,7 @@ struct request_sock; - #define LSM_UNSAFE_PTRACE 2 - #define LSM_UNSAFE_PTRACE_CAP 4 - -+#ifdef CONFIG_MMU - /* - * If a hint addr is less than mmap_min_addr change hint to be as - * low as possible but still greater than mmap_min_addr -@@ -135,6 +141,7 @@ static inline unsigned long round_hint_to_min(unsigned long hint) - } - extern int mmap_min_addr_handler(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, loff_t *ppos); -+#endif - - #ifdef CONFIG_SECURITY - -diff --git a/include/net/ip.h b/include/net/ip.h -index 2f47e54..69db943 100644 ---- a/include/net/ip.h -+++ b/include/net/ip.h -@@ -342,6 +342,7 @@ enum ip_defrag_users - IP_DEFRAG_CALL_RA_CHAIN, - IP_DEFRAG_CONNTRACK_IN, - IP_DEFRAG_CONNTRACK_OUT, -+ IP_DEFRAG_CONNTRACK_BRIDGE_IN, - IP_DEFRAG_VS_IN, - IP_DEFRAG_VS_OUT, - IP_DEFRAG_VS_FWD -diff --git a/include/net/ipv6.h b/include/net/ipv6.h -index 8c31d8a..639bbf0 100644 ---- a/include/net/ipv6.h -+++ b/include/net/ipv6.h -@@ -354,8 +354,16 @@ static inline int ipv6_prefix_equal(const struct in6_addr *a1, - - struct inet_frag_queue; - -+enum ip6_defrag_users { -+ IP6_DEFRAG_LOCAL_DELIVER, -+ IP6_DEFRAG_CONNTRACK_IN, -+ IP6_DEFRAG_CONNTRACK_OUT, -+ IP6_DEFRAG_CONNTRACK_BRIDGE_IN, -+}; -+ - struct ip6_create_arg { - __be32 id; -+ u32 user; - struct in6_addr *src; - struct in6_addr *dst; - }; -diff --git a/include/net/netfilter/ipv6/nf_conntrack_ipv6.h b/include/net/netfilter/ipv6/nf_conntrack_ipv6.h -index abc55ad..1ee717e 100644 ---- a/include/net/netfilter/ipv6/nf_conntrack_ipv6.h -+++ b/include/net/netfilter/ipv6/nf_conntrack_ipv6.h -@@ -9,7 +9,7 @@ extern struct nf_conntrack_l4proto nf_conntrack_l4proto_icmpv6; - - extern int nf_ct_frag6_init(void); - extern void nf_ct_frag6_cleanup(void); --extern struct sk_buff *nf_ct_frag6_gather(struct sk_buff *skb); -+extern struct sk_buff *nf_ct_frag6_gather(struct sk_buff *skb, u32 user); - extern void nf_ct_frag6_output(unsigned int hooknum, struct sk_buff *skb, - struct net_device *in, - struct net_device *out, -diff --git a/kernel/cpu.c b/kernel/cpu.c -index 6ba0f1e..b216886 100644 ---- a/kernel/cpu.c -+++ b/kernel/cpu.c -@@ -212,6 +212,8 @@ static int __ref _cpu_down(unsigned int cpu, int tasks_frozen) - err = __raw_notifier_call_chain(&cpu_chain, CPU_DOWN_PREPARE | mod, - hcpu, -1, &nr_calls); - if (err == NOTIFY_BAD) { -+ set_cpu_active(cpu, true); -+ - nr_calls--; - __raw_notifier_call_chain(&cpu_chain, CPU_DOWN_FAILED | mod, - hcpu, nr_calls, NULL); -@@ -223,11 +225,11 @@ static int __ref _cpu_down(unsigned int cpu, int tasks_frozen) - - /* Ensure that we are not runnable on dying cpu */ - cpumask_copy(old_allowed, ¤t->cpus_allowed); -- set_cpus_allowed_ptr(current, -- cpumask_of(cpumask_any_but(cpu_online_mask, cpu))); -+ set_cpus_allowed_ptr(current, cpu_active_mask); - - err = __stop_machine(take_cpu_down, &tcd_param, cpumask_of(cpu)); - if (err) { -+ set_cpu_active(cpu, true); - /* CPU didn't die: tell everyone. Can't complain. */ - if (raw_notifier_call_chain(&cpu_chain, CPU_DOWN_FAILED | mod, - hcpu) == NOTIFY_BAD) -@@ -292,9 +294,6 @@ int __ref cpu_down(unsigned int cpu) - - err = _cpu_down(cpu, 0); - -- if (cpu_online(cpu)) -- set_cpu_active(cpu, true); -- - out: - cpu_maps_update_done(); - stop_machine_destroy(); -@@ -387,6 +386,15 @@ int disable_nonboot_cpus(void) - * with the userspace trying to use the CPU hotplug at the same time - */ - cpumask_clear(frozen_cpus); -+ -+ for_each_online_cpu(cpu) { -+ if (cpu == first_cpu) -+ continue; -+ set_cpu_active(cpu, false); -+ } -+ -+ synchronize_sched(); -+ - printk("Disabling non-boot CPUs ...\n"); - for_each_online_cpu(cpu) { - if (cpu == first_cpu) -diff --git a/kernel/cpuset.c b/kernel/cpuset.c -index b5cb469..39e5121 100644 ---- a/kernel/cpuset.c -+++ b/kernel/cpuset.c -@@ -873,7 +873,7 @@ static int update_cpumask(struct cpuset *cs, struct cpuset *trialcs, - if (retval < 0) - return retval; - -- if (!cpumask_subset(trialcs->cpus_allowed, cpu_online_mask)) -+ if (!cpumask_subset(trialcs->cpus_allowed, cpu_active_mask)) - return -EINVAL; - } - retval = validate_change(cs, trialcs); -@@ -2011,7 +2011,7 @@ static void scan_for_empty_cpusets(struct cpuset *root) - } - - /* Continue past cpusets with all cpus, mems online */ -- if (cpumask_subset(cp->cpus_allowed, cpu_online_mask) && -+ if (cpumask_subset(cp->cpus_allowed, cpu_active_mask) && - nodes_subset(cp->mems_allowed, node_states[N_HIGH_MEMORY])) - continue; - -@@ -2020,7 +2020,7 @@ static void scan_for_empty_cpusets(struct cpuset *root) - /* Remove offline cpus and mems from this cpuset. */ - mutex_lock(&callback_mutex); - cpumask_and(cp->cpus_allowed, cp->cpus_allowed, -- cpu_online_mask); -+ cpu_active_mask); - nodes_and(cp->mems_allowed, cp->mems_allowed, - node_states[N_HIGH_MEMORY]); - mutex_unlock(&callback_mutex); -@@ -2058,8 +2058,10 @@ static int cpuset_track_online_cpus(struct notifier_block *unused_nb, - switch (phase) { - case CPU_ONLINE: - case CPU_ONLINE_FROZEN: -- case CPU_DEAD: -- case CPU_DEAD_FROZEN: -+ case CPU_DOWN_PREPARE: -+ case CPU_DOWN_PREPARE_FROZEN: -+ case CPU_DOWN_FAILED: -+ case CPU_DOWN_FAILED_FROZEN: - break; - - default: -@@ -2068,7 +2070,7 @@ static int cpuset_track_online_cpus(struct notifier_block *unused_nb, - - cgroup_lock(); - mutex_lock(&callback_mutex); -- cpumask_copy(top_cpuset.cpus_allowed, cpu_online_mask); -+ cpumask_copy(top_cpuset.cpus_allowed, cpu_active_mask); - mutex_unlock(&callback_mutex); - scan_for_empty_cpusets(&top_cpuset); - ndoms = generate_sched_domains(&doms, &attr); -@@ -2115,7 +2117,7 @@ static int cpuset_track_online_nodes(struct notifier_block *self, - - void __init cpuset_init_smp(void) - { -- cpumask_copy(top_cpuset.cpus_allowed, cpu_online_mask); -+ cpumask_copy(top_cpuset.cpus_allowed, cpu_active_mask); - top_cpuset.mems_allowed = node_states[N_HIGH_MEMORY]; - - hotcpu_notifier(cpuset_track_online_cpus, 0); -diff --git a/kernel/sched.c b/kernel/sched.c -index d079a9f..dd0dccd 100644 ---- a/kernel/sched.c -+++ b/kernel/sched.c -@@ -2036,6 +2036,9 @@ task_hot(struct task_struct *p, u64 now, struct sched_domain *sd) - { - s64 delta; - -+ if (p->sched_class != &fair_sched_class) -+ return 0; -+ - /* - * Buddy candidates are cache hot: - */ -@@ -2044,9 +2047,6 @@ task_hot(struct task_struct *p, u64 now, struct sched_domain *sd) - &p->se == cfs_rq_of(&p->se)->last)) - return 1; - -- if (p->sched_class != &fair_sched_class) -- return 0; -- - if (sysctl_sched_migration_cost == -1) - return 1; - if (sysctl_sched_migration_cost == 0) -@@ -4139,7 +4139,7 @@ static int load_balance(int this_cpu, struct rq *this_rq, - unsigned long flags; - struct cpumask *cpus = __get_cpu_var(load_balance_tmpmask); - -- cpumask_copy(cpus, cpu_online_mask); -+ cpumask_copy(cpus, cpu_active_mask); - - /* - * When power savings policy is enabled for the parent domain, idle -@@ -4302,7 +4302,7 @@ load_balance_newidle(int this_cpu, struct rq *this_rq, struct sched_domain *sd) - int all_pinned = 0; - struct cpumask *cpus = __get_cpu_var(load_balance_tmpmask); - -- cpumask_copy(cpus, cpu_online_mask); -+ cpumask_copy(cpus, cpu_active_mask); - - /* - * When power savings policy is enabled for the parent domain, idle -@@ -4699,7 +4699,7 @@ int select_nohz_load_balancer(int stop_tick) - cpumask_set_cpu(cpu, nohz.cpu_mask); - - /* time for ilb owner also to sleep */ -- if (cpumask_weight(nohz.cpu_mask) == num_online_cpus()) { -+ if (cpumask_weight(nohz.cpu_mask) == num_active_cpus()) { - if (atomic_read(&nohz.load_balancer) == cpu) - atomic_set(&nohz.load_balancer, -1); - return 0; -@@ -7075,7 +7075,7 @@ int set_cpus_allowed_ptr(struct task_struct *p, const struct cpumask *new_mask) - int ret = 0; - - rq = task_rq_lock(p, &flags); -- if (!cpumask_intersects(new_mask, cpu_online_mask)) { -+ if (!cpumask_intersects(new_mask, cpu_active_mask)) { - ret = -EINVAL; - goto out; - } -@@ -7097,7 +7097,7 @@ int set_cpus_allowed_ptr(struct task_struct *p, const struct cpumask *new_mask) - if (cpumask_test_cpu(task_cpu(p), new_mask)) - goto out; - -- if (migrate_task(p, cpumask_any_and(cpu_online_mask, new_mask), &req)) { -+ if (migrate_task(p, cpumask_any_and(cpu_active_mask, new_mask), &req)) { - /* Need help from migration thread: drop lock and wait. */ - struct task_struct *mt = rq->migration_thread; - -@@ -7251,19 +7251,19 @@ static void move_task_off_dead_cpu(int dead_cpu, struct task_struct *p) - - again: - /* Look for allowed, online CPU in same node. */ -- for_each_cpu_and(dest_cpu, nodemask, cpu_online_mask) -+ for_each_cpu_and(dest_cpu, nodemask, cpu_active_mask) - if (cpumask_test_cpu(dest_cpu, &p->cpus_allowed)) - goto move; - - /* Any allowed, online CPU? */ -- dest_cpu = cpumask_any_and(&p->cpus_allowed, cpu_online_mask); -+ dest_cpu = cpumask_any_and(&p->cpus_allowed, cpu_active_mask); - if (dest_cpu < nr_cpu_ids) - goto move; - - /* No more Mr. Nice Guy. */ - if (dest_cpu >= nr_cpu_ids) { - cpuset_cpus_allowed_locked(p, &p->cpus_allowed); -- dest_cpu = cpumask_any_and(cpu_online_mask, &p->cpus_allowed); -+ dest_cpu = cpumask_any_and(cpu_active_mask, &p->cpus_allowed); - - /* - * Don't tell them about moving exiting tasks or -@@ -7292,7 +7292,7 @@ move: - */ - static void migrate_nr_uninterruptible(struct rq *rq_src) - { -- struct rq *rq_dest = cpu_rq(cpumask_any(cpu_online_mask)); -+ struct rq *rq_dest = cpu_rq(cpumask_any(cpu_active_mask)); - unsigned long flags; - - local_irq_save(flags); -@@ -7546,7 +7546,7 @@ static ctl_table *sd_alloc_ctl_cpu_table(int cpu) - static struct ctl_table_header *sd_sysctl_header; - static void register_sched_domain_sysctl(void) - { -- int i, cpu_num = num_online_cpus(); -+ int i, cpu_num = num_possible_cpus(); - struct ctl_table *entry = sd_alloc_ctl_entry(cpu_num + 1); - char buf[32]; - -@@ -7556,7 +7556,7 @@ static void register_sched_domain_sysctl(void) - if (entry == NULL) - return; - -- for_each_online_cpu(i) { -+ for_each_possible_cpu(i) { - snprintf(buf, 32, "cpu%d", i); - entry->procname = kstrdup(buf, GFP_KERNEL); - entry->mode = 0555; -@@ -7925,6 +7925,8 @@ sd_parent_degenerate(struct sched_domain *sd, struct sched_domain *parent) - - static void free_rootdomain(struct root_domain *rd) - { -+ synchronize_sched(); -+ - cpupri_cleanup(&rd->cpupri); - - free_cpumask_var(rd->rto_mask); -@@ -9042,7 +9044,7 @@ match1: - if (doms_new == NULL) { - ndoms_cur = 0; - doms_new = fallback_doms; -- cpumask_andnot(&doms_new[0], cpu_online_mask, cpu_isolated_map); -+ cpumask_andnot(&doms_new[0], cpu_active_mask, cpu_isolated_map); - WARN_ON_ONCE(dattr_new); - } - -@@ -9173,8 +9175,10 @@ static int update_sched_domains(struct notifier_block *nfb, - switch (action) { - case CPU_ONLINE: - case CPU_ONLINE_FROZEN: -- case CPU_DEAD: -- case CPU_DEAD_FROZEN: -+ case CPU_DOWN_PREPARE: -+ case CPU_DOWN_PREPARE_FROZEN: -+ case CPU_DOWN_FAILED: -+ case CPU_DOWN_FAILED_FROZEN: - partition_sched_domains(1, NULL, NULL); - return NOTIFY_OK; - -@@ -9221,7 +9225,7 @@ void __init sched_init_smp(void) - #endif - get_online_cpus(); - mutex_lock(&sched_domains_mutex); -- arch_init_sched_domains(cpu_online_mask); -+ arch_init_sched_domains(cpu_active_mask); - cpumask_andnot(non_isolated_cpus, cpu_possible_mask, cpu_isolated_map); - if (cpumask_empty(non_isolated_cpus)) - cpumask_set_cpu(smp_processor_id(), non_isolated_cpus); -diff --git a/kernel/sched_fair.c b/kernel/sched_fair.c -index 5488a5d..199228b 100644 ---- a/kernel/sched_fair.c -+++ b/kernel/sched_fair.c -@@ -1374,6 +1374,9 @@ static int select_task_rq_fair(struct task_struct *p, int sd_flag, int wake_flag - - rcu_read_lock(); - for_each_domain(cpu, tmp) { -+ if (!(tmp->flags & SD_LOAD_BALANCE)) -+ continue; -+ - /* - * If power savings logic is enabled for a domain, see if we - * are not overloaded, if so, don't balance wider. -diff --git a/kernel/sysctl.c b/kernel/sysctl.c -index 0d949c5..dd84be9 100644 ---- a/kernel/sysctl.c -+++ b/kernel/sysctl.c -@@ -1200,6 +1200,7 @@ static struct ctl_table vm_table[] = { - .extra2 = (void *)&hugetlb_infinity, - }, - #endif -+#ifdef CONFIG_MMU - { - .ctl_name = VM_LOWMEM_RESERVE_RATIO, - .procname = "lowmem_reserve_ratio", -@@ -1353,6 +1354,7 @@ static struct ctl_table vm_table[] = { - .mode = 0644, - .proc_handler = &mmap_min_addr_handler, - }, -+#endif - #ifdef CONFIG_NUMA - { - .ctl_name = CTL_UNNUMBERED, -@@ -1605,7 +1607,8 @@ static struct ctl_table debug_table[] = { - .data = &show_unhandled_signals, - .maxlen = sizeof(int), - .mode = 0644, -- .proc_handler = proc_dointvec -+ .proc_handler = proc_dointvec_minmax, -+ .extra1 = &zero, - }, - #endif - { .ctl_name = 0 } -diff --git a/kernel/time/clockevents.c b/kernel/time/clockevents.c -index 620b58a..9484be4 100644 ---- a/kernel/time/clockevents.c -+++ b/kernel/time/clockevents.c -@@ -237,8 +237,9 @@ void clockevents_exchange_device(struct clock_event_device *old, - */ - void clockevents_notify(unsigned long reason, void *arg) - { -- struct list_head *node, *tmp; -+ struct clock_event_device *dev, *tmp; - unsigned long flags; -+ int cpu; - - spin_lock_irqsave(&clockevents_lock, flags); - clockevents_do_notify(reason, arg); -@@ -249,8 +250,19 @@ void clockevents_notify(unsigned long reason, void *arg) - * Unregister the clock event devices which were - * released from the users in the notify chain. - */ -- list_for_each_safe(node, tmp, &clockevents_released) -- list_del(node); -+ list_for_each_entry_safe(dev, tmp, &clockevents_released, list) -+ list_del(&dev->list); -+ /* -+ * Now check whether the CPU has left unused per cpu devices -+ */ -+ cpu = *((int *)arg); -+ list_for_each_entry_safe(dev, tmp, &clockevent_devices, list) { -+ if (cpumask_test_cpu(cpu, dev->cpumask) && -+ cpumask_weight(dev->cpumask) == 1) { -+ BUG_ON(dev->mode != CLOCK_EVT_MODE_UNUSED); -+ list_del(&dev->list); -+ } -+ } - break; - default: - break; -diff --git a/lib/dma-debug.c b/lib/dma-debug.c -index ce6b7ea..5a77c7c 100644 ---- a/lib/dma-debug.c -+++ b/lib/dma-debug.c -@@ -670,12 +670,13 @@ static int device_dma_allocations(struct device *dev) - return count; - } - --static int dma_debug_device_change(struct notifier_block *nb, -- unsigned long action, void *data) -+static int dma_debug_device_change(struct notifier_block *nb, unsigned long action, void *data) - { - struct device *dev = data; - int count; - -+ if (global_disable) -+ return 0; - - switch (action) { - case BUS_NOTIFY_UNBOUND_DRIVER: -@@ -697,6 +698,9 @@ void dma_debug_add_bus(struct bus_type *bus) - { - struct notifier_block *nb; - -+ if (global_disable) -+ return; -+ - nb = kzalloc(sizeof(struct notifier_block), GFP_KERNEL); - if (nb == NULL) { - pr_err("dma_debug_add_bus: out of memory\n"); -diff --git a/mm/Kconfig b/mm/Kconfig -index 44cf6f0..2c19c0b 100644 ---- a/mm/Kconfig -+++ b/mm/Kconfig -@@ -227,6 +227,7 @@ config KSM - - config DEFAULT_MMAP_MIN_ADDR - int "Low address space to protect from user allocation" -+ depends on MMU - default 4096 - help - This is the portion of low virtual memory which should be protected -diff --git a/mm/internal.h b/mm/internal.h -index 22ec8d2..17bc0df 100644 ---- a/mm/internal.h -+++ b/mm/internal.h -@@ -107,9 +107,10 @@ static inline int is_mlocked_vma(struct vm_area_struct *vma, struct page *page) - } - - /* -- * must be called with vma's mmap_sem held for read, and page locked. -+ * must be called with vma's mmap_sem held for read or write, and page locked. - */ - extern void mlock_vma_page(struct page *page); -+extern void munlock_vma_page(struct page *page); - - /* - * Clear the page's PageMlocked(). This can be useful in a situation where -diff --git a/mm/ksm.c b/mm/ksm.c -index 5575f86..e9501f8 100644 ---- a/mm/ksm.c -+++ b/mm/ksm.c -@@ -34,6 +34,7 @@ - #include - - #include -+#include "internal.h" - - /* - * A few notes about the KSM scanning process, -@@ -767,15 +768,14 @@ static int try_to_merge_one_page(struct vm_area_struct *vma, - * ptes are necessarily already write-protected. But in either - * case, we need to lock and check page_count is not raised. - */ -- if (write_protect_page(vma, oldpage, &orig_pte)) { -- unlock_page(oldpage); -- goto out_putpage; -- } -- unlock_page(oldpage); -- -- if (pages_identical(oldpage, newpage)) -+ if (write_protect_page(vma, oldpage, &orig_pte) == 0 && -+ pages_identical(oldpage, newpage)) - err = replace_page(vma, oldpage, newpage, orig_pte); - -+ if ((vma->vm_flags & VM_LOCKED) && !err) -+ munlock_vma_page(oldpage); -+ -+ unlock_page(oldpage); - out_putpage: - put_page(oldpage); - put_page(newpage); -diff --git a/mm/memcontrol.c b/mm/memcontrol.c -index 6314015..5dc1037 100644 ---- a/mm/memcontrol.c -+++ b/mm/memcontrol.c -@@ -758,7 +758,13 @@ int task_in_mem_cgroup(struct task_struct *task, const struct mem_cgroup *mem) - task_unlock(task); - if (!curr) - return 0; -- if (curr->use_hierarchy) -+ /* -+ * We should check use_hierarchy of "mem" not "curr". Because checking -+ * use_hierarchy of "curr" here make this function true if hierarchy is -+ * enabled in "curr" and "curr" is a child of "mem" in *cgroup* -+ * hierarchy(even if use_hierarchy is disabled in "mem"). -+ */ -+ if (mem->use_hierarchy) - ret = css_is_ancestor(&curr->css, &mem->css); - else - ret = (curr == mem); -diff --git a/mm/mlock.c b/mm/mlock.c -index bd6f0e4..2e05c97 100644 ---- a/mm/mlock.c -+++ b/mm/mlock.c -@@ -99,14 +99,14 @@ void mlock_vma_page(struct page *page) - * not get another chance to clear PageMlocked. If we successfully - * isolate the page and try_to_munlock() detects other VM_LOCKED vmas - * mapping the page, it will restore the PageMlocked state, unless the page -- * is mapped in a non-linear vma. So, we go ahead and SetPageMlocked(), -+ * is mapped in a non-linear vma. So, we go ahead and ClearPageMlocked(), - * perhaps redundantly. - * If we lose the isolation race, and the page is mapped by other VM_LOCKED - * vmas, we'll detect this in vmscan--via try_to_munlock() or try_to_unmap() - * either of which will restore the PageMlocked state by calling - * mlock_vma_page() above, if it can grab the vma's mmap sem. - */ --static void munlock_vma_page(struct page *page) -+void munlock_vma_page(struct page *page) - { - BUG_ON(!PageLocked(page)); - -diff --git a/mm/oom_kill.c b/mm/oom_kill.c -index ea2147d..9092b43 100644 ---- a/mm/oom_kill.c -+++ b/mm/oom_kill.c -@@ -404,7 +404,7 @@ static int oom_kill_process(struct task_struct *p, gfp_t gfp_mask, int order, - cpuset_print_task_mems_allowed(current); - task_unlock(current); - dump_stack(); -- mem_cgroup_print_oom_info(mem, current); -+ mem_cgroup_print_oom_info(mem, p); - show_mem(); - if (sysctl_oom_dump_tasks) - dump_tasks(mem); -diff --git a/mm/vmscan.c b/mm/vmscan.c -index 777af57..692807f 100644 ---- a/mm/vmscan.c -+++ b/mm/vmscan.c -@@ -1464,20 +1464,26 @@ static int inactive_file_is_low(struct zone *zone, struct scan_control *sc) - return low; - } - -+static int inactive_list_is_low(struct zone *zone, struct scan_control *sc, -+ int file) -+{ -+ if (file) -+ return inactive_file_is_low(zone, sc); -+ else -+ return inactive_anon_is_low(zone, sc); -+} -+ - static unsigned long shrink_list(enum lru_list lru, unsigned long nr_to_scan, - struct zone *zone, struct scan_control *sc, int priority) - { - int file = is_file_lru(lru); - -- if (lru == LRU_ACTIVE_FILE && inactive_file_is_low(zone, sc)) { -- shrink_active_list(nr_to_scan, zone, sc, priority, file); -+ if (is_active_lru(lru)) { -+ if (inactive_list_is_low(zone, sc, file)) -+ shrink_active_list(nr_to_scan, zone, sc, priority, file); - return 0; - } - -- if (lru == LRU_ACTIVE_ANON && inactive_anon_is_low(zone, sc)) { -- shrink_active_list(nr_to_scan, zone, sc, priority, file); -- return 0; -- } - return shrink_inactive_list(nr_to_scan, zone, sc, priority, file); - } - -diff --git a/net/ipv4/netfilter/nf_defrag_ipv4.c b/net/ipv4/netfilter/nf_defrag_ipv4.c -index fa2d6b6..331ead3 100644 ---- a/net/ipv4/netfilter/nf_defrag_ipv4.c -+++ b/net/ipv4/netfilter/nf_defrag_ipv4.c -@@ -14,6 +14,7 @@ - #include - #include - -+#include - #include - #include - -@@ -34,6 +35,20 @@ static int nf_ct_ipv4_gather_frags(struct sk_buff *skb, u_int32_t user) - return err; - } - -+static enum ip_defrag_users nf_ct_defrag_user(unsigned int hooknum, -+ struct sk_buff *skb) -+{ -+#ifdef CONFIG_BRIDGE_NETFILTER -+ if (skb->nf_bridge && -+ skb->nf_bridge->mask & BRNF_NF_BRIDGE_PREROUTING) -+ return IP_DEFRAG_CONNTRACK_BRIDGE_IN; -+#endif -+ if (hooknum == NF_INET_PRE_ROUTING) -+ return IP_DEFRAG_CONNTRACK_IN; -+ else -+ return IP_DEFRAG_CONNTRACK_OUT; -+} -+ - static unsigned int ipv4_conntrack_defrag(unsigned int hooknum, - struct sk_buff *skb, - const struct net_device *in, -@@ -50,10 +65,8 @@ static unsigned int ipv4_conntrack_defrag(unsigned int hooknum, - #endif - /* Gather fragments. */ - if (ip_hdr(skb)->frag_off & htons(IP_MF | IP_OFFSET)) { -- if (nf_ct_ipv4_gather_frags(skb, -- hooknum == NF_INET_PRE_ROUTING ? -- IP_DEFRAG_CONNTRACK_IN : -- IP_DEFRAG_CONNTRACK_OUT)) -+ enum ip_defrag_users user = nf_ct_defrag_user(hooknum, skb); -+ if (nf_ct_ipv4_gather_frags(skb, user)) - return NF_STOLEN; - } - return NF_ACCEPT; -diff --git a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c -index 5f2ec20..0956eba 100644 ---- a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c -+++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c -@@ -20,6 +20,7 @@ - #include - #include - -+#include - #include - #include - #include -@@ -187,6 +188,21 @@ out: - return nf_conntrack_confirm(skb); - } - -+static enum ip6_defrag_users nf_ct6_defrag_user(unsigned int hooknum, -+ struct sk_buff *skb) -+{ -+#ifdef CONFIG_BRIDGE_NETFILTER -+ if (skb->nf_bridge && -+ skb->nf_bridge->mask & BRNF_NF_BRIDGE_PREROUTING) -+ return IP6_DEFRAG_CONNTRACK_BRIDGE_IN; -+#endif -+ if (hooknum == NF_INET_PRE_ROUTING) -+ return IP6_DEFRAG_CONNTRACK_IN; -+ else -+ return IP6_DEFRAG_CONNTRACK_OUT; -+ -+} -+ - static unsigned int ipv6_defrag(unsigned int hooknum, - struct sk_buff *skb, - const struct net_device *in, -@@ -199,8 +215,7 @@ static unsigned int ipv6_defrag(unsigned int hooknum, - if (skb->nfct) - return NF_ACCEPT; - -- reasm = nf_ct_frag6_gather(skb); -- -+ reasm = nf_ct_frag6_gather(skb, nf_ct6_defrag_user(hooknum, skb)); - /* queued */ - if (reasm == NULL) - return NF_STOLEN; -diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c -index f3aba25..4b6a539 100644 ---- a/net/ipv6/netfilter/nf_conntrack_reasm.c -+++ b/net/ipv6/netfilter/nf_conntrack_reasm.c -@@ -170,13 +170,14 @@ out: - /* Creation primitives. */ - - static __inline__ struct nf_ct_frag6_queue * --fq_find(__be32 id, struct in6_addr *src, struct in6_addr *dst) -+fq_find(__be32 id, u32 user, struct in6_addr *src, struct in6_addr *dst) - { - struct inet_frag_queue *q; - struct ip6_create_arg arg; - unsigned int hash; - - arg.id = id; -+ arg.user = user; - arg.src = src; - arg.dst = dst; - -@@ -561,7 +562,7 @@ find_prev_fhdr(struct sk_buff *skb, u8 *prevhdrp, int *prevhoff, int *fhoff) - return 0; - } - --struct sk_buff *nf_ct_frag6_gather(struct sk_buff *skb) -+struct sk_buff *nf_ct_frag6_gather(struct sk_buff *skb, u32 user) - { - struct sk_buff *clone; - struct net_device *dev = skb->dev; -@@ -607,7 +608,7 @@ struct sk_buff *nf_ct_frag6_gather(struct sk_buff *skb) - if (atomic_read(&nf_init_frags.mem) > nf_init_frags.high_thresh) - nf_ct_frag6_evictor(); - -- fq = fq_find(fhdr->identification, &hdr->saddr, &hdr->daddr); -+ fq = fq_find(fhdr->identification, user, &hdr->saddr, &hdr->daddr); - if (fq == NULL) { - pr_debug("Can't find and can't create new queue\n"); - goto ret_orig; -diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c -index da5bd0e..4d18699 100644 ---- a/net/ipv6/reassembly.c -+++ b/net/ipv6/reassembly.c -@@ -72,6 +72,7 @@ struct frag_queue - struct inet_frag_queue q; - - __be32 id; /* fragment id */ -+ u32 user; - struct in6_addr saddr; - struct in6_addr daddr; - -@@ -141,7 +142,7 @@ int ip6_frag_match(struct inet_frag_queue *q, void *a) - struct ip6_create_arg *arg = a; - - fq = container_of(q, struct frag_queue, q); -- return (fq->id == arg->id && -+ return (fq->id == arg->id && fq->user == arg->user && - ipv6_addr_equal(&fq->saddr, arg->src) && - ipv6_addr_equal(&fq->daddr, arg->dst)); - } -@@ -163,6 +164,7 @@ void ip6_frag_init(struct inet_frag_queue *q, void *a) - struct ip6_create_arg *arg = a; - - fq->id = arg->id; -+ fq->user = arg->user; - ipv6_addr_copy(&fq->saddr, arg->src); - ipv6_addr_copy(&fq->daddr, arg->dst); - } -@@ -244,6 +246,7 @@ fq_find(struct net *net, __be32 id, struct in6_addr *src, struct in6_addr *dst, - unsigned int hash; - - arg.id = id; -+ arg.user = IP6_DEFRAG_LOCAL_DELIVER; - arg.src = src; - arg.dst = dst; - -diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c -index f1362f3..fbffce9 100644 ---- a/net/mac80211/ibss.c -+++ b/net/mac80211/ibss.c -@@ -455,6 +455,10 @@ static void ieee80211_sta_merge_ibss(struct ieee80211_sub_if_data *sdata) - - ieee80211_sta_expire(sdata, IEEE80211_IBSS_INACTIVITY_LIMIT); - -+ if (time_before(jiffies, ifibss->last_scan_completed + -+ IEEE80211_IBSS_MERGE_INTERVAL)) -+ return; -+ - if (ieee80211_sta_active_ibss(sdata)) - return; - -diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c -index dc5049d..f13d181 100644 ---- a/net/mac80211/mlme.c -+++ b/net/mac80211/mlme.c -@@ -904,6 +904,14 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, - sdata->u.mgd.flags &= ~(IEEE80211_STA_CONNECTION_POLL | - IEEE80211_STA_BEACON_POLL); - -+ /* -+ * Always handle WMM once after association regardless -+ * of the first value the AP uses. Setting -1 here has -+ * that effect because the AP values is an unsigned -+ * 4-bit value. -+ */ -+ sdata->u.mgd.wmm_last_param_set = -1; -+ - ieee80211_led_assoc(local, 1); - - sdata->vif.bss_conf.assoc = 1; -diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c -index eaa4118..d398197 100644 ---- a/net/mac80211/tx.c -+++ b/net/mac80211/tx.c -@@ -1401,6 +1401,7 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, - - if ((local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) && - local->hw.conf.dynamic_ps_timeout > 0 && -+ !local->quiescing && - !(local->scanning) && local->ps_sdata) { - if (local->hw.conf.flags & IEEE80211_CONF_PS) { - ieee80211_stop_queues_by_reason(&local->hw, -diff --git a/net/mac80211/util.c b/net/mac80211/util.c -index cbc5d20..51e0bd2 100644 ---- a/net/mac80211/util.c -+++ b/net/mac80211/util.c -@@ -1031,7 +1031,19 @@ int ieee80211_reconfig(struct ieee80211_local *local) - - /* restart hardware */ - if (local->open_count) { -+ /* -+ * Upon resume hardware can sometimes be goofy due to -+ * various platform / driver / bus issues, so restarting -+ * the device may at times not work immediately. Propagate -+ * the error. -+ */ - res = drv_start(local); -+ if (res) { -+ WARN(local->suspended, "Harware became unavailable " -+ "upon resume. This is could be a software issue" -+ "prior to suspend or a harware issue\n"); -+ return res; -+ } - - ieee80211_led_radio(local, true); - } -diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c -index 0a6b7a0..0d86248 100644 ---- a/net/wireless/mlme.c -+++ b/net/wireless/mlme.c -@@ -94,7 +94,18 @@ void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len) - } - } - -- WARN_ON(!bss); -+ /* -+ * We might be coming here because the driver reported -+ * a successful association at the same time as the -+ * user requested a deauth. In that case, we will have -+ * removed the BSS from the auth_bsses list due to the -+ * deauth request when the assoc response makes it. If -+ * the two code paths acquire the lock the other way -+ * around, that's just the standard situation of a -+ * deauth being requested while connected. -+ */ -+ if (!bss) -+ goto out; - } else if (wdev->conn) { - cfg80211_sme_failed_assoc(wdev); - need_connect_result = false; -diff --git a/security/Makefile b/security/Makefile -index 95ecc06..510bbc8 100644 ---- a/security/Makefile -+++ b/security/Makefile -@@ -8,7 +8,8 @@ subdir-$(CONFIG_SECURITY_SMACK) += smack - subdir-$(CONFIG_SECURITY_TOMOYO) += tomoyo - - # always enable default capabilities --obj-y += commoncap.o min_addr.o -+obj-y += commoncap.o -+obj-$(CONFIG_MMU) += min_addr.o - - # Object file lists - obj-$(CONFIG_SECURITY) += security.o capability.o -diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c -index 06ec722..1cad4c7 100644 ---- a/security/keys/keyctl.c -+++ b/security/keys/keyctl.c -@@ -1236,6 +1236,7 @@ long keyctl_get_security(key_serial_t keyid, - */ - long keyctl_session_to_parent(void) - { -+#ifdef TIF_NOTIFY_RESUME - struct task_struct *me, *parent; - const struct cred *mycred, *pcred; - struct cred *cred, *oldcred; -@@ -1326,6 +1327,15 @@ not_permitted: - error_keyring: - key_ref_put(keyring_r); - return ret; -+ -+#else /* !TIF_NOTIFY_RESUME */ -+ /* -+ * To be removed when TIF_NOTIFY_RESUME has been implemented on -+ * m68k/xtensa -+ */ -+#warning TIF_NOTIFY_RESUME not implemented -+ return -EOPNOTSUPP; -+#endif /* !TIF_NOTIFY_RESUME */ - } - - /*****************************************************************************/ -diff --git a/sound/mips/sgio2audio.c b/sound/mips/sgio2audio.c -index 8691f4c..f1d9d16 100644 ---- a/sound/mips/sgio2audio.c -+++ b/sound/mips/sgio2audio.c -@@ -609,7 +609,7 @@ static int snd_sgio2audio_pcm_hw_params(struct snd_pcm_substream *substream, - /* alloc virtual 'dma' area */ - if (runtime->dma_area) - vfree(runtime->dma_area); -- runtime->dma_area = vmalloc(size); -+ runtime->dma_area = vmalloc_user(size); - if (runtime->dma_area == NULL) - return -ENOMEM; - runtime->dma_bytes = size; -diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c -index 7058371..e40d31f 100644 ---- a/sound/pci/hda/patch_realtek.c -+++ b/sound/pci/hda/patch_realtek.c -@@ -9141,6 +9141,8 @@ static struct alc_config_preset alc882_presets[] = { - .dac_nids = alc883_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc889_adc_nids), - .adc_nids = alc889_adc_nids, -+ .capsrc_nids = alc889_capsrc_nids, -+ .capsrc_nids = alc889_capsrc_nids, - .dig_out_nid = ALC883_DIGOUT_NID, - .dig_in_nid = ALC883_DIGIN_NID, - .slave_dig_outs = alc883_slave_dig_outs, -@@ -9187,6 +9189,7 @@ static struct alc_config_preset alc882_presets[] = { - .dac_nids = alc883_dac_nids, - .adc_nids = alc883_adc_nids_alt, - .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt), -+ .capsrc_nids = alc883_capsrc_nids, - .dig_out_nid = ALC883_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), - .channel_mode = alc883_3ST_2ch_modes, -@@ -9333,6 +9336,7 @@ static struct alc_config_preset alc882_presets[] = { - .dac_nids = alc883_dac_nids, - .adc_nids = alc883_adc_nids_alt, - .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt), -+ .capsrc_nids = alc883_capsrc_nids, - .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes), - .channel_mode = alc883_sixstack_modes, - .input_mux = &alc883_capture_source, -@@ -9394,6 +9398,7 @@ static struct alc_config_preset alc882_presets[] = { - .dac_nids = alc883_dac_nids, - .adc_nids = alc883_adc_nids_alt, - .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt), -+ .capsrc_nids = alc883_capsrc_nids, - .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), - .channel_mode = alc883_3ST_2ch_modes, - .input_mux = &alc883_lenovo_101e_capture_source, -@@ -9573,6 +9578,7 @@ static struct alc_config_preset alc882_presets[] = { - alc880_gpio1_init_verbs }, - .adc_nids = alc883_adc_nids, - .num_adc_nids = ARRAY_SIZE(alc883_adc_nids), -+ .capsrc_nids = alc883_capsrc_nids, - .dac_nids = alc883_dac_nids, - .num_dacs = ARRAY_SIZE(alc883_dac_nids), - .channel_mode = alc889A_mb31_6ch_modes, -diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c b/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c -index d057e64..5cfa608 100644 ---- a/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c -+++ b/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c -@@ -51,7 +51,7 @@ static int snd_pcm_alloc_vmalloc_buffer(struct snd_pcm_substream *subs, size_t s - return 0; /* already enough large */ - vfree(runtime->dma_area); - } -- runtime->dma_area = vmalloc_32(size); -+ runtime->dma_area = vmalloc_32_user(size); - if (! runtime->dma_area) - return -ENOMEM; - runtime->dma_bytes = size; -diff --git a/sound/soc/codecs/wm8974.c b/sound/soc/codecs/wm8974.c -index 98d663a..b0bd1c0 100644 ---- a/sound/soc/codecs/wm8974.c -+++ b/sound/soc/codecs/wm8974.c -@@ -47,7 +47,7 @@ static const u16 wm8974_reg[WM8974_CACHEREGNUM] = { - }; - - #define WM8974_POWER1_BIASEN 0x08 --#define WM8974_POWER1_BUFIOEN 0x10 -+#define WM8974_POWER1_BUFIOEN 0x04 - - struct wm8974_priv { - struct snd_soc_codec codec; -diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c -index 1fd4e88..e9123f5 100644 ---- a/sound/soc/codecs/wm9712.c -+++ b/sound/soc/codecs/wm9712.c -@@ -464,7 +464,8 @@ static int ac97_write(struct snd_soc_codec *codec, unsigned int reg, - { - u16 *cache = codec->reg_cache; - -- soc_ac97_ops.write(codec->ac97, reg, val); -+ if (reg < 0x7c) -+ soc_ac97_ops.write(codec->ac97, reg, val); - reg = reg >> 1; - if (reg < (ARRAY_SIZE(wm9712_reg))) - cache[reg] = val; -diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c -index 8db0374..8803d9d 100644 ---- a/sound/usb/usbaudio.c -+++ b/sound/usb/usbaudio.c -@@ -752,7 +752,7 @@ static int snd_pcm_alloc_vmalloc_buffer(struct snd_pcm_substream *subs, size_t s - return 0; /* already large enough */ - vfree(runtime->dma_area); - } -- runtime->dma_area = vmalloc(size); -+ runtime->dma_area = vmalloc_user(size); - if (!runtime->dma_area) - return -ENOMEM; - runtime->dma_bytes = size; diff --git a/debian/patches/bugfix/all/stable/2.6.32.4.patch b/debian/patches/bugfix/all/stable/2.6.32.4.patch deleted file mode 100644 index 5d06a2a78..000000000 --- a/debian/patches/bugfix/all/stable/2.6.32.4.patch +++ /dev/null @@ -1,4651 +0,0 @@ -diff --git a/Makefile b/Makefile -index 482dcdd..6d13598 100644 -diff --git a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c -index 9a3334a..62619f2 100644 ---- a/arch/alpha/kernel/osf_sys.c -+++ b/arch/alpha/kernel/osf_sys.c -@@ -178,25 +178,18 @@ SYSCALL_DEFINE6(osf_mmap, unsigned long, addr, unsigned long, len, - unsigned long, prot, unsigned long, flags, unsigned long, fd, - unsigned long, off) - { -- struct file *file = NULL; -- unsigned long ret = -EBADF; -+ unsigned long ret = -EINVAL; - - #if 0 - if (flags & (_MAP_HASSEMAPHORE | _MAP_INHERIT | _MAP_UNALIGNED)) - printk("%s: unimplemented OSF mmap flags %04lx\n", - current->comm, flags); - #endif -- if (!(flags & MAP_ANONYMOUS)) { -- file = fget(fd); -- if (!file) -- goto out; -- } -- flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); -- down_write(¤t->mm->mmap_sem); -- ret = do_mmap(file, addr, len, prot, flags, off); -- up_write(¤t->mm->mmap_sem); -- if (file) -- fput(file); -+ if ((off + PAGE_ALIGN(len)) < off) -+ goto out; -+ if (off & ~PAGE_MASK) -+ goto out; -+ ret = sys_mmap_pgoff(addr, len, prot, flags, fd, off >> PAGE_SHIFT); - out: - return ret; - } -diff --git a/arch/arm/include/asm/mman.h b/arch/arm/include/asm/mman.h -index 8eebf89..41f99c5 100644 ---- a/arch/arm/include/asm/mman.h -+++ b/arch/arm/include/asm/mman.h -@@ -1 +1,4 @@ - #include -+ -+#define arch_mmap_check(addr, len, flags) \ -+ (((flags) & MAP_FIXED && (addr) < FIRST_USER_ADDRESS) ? -EINVAL : 0) -diff --git a/arch/arm/kernel/calls.S b/arch/arm/kernel/calls.S -index fafce1b..4f07168 100644 ---- a/arch/arm/kernel/calls.S -+++ b/arch/arm/kernel/calls.S -@@ -172,7 +172,7 @@ - /* 160 */ CALL(sys_sched_get_priority_min) - CALL(sys_sched_rr_get_interval) - CALL(sys_nanosleep) -- CALL(sys_arm_mremap) -+ CALL(sys_mremap) - CALL(sys_setresuid16) - /* 165 */ CALL(sys_getresuid16) - CALL(sys_ni_syscall) /* vm86 */ -diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S -index f0fe95b..2c1db77 100644 ---- a/arch/arm/kernel/entry-common.S -+++ b/arch/arm/kernel/entry-common.S -@@ -416,12 +416,12 @@ sys_mmap2: - tst r5, #PGOFF_MASK - moveq r5, r5, lsr #PAGE_SHIFT - 12 - streq r5, [sp, #4] -- beq do_mmap2 -+ beq sys_mmap_pgoff - mov r0, #-EINVAL - mov pc, lr - #else - str r5, [sp, #4] -- b do_mmap2 -+ b sys_mmap_pgoff - #endif - ENDPROC(sys_mmap2) - -diff --git a/arch/arm/kernel/sys_arm.c b/arch/arm/kernel/sys_arm.c -index 78ecaac..ae4027b 100644 ---- a/arch/arm/kernel/sys_arm.c -+++ b/arch/arm/kernel/sys_arm.c -@@ -28,41 +28,6 @@ - #include - #include - --extern unsigned long do_mremap(unsigned long addr, unsigned long old_len, -- unsigned long new_len, unsigned long flags, -- unsigned long new_addr); -- --/* common code for old and new mmaps */ --inline long do_mmap2( -- unsigned long addr, unsigned long len, -- unsigned long prot, unsigned long flags, -- unsigned long fd, unsigned long pgoff) --{ -- int error = -EINVAL; -- struct file * file = NULL; -- -- flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); -- -- if (flags & MAP_FIXED && addr < FIRST_USER_ADDRESS) -- goto out; -- -- error = -EBADF; -- if (!(flags & MAP_ANONYMOUS)) { -- file = fget(fd); -- if (!file) -- goto out; -- } -- -- down_write(¤t->mm->mmap_sem); -- error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); -- up_write(¤t->mm->mmap_sem); -- -- if (file) -- fput(file); --out: -- return error; --} -- - struct mmap_arg_struct { - unsigned long addr; - unsigned long len; -@@ -84,29 +49,11 @@ asmlinkage int old_mmap(struct mmap_arg_struct __user *arg) - if (a.offset & ~PAGE_MASK) - goto out; - -- error = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT); -+ error = sys_mmap_pgoff(a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT); - out: - return error; - } - --asmlinkage unsigned long --sys_arm_mremap(unsigned long addr, unsigned long old_len, -- unsigned long new_len, unsigned long flags, -- unsigned long new_addr) --{ -- unsigned long ret = -EINVAL; -- -- if (flags & MREMAP_FIXED && new_addr < FIRST_USER_ADDRESS) -- goto out; -- -- down_write(¤t->mm->mmap_sem); -- ret = do_mremap(addr, old_len, new_len, flags, new_addr); -- up_write(¤t->mm->mmap_sem); -- --out: -- return ret; --} -- - /* - * Perform the select(nd, in, out, ex, tv) and mmap() system - * calls. -diff --git a/arch/arm/mm/mmap.c b/arch/arm/mm/mmap.c -index 2b79964..f5abc51 100644 ---- a/arch/arm/mm/mmap.c -+++ b/arch/arm/mm/mmap.c -@@ -54,7 +54,8 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr, - * We enforce the MAP_FIXED case. - */ - if (flags & MAP_FIXED) { -- if (aliasing && flags & MAP_SHARED && addr & (SHMLBA - 1)) -+ if (aliasing && flags & MAP_SHARED && -+ (addr - (pgoff << PAGE_SHIFT)) & (SHMLBA - 1)) - return -EINVAL; - return addr; - } -diff --git a/arch/avr32/include/asm/syscalls.h b/arch/avr32/include/asm/syscalls.h -index 483d666..66a1972 100644 ---- a/arch/avr32/include/asm/syscalls.h -+++ b/arch/avr32/include/asm/syscalls.h -@@ -29,10 +29,6 @@ asmlinkage int sys_sigaltstack(const stack_t __user *, stack_t __user *, - struct pt_regs *); - asmlinkage int sys_rt_sigreturn(struct pt_regs *); - --/* kernel/sys_avr32.c */ --asmlinkage long sys_mmap2(unsigned long, unsigned long, unsigned long, -- unsigned long, unsigned long, off_t); -- - /* mm/cache.c */ - asmlinkage int sys_cacheflush(int, void __user *, size_t); - -diff --git a/arch/avr32/kernel/sys_avr32.c b/arch/avr32/kernel/sys_avr32.c -index 5d2daea..459349b 100644 ---- a/arch/avr32/kernel/sys_avr32.c -+++ b/arch/avr32/kernel/sys_avr32.c -@@ -5,39 +5,8 @@ - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ --#include --#include --#include --#include - #include - --#include --#include --#include -- --asmlinkage long sys_mmap2(unsigned long addr, unsigned long len, -- unsigned long prot, unsigned long flags, -- unsigned long fd, off_t offset) --{ -- int error = -EBADF; -- struct file *file = NULL; -- -- flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); -- if (!(flags & MAP_ANONYMOUS)) { -- file = fget(fd); -- if (!file) -- return error; -- } -- -- down_write(¤t->mm->mmap_sem); -- error = do_mmap_pgoff(file, addr, len, prot, flags, offset); -- up_write(¤t->mm->mmap_sem); -- -- if (file) -- fput(file); -- return error; --} -- - int kernel_execve(const char *file, char **argv, char **envp) - { - register long scno asm("r8") = __NR_execve; -diff --git a/arch/avr32/kernel/syscall-stubs.S b/arch/avr32/kernel/syscall-stubs.S -index f7244cd..0447a3e 100644 ---- a/arch/avr32/kernel/syscall-stubs.S -+++ b/arch/avr32/kernel/syscall-stubs.S -@@ -61,7 +61,7 @@ __sys_execve: - __sys_mmap2: - pushm lr - st.w --sp, ARG6 -- call sys_mmap2 -+ call sys_mmap_pgoff - sub sp, -4 - popm pc - -diff --git a/arch/blackfin/kernel/sys_bfin.c b/arch/blackfin/kernel/sys_bfin.c -index afcef12..2e7f8e1 100644 ---- a/arch/blackfin/kernel/sys_bfin.c -+++ b/arch/blackfin/kernel/sys_bfin.c -@@ -22,39 +22,6 @@ - #include - #include - --/* common code for old and new mmaps */ --static inline long --do_mmap2(unsigned long addr, unsigned long len, -- unsigned long prot, unsigned long flags, -- unsigned long fd, unsigned long pgoff) --{ -- int error = -EBADF; -- struct file *file = NULL; -- -- flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); -- if (!(flags & MAP_ANONYMOUS)) { -- file = fget(fd); -- if (!file) -- goto out; -- } -- -- down_write(¤t->mm->mmap_sem); -- error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); -- up_write(¤t->mm->mmap_sem); -- -- if (file) -- fput(file); -- out: -- return error; --} -- --asmlinkage long sys_mmap2(unsigned long addr, unsigned long len, -- unsigned long prot, unsigned long flags, -- unsigned long fd, unsigned long pgoff) --{ -- return do_mmap2(addr, len, prot, flags, fd, pgoff); --} -- - asmlinkage void *sys_sram_alloc(size_t size, unsigned long flags) - { - return sram_alloc_with_lsl(size, flags); -diff --git a/arch/blackfin/mach-common/entry.S b/arch/blackfin/mach-common/entry.S -index 94a0375..1d8f00a 100644 ---- a/arch/blackfin/mach-common/entry.S -+++ b/arch/blackfin/mach-common/entry.S -@@ -1422,7 +1422,7 @@ ENTRY(_sys_call_table) - .long _sys_ni_syscall /* streams2 */ - .long _sys_vfork /* 190 */ - .long _sys_getrlimit -- .long _sys_mmap2 -+ .long _sys_mmap_pgoff - .long _sys_truncate64 - .long _sys_ftruncate64 - .long _sys_stat64 /* 195 */ -diff --git a/arch/cris/kernel/sys_cris.c b/arch/cris/kernel/sys_cris.c -index 2ad962c..c2bbb1a 100644 ---- a/arch/cris/kernel/sys_cris.c -+++ b/arch/cris/kernel/sys_cris.c -@@ -26,31 +26,6 @@ - #include - #include - --/* common code for old and new mmaps */ --static inline long --do_mmap2(unsigned long addr, unsigned long len, unsigned long prot, -- unsigned long flags, unsigned long fd, unsigned long pgoff) --{ -- int error = -EBADF; -- struct file * file = NULL; -- -- flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); -- if (!(flags & MAP_ANONYMOUS)) { -- file = fget(fd); -- if (!file) -- goto out; -- } -- -- down_write(¤t->mm->mmap_sem); -- error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); -- up_write(¤t->mm->mmap_sem); -- -- if (file) -- fput(file); --out: -- return error; --} -- - asmlinkage unsigned long old_mmap(unsigned long __user *args) - { - unsigned long buffer[6]; -@@ -63,7 +38,7 @@ asmlinkage unsigned long old_mmap(unsigned long __user *args) - if (buffer[5] & ~PAGE_MASK) /* verify that offset is on page boundary */ - goto out; - -- err = do_mmap2(buffer[0], buffer[1], buffer[2], buffer[3], -+ err = sys_mmap_pgoff(buffer[0], buffer[1], buffer[2], buffer[3], - buffer[4], buffer[5] >> PAGE_SHIFT); - out: - return err; -@@ -73,7 +48,8 @@ asmlinkage long - sys_mmap2(unsigned long addr, unsigned long len, unsigned long prot, - unsigned long flags, unsigned long fd, unsigned long pgoff) - { -- return do_mmap2(addr, len, prot, flags, fd, pgoff); -+ /* bug(?): 8Kb pages here */ -+ return sys_mmap_pgoff(addr, len, prot, flags, fd, pgoff); - } - - /* -diff --git a/arch/frv/kernel/sys_frv.c b/arch/frv/kernel/sys_frv.c -index 2b6b528..1d3d4c9 100644 ---- a/arch/frv/kernel/sys_frv.c -+++ b/arch/frv/kernel/sys_frv.c -@@ -31,9 +31,6 @@ asmlinkage long sys_mmap2(unsigned long addr, unsigned long len, - unsigned long prot, unsigned long flags, - unsigned long fd, unsigned long pgoff) - { -- int error = -EBADF; -- struct file * file = NULL; -- - /* As with sparc32, make sure the shift for mmap2 is constant - (12), no matter what PAGE_SIZE we have.... */ - -@@ -41,69 +38,10 @@ asmlinkage long sys_mmap2(unsigned long addr, unsigned long len, - trying to map something we can't */ - if (pgoff & ((1 << (PAGE_SHIFT - 12)) - 1)) - return -EINVAL; -- pgoff >>= PAGE_SHIFT - 12; -- -- flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); -- if (!(flags & MAP_ANONYMOUS)) { -- file = fget(fd); -- if (!file) -- goto out; -- } -- -- down_write(¤t->mm->mmap_sem); -- error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); -- up_write(¤t->mm->mmap_sem); -- -- if (file) -- fput(file); --out: -- return error; --} -- --#if 0 /* DAVIDM - do we want this */ --struct mmap_arg_struct64 { -- __u32 addr; -- __u32 len; -- __u32 prot; -- __u32 flags; -- __u64 offset; /* 64 bits */ -- __u32 fd; --}; -- --asmlinkage long sys_mmap64(struct mmap_arg_struct64 *arg) --{ -- int error = -EFAULT; -- struct file * file = NULL; -- struct mmap_arg_struct64 a; -- unsigned long pgoff; -- -- if (copy_from_user(&a, arg, sizeof(a))) -- return -EFAULT; -- -- if ((long)a.offset & ~PAGE_MASK) -- return -EINVAL; -- -- pgoff = a.offset >> PAGE_SHIFT; -- if ((a.offset >> PAGE_SHIFT) != pgoff) -- return -EINVAL; -- -- if (!(a.flags & MAP_ANONYMOUS)) { -- error = -EBADF; -- file = fget(a.fd); -- if (!file) -- goto out; -- } -- a.flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); - -- down_write(¤t->mm->mmap_sem); -- error = do_mmap_pgoff(file, a.addr, a.len, a.prot, a.flags, pgoff); -- up_write(¤t->mm->mmap_sem); -- if (file) -- fput(file); --out: -- return error; -+ return sys_mmap_pgoff(addr, len, prot, flags, fd, -+ pgoff >> (PAGE_SHIFT - 12)); - } --#endif - - /* - * sys_ipc() is the de-multiplexer for the SysV IPC calls.. -diff --git a/arch/h8300/kernel/sys_h8300.c b/arch/h8300/kernel/sys_h8300.c -index 8cb5d73..b5969db 100644 ---- a/arch/h8300/kernel/sys_h8300.c -+++ b/arch/h8300/kernel/sys_h8300.c -@@ -26,39 +26,6 @@ - #include - #include - --/* common code for old and new mmaps */ --static inline long do_mmap2( -- unsigned long addr, unsigned long len, -- unsigned long prot, unsigned long flags, -- unsigned long fd, unsigned long pgoff) --{ -- int error = -EBADF; -- struct file * file = NULL; -- -- flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); -- if (!(flags & MAP_ANONYMOUS)) { -- file = fget(fd); -- if (!file) -- goto out; -- } -- -- down_write(¤t->mm->mmap_sem); -- error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); -- up_write(¤t->mm->mmap_sem); -- -- if (file) -- fput(file); --out: -- return error; --} -- --asmlinkage long sys_mmap2(unsigned long addr, unsigned long len, -- unsigned long prot, unsigned long flags, -- unsigned long fd, unsigned long pgoff) --{ -- return do_mmap2(addr, len, prot, flags, fd, pgoff); --} -- - /* - * Perform the select(nd, in, out, ex, tv) and mmap() system - * calls. Linux/m68k cloned Linux/i386, which didn't use to be able to -@@ -87,57 +54,11 @@ asmlinkage int old_mmap(struct mmap_arg_struct *arg) - if (a.offset & ~PAGE_MASK) - goto out; - -- a.flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); -- -- error = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT); --out: -- return error; --} -- --#if 0 /* DAVIDM - do we want this */ --struct mmap_arg_struct64 { -- __u32 addr; -- __u32 len; -- __u32 prot; -- __u32 flags; -- __u64 offset; /* 64 bits */ -- __u32 fd; --}; -- --asmlinkage long sys_mmap64(struct mmap_arg_struct64 *arg) --{ -- int error = -EFAULT; -- struct file * file = NULL; -- struct mmap_arg_struct64 a; -- unsigned long pgoff; -- -- if (copy_from_user(&a, arg, sizeof(a))) -- return -EFAULT; -- -- if ((long)a.offset & ~PAGE_MASK) -- return -EINVAL; -- -- pgoff = a.offset >> PAGE_SHIFT; -- if ((a.offset >> PAGE_SHIFT) != pgoff) -- return -EINVAL; -- -- if (!(a.flags & MAP_ANONYMOUS)) { -- error = -EBADF; -- file = fget(a.fd); -- if (!file) -- goto out; -- } -- a.flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); -- -- down_write(¤t->mm->mmap_sem); -- error = do_mmap_pgoff(file, a.addr, a.len, a.prot, a.flags, pgoff); -- up_write(¤t->mm->mmap_sem); -- if (file) -- fput(file); -+ error = sys_mmap_pgoff(a.addr, a.len, a.prot, a.flags, a.fd, -+ a.offset >> PAGE_SHIFT); - out: - return error; - } --#endif - - struct sel_arg_struct { - unsigned long n; -diff --git a/arch/h8300/kernel/syscalls.S b/arch/h8300/kernel/syscalls.S -index 4eb67fa..2d69881 100644 ---- a/arch/h8300/kernel/syscalls.S -+++ b/arch/h8300/kernel/syscalls.S -@@ -206,7 +206,7 @@ SYMBOL_NAME_LABEL(sys_call_table) - .long SYMBOL_NAME(sys_ni_syscall) /* streams2 */ - .long SYMBOL_NAME(sys_vfork) /* 190 */ - .long SYMBOL_NAME(sys_getrlimit) -- .long SYMBOL_NAME(sys_mmap2) -+ .long SYMBOL_NAME(sys_mmap_pgoff) - .long SYMBOL_NAME(sys_truncate64) - .long SYMBOL_NAME(sys_ftruncate64) - .long SYMBOL_NAME(sys_stat64) /* 195 */ -diff --git a/arch/ia64/ia32/sys_ia32.c b/arch/ia64/ia32/sys_ia32.c -index 625ed8f..e031ee8 100644 ---- a/arch/ia64/ia32/sys_ia32.c -+++ b/arch/ia64/ia32/sys_ia32.c -@@ -858,6 +858,9 @@ ia32_do_mmap (struct file *file, unsigned long addr, unsigned long len, int prot - - prot = get_prot32(prot); - -+ if (flags & MAP_HUGETLB) -+ return -ENOMEM; -+ - #if PAGE_SHIFT > IA32_PAGE_SHIFT - mutex_lock(&ia32_mmap_mutex); - { -diff --git a/arch/ia64/kernel/sys_ia64.c b/arch/ia64/kernel/sys_ia64.c -index 92ed83f..609d500 100644 ---- a/arch/ia64/kernel/sys_ia64.c -+++ b/arch/ia64/kernel/sys_ia64.c -@@ -100,51 +100,7 @@ sys_getpagesize (void) - asmlinkage unsigned long - ia64_brk (unsigned long brk) - { -- unsigned long rlim, retval, newbrk, oldbrk; -- struct mm_struct *mm = current->mm; -- -- /* -- * Most of this replicates the code in sys_brk() except for an additional safety -- * check and the clearing of r8. However, we can't call sys_brk() because we need -- * to acquire the mmap_sem before we can do the test... -- */ -- down_write(&mm->mmap_sem); -- -- if (brk < mm->end_code) -- goto out; -- newbrk = PAGE_ALIGN(brk); -- oldbrk = PAGE_ALIGN(mm->brk); -- if (oldbrk == newbrk) -- goto set_brk; -- -- /* Always allow shrinking brk. */ -- if (brk <= mm->brk) { -- if (!do_munmap(mm, newbrk, oldbrk-newbrk)) -- goto set_brk; -- goto out; -- } -- -- /* Check against unimplemented/unmapped addresses: */ -- if ((newbrk - oldbrk) > RGN_MAP_LIMIT || REGION_OFFSET(newbrk) > RGN_MAP_LIMIT) -- goto out; -- -- /* Check against rlimit.. */ -- rlim = current->signal->rlim[RLIMIT_DATA].rlim_cur; -- if (rlim < RLIM_INFINITY && brk - mm->start_data > rlim) -- goto out; -- -- /* Check against existing mmap mappings. */ -- if (find_vma_intersection(mm, oldbrk, newbrk+PAGE_SIZE)) -- goto out; -- -- /* Ok, looks good - let it rip. */ -- if (do_brk(oldbrk, newbrk-oldbrk) != oldbrk) -- goto out; --set_brk: -- mm->brk = brk; --out: -- retval = mm->brk; -- up_write(&mm->mmap_sem); -+ unsigned long retval = sys_brk(brk); - force_successful_syscall_return(); - return retval; - } -@@ -185,39 +141,6 @@ int ia64_mmap_check(unsigned long addr, unsigned long len, - return 0; - } - --static inline unsigned long --do_mmap2 (unsigned long addr, unsigned long len, int prot, int flags, int fd, unsigned long pgoff) --{ -- struct file *file = NULL; -- -- flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); -- if (!(flags & MAP_ANONYMOUS)) { -- file = fget(fd); -- if (!file) -- return -EBADF; -- -- if (!file->f_op || !file->f_op->mmap) { -- addr = -ENODEV; -- goto out; -- } -- } -- -- /* Careful about overflows.. */ -- len = PAGE_ALIGN(len); -- if (!len || len > TASK_SIZE) { -- addr = -EINVAL; -- goto out; -- } -- -- down_write(¤t->mm->mmap_sem); -- addr = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); -- up_write(¤t->mm->mmap_sem); -- --out: if (file) -- fput(file); -- return addr; --} -- - /* - * mmap2() is like mmap() except that the offset is expressed in units - * of PAGE_SIZE (instead of bytes). This allows to mmap2() (pieces -@@ -226,7 +149,7 @@ out: if (file) - asmlinkage unsigned long - sys_mmap2 (unsigned long addr, unsigned long len, int prot, int flags, int fd, long pgoff) - { -- addr = do_mmap2(addr, len, prot, flags, fd, pgoff); -+ addr = sys_mmap_pgoff(addr, len, prot, flags, fd, pgoff); - if (!IS_ERR((void *) addr)) - force_successful_syscall_return(); - return addr; -@@ -238,7 +161,7 @@ sys_mmap (unsigned long addr, unsigned long len, int prot, int flags, int fd, lo - if (offset_in_page(off) != 0) - return -EINVAL; - -- addr = do_mmap2(addr, len, prot, flags, fd, off >> PAGE_SHIFT); -+ addr = sys_mmap_pgoff(addr, len, prot, flags, fd, off >> PAGE_SHIFT); - if (!IS_ERR((void *) addr)) - force_successful_syscall_return(); - return addr; -diff --git a/arch/m32r/kernel/sys_m32r.c b/arch/m32r/kernel/sys_m32r.c -index 305ac85..d3c865c 100644 ---- a/arch/m32r/kernel/sys_m32r.c -+++ b/arch/m32r/kernel/sys_m32r.c -@@ -76,30 +76,6 @@ asmlinkage int sys_tas(int __user *addr) - return oldval; - } - --asmlinkage long sys_mmap2(unsigned long addr, unsigned long len, -- unsigned long prot, unsigned long flags, -- unsigned long fd, unsigned long pgoff) --{ -- int error = -EBADF; -- struct file *file = NULL; -- -- flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); -- if (!(flags & MAP_ANONYMOUS)) { -- file = fget(fd); -- if (!file) -- goto out; -- } -- -- down_write(¤t->mm->mmap_sem); -- error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); -- up_write(¤t->mm->mmap_sem); -- -- if (file) -- fput(file); --out: -- return error; --} -- - /* - * sys_ipc() is the de-multiplexer for the SysV IPC calls.. - * -diff --git a/arch/m32r/kernel/syscall_table.S b/arch/m32r/kernel/syscall_table.S -index aa3bf4c..60536e2 100644 ---- a/arch/m32r/kernel/syscall_table.S -+++ b/arch/m32r/kernel/syscall_table.S -@@ -191,7 +191,7 @@ ENTRY(sys_call_table) - .long sys_ni_syscall /* streams2 */ - .long sys_vfork /* 190 */ - .long sys_getrlimit -- .long sys_mmap2 -+ .long sys_mmap_pgoff - .long sys_truncate64 - .long sys_ftruncate64 - .long sys_stat64 /* 195 */ -diff --git a/arch/m68k/kernel/sys_m68k.c b/arch/m68k/kernel/sys_m68k.c -index 7deb402..218f441 100644 ---- a/arch/m68k/kernel/sys_m68k.c -+++ b/arch/m68k/kernel/sys_m68k.c -@@ -29,37 +29,16 @@ - #include - #include - --/* common code for old and new mmaps */ --static inline long do_mmap2( -- unsigned long addr, unsigned long len, -- unsigned long prot, unsigned long flags, -- unsigned long fd, unsigned long pgoff) --{ -- int error = -EBADF; -- struct file * file = NULL; -- -- flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); -- if (!(flags & MAP_ANONYMOUS)) { -- file = fget(fd); -- if (!file) -- goto out; -- } -- -- down_write(¤t->mm->mmap_sem); -- error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); -- up_write(¤t->mm->mmap_sem); -- -- if (file) -- fput(file); --out: -- return error; --} -- - asmlinkage long sys_mmap2(unsigned long addr, unsigned long len, - unsigned long prot, unsigned long flags, - unsigned long fd, unsigned long pgoff) - { -- return do_mmap2(addr, len, prot, flags, fd, pgoff); -+ /* -+ * This is wrong for sun3 - there PAGE_SIZE is 8Kb, -+ * so we need to shift the argument down by 1; m68k mmap64(3) -+ * (in libc) expects the last argument of mmap2 in 4Kb units. -+ */ -+ return sys_mmap_pgoff(addr, len, prot, flags, fd, pgoff); - } - - /* -@@ -90,57 +69,11 @@ asmlinkage int old_mmap(struct mmap_arg_struct __user *arg) - if (a.offset & ~PAGE_MASK) - goto out; - -- a.flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); -- -- error = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT); --out: -- return error; --} -- --#if 0 --struct mmap_arg_struct64 { -- __u32 addr; -- __u32 len; -- __u32 prot; -- __u32 flags; -- __u64 offset; /* 64 bits */ -- __u32 fd; --}; -- --asmlinkage long sys_mmap64(struct mmap_arg_struct64 *arg) --{ -- int error = -EFAULT; -- struct file * file = NULL; -- struct mmap_arg_struct64 a; -- unsigned long pgoff; -- -- if (copy_from_user(&a, arg, sizeof(a))) -- return -EFAULT; -- -- if ((long)a.offset & ~PAGE_MASK) -- return -EINVAL; -- -- pgoff = a.offset >> PAGE_SHIFT; -- if ((a.offset >> PAGE_SHIFT) != pgoff) -- return -EINVAL; -- -- if (!(a.flags & MAP_ANONYMOUS)) { -- error = -EBADF; -- file = fget(a.fd); -- if (!file) -- goto out; -- } -- a.flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); -- -- down_write(¤t->mm->mmap_sem); -- error = do_mmap_pgoff(file, a.addr, a.len, a.prot, a.flags, pgoff); -- up_write(¤t->mm->mmap_sem); -- if (file) -- fput(file); -+ error = sys_mmap_pgoff(a.addr, a.len, a.prot, a.flags, a.fd, -+ a.offset >> PAGE_SHIFT); - out: - return error; - } --#endif - - struct sel_arg_struct { - unsigned long n; -diff --git a/arch/m68knommu/kernel/sys_m68k.c b/arch/m68knommu/kernel/sys_m68k.c -index efdd090..b67cbc7 100644 ---- a/arch/m68knommu/kernel/sys_m68k.c -+++ b/arch/m68knommu/kernel/sys_m68k.c -@@ -27,39 +27,6 @@ - #include - #include - --/* common code for old and new mmaps */ --static inline long do_mmap2( -- unsigned long addr, unsigned long len, -- unsigned long prot, unsigned long flags, -- unsigned long fd, unsigned long pgoff) --{ -- int error = -EBADF; -- struct file * file = NULL; -- -- flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); -- if (!(flags & MAP_ANONYMOUS)) { -- file = fget(fd); -- if (!file) -- goto out; -- } -- -- down_write(¤t->mm->mmap_sem); -- error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); -- up_write(¤t->mm->mmap_sem); -- -- if (file) -- fput(file); --out: -- return error; --} -- --asmlinkage long sys_mmap2(unsigned long addr, unsigned long len, -- unsigned long prot, unsigned long flags, -- unsigned long fd, unsigned long pgoff) --{ -- return do_mmap2(addr, len, prot, flags, fd, pgoff); --} -- - /* - * Perform the select(nd, in, out, ex, tv) and mmap() system - * calls. Linux/m68k cloned Linux/i386, which didn't use to be able to -@@ -88,9 +55,8 @@ asmlinkage int old_mmap(struct mmap_arg_struct *arg) - if (a.offset & ~PAGE_MASK) - goto out; - -- a.flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); -- -- error = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT); -+ error = sys_mmap_pgoff(a.addr, a.len, a.prot, a.flags, a.fd, -+ a.offset >> PAGE_SHIFT); - out: - return error; - } -diff --git a/arch/m68knommu/kernel/syscalltable.S b/arch/m68knommu/kernel/syscalltable.S -index 23535cc..486837e 100644 ---- a/arch/m68knommu/kernel/syscalltable.S -+++ b/arch/m68knommu/kernel/syscalltable.S -@@ -210,7 +210,7 @@ ENTRY(sys_call_table) - .long sys_ni_syscall /* streams2 */ - .long sys_vfork /* 190 */ - .long sys_getrlimit -- .long sys_mmap2 -+ .long sys_mmap_pgoff - .long sys_truncate64 - .long sys_ftruncate64 - .long sys_stat64 /* 195 */ -diff --git a/arch/microblaze/kernel/sys_microblaze.c b/arch/microblaze/kernel/sys_microblaze.c -index 07cabed..9f3c205 100644 ---- a/arch/microblaze/kernel/sys_microblaze.c -+++ b/arch/microblaze/kernel/sys_microblaze.c -@@ -62,46 +62,14 @@ out: - return error; - } - --asmlinkage long --sys_mmap2(unsigned long addr, unsigned long len, -- unsigned long prot, unsigned long flags, -- unsigned long fd, unsigned long pgoff) --{ -- struct file *file = NULL; -- int ret = -EBADF; -- -- flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); -- if (!(flags & MAP_ANONYMOUS)) { -- file = fget(fd); -- if (!file) { -- printk(KERN_INFO "no fd in mmap\r\n"); -- goto out; -- } -- } -- -- down_write(¤t->mm->mmap_sem); -- ret = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); -- up_write(¤t->mm->mmap_sem); -- if (file) -- fput(file); --out: -- return ret; --} -- - asmlinkage long sys_mmap(unsigned long addr, unsigned long len, - unsigned long prot, unsigned long flags, - unsigned long fd, off_t pgoff) - { -- int err = -EINVAL; -- -- if (pgoff & ~PAGE_MASK) { -- printk(KERN_INFO "no pagemask in mmap\r\n"); -- goto out; -- } -+ if (pgoff & ~PAGE_MASK) -+ return -EINVAL; - -- err = sys_mmap2(addr, len, prot, flags, fd, pgoff >> PAGE_SHIFT); --out: -- return err; -+ return sys_mmap_pgoff(addr, len, prot, flags, fd, pgoff >> PAGE_SHIFT); - } - - /* -diff --git a/arch/microblaze/kernel/syscall_table.S b/arch/microblaze/kernel/syscall_table.S -index ecec191..eb50ce5 100644 ---- a/arch/microblaze/kernel/syscall_table.S -+++ b/arch/microblaze/kernel/syscall_table.S -@@ -196,7 +196,7 @@ ENTRY(sys_call_table) - .long sys_ni_syscall /* reserved for streams2 */ - .long sys_vfork /* 190 */ - .long sys_getrlimit -- .long sys_mmap2 /* mmap2 */ -+ .long sys_mmap_pgoff /* mmap2 */ - .long sys_truncate64 - .long sys_ftruncate64 - .long sys_stat64 /* 195 */ -diff --git a/arch/mips/kernel/linux32.c b/arch/mips/kernel/linux32.c -index b77fefa..ea4a746 100644 ---- a/arch/mips/kernel/linux32.c -+++ b/arch/mips/kernel/linux32.c -@@ -67,28 +67,13 @@ SYSCALL_DEFINE6(32_mmap2, unsigned long, addr, unsigned long, len, - unsigned long, prot, unsigned long, flags, unsigned long, fd, - unsigned long, pgoff) - { -- struct file * file = NULL; - unsigned long error; - - error = -EINVAL; - if (pgoff & (~PAGE_MASK >> 12)) - goto out; -- pgoff >>= PAGE_SHIFT-12; -- -- if (!(flags & MAP_ANONYMOUS)) { -- error = -EBADF; -- file = fget(fd); -- if (!file) -- goto out; -- } -- flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); -- -- down_write(¤t->mm->mmap_sem); -- error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); -- up_write(¤t->mm->mmap_sem); -- if (file) -- fput(file); -- -+ error = sys_mmap_pgoff(addr, len, prot, flags, fd, -+ pgoff >> (PAGE_SHIFT-12)); - out: - return error; - } -diff --git a/arch/mips/kernel/syscall.c b/arch/mips/kernel/syscall.c -index fe0d798..3f7f466 100644 ---- a/arch/mips/kernel/syscall.c -+++ b/arch/mips/kernel/syscall.c -@@ -93,7 +93,8 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, - * We do not accept a shared mapping if it would violate - * cache aliasing constraints. - */ -- if ((flags & MAP_SHARED) && (addr & shm_align_mask)) -+ if ((flags & MAP_SHARED) && -+ ((addr - (pgoff << PAGE_SHIFT)) & shm_align_mask)) - return -EINVAL; - return addr; - } -@@ -129,31 +130,6 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, - } - } - --/* common code for old and new mmaps */ --static inline unsigned long --do_mmap2(unsigned long addr, unsigned long len, unsigned long prot, -- unsigned long flags, unsigned long fd, unsigned long pgoff) --{ -- unsigned long error = -EBADF; -- struct file * file = NULL; -- -- flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); -- if (!(flags & MAP_ANONYMOUS)) { -- file = fget(fd); -- if (!file) -- goto out; -- } -- -- down_write(¤t->mm->mmap_sem); -- error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); -- up_write(¤t->mm->mmap_sem); -- -- if (file) -- fput(file); --out: -- return error; --} -- - SYSCALL_DEFINE6(mips_mmap, unsigned long, addr, unsigned long, len, - unsigned long, prot, unsigned long, flags, unsigned long, - fd, off_t, offset) -@@ -164,7 +140,7 @@ SYSCALL_DEFINE6(mips_mmap, unsigned long, addr, unsigned long, len, - if (offset & ~PAGE_MASK) - goto out; - -- result = do_mmap2(addr, len, prot, flags, fd, offset >> PAGE_SHIFT); -+ result = sys_mmap_pgoff(addr, len, prot, flags, fd, offset >> PAGE_SHIFT); - - out: - return result; -@@ -177,7 +153,7 @@ SYSCALL_DEFINE6(mips_mmap2, unsigned long, addr, unsigned long, len, - if (pgoff & (~PAGE_MASK >> 12)) - return -EINVAL; - -- return do_mmap2(addr, len, prot, flags, fd, pgoff >> (PAGE_SHIFT-12)); -+ return sys_mmap_pgoff(addr, len, prot, flags, fd, pgoff >> (PAGE_SHIFT-12)); - } - - save_static_function(sys_fork); -diff --git a/arch/mn10300/include/asm/mman.h b/arch/mn10300/include/asm/mman.h -index 8eebf89..db5c53d 100644 ---- a/arch/mn10300/include/asm/mman.h -+++ b/arch/mn10300/include/asm/mman.h -@@ -1 +1,6 @@ - #include -+ -+#define MIN_MAP_ADDR PAGE_SIZE /* minimum fixed mmap address */ -+ -+#define arch_mmap_check(addr, len, flags) \ -+ (((flags) & MAP_FIXED && (addr) < MIN_MAP_ADDR) ? -EINVAL : 0) -diff --git a/arch/mn10300/kernel/entry.S b/arch/mn10300/kernel/entry.S -index a94e7ea..c9ee6c0 100644 ---- a/arch/mn10300/kernel/entry.S -+++ b/arch/mn10300/kernel/entry.S -@@ -578,7 +578,7 @@ ENTRY(sys_call_table) - .long sys_ni_syscall /* reserved for streams2 */ - .long sys_vfork /* 190 */ - .long sys_getrlimit -- .long sys_mmap2 -+ .long sys_mmap_pgoff - .long sys_truncate64 - .long sys_ftruncate64 - .long sys_stat64 /* 195 */ -diff --git a/arch/mn10300/kernel/sys_mn10300.c b/arch/mn10300/kernel/sys_mn10300.c -index 8ca5af0..17cc6ce 100644 ---- a/arch/mn10300/kernel/sys_mn10300.c -+++ b/arch/mn10300/kernel/sys_mn10300.c -@@ -23,47 +23,13 @@ - - #include - --#define MIN_MAP_ADDR PAGE_SIZE /* minimum fixed mmap address */ -- --/* -- * memory mapping syscall -- */ --asmlinkage long sys_mmap2(unsigned long addr, unsigned long len, -- unsigned long prot, unsigned long flags, -- unsigned long fd, unsigned long pgoff) --{ -- struct file *file = NULL; -- long error = -EINVAL; -- -- flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); -- -- if (flags & MAP_FIXED && addr < MIN_MAP_ADDR) -- goto out; -- -- error = -EBADF; -- if (!(flags & MAP_ANONYMOUS)) { -- file = fget(fd); -- if (!file) -- goto out; -- } -- -- down_write(¤t->mm->mmap_sem); -- error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); -- up_write(¤t->mm->mmap_sem); -- -- if (file) -- fput(file); --out: -- return error; --} -- - asmlinkage long old_mmap(unsigned long addr, unsigned long len, - unsigned long prot, unsigned long flags, - unsigned long fd, unsigned long offset) - { - if (offset & ~PAGE_MASK) - return -EINVAL; -- return sys_mmap2(addr, len, prot, flags, fd, offset >> PAGE_SHIFT); -+ return sys_mmap_pgoff(addr, len, prot, flags, fd, offset >> PAGE_SHIFT); - } - - struct sel_arg_struct { -diff --git a/arch/parisc/kernel/sys_parisc.c b/arch/parisc/kernel/sys_parisc.c -index 71b3195..9147391 100644 ---- a/arch/parisc/kernel/sys_parisc.c -+++ b/arch/parisc/kernel/sys_parisc.c -@@ -110,37 +110,14 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, - return addr; - } - --static unsigned long do_mmap2(unsigned long addr, unsigned long len, -- unsigned long prot, unsigned long flags, unsigned long fd, -- unsigned long pgoff) --{ -- struct file * file = NULL; -- unsigned long error = -EBADF; -- if (!(flags & MAP_ANONYMOUS)) { -- file = fget(fd); -- if (!file) -- goto out; -- } -- -- flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); -- -- down_write(¤t->mm->mmap_sem); -- error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); -- up_write(¤t->mm->mmap_sem); -- -- if (file != NULL) -- fput(file); --out: -- return error; --} -- - asmlinkage unsigned long sys_mmap2(unsigned long addr, unsigned long len, - unsigned long prot, unsigned long flags, unsigned long fd, - unsigned long pgoff) - { - /* Make sure the shift for mmap2 is constant (12), no matter what PAGE_SIZE - we have. */ -- return do_mmap2(addr, len, prot, flags, fd, pgoff >> (PAGE_SHIFT - 12)); -+ return sys_mmap_pgoff(addr, len, prot, flags, fd, -+ pgoff >> (PAGE_SHIFT - 12)); - } - - asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len, -@@ -148,7 +125,8 @@ asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len, - unsigned long offset) - { - if (!(offset & ~PAGE_MASK)) { -- return do_mmap2(addr, len, prot, flags, fd, offset >> PAGE_SHIFT); -+ return sys_mmap_pgoff(addr, len, prot, flags, fd, -+ offset >> PAGE_SHIFT); - } else { - return -EINVAL; - } -diff --git a/arch/powerpc/include/asm/module.h b/arch/powerpc/include/asm/module.h -index 0845488..0192a4e 100644 ---- a/arch/powerpc/include/asm/module.h -+++ b/arch/powerpc/include/asm/module.h -@@ -87,5 +87,10 @@ struct exception_table_entry; - void sort_ex_table(struct exception_table_entry *start, - struct exception_table_entry *finish); - -+#ifdef CONFIG_MODVERSIONS -+#define ARCH_RELOCATES_KCRCTAB -+ -+extern const unsigned long reloc_start[]; -+#endif - #endif /* __KERNEL__ */ - #endif /* _ASM_POWERPC_MODULE_H */ -diff --git a/arch/powerpc/kernel/syscalls.c b/arch/powerpc/kernel/syscalls.c -index c04832c..3370e62 100644 ---- a/arch/powerpc/kernel/syscalls.c -+++ b/arch/powerpc/kernel/syscalls.c -@@ -140,7 +140,6 @@ static inline unsigned long do_mmap2(unsigned long addr, size_t len, - unsigned long prot, unsigned long flags, - unsigned long fd, unsigned long off, int shift) - { -- struct file * file = NULL; - unsigned long ret = -EINVAL; - - if (!arch_validate_prot(prot)) -@@ -151,20 +150,8 @@ static inline unsigned long do_mmap2(unsigned long addr, size_t len, - goto out; - off >>= shift; - } -- -- ret = -EBADF; -- if (!(flags & MAP_ANONYMOUS)) { -- if (!(file = fget(fd))) -- goto out; -- } -- -- flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); - -- down_write(¤t->mm->mmap_sem); -- ret = do_mmap_pgoff(file, addr, len, prot, flags, off); -- up_write(¤t->mm->mmap_sem); -- if (file) -- fput(file); -+ ret = sys_mmap_pgoff(addr, len, prot, flags, fd, off); - out: - return ret; - } -diff --git a/arch/powerpc/kernel/vmlinux.lds.S b/arch/powerpc/kernel/vmlinux.lds.S -index 27735a7..dcd01c8 100644 ---- a/arch/powerpc/kernel/vmlinux.lds.S -+++ b/arch/powerpc/kernel/vmlinux.lds.S -@@ -38,6 +38,9 @@ jiffies = jiffies_64 + 4; - #endif - SECTIONS - { -+ . = 0; -+ reloc_start = .; -+ - . = KERNELBASE; - - /* -diff --git a/arch/s390/kernel/compat_linux.c b/arch/s390/kernel/compat_linux.c -index 0debcec..9c746c0 100644 ---- a/arch/s390/kernel/compat_linux.c -+++ b/arch/s390/kernel/compat_linux.c -@@ -683,38 +683,6 @@ struct mmap_arg_struct_emu31 { - u32 offset; - }; - --/* common code for old and new mmaps */ --static inline long do_mmap2( -- unsigned long addr, unsigned long len, -- unsigned long prot, unsigned long flags, -- unsigned long fd, unsigned long pgoff) --{ -- struct file * file = NULL; -- unsigned long error = -EBADF; -- -- flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); -- if (!(flags & MAP_ANONYMOUS)) { -- file = fget(fd); -- if (!file) -- goto out; -- } -- -- down_write(¤t->mm->mmap_sem); -- error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); -- if (!IS_ERR((void *) error) && error + len >= 0x80000000ULL) { -- /* Result is out of bounds. */ -- do_munmap(current->mm, addr, len); -- error = -ENOMEM; -- } -- up_write(¤t->mm->mmap_sem); -- -- if (file) -- fput(file); --out: -- return error; --} -- -- - asmlinkage unsigned long - old32_mmap(struct mmap_arg_struct_emu31 __user *arg) - { -@@ -728,7 +696,8 @@ old32_mmap(struct mmap_arg_struct_emu31 __user *arg) - if (a.offset & ~PAGE_MASK) - goto out; - -- error = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT); -+ error = sys_mmap_pgoff(a.addr, a.len, a.prot, a.flags, a.fd, -+ a.offset >> PAGE_SHIFT); - out: - return error; - } -@@ -741,7 +710,7 @@ sys32_mmap2(struct mmap_arg_struct_emu31 __user *arg) - - if (copy_from_user(&a, arg, sizeof(a))) - goto out; -- error = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset); -+ error = sys_mmap_pgoff(a.addr, a.len, a.prot, a.flags, a.fd, a.offset); - out: - return error; - } -diff --git a/arch/s390/kernel/sys_s390.c b/arch/s390/kernel/sys_s390.c -index e9d94f6..86a74c9 100644 ---- a/arch/s390/kernel/sys_s390.c -+++ b/arch/s390/kernel/sys_s390.c -@@ -32,32 +32,6 @@ - #include - #include "entry.h" - --/* common code for old and new mmaps */ --static inline long do_mmap2( -- unsigned long addr, unsigned long len, -- unsigned long prot, unsigned long flags, -- unsigned long fd, unsigned long pgoff) --{ -- long error = -EBADF; -- struct file * file = NULL; -- -- flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); -- if (!(flags & MAP_ANONYMOUS)) { -- file = fget(fd); -- if (!file) -- goto out; -- } -- -- down_write(¤t->mm->mmap_sem); -- error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); -- up_write(¤t->mm->mmap_sem); -- -- if (file) -- fput(file); --out: -- return error; --} -- - /* - * Perform the select(nd, in, out, ex, tv) and mmap() system - * calls. Linux for S/390 isn't able to handle more than 5 -@@ -81,7 +55,7 @@ SYSCALL_DEFINE1(mmap2, struct mmap_arg_struct __user *, arg) - - if (copy_from_user(&a, arg, sizeof(a))) - goto out; -- error = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset); -+ error = sys_mmap_pgoff(a.addr, a.len, a.prot, a.flags, a.fd, a.offset); - out: - return error; - } -@@ -98,7 +72,7 @@ SYSCALL_DEFINE1(s390_old_mmap, struct mmap_arg_struct __user *, arg) - if (a.offset & ~PAGE_MASK) - goto out; - -- error = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT); -+ error = sys_mmap_pgoff(a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT); - out: - return error; - } -diff --git a/arch/score/kernel/sys_score.c b/arch/score/kernel/sys_score.c -index 0012494..856ed68 100644 ---- a/arch/score/kernel/sys_score.c -+++ b/arch/score/kernel/sys_score.c -@@ -36,34 +36,16 @@ asmlinkage long - sys_mmap2(unsigned long addr, unsigned long len, unsigned long prot, - unsigned long flags, unsigned long fd, unsigned long pgoff) - { -- int error = -EBADF; -- struct file *file = NULL; -- -- if (pgoff & (~PAGE_MASK >> 12)) -- return -EINVAL; -- -- flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); -- if (!(flags & MAP_ANONYMOUS)) { -- file = fget(fd); -- if (!file) -- return error; -- } -- -- down_write(¤t->mm->mmap_sem); -- error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); -- up_write(¤t->mm->mmap_sem); -- -- if (file) -- fput(file); -- -- return error; -+ return sys_mmap_pgoff(addr, len, prot, flags, fd, pgoff); - } - - asmlinkage long - sys_mmap(unsigned long addr, unsigned long len, unsigned long prot, -- unsigned long flags, unsigned long fd, off_t pgoff) -+ unsigned long flags, unsigned long fd, off_t offset) - { -- return sys_mmap2(addr, len, prot, flags, fd, pgoff >> PAGE_SHIFT); -+ if (unlikely(offset & ~PAGE_MASK)) -+ return -EINVAL; -+ return sys_mmap_pgoff(addr, len, prot, flags, fd, offset >> PAGE_SHIFT); - } - - asmlinkage long -diff --git a/arch/sh/kernel/sys_sh.c b/arch/sh/kernel/sys_sh.c -index 8aa5d1c..71399cd 100644 ---- a/arch/sh/kernel/sys_sh.c -+++ b/arch/sh/kernel/sys_sh.c -@@ -28,37 +28,13 @@ - #include - #include - --static inline long --do_mmap2(unsigned long addr, unsigned long len, unsigned long prot, -- unsigned long flags, int fd, unsigned long pgoff) --{ -- int error = -EBADF; -- struct file *file = NULL; -- -- flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); -- if (!(flags & MAP_ANONYMOUS)) { -- file = fget(fd); -- if (!file) -- goto out; -- } -- -- down_write(¤t->mm->mmap_sem); -- error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); -- up_write(¤t->mm->mmap_sem); -- -- if (file) -- fput(file); --out: -- return error; --} -- - asmlinkage int old_mmap(unsigned long addr, unsigned long len, - unsigned long prot, unsigned long flags, - int fd, unsigned long off) - { - if (off & ~PAGE_MASK) - return -EINVAL; -- return do_mmap2(addr, len, prot, flags, fd, off>>PAGE_SHIFT); -+ return sys_mmap_pgoff(addr, len, prot, flags, fd, off>>PAGE_SHIFT); - } - - asmlinkage long sys_mmap2(unsigned long addr, unsigned long len, -@@ -74,7 +50,7 @@ asmlinkage long sys_mmap2(unsigned long addr, unsigned long len, - - pgoff >>= PAGE_SHIFT - 12; - -- return do_mmap2(addr, len, prot, flags, fd, pgoff); -+ return sys_mmap_pgoff(addr, len, prot, flags, fd, pgoff); - } - - /* -diff --git a/arch/sh/mm/mmap.c b/arch/sh/mm/mmap.c -index d2984fa..afeb710 100644 ---- a/arch/sh/mm/mmap.c -+++ b/arch/sh/mm/mmap.c -@@ -54,7 +54,8 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, - /* We do not accept a shared mapping if it would violate - * cache aliasing constraints. - */ -- if ((flags & MAP_SHARED) && (addr & shm_align_mask)) -+ if ((flags & MAP_SHARED) && -+ ((addr - (pgoff << PAGE_SHIFT)) & shm_align_mask)) - return -EINVAL; - return addr; - } -diff --git a/arch/sparc/kernel/sys_sparc_32.c b/arch/sparc/kernel/sys_sparc_32.c -index 03035c8..3a82e65 100644 ---- a/arch/sparc/kernel/sys_sparc_32.c -+++ b/arch/sparc/kernel/sys_sparc_32.c -@@ -45,7 +45,8 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsi - /* We do not accept a shared mapping if it would violate - * cache aliasing constraints. - */ -- if ((flags & MAP_SHARED) && (addr & (SHMLBA - 1))) -+ if ((flags & MAP_SHARED) && -+ ((addr - (pgoff << PAGE_SHIFT)) & (SHMLBA - 1))) - return -EINVAL; - return addr; - } -@@ -79,15 +80,6 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsi - } - } - --asmlinkage unsigned long sparc_brk(unsigned long brk) --{ -- if(ARCH_SUN4C) { -- if ((brk & 0xe0000000) != (current->mm->brk & 0xe0000000)) -- return current->mm->brk; -- } -- return sys_brk(brk); --} -- - /* - * sys_pipe() is the normal C calling standard for creating - * a pipe. It's not the way unix traditionally does this, though. -@@ -234,31 +226,6 @@ int sparc_mmap_check(unsigned long addr, unsigned long len) - } - - /* Linux version of mmap */ --static unsigned long do_mmap2(unsigned long addr, unsigned long len, -- unsigned long prot, unsigned long flags, unsigned long fd, -- unsigned long pgoff) --{ -- struct file * file = NULL; -- unsigned long retval = -EBADF; -- -- if (!(flags & MAP_ANONYMOUS)) { -- file = fget(fd); -- if (!file) -- goto out; -- } -- -- len = PAGE_ALIGN(len); -- flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); -- -- down_write(¤t->mm->mmap_sem); -- retval = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); -- up_write(¤t->mm->mmap_sem); -- -- if (file) -- fput(file); --out: -- return retval; --} - - asmlinkage unsigned long sys_mmap2(unsigned long addr, unsigned long len, - unsigned long prot, unsigned long flags, unsigned long fd, -@@ -266,14 +233,16 @@ asmlinkage unsigned long sys_mmap2(unsigned long addr, unsigned long len, - { - /* Make sure the shift for mmap2 is constant (12), no matter what PAGE_SIZE - we have. */ -- return do_mmap2(addr, len, prot, flags, fd, pgoff >> (PAGE_SHIFT - 12)); -+ return sys_mmap_pgoff(addr, len, prot, flags, fd, -+ pgoff >> (PAGE_SHIFT - 12)); - } - - asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len, - unsigned long prot, unsigned long flags, unsigned long fd, - unsigned long off) - { -- return do_mmap2(addr, len, prot, flags, fd, off >> PAGE_SHIFT); -+ /* no alignment check? */ -+ return sys_mmap_pgoff(addr, len, prot, flags, fd, off >> PAGE_SHIFT); - } - - long sparc_remap_file_pages(unsigned long start, unsigned long size, -@@ -287,27 +256,6 @@ long sparc_remap_file_pages(unsigned long start, unsigned long size, - (pgoff >> (PAGE_SHIFT - 12)), flags); - } - --extern unsigned long do_mremap(unsigned long addr, -- unsigned long old_len, unsigned long new_len, -- unsigned long flags, unsigned long new_addr); -- --asmlinkage unsigned long sparc_mremap(unsigned long addr, -- unsigned long old_len, unsigned long new_len, -- unsigned long flags, unsigned long new_addr) --{ -- unsigned long ret = -EINVAL; -- -- if (unlikely(sparc_mmap_check(addr, old_len))) -- goto out; -- if (unlikely(sparc_mmap_check(new_addr, new_len))) -- goto out; -- down_write(¤t->mm->mmap_sem); -- ret = do_mremap(addr, old_len, new_len, flags, new_addr); -- up_write(¤t->mm->mmap_sem); --out: -- return ret; --} -- - /* we come to here via sys_nis_syscall so it can setup the regs argument */ - asmlinkage unsigned long - c_sys_nis_syscall (struct pt_regs *regs) -diff --git a/arch/sparc/kernel/sys_sparc_64.c b/arch/sparc/kernel/sys_sparc_64.c -index e2d1024..cfa0e19 100644 ---- a/arch/sparc/kernel/sys_sparc_64.c -+++ b/arch/sparc/kernel/sys_sparc_64.c -@@ -317,10 +317,14 @@ bottomup: - unsigned long get_fb_unmapped_area(struct file *filp, unsigned long orig_addr, unsigned long len, unsigned long pgoff, unsigned long flags) - { - unsigned long align_goal, addr = -ENOMEM; -+ unsigned long (*get_area)(struct file *, unsigned long, -+ unsigned long, unsigned long, unsigned long); -+ -+ get_area = current->mm->get_unmapped_area; - - if (flags & MAP_FIXED) { - /* Ok, don't mess with it. */ -- return get_unmapped_area(NULL, orig_addr, len, pgoff, flags); -+ return get_area(NULL, orig_addr, len, pgoff, flags); - } - flags &= ~MAP_SHARED; - -@@ -333,7 +337,7 @@ unsigned long get_fb_unmapped_area(struct file *filp, unsigned long orig_addr, u - align_goal = (64UL * 1024); - - do { -- addr = get_unmapped_area(NULL, orig_addr, len + (align_goal - PAGE_SIZE), pgoff, flags); -+ addr = get_area(NULL, orig_addr, len + (align_goal - PAGE_SIZE), pgoff, flags); - if (!(addr & ~PAGE_MASK)) { - addr = (addr + (align_goal - 1UL)) & ~(align_goal - 1UL); - break; -@@ -351,7 +355,7 @@ unsigned long get_fb_unmapped_area(struct file *filp, unsigned long orig_addr, u - * be obtained. - */ - if (addr & ~PAGE_MASK) -- addr = get_unmapped_area(NULL, orig_addr, len, pgoff, flags); -+ addr = get_area(NULL, orig_addr, len, pgoff, flags); - - return addr; - } -@@ -399,18 +403,6 @@ void arch_pick_mmap_layout(struct mm_struct *mm) - } - } - --SYSCALL_DEFINE1(sparc_brk, unsigned long, brk) --{ -- /* People could try to be nasty and use ta 0x6d in 32bit programs */ -- if (test_thread_flag(TIF_32BIT) && brk >= STACK_TOP32) -- return current->mm->brk; -- -- if (unlikely(straddles_64bit_va_hole(current->mm->brk, brk))) -- return current->mm->brk; -- -- return sys_brk(brk); --} -- - /* - * sys_pipe() is the normal C calling standard for creating - * a pipe. It's not the way unix traditionally does this, though. -@@ -568,23 +560,13 @@ SYSCALL_DEFINE6(mmap, unsigned long, addr, unsigned long, len, - unsigned long, prot, unsigned long, flags, unsigned long, fd, - unsigned long, off) - { -- struct file * file = NULL; -- unsigned long retval = -EBADF; -- -- if (!(flags & MAP_ANONYMOUS)) { -- file = fget(fd); -- if (!file) -- goto out; -- } -- flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); -- len = PAGE_ALIGN(len); -+ unsigned long retval = -EINVAL; - -- down_write(¤t->mm->mmap_sem); -- retval = do_mmap(file, addr, len, prot, flags, off); -- up_write(¤t->mm->mmap_sem); -- -- if (file) -- fput(file); -+ if ((off + PAGE_ALIGN(len)) < off) -+ goto out; -+ if (off & ~PAGE_MASK) -+ goto out; -+ retval = sys_mmap_pgoff(addr, len, prot, flags, fd, off >> PAGE_SHIFT); - out: - return retval; - } -@@ -614,12 +596,6 @@ SYSCALL_DEFINE5(64_mremap, unsigned long, addr, unsigned long, old_len, - - if (test_thread_flag(TIF_32BIT)) - goto out; -- if (unlikely(new_len >= VA_EXCLUDE_START)) -- goto out; -- if (unlikely(sparc_mmap_check(addr, old_len))) -- goto out; -- if (unlikely(sparc_mmap_check(new_addr, new_len))) -- goto out; - - down_write(¤t->mm->mmap_sem); - ret = do_mremap(addr, old_len, new_len, flags, new_addr); -diff --git a/arch/sparc/kernel/systbls.h b/arch/sparc/kernel/systbls.h -index a63c5d2..d2f999a 100644 ---- a/arch/sparc/kernel/systbls.h -+++ b/arch/sparc/kernel/systbls.h -@@ -9,7 +9,6 @@ - struct new_utsname; - - extern asmlinkage unsigned long sys_getpagesize(void); --extern asmlinkage unsigned long sparc_brk(unsigned long brk); - extern asmlinkage long sparc_pipe(struct pt_regs *regs); - extern asmlinkage long sys_ipc(unsigned int call, int first, - unsigned long second, -diff --git a/arch/sparc/kernel/systbls_32.S b/arch/sparc/kernel/systbls_32.S -index 0f1658d..14f950a 100644 ---- a/arch/sparc/kernel/systbls_32.S -+++ b/arch/sparc/kernel/systbls_32.S -@@ -19,7 +19,7 @@ sys_call_table: - /*0*/ .long sys_restart_syscall, sys_exit, sys_fork, sys_read, sys_write - /*5*/ .long sys_open, sys_close, sys_wait4, sys_creat, sys_link - /*10*/ .long sys_unlink, sunos_execv, sys_chdir, sys_chown16, sys_mknod --/*15*/ .long sys_chmod, sys_lchown16, sparc_brk, sys_nis_syscall, sys_lseek -+/*15*/ .long sys_chmod, sys_lchown16, sys_brk, sys_nis_syscall, sys_lseek - /*20*/ .long sys_getpid, sys_capget, sys_capset, sys_setuid16, sys_getuid16 - /*25*/ .long sys_vmsplice, sys_ptrace, sys_alarm, sys_sigaltstack, sys_pause - /*30*/ .long sys_utime, sys_lchown, sys_fchown, sys_access, sys_nice -@@ -67,7 +67,7 @@ sys_call_table: - /*235*/ .long sys_fstatfs64, sys_llseek, sys_mlock, sys_munlock, sys_mlockall - /*240*/ .long sys_munlockall, sys_sched_setparam, sys_sched_getparam, sys_sched_setscheduler, sys_sched_getscheduler - /*245*/ .long sys_sched_yield, sys_sched_get_priority_max, sys_sched_get_priority_min, sys_sched_rr_get_interval, sys_nanosleep --/*250*/ .long sparc_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys_nfsservctl -+/*250*/ .long sys_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys_nfsservctl - /*255*/ .long sys_sync_file_range, sys_clock_settime, sys_clock_gettime, sys_clock_getres, sys_clock_nanosleep - /*260*/ .long sys_sched_getaffinity, sys_sched_setaffinity, sys_timer_settime, sys_timer_gettime, sys_timer_getoverrun - /*265*/ .long sys_timer_delete, sys_timer_create, sys_nis_syscall, sys_io_setup, sys_io_destroy -diff --git a/arch/sparc/kernel/systbls_64.S b/arch/sparc/kernel/systbls_64.S -index 009825f..f63c871 100644 ---- a/arch/sparc/kernel/systbls_64.S -+++ b/arch/sparc/kernel/systbls_64.S -@@ -21,7 +21,7 @@ sys_call_table32: - /*0*/ .word sys_restart_syscall, sys32_exit, sys_fork, sys_read, sys_write - /*5*/ .word sys32_open, sys_close, sys32_wait4, sys32_creat, sys_link - /*10*/ .word sys_unlink, sunos_execv, sys_chdir, sys_chown16, sys32_mknod --/*15*/ .word sys_chmod, sys_lchown16, sys_sparc_brk, sys32_perfctr, sys32_lseek -+/*15*/ .word sys_chmod, sys_lchown16, sys_brk, sys32_perfctr, sys32_lseek - /*20*/ .word sys_getpid, sys_capget, sys_capset, sys_setuid16, sys_getuid16 - /*25*/ .word sys32_vmsplice, compat_sys_ptrace, sys_alarm, sys32_sigaltstack, sys_pause - /*30*/ .word compat_sys_utime, sys_lchown, sys_fchown, sys32_access, sys32_nice -@@ -96,7 +96,7 @@ sys_call_table: - /*0*/ .word sys_restart_syscall, sparc_exit, sys_fork, sys_read, sys_write - /*5*/ .word sys_open, sys_close, sys_wait4, sys_creat, sys_link - /*10*/ .word sys_unlink, sys_nis_syscall, sys_chdir, sys_chown, sys_mknod --/*15*/ .word sys_chmod, sys_lchown, sys_sparc_brk, sys_perfctr, sys_lseek -+/*15*/ .word sys_chmod, sys_lchown, sys_brk, sys_perfctr, sys_lseek - /*20*/ .word sys_getpid, sys_capget, sys_capset, sys_setuid, sys_getuid - /*25*/ .word sys_vmsplice, sys_ptrace, sys_alarm, sys_sigaltstack, sys_nis_syscall - /*30*/ .word sys_utime, sys_nis_syscall, sys_nis_syscall, sys_access, sys_nice -diff --git a/arch/um/kernel/syscall.c b/arch/um/kernel/syscall.c -index a4625c7..cccab85 100644 ---- a/arch/um/kernel/syscall.c -+++ b/arch/um/kernel/syscall.c -@@ -8,6 +8,7 @@ - #include "linux/mm.h" - #include "linux/sched.h" - #include "linux/utsname.h" -+#include "linux/syscalls.h" - #include "asm/current.h" - #include "asm/mman.h" - #include "asm/uaccess.h" -@@ -37,31 +38,6 @@ long sys_vfork(void) - return ret; - } - --/* common code for old and new mmaps */ --long sys_mmap2(unsigned long addr, unsigned long len, -- unsigned long prot, unsigned long flags, -- unsigned long fd, unsigned long pgoff) --{ -- long error = -EBADF; -- struct file * file = NULL; -- -- flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); -- if (!(flags & MAP_ANONYMOUS)) { -- file = fget(fd); -- if (!file) -- goto out; -- } -- -- down_write(¤t->mm->mmap_sem); -- error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); -- up_write(¤t->mm->mmap_sem); -- -- if (file) -- fput(file); -- out: -- return error; --} -- - long old_mmap(unsigned long addr, unsigned long len, - unsigned long prot, unsigned long flags, - unsigned long fd, unsigned long offset) -@@ -70,7 +46,7 @@ long old_mmap(unsigned long addr, unsigned long len, - if (offset & ~PAGE_MASK) - goto out; - -- err = sys_mmap2(addr, len, prot, flags, fd, offset >> PAGE_SHIFT); -+ err = sys_mmap_pgoff(addr, len, prot, flags, fd, offset >> PAGE_SHIFT); - out: - return err; - } -diff --git a/arch/um/sys-i386/shared/sysdep/syscalls.h b/arch/um/sys-i386/shared/sysdep/syscalls.h -index 9056981..e778767 100644 ---- a/arch/um/sys-i386/shared/sysdep/syscalls.h -+++ b/arch/um/sys-i386/shared/sysdep/syscalls.h -@@ -20,7 +20,3 @@ extern syscall_handler_t *sys_call_table[]; - #define EXECUTE_SYSCALL(syscall, regs) \ - ((long (*)(struct syscall_args)) \ - (*sys_call_table[syscall]))(SYSCALL_ARGS(®s->regs)) -- --extern long sys_mmap2(unsigned long addr, unsigned long len, -- unsigned long prot, unsigned long flags, -- unsigned long fd, unsigned long pgoff); -diff --git a/arch/x86/Kconfig.cpu b/arch/x86/Kconfig.cpu -index 2649840..f2824fb 100644 ---- a/arch/x86/Kconfig.cpu -+++ b/arch/x86/Kconfig.cpu -@@ -400,7 +400,7 @@ config X86_TSC - - config X86_CMPXCHG64 - def_bool y -- depends on !M386 && !M486 -+ depends on X86_PAE || X86_64 || MCORE2 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MATOM - - # this should be set for all -march=.. options where the compiler - # generates cmov. -diff --git a/arch/x86/ia32/ia32entry.S b/arch/x86/ia32/ia32entry.S -index 581b056..5294d84 100644 ---- a/arch/x86/ia32/ia32entry.S -+++ b/arch/x86/ia32/ia32entry.S -@@ -696,7 +696,7 @@ ia32_sys_call_table: - .quad quiet_ni_syscall /* streams2 */ - .quad stub32_vfork /* 190 */ - .quad compat_sys_getrlimit -- .quad sys32_mmap2 -+ .quad sys_mmap_pgoff - .quad sys32_truncate64 - .quad sys32_ftruncate64 - .quad sys32_stat64 /* 195 */ -diff --git a/arch/x86/ia32/sys_ia32.c b/arch/x86/ia32/sys_ia32.c -index 9f55271..016218c 100644 ---- a/arch/x86/ia32/sys_ia32.c -+++ b/arch/x86/ia32/sys_ia32.c -@@ -155,9 +155,6 @@ struct mmap_arg_struct { - asmlinkage long sys32_mmap(struct mmap_arg_struct __user *arg) - { - struct mmap_arg_struct a; -- struct file *file = NULL; -- unsigned long retval; -- struct mm_struct *mm ; - - if (copy_from_user(&a, arg, sizeof(a))) - return -EFAULT; -@@ -165,22 +162,8 @@ asmlinkage long sys32_mmap(struct mmap_arg_struct __user *arg) - if (a.offset & ~PAGE_MASK) - return -EINVAL; - -- if (!(a.flags & MAP_ANONYMOUS)) { -- file = fget(a.fd); -- if (!file) -- return -EBADF; -- } -- -- mm = current->mm; -- down_write(&mm->mmap_sem); -- retval = do_mmap_pgoff(file, a.addr, a.len, a.prot, a.flags, -+ return sys_mmap_pgoff(a.addr, a.len, a.prot, a.flags, a.fd, - a.offset>>PAGE_SHIFT); -- if (file) -- fput(file); -- -- up_write(&mm->mmap_sem); -- -- return retval; - } - - asmlinkage long sys32_mprotect(unsigned long start, size_t len, -@@ -539,30 +522,6 @@ asmlinkage long sys32_sendfile(int out_fd, int in_fd, - return ret; - } - --asmlinkage long sys32_mmap2(unsigned long addr, unsigned long len, -- unsigned long prot, unsigned long flags, -- unsigned long fd, unsigned long pgoff) --{ -- struct mm_struct *mm = current->mm; -- unsigned long error; -- struct file *file = NULL; -- -- flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); -- if (!(flags & MAP_ANONYMOUS)) { -- file = fget(fd); -- if (!file) -- return -EBADF; -- } -- -- down_write(&mm->mmap_sem); -- error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); -- up_write(&mm->mmap_sem); -- -- if (file) -- fput(file); -- return error; --} -- - asmlinkage long sys32_olduname(struct oldold_utsname __user *name) - { - char *arch = "x86_64"; -diff --git a/arch/x86/include/asm/sys_ia32.h b/arch/x86/include/asm/sys_ia32.h -index 72a6dcd..77c1184 100644 ---- a/arch/x86/include/asm/sys_ia32.h -+++ b/arch/x86/include/asm/sys_ia32.h -@@ -62,9 +62,6 @@ asmlinkage long sys32_pwrite(unsigned int, char __user *, u32, u32, u32); - asmlinkage long sys32_personality(unsigned long); - asmlinkage long sys32_sendfile(int, int, compat_off_t __user *, s32); - --asmlinkage long sys32_mmap2(unsigned long, unsigned long, unsigned long, -- unsigned long, unsigned long, unsigned long); -- - struct oldold_utsname; - struct old_utsname; - asmlinkage long sys32_olduname(struct oldold_utsname __user *); -diff --git a/arch/x86/include/asm/syscalls.h b/arch/x86/include/asm/syscalls.h -index 372b76e..1bb6e39 100644 ---- a/arch/x86/include/asm/syscalls.h -+++ b/arch/x86/include/asm/syscalls.h -@@ -55,8 +55,6 @@ struct sel_arg_struct; - struct oldold_utsname; - struct old_utsname; - --asmlinkage long sys_mmap2(unsigned long, unsigned long, unsigned long, -- unsigned long, unsigned long, unsigned long); - asmlinkage int old_mmap(struct mmap_arg_struct __user *); - asmlinkage int old_select(struct sel_arg_struct __user *); - asmlinkage int sys_ipc(uint, int, int, int, void __user *, long); -diff --git a/arch/x86/kernel/sys_i386_32.c b/arch/x86/kernel/sys_i386_32.c -index 1884a8d..dee1ff7 100644 ---- a/arch/x86/kernel/sys_i386_32.c -+++ b/arch/x86/kernel/sys_i386_32.c -@@ -24,31 +24,6 @@ - - #include - --asmlinkage long sys_mmap2(unsigned long addr, unsigned long len, -- unsigned long prot, unsigned long flags, -- unsigned long fd, unsigned long pgoff) --{ -- int error = -EBADF; -- struct file *file = NULL; -- struct mm_struct *mm = current->mm; -- -- flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); -- if (!(flags & MAP_ANONYMOUS)) { -- file = fget(fd); -- if (!file) -- goto out; -- } -- -- down_write(&mm->mmap_sem); -- error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); -- up_write(&mm->mmap_sem); -- -- if (file) -- fput(file); --out: -- return error; --} -- - /* - * Perform the select(nd, in, out, ex, tv) and mmap() system - * calls. Linux/i386 didn't use to be able to handle more than -@@ -77,7 +52,7 @@ asmlinkage int old_mmap(struct mmap_arg_struct __user *arg) - if (a.offset & ~PAGE_MASK) - goto out; - -- err = sys_mmap2(a.addr, a.len, a.prot, a.flags, -+ err = sys_mmap_pgoff(a.addr, a.len, a.prot, a.flags, - a.fd, a.offset >> PAGE_SHIFT); - out: - return err; -diff --git a/arch/x86/kernel/sys_x86_64.c b/arch/x86/kernel/sys_x86_64.c -index 45e00eb..8aa2057 100644 ---- a/arch/x86/kernel/sys_x86_64.c -+++ b/arch/x86/kernel/sys_x86_64.c -@@ -23,26 +23,11 @@ SYSCALL_DEFINE6(mmap, unsigned long, addr, unsigned long, len, - unsigned long, fd, unsigned long, off) - { - long error; -- struct file *file; -- - error = -EINVAL; - if (off & ~PAGE_MASK) - goto out; - -- error = -EBADF; -- file = NULL; -- flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); -- if (!(flags & MAP_ANONYMOUS)) { -- file = fget(fd); -- if (!file) -- goto out; -- } -- down_write(¤t->mm->mmap_sem); -- error = do_mmap_pgoff(file, addr, len, prot, flags, off >> PAGE_SHIFT); -- up_write(¤t->mm->mmap_sem); -- -- if (file) -- fput(file); -+ error = sys_mmap_pgoff(addr, len, prot, flags, fd, off >> PAGE_SHIFT); - out: - return error; - } -diff --git a/arch/x86/kernel/syscall_table_32.S b/arch/x86/kernel/syscall_table_32.S -index 0157cd2..76d70a4 100644 ---- a/arch/x86/kernel/syscall_table_32.S -+++ b/arch/x86/kernel/syscall_table_32.S -@@ -191,7 +191,7 @@ ENTRY(sys_call_table) - .long sys_ni_syscall /* reserved for streams2 */ - .long ptregs_vfork /* 190 */ - .long sys_getrlimit -- .long sys_mmap2 -+ .long sys_mmap_pgoff - .long sys_truncate64 - .long sys_ftruncate64 - .long sys_stat64 /* 195 */ -diff --git a/arch/xtensa/include/asm/syscall.h b/arch/xtensa/include/asm/syscall.h -index 05cebf8..4352dbe 100644 ---- a/arch/xtensa/include/asm/syscall.h -+++ b/arch/xtensa/include/asm/syscall.h -@@ -13,8 +13,6 @@ struct sigaction; - asmlinkage long xtensa_execve(char*, char**, char**, struct pt_regs*); - asmlinkage long xtensa_clone(unsigned long, unsigned long, struct pt_regs*); - asmlinkage long xtensa_pipe(int __user *); --asmlinkage long xtensa_mmap2(unsigned long, unsigned long, unsigned long, -- unsigned long, unsigned long, unsigned long); - asmlinkage long xtensa_ptrace(long, long, long, long); - asmlinkage long xtensa_sigreturn(struct pt_regs*); - asmlinkage long xtensa_rt_sigreturn(struct pt_regs*); -diff --git a/arch/xtensa/include/asm/unistd.h b/arch/xtensa/include/asm/unistd.h -index c092c8f..9a5c354 100644 ---- a/arch/xtensa/include/asm/unistd.h -+++ b/arch/xtensa/include/asm/unistd.h -@@ -189,7 +189,7 @@ __SYSCALL( 79, sys_fremovexattr, 2) - /* File Map / Shared Memory Operations */ - - #define __NR_mmap2 80 --__SYSCALL( 80, xtensa_mmap2, 6) -+__SYSCALL( 80, sys_mmap_pgoff, 6) - #define __NR_munmap 81 - __SYSCALL( 81, sys_munmap, 2) - #define __NR_mprotect 82 -diff --git a/arch/xtensa/kernel/syscall.c b/arch/xtensa/kernel/syscall.c -index ac15ecb..1e67bab 100644 ---- a/arch/xtensa/kernel/syscall.c -+++ b/arch/xtensa/kernel/syscall.c -@@ -57,31 +57,6 @@ asmlinkage long xtensa_pipe(int __user *userfds) - return error; - } - -- --asmlinkage long xtensa_mmap2(unsigned long addr, unsigned long len, -- unsigned long prot, unsigned long flags, -- unsigned long fd, unsigned long pgoff) --{ -- int error = -EBADF; -- struct file * file = NULL; -- -- flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); -- if (!(flags & MAP_ANONYMOUS)) { -- file = fget(fd); -- if (!file) -- goto out; -- } -- -- down_write(¤t->mm->mmap_sem); -- error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); -- up_write(¤t->mm->mmap_sem); -- -- if (file) -- fput(file); --out: -- return error; --} -- - asmlinkage long xtensa_shmat(int shmid, char __user *shmaddr, int shmflg) - { - unsigned long ret; -diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c -index 3cb56a0..4dcfef0 100644 ---- a/drivers/char/agp/intel-agp.c -+++ b/drivers/char/agp/intel-agp.c -@@ -178,6 +178,7 @@ static struct _intel_private { - * popup and for the GTT. - */ - int gtt_entries; /* i830+ */ -+ int gtt_total_size; - union { - void __iomem *i9xx_flush_page; - void *i8xx_flush_page; -@@ -1153,7 +1154,7 @@ static int intel_i915_configure(void) - readl(intel_private.registers+I810_PGETBL_CTL); /* PCI Posting. */ - - if (agp_bridge->driver->needs_scratch_page) { -- for (i = intel_private.gtt_entries; i < current_size->num_entries; i++) { -+ for (i = intel_private.gtt_entries; i < intel_private.gtt_total_size; i++) { - writel(agp_bridge->scratch_page, intel_private.gtt+i); - } - readl(intel_private.gtt+i-1); /* PCI Posting. */ -@@ -1308,6 +1309,8 @@ static int intel_i915_create_gatt_table(struct agp_bridge_data *bridge) - if (!intel_private.gtt) - return -ENOMEM; - -+ intel_private.gtt_total_size = gtt_map_size / 4; -+ - temp &= 0xfff80000; - - intel_private.registers = ioremap(temp, 128 * 4096); -@@ -1395,6 +1398,8 @@ static int intel_i965_create_gatt_table(struct agp_bridge_data *bridge) - if (!intel_private.gtt) - return -ENOMEM; - -+ intel_private.gtt_total_size = gtt_size / 4; -+ - intel_private.registers = ioremap(temp, 128 * 4096); - if (!intel_private.registers) { - iounmap(intel_private.gtt); -diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c -index 6810443..73655ae 100644 ---- a/drivers/cpuidle/governors/menu.c -+++ b/drivers/cpuidle/governors/menu.c -@@ -18,6 +18,7 @@ - #include - #include - #include -+#include - - #define BUCKETS 12 - #define RESOLUTION 1024 -@@ -169,6 +170,12 @@ static DEFINE_PER_CPU(struct menu_device, menu_devices); - - static void menu_update(struct cpuidle_device *dev); - -+/* This implements DIV_ROUND_CLOSEST but avoids 64 bit division */ -+static u64 div_round64(u64 dividend, u32 divisor) -+{ -+ return div_u64(dividend + (divisor / 2), divisor); -+} -+ - /** - * menu_select - selects the next idle state to enter - * @dev: the CPU -@@ -209,9 +216,8 @@ static int menu_select(struct cpuidle_device *dev) - data->correction_factor[data->bucket] = RESOLUTION * DECAY; - - /* Make sure to round up for half microseconds */ -- data->predicted_us = DIV_ROUND_CLOSEST( -- data->expected_us * data->correction_factor[data->bucket], -- RESOLUTION * DECAY); -+ data->predicted_us = div_round64(data->expected_us * data->correction_factor[data->bucket], -+ RESOLUTION * DECAY); - - /* - * We want to default to C1 (hlt), not to busy polling -diff --git a/drivers/gpu/drm/ati_pcigart.c b/drivers/gpu/drm/ati_pcigart.c -index 628eae3..a1fce68 100644 ---- a/drivers/gpu/drm/ati_pcigart.c -+++ b/drivers/gpu/drm/ati_pcigart.c -@@ -39,8 +39,7 @@ static int drm_ati_alloc_pcigart_table(struct drm_device *dev, - struct drm_ati_pcigart_info *gart_info) - { - gart_info->table_handle = drm_pci_alloc(dev, gart_info->table_size, -- PAGE_SIZE, -- gart_info->table_mask); -+ PAGE_SIZE); - if (gart_info->table_handle == NULL) - return -ENOMEM; - -@@ -112,6 +111,13 @@ int drm_ati_pcigart_init(struct drm_device *dev, struct drm_ati_pcigart_info *ga - if (gart_info->gart_table_location == DRM_ATI_GART_MAIN) { - DRM_DEBUG("PCI: no table in VRAM: using normal RAM\n"); - -+ if (pci_set_dma_mask(dev->pdev, gart_info->table_mask)) { -+ DRM_ERROR("fail to set dma mask to 0x%Lx\n", -+ gart_info->table_mask); -+ ret = 1; -+ goto done; -+ } -+ - ret = drm_ati_alloc_pcigart_table(dev, gart_info); - if (ret) { - DRM_ERROR("cannot allocate PCI GART page!\n"); -diff --git a/drivers/gpu/drm/drm_bufs.c b/drivers/gpu/drm/drm_bufs.c -index 3d09e30..8417cc4 100644 ---- a/drivers/gpu/drm/drm_bufs.c -+++ b/drivers/gpu/drm/drm_bufs.c -@@ -326,7 +326,7 @@ static int drm_addmap_core(struct drm_device * dev, resource_size_t offset, - * As we're limiting the address to 2^32-1 (or less), - * casting it down to 32 bits is no problem, but we - * need to point to a 64bit variable first. */ -- dmah = drm_pci_alloc(dev, map->size, map->size, 0xffffffffUL); -+ dmah = drm_pci_alloc(dev, map->size, map->size); - if (!dmah) { - kfree(map); - return -ENOMEM; -@@ -885,7 +885,7 @@ int drm_addbufs_pci(struct drm_device * dev, struct drm_buf_desc * request) - - while (entry->buf_count < count) { - -- dmah = drm_pci_alloc(dev, PAGE_SIZE << page_order, 0x1000, 0xfffffffful); -+ dmah = drm_pci_alloc(dev, PAGE_SIZE << page_order, 0x1000); - - if (!dmah) { - /* Set count correctly so we free the proper amount. */ -diff --git a/drivers/gpu/drm/drm_pci.c b/drivers/gpu/drm/drm_pci.c -index 577094f..e68ebf9 100644 ---- a/drivers/gpu/drm/drm_pci.c -+++ b/drivers/gpu/drm/drm_pci.c -@@ -47,8 +47,7 @@ - /** - * \brief Allocate a PCI consistent memory block, for DMA. - */ --drm_dma_handle_t *drm_pci_alloc(struct drm_device * dev, size_t size, size_t align, -- dma_addr_t maxaddr) -+drm_dma_handle_t *drm_pci_alloc(struct drm_device * dev, size_t size, size_t align) - { - drm_dma_handle_t *dmah; - #if 1 -@@ -63,11 +62,6 @@ drm_dma_handle_t *drm_pci_alloc(struct drm_device * dev, size_t size, size_t ali - if (align > size) - return NULL; - -- if (pci_set_dma_mask(dev->pdev, maxaddr) != 0) { -- DRM_ERROR("Setting pci dma mask failed\n"); -- return NULL; -- } -- - dmah = kmalloc(sizeof(drm_dma_handle_t), GFP_KERNEL); - if (!dmah) - return NULL; -diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c -index e5b138b..bc2db7d 100644 ---- a/drivers/gpu/drm/i915/i915_dma.c -+++ b/drivers/gpu/drm/i915/i915_dma.c -@@ -123,7 +123,7 @@ static int i915_init_phys_hws(struct drm_device *dev) - drm_i915_private_t *dev_priv = dev->dev_private; - /* Program Hardware Status Page */ - dev_priv->status_page_dmah = -- drm_pci_alloc(dev, PAGE_SIZE, PAGE_SIZE, 0xffffffff); -+ drm_pci_alloc(dev, PAGE_SIZE, PAGE_SIZE); - - if (!dev_priv->status_page_dmah) { - DRM_ERROR("Can not allocate hardware status page\n"); -@@ -1111,7 +1111,8 @@ static void i915_setup_compression(struct drm_device *dev, int size) - { - struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_mm_node *compressed_fb, *compressed_llb; -- unsigned long cfb_base, ll_base; -+ unsigned long cfb_base; -+ unsigned long ll_base = 0; - - /* Leave 1M for line length buffer & misc. */ - compressed_fb = drm_mm_search_free(&dev_priv->vram, size, 4096, 0); -diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h -index ecbafd0..791fded 100644 ---- a/drivers/gpu/drm/i915/i915_drv.h -+++ b/drivers/gpu/drm/i915/i915_drv.h -@@ -546,6 +546,7 @@ typedef struct drm_i915_private { - struct timer_list idle_timer; - bool busy; - u16 orig_clock; -+ struct drm_connector *int_lvds_connector; - } drm_i915_private_t; - - /** driver private structure attached to each drm_gem_object */ -diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c -index 5ddbd38..df2c625 100644 ---- a/drivers/gpu/drm/i915/i915_gem.c -+++ b/drivers/gpu/drm/i915/i915_gem.c -@@ -2010,9 +2010,6 @@ i915_gem_object_unbind(struct drm_gem_object *obj) - /* blow away mappings if mapped through GTT */ - i915_gem_release_mmap(obj); - -- if (obj_priv->fence_reg != I915_FENCE_REG_NONE) -- i915_gem_clear_fence_reg(obj); -- - /* Move the object to the CPU domain to ensure that - * any possible CPU writes while it's not in the GTT - * are flushed when we go to remap it. This will -@@ -2028,6 +2025,10 @@ i915_gem_object_unbind(struct drm_gem_object *obj) - - BUG_ON(obj_priv->active); - -+ /* release the fence reg _after_ flushing */ -+ if (obj_priv->fence_reg != I915_FENCE_REG_NONE) -+ i915_gem_clear_fence_reg(obj); -+ - if (obj_priv->agp_mem != NULL) { - drm_unbind_agp(obj_priv->agp_mem); - drm_free_agp(obj_priv->agp_mem, obj->size / PAGE_SIZE); -@@ -2570,9 +2571,6 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment) - bool retry_alloc = false; - int ret; - -- if (dev_priv->mm.suspended) -- return -EBUSY; -- - if (obj_priv->madv != I915_MADV_WILLNEED) { - DRM_ERROR("Attempting to bind a purgeable object\n"); - return -EINVAL; -@@ -4639,7 +4637,7 @@ int i915_gem_init_phys_object(struct drm_device *dev, - - phys_obj->id = id; - -- phys_obj->handle = drm_pci_alloc(dev, size, 0, 0xffffffff); -+ phys_obj->handle = drm_pci_alloc(dev, size, 0); - if (!phys_obj->handle) { - ret = -ENOMEM; - goto kfree_obj; -diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h -index 1687edf..54e5907 100644 ---- a/drivers/gpu/drm/i915/i915_reg.h -+++ b/drivers/gpu/drm/i915/i915_reg.h -@@ -968,6 +968,8 @@ - #define LVDS_PORT_EN (1 << 31) - /* Selects pipe B for LVDS data. Must be set on pre-965. */ - #define LVDS_PIPEB_SELECT (1 << 30) -+/* LVDS dithering flag on 965/g4x platform */ -+#define LVDS_ENABLE_DITHER (1 << 25) - /* Enable border for unscaled (or aspect-scaled) display */ - #define LVDS_BORDER_ENABLE (1 << 15) - /* -@@ -1737,6 +1739,8 @@ - - /* Display & cursor control */ - -+/* dithering flag on Ironlake */ -+#define PIPE_ENABLE_DITHER (1 << 4) - /* Pipe A */ - #define PIPEADSL 0x70000 - #define PIPEACONF 0x70008 -diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c -index f1de53b..121b92e 100644 ---- a/drivers/gpu/drm/i915/intel_display.c -+++ b/drivers/gpu/drm/i915/intel_display.c -@@ -1473,6 +1473,10 @@ static void igdng_crtc_dpms(struct drm_crtc *crtc, int mode) - int trans_vsync_reg = (pipe == 0) ? TRANS_VSYNC_A : TRANS_VSYNC_B; - u32 temp; - int tries = 5, j, n; -+ u32 pipe_bpc; -+ -+ temp = I915_READ(pipeconf_reg); -+ pipe_bpc = temp & PIPE_BPC_MASK; - - /* XXX: When our outputs are all unaware of DPMS modes other than off - * and on, we should map those modes to DRM_MODE_DPMS_OFF in the CRTC. -@@ -1504,6 +1508,12 @@ static void igdng_crtc_dpms(struct drm_crtc *crtc, int mode) - - /* enable PCH FDI RX PLL, wait warmup plus DMI latency */ - temp = I915_READ(fdi_rx_reg); -+ /* -+ * make the BPC in FDI Rx be consistent with that in -+ * pipeconf reg. -+ */ -+ temp &= ~(0x7 << 16); -+ temp |= (pipe_bpc << 11); - I915_WRITE(fdi_rx_reg, temp | FDI_RX_PLL_ENABLE | - FDI_SEL_PCDCLK | - FDI_DP_PORT_WIDTH_X4); /* default 4 lanes */ -@@ -1644,6 +1654,12 @@ static void igdng_crtc_dpms(struct drm_crtc *crtc, int mode) - - /* enable PCH transcoder */ - temp = I915_READ(transconf_reg); -+ /* -+ * make the BPC in transcoder be consistent with -+ * that in pipeconf reg. -+ */ -+ temp &= ~PIPE_BPC_MASK; -+ temp |= pipe_bpc; - I915_WRITE(transconf_reg, temp | TRANS_ENABLE); - I915_READ(transconf_reg); - -@@ -1722,6 +1738,9 @@ static void igdng_crtc_dpms(struct drm_crtc *crtc, int mode) - I915_READ(fdi_tx_reg); - - temp = I915_READ(fdi_rx_reg); -+ /* BPC in FDI rx is consistent with that in pipeconf */ -+ temp &= ~(0x07 << 16); -+ temp |= (pipe_bpc << 11); - I915_WRITE(fdi_rx_reg, temp & ~FDI_RX_ENABLE); - I915_READ(fdi_rx_reg); - -@@ -1765,7 +1784,12 @@ static void igdng_crtc_dpms(struct drm_crtc *crtc, int mode) - } - } - } -- -+ temp = I915_READ(transconf_reg); -+ /* BPC in transcoder is consistent with that in pipeconf */ -+ temp &= ~PIPE_BPC_MASK; -+ temp |= pipe_bpc; -+ I915_WRITE(transconf_reg, temp); -+ I915_READ(transconf_reg); - udelay(100); - - /* disable PCH DPLL */ -@@ -2877,6 +2901,18 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, - - /* determine panel color depth */ - temp = I915_READ(pipeconf_reg); -+ temp &= ~PIPE_BPC_MASK; -+ if (is_lvds) { -+ int lvds_reg = I915_READ(PCH_LVDS); -+ /* the BPC will be 6 if it is 18-bit LVDS panel */ -+ if ((lvds_reg & LVDS_A3_POWER_MASK) == LVDS_A3_POWER_UP) -+ temp |= PIPE_8BPC; -+ else -+ temp |= PIPE_6BPC; -+ } else -+ temp |= PIPE_8BPC; -+ I915_WRITE(pipeconf_reg, temp); -+ I915_READ(pipeconf_reg); - - switch (temp & PIPE_BPC_MASK) { - case PIPE_8BPC: -@@ -3104,7 +3140,20 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, - * appropriately here, but we need to look more thoroughly into how - * panels behave in the two modes. - */ -- -+ /* set the dithering flag */ -+ if (IS_I965G(dev)) { -+ if (dev_priv->lvds_dither) { -+ if (IS_IGDNG(dev)) -+ pipeconf |= PIPE_ENABLE_DITHER; -+ else -+ lvds |= LVDS_ENABLE_DITHER; -+ } else { -+ if (IS_IGDNG(dev)) -+ pipeconf &= ~PIPE_ENABLE_DITHER; -+ else -+ lvds &= ~LVDS_ENABLE_DITHER; -+ } -+ } - I915_WRITE(lvds_reg, lvds); - I915_READ(lvds_reg); - } -@@ -3688,125 +3737,6 @@ static void intel_gpu_idle_timer(unsigned long arg) - queue_work(dev_priv->wq, &dev_priv->idle_work); - } - --void intel_increase_renderclock(struct drm_device *dev, bool schedule) --{ -- drm_i915_private_t *dev_priv = dev->dev_private; -- -- if (IS_IGDNG(dev)) -- return; -- -- if (!dev_priv->render_reclock_avail) { -- DRM_DEBUG("not reclocking render clock\n"); -- return; -- } -- -- /* Restore render clock frequency to original value */ -- if (IS_G4X(dev) || IS_I9XX(dev)) -- pci_write_config_word(dev->pdev, GCFGC, dev_priv->orig_clock); -- else if (IS_I85X(dev)) -- pci_write_config_word(dev->pdev, HPLLCC, dev_priv->orig_clock); -- DRM_DEBUG("increasing render clock frequency\n"); -- -- /* Schedule downclock */ -- if (schedule) -- mod_timer(&dev_priv->idle_timer, jiffies + -- msecs_to_jiffies(GPU_IDLE_TIMEOUT)); --} -- --void intel_decrease_renderclock(struct drm_device *dev) --{ -- drm_i915_private_t *dev_priv = dev->dev_private; -- -- if (IS_IGDNG(dev)) -- return; -- -- if (!dev_priv->render_reclock_avail) { -- DRM_DEBUG("not reclocking render clock\n"); -- return; -- } -- -- if (IS_G4X(dev)) { -- u16 gcfgc; -- -- /* Adjust render clock... */ -- pci_read_config_word(dev->pdev, GCFGC, &gcfgc); -- -- /* Down to minimum... */ -- gcfgc &= ~GM45_GC_RENDER_CLOCK_MASK; -- gcfgc |= GM45_GC_RENDER_CLOCK_266_MHZ; -- -- pci_write_config_word(dev->pdev, GCFGC, gcfgc); -- } else if (IS_I965G(dev)) { -- u16 gcfgc; -- -- /* Adjust render clock... */ -- pci_read_config_word(dev->pdev, GCFGC, &gcfgc); -- -- /* Down to minimum... */ -- gcfgc &= ~I965_GC_RENDER_CLOCK_MASK; -- gcfgc |= I965_GC_RENDER_CLOCK_267_MHZ; -- -- pci_write_config_word(dev->pdev, GCFGC, gcfgc); -- } else if (IS_I945G(dev) || IS_I945GM(dev)) { -- u16 gcfgc; -- -- /* Adjust render clock... */ -- pci_read_config_word(dev->pdev, GCFGC, &gcfgc); -- -- /* Down to minimum... */ -- gcfgc &= ~I945_GC_RENDER_CLOCK_MASK; -- gcfgc |= I945_GC_RENDER_CLOCK_166_MHZ; -- -- pci_write_config_word(dev->pdev, GCFGC, gcfgc); -- } else if (IS_I915G(dev)) { -- u16 gcfgc; -- -- /* Adjust render clock... */ -- pci_read_config_word(dev->pdev, GCFGC, &gcfgc); -- -- /* Down to minimum... */ -- gcfgc &= ~I915_GC_RENDER_CLOCK_MASK; -- gcfgc |= I915_GC_RENDER_CLOCK_166_MHZ; -- -- pci_write_config_word(dev->pdev, GCFGC, gcfgc); -- } else if (IS_I85X(dev)) { -- u16 hpllcc; -- -- /* Adjust render clock... */ -- pci_read_config_word(dev->pdev, HPLLCC, &hpllcc); -- -- /* Up to maximum... */ -- hpllcc &= ~GC_CLOCK_CONTROL_MASK; -- hpllcc |= GC_CLOCK_133_200; -- -- pci_write_config_word(dev->pdev, HPLLCC, hpllcc); -- } -- DRM_DEBUG("decreasing render clock frequency\n"); --} -- --/* Note that no increase function is needed for this - increase_renderclock() -- * will also rewrite these bits -- */ --void intel_decrease_displayclock(struct drm_device *dev) --{ -- if (IS_IGDNG(dev)) -- return; -- -- if (IS_I945G(dev) || IS_I945GM(dev) || IS_I915G(dev) || -- IS_I915GM(dev)) { -- u16 gcfgc; -- -- /* Adjust render clock... */ -- pci_read_config_word(dev->pdev, GCFGC, &gcfgc); -- -- /* Down to minimum... */ -- gcfgc &= ~0xf0; -- gcfgc |= 0x80; -- -- pci_write_config_word(dev->pdev, GCFGC, gcfgc); -- } --} -- - #define CRTC_IDLE_TIMEOUT 1000 /* ms */ - - static void intel_crtc_idle_timer(unsigned long arg) -@@ -3920,12 +3850,6 @@ static void intel_idle_update(struct work_struct *work) - - mutex_lock(&dev->struct_mutex); - -- /* GPU isn't processing, downclock it. */ -- if (!dev_priv->busy) { -- intel_decrease_renderclock(dev); -- intel_decrease_displayclock(dev); -- } -- - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - /* Skip inactive CRTCs */ - if (!crtc->fb) -@@ -3960,7 +3884,6 @@ void intel_mark_busy(struct drm_device *dev, struct drm_gem_object *obj) - return; - - dev_priv->busy = true; -- intel_increase_renderclock(dev, true); - - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - if (!crtc->fb) -@@ -4465,7 +4388,6 @@ void intel_modeset_cleanup(struct drm_device *dev) - del_timer_sync(&intel_crtc->idle_timer); - } - -- intel_increase_renderclock(dev, false); - del_timer_sync(&dev_priv->idle_timer); - - mutex_unlock(&dev->struct_mutex); -diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c -index 05598ae..0e0e4b4 100644 ---- a/drivers/gpu/drm/i915/intel_lvds.c -+++ b/drivers/gpu/drm/i915/intel_lvds.c -@@ -679,7 +679,14 @@ static int intel_lid_notify(struct notifier_block *nb, unsigned long val, - struct drm_i915_private *dev_priv = - container_of(nb, struct drm_i915_private, lid_notifier); - struct drm_device *dev = dev_priv->dev; -+ struct drm_connector *connector = dev_priv->int_lvds_connector; - -+ /* -+ * check and update the status of LVDS connector after receiving -+ * the LID nofication event. -+ */ -+ if (connector) -+ connector->status = connector->funcs->detect(connector); - if (!acpi_lid_open()) { - dev_priv->modeset_on_lid = 1; - return NOTIFY_OK; -@@ -1085,6 +1092,8 @@ out: - DRM_DEBUG("lid notifier registration failed\n"); - dev_priv->lid_notifier.notifier_call = NULL; - } -+ /* keep the LVDS connector */ -+ dev_priv->int_lvds_connector = connector; - drm_sysfs_connector_add(connector); - return; - -diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig -index 700e93a..c1f7ea0 100644 ---- a/drivers/hwmon/Kconfig -+++ b/drivers/hwmon/Kconfig -@@ -374,7 +374,7 @@ config SENSORS_GL520SM - - config SENSORS_CORETEMP - tristate "Intel Core/Core2/Atom temperature sensor" -- depends on X86 && EXPERIMENTAL -+ depends on X86 && PCI && EXPERIMENTAL - help - If you say yes here you get support for the temperature - sensor inside your CPU. Most of the family 6 CPUs -diff --git a/drivers/hwmon/adt7462.c b/drivers/hwmon/adt7462.c -index 1852f27..262c133 100644 ---- a/drivers/hwmon/adt7462.c -+++ b/drivers/hwmon/adt7462.c -@@ -97,7 +97,7 @@ I2C_CLIENT_INSMOD_1(adt7462); - #define ADT7462_PIN24_SHIFT 6 - #define ADT7462_PIN26_VOLT_INPUT 0x08 - #define ADT7462_PIN25_VOLT_INPUT 0x20 --#define ADT7462_PIN28_SHIFT 6 /* cfg3 */ -+#define ADT7462_PIN28_SHIFT 4 /* cfg3 */ - #define ADT7462_PIN28_VOLT 0x5 - - #define ADT7462_REG_ALARM1 0xB8 -diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c -index caef39c..2d7bcee 100644 ---- a/drivers/hwmon/coretemp.c -+++ b/drivers/hwmon/coretemp.c -@@ -33,6 +33,7 @@ - #include - #include - #include -+#include - #include - #include - -@@ -161,6 +162,7 @@ static int __devinit adjust_tjmax(struct cpuinfo_x86 *c, u32 id, struct device * - int usemsr_ee = 1; - int err; - u32 eax, edx; -+ struct pci_dev *host_bridge; - - /* Early chips have no MSR for TjMax */ - -@@ -168,11 +170,21 @@ static int __devinit adjust_tjmax(struct cpuinfo_x86 *c, u32 id, struct device * - usemsr_ee = 0; - } - -- /* Atoms seems to have TjMax at 90C */ -+ /* Atom CPUs */ - - if (c->x86_model == 0x1c) { - usemsr_ee = 0; -- tjmax = 90000; -+ -+ host_bridge = pci_get_bus_and_slot(0, PCI_DEVFN(0, 0)); -+ -+ if (host_bridge && host_bridge->vendor == PCI_VENDOR_ID_INTEL -+ && (host_bridge->device == 0xa000 /* NM10 based nettop */ -+ || host_bridge->device == 0xa010)) /* NM10 based netbook */ -+ tjmax = 100000; -+ else -+ tjmax = 90000; -+ -+ pci_dev_put(host_bridge); - } - - if ((c->x86_model > 0xe) && (usemsr_ee)) { -diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c -index 85f0e8c..1f552c6 100644 ---- a/drivers/mmc/card/block.c -+++ b/drivers/mmc/card/block.c -@@ -85,7 +85,14 @@ static void mmc_blk_put(struct mmc_blk_data *md) - mutex_lock(&open_lock); - md->usage--; - if (md->usage == 0) { -+ int devmaj = MAJOR(disk_devt(md->disk)); - int devidx = MINOR(disk_devt(md->disk)) >> MMC_SHIFT; -+ -+ if (!devmaj) -+ devidx = md->disk->first_minor >> MMC_SHIFT; -+ -+ blk_cleanup_queue(md->queue.queue); -+ - __clear_bit(devidx, dev_use); - - put_disk(md->disk); -@@ -613,6 +620,7 @@ static int mmc_blk_probe(struct mmc_card *card) - return 0; - - out: -+ mmc_cleanup_queue(&md->queue); - mmc_blk_put(md); - - return err; -diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c -index 49e5823..c5a7a85 100644 ---- a/drivers/mmc/card/queue.c -+++ b/drivers/mmc/card/queue.c -@@ -90,9 +90,10 @@ static void mmc_request(struct request_queue *q) - struct request *req; - - if (!mq) { -- printk(KERN_ERR "MMC: killing requests for dead queue\n"); -- while ((req = blk_fetch_request(q)) != NULL) -+ while ((req = blk_fetch_request(q)) != NULL) { -+ req->cmd_flags |= REQ_QUIET; - __blk_end_request_all(req, -EIO); -+ } - return; - } - -@@ -223,17 +224,18 @@ void mmc_cleanup_queue(struct mmc_queue *mq) - struct request_queue *q = mq->queue; - unsigned long flags; - -- /* Mark that we should start throwing out stragglers */ -- spin_lock_irqsave(q->queue_lock, flags); -- q->queuedata = NULL; -- spin_unlock_irqrestore(q->queue_lock, flags); -- - /* Make sure the queue isn't suspended, as that will deadlock */ - mmc_queue_resume(mq); - - /* Then terminate our worker thread */ - kthread_stop(mq->thread); - -+ /* Empty the queue */ -+ spin_lock_irqsave(q->queue_lock, flags); -+ q->queuedata = NULL; -+ blk_start_queue(q); -+ spin_unlock_irqrestore(q->queue_lock, flags); -+ - if (mq->bounce_sg) - kfree(mq->bounce_sg); - mq->bounce_sg = NULL; -@@ -245,8 +247,6 @@ void mmc_cleanup_queue(struct mmc_queue *mq) - kfree(mq->bounce_buf); - mq->bounce_buf = NULL; - -- blk_cleanup_queue(mq->queue); -- - mq->card = NULL; - } - EXPORT_SYMBOL(mmc_cleanup_queue); -diff --git a/drivers/net/wireless/ath/ath5k/eeprom.c b/drivers/net/wireless/ath/ath5k/eeprom.c -index 7918852..9a96550 100644 ---- a/drivers/net/wireless/ath/ath5k/eeprom.c -+++ b/drivers/net/wireless/ath/ath5k/eeprom.c -@@ -97,7 +97,7 @@ ath5k_eeprom_init_header(struct ath5k_hw *ah) - struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; - int ret; - u16 val; -- u32 cksum, offset; -+ u32 cksum, offset, eep_max = AR5K_EEPROM_INFO_MAX; - - /* - * Read values from EEPROM and store them in the capability structure -@@ -116,12 +116,38 @@ ath5k_eeprom_init_header(struct ath5k_hw *ah) - * Validate the checksum of the EEPROM date. There are some - * devices with invalid EEPROMs. - */ -- for (cksum = 0, offset = 0; offset < AR5K_EEPROM_INFO_MAX; offset++) { -+ AR5K_EEPROM_READ(AR5K_EEPROM_SIZE_UPPER, val); -+ if (val) { -+ eep_max = (val & AR5K_EEPROM_SIZE_UPPER_MASK) << -+ AR5K_EEPROM_SIZE_ENDLOC_SHIFT; -+ AR5K_EEPROM_READ(AR5K_EEPROM_SIZE_LOWER, val); -+ eep_max = (eep_max | val) - AR5K_EEPROM_INFO_BASE; -+ -+ /* -+ * Fail safe check to prevent stupid loops due -+ * to busted EEPROMs. XXX: This value is likely too -+ * big still, waiting on a better value. -+ */ -+ if (eep_max > (3 * AR5K_EEPROM_INFO_MAX)) { -+ ATH5K_ERR(ah->ah_sc, "Invalid max custom EEPROM size: " -+ "%d (0x%04x) max expected: %d (0x%04x)\n", -+ eep_max, eep_max, -+ 3 * AR5K_EEPROM_INFO_MAX, -+ 3 * AR5K_EEPROM_INFO_MAX); -+ return -EIO; -+ } -+ } -+ -+ for (cksum = 0, offset = 0; offset < eep_max; offset++) { - AR5K_EEPROM_READ(AR5K_EEPROM_INFO(offset), val); - cksum ^= val; - } - if (cksum != AR5K_EEPROM_INFO_CKSUM) { -- ATH5K_ERR(ah->ah_sc, "Invalid EEPROM checksum 0x%04x\n", cksum); -+ ATH5K_ERR(ah->ah_sc, "Invalid EEPROM " -+ "checksum: 0x%04x eep_max: 0x%04x (%s)\n", -+ cksum, eep_max, -+ eep_max == AR5K_EEPROM_INFO_MAX ? -+ "default size" : "custom size"); - return -EIO; - } - -diff --git a/drivers/net/wireless/ath/ath5k/eeprom.h b/drivers/net/wireless/ath/ath5k/eeprom.h -index 0123f35..473a483 100644 ---- a/drivers/net/wireless/ath/ath5k/eeprom.h -+++ b/drivers/net/wireless/ath/ath5k/eeprom.h -@@ -37,6 +37,14 @@ - #define AR5K_EEPROM_RFKILL_POLARITY_S 1 - - #define AR5K_EEPROM_REG_DOMAIN 0x00bf /* EEPROM regdom */ -+ -+/* FLASH(EEPROM) Defines for AR531X chips */ -+#define AR5K_EEPROM_SIZE_LOWER 0x1b /* size info -- lower */ -+#define AR5K_EEPROM_SIZE_UPPER 0x1c /* size info -- upper */ -+#define AR5K_EEPROM_SIZE_UPPER_MASK 0xfff0 -+#define AR5K_EEPROM_SIZE_UPPER_SHIFT 4 -+#define AR5K_EEPROM_SIZE_ENDLOC_SHIFT 12 -+ - #define AR5K_EEPROM_CHECKSUM 0x00c0 /* EEPROM checksum */ - #define AR5K_EEPROM_INFO_BASE 0x00c0 /* EEPROM header */ - #define AR5K_EEPROM_INFO_MAX (0x400 - AR5K_EEPROM_INFO_BASE) -diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c -index f4e2e84..99331ed 100644 ---- a/drivers/net/wireless/iwlwifi/iwl-4965.c -+++ b/drivers/net/wireless/iwlwifi/iwl-4965.c -@@ -2087,7 +2087,7 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv, - struct ieee80211_tx_info *info; - struct iwl4965_tx_resp *tx_resp = (void *)&pkt->u.raw[0]; - u32 status = le32_to_cpu(tx_resp->u.status); -- int tid = MAX_TID_COUNT; -+ int tid = MAX_TID_COUNT - 1; - int sta_id; - int freed; - u8 *qc = NULL; -diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h -index c2d9b7a..cea2ee2 100644 ---- a/drivers/net/wireless/iwlwifi/iwl-dev.h -+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h -@@ -703,7 +703,7 @@ extern void iwl_txq_ctx_stop(struct iwl_priv *priv); - extern int iwl_queue_space(const struct iwl_queue *q); - static inline int iwl_queue_used(const struct iwl_queue *q, int i) - { -- return q->write_ptr > q->read_ptr ? -+ return q->write_ptr >= q->read_ptr ? - (i >= q->read_ptr && i < q->write_ptr) : - !(i < q->read_ptr && i >= q->write_ptr); - } -diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c -index 6c95af3..06d66a1 100644 ---- a/drivers/net/wireless/libertas/scan.c -+++ b/drivers/net/wireless/libertas/scan.c -@@ -399,11 +399,8 @@ int lbs_scan_networks(struct lbs_private *priv, int full_scan) - chan_count = lbs_scan_create_channel_list(priv, chan_list); - - netif_stop_queue(priv->dev); -- netif_carrier_off(priv->dev); -- if (priv->mesh_dev) { -+ if (priv->mesh_dev) - netif_stop_queue(priv->mesh_dev); -- netif_carrier_off(priv->mesh_dev); -- } - - /* Prepare to continue an interrupted scan */ - lbs_deb_scan("chan_count %d, scan_channel %d\n", -@@ -467,16 +464,13 @@ out2: - priv->scan_channel = 0; - - out: -- if (priv->connect_status == LBS_CONNECTED) { -- netif_carrier_on(priv->dev); -- if (!priv->tx_pending_len) -- netif_wake_queue(priv->dev); -- } -- if (priv->mesh_dev && (priv->mesh_connect_status == LBS_CONNECTED)) { -- netif_carrier_on(priv->mesh_dev); -- if (!priv->tx_pending_len) -- netif_wake_queue(priv->mesh_dev); -- } -+ if (priv->connect_status == LBS_CONNECTED && !priv->tx_pending_len) -+ netif_wake_queue(priv->dev); -+ -+ if (priv->mesh_dev && (priv->mesh_connect_status == LBS_CONNECTED) && -+ !priv->tx_pending_len) -+ netif_wake_queue(priv->mesh_dev); -+ - kfree(chan_list); - - lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret); -diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c -index f7a4701..473e5f2 100644 ---- a/drivers/rtc/rtc-cmos.c -+++ b/drivers/rtc/rtc-cmos.c -@@ -1099,9 +1099,9 @@ static int cmos_pnp_resume(struct pnp_dev *pnp) - #define cmos_pnp_resume NULL - #endif - --static void cmos_pnp_shutdown(struct device *pdev) -+static void cmos_pnp_shutdown(struct pnp_dev *pnp) - { -- if (system_state == SYSTEM_POWER_OFF && !cmos_poweroff(pdev)) -+ if (system_state == SYSTEM_POWER_OFF && !cmos_poweroff(&pnp->dev)) - return; - - cmos_do_shutdown(); -@@ -1120,15 +1120,12 @@ static struct pnp_driver cmos_pnp_driver = { - .id_table = rtc_ids, - .probe = cmos_pnp_probe, - .remove = __exit_p(cmos_pnp_remove), -+ .shutdown = cmos_pnp_shutdown, - - /* flag ensures resume() gets called, and stops syslog spam */ - .flags = PNP_DRIVER_RES_DO_NOT_CHANGE, - .suspend = cmos_pnp_suspend, - .resume = cmos_pnp_resume, -- .driver = { -- .name = (char *)driver_name, -- .shutdown = cmos_pnp_shutdown, -- } - }; - - #endif /* CONFIG_PNP */ -diff --git a/drivers/xen/manage.c b/drivers/xen/manage.c -index c499793..5d42d55 100644 ---- a/drivers/xen/manage.c -+++ b/drivers/xen/manage.c -@@ -102,15 +102,15 @@ static void do_suspend(void) - goto out_thaw; - } - -+ printk(KERN_DEBUG "suspending xenstore...\n"); -+ xs_suspend(); -+ - err = dpm_suspend_noirq(PMSG_SUSPEND); - if (err) { - printk(KERN_ERR "dpm_suspend_noirq failed: %d\n", err); - goto out_resume; - } - -- printk(KERN_DEBUG "suspending xenstore...\n"); -- xs_suspend(); -- - err = stop_machine(xen_suspend, &cancelled, cpumask_of(0)); - - dpm_resume_noirq(PMSG_RESUME); -@@ -120,13 +120,13 @@ static void do_suspend(void) - cancelled = 1; - } - -+out_resume: - if (!cancelled) { - xen_arch_resume(); - xs_resume(); - } else - xs_suspend_cancel(); - --out_resume: - dpm_resume_end(PMSG_RESUME); - - /* Make sure timer events get retriggered on all CPUs */ -diff --git a/fs/exofs/inode.c b/fs/exofs/inode.c -index 6c10f74..6f7df0f 100644 ---- a/fs/exofs/inode.c -+++ b/fs/exofs/inode.c -@@ -731,13 +731,28 @@ static int exofs_write_begin_export(struct file *file, - fsdata); - } - -+static int exofs_write_end(struct file *file, struct address_space *mapping, -+ loff_t pos, unsigned len, unsigned copied, -+ struct page *page, void *fsdata) -+{ -+ struct inode *inode = mapping->host; -+ /* According to comment in simple_write_end i_mutex is held */ -+ loff_t i_size = inode->i_size; -+ int ret; -+ -+ ret = simple_write_end(file, mapping,pos, len, copied, page, fsdata); -+ if (i_size != inode->i_size) -+ mark_inode_dirty(inode); -+ return ret; -+} -+ - const struct address_space_operations exofs_aops = { - .readpage = exofs_readpage, - .readpages = exofs_readpages, - .writepage = exofs_writepage, - .writepages = exofs_writepages, - .write_begin = exofs_write_begin_export, -- .write_end = simple_write_end, -+ .write_end = exofs_write_end, - }; - - /****************************************************************************** -diff --git a/fs/fcntl.c b/fs/fcntl.c -index 2cf93ec..97e01dc 100644 ---- a/fs/fcntl.c -+++ b/fs/fcntl.c -@@ -618,60 +618,90 @@ static DEFINE_RWLOCK(fasync_lock); - static struct kmem_cache *fasync_cache __read_mostly; - - /* -- * fasync_helper() is used by almost all character device drivers -- * to set up the fasync queue. It returns negative on error, 0 if it did -- * no changes and positive if it added/deleted the entry. -+ * Remove a fasync entry. If successfully removed, return -+ * positive and clear the FASYNC flag. If no entry exists, -+ * do nothing and return 0. -+ * -+ * NOTE! It is very important that the FASYNC flag always -+ * match the state "is the filp on a fasync list". -+ * -+ * We always take the 'filp->f_lock', in since fasync_lock -+ * needs to be irq-safe. - */ --int fasync_helper(int fd, struct file * filp, int on, struct fasync_struct **fapp) -+static int fasync_remove_entry(struct file *filp, struct fasync_struct **fapp) - { - struct fasync_struct *fa, **fp; -- struct fasync_struct *new = NULL; - int result = 0; - -- if (on) { -- new = kmem_cache_alloc(fasync_cache, GFP_KERNEL); -- if (!new) -- return -ENOMEM; -+ spin_lock(&filp->f_lock); -+ write_lock_irq(&fasync_lock); -+ for (fp = fapp; (fa = *fp) != NULL; fp = &fa->fa_next) { -+ if (fa->fa_file != filp) -+ continue; -+ *fp = fa->fa_next; -+ kmem_cache_free(fasync_cache, fa); -+ filp->f_flags &= ~FASYNC; -+ result = 1; -+ break; - } -+ write_unlock_irq(&fasync_lock); -+ spin_unlock(&filp->f_lock); -+ return result; -+} -+ -+/* -+ * Add a fasync entry. Return negative on error, positive if -+ * added, and zero if did nothing but change an existing one. -+ * -+ * NOTE! It is very important that the FASYNC flag always -+ * match the state "is the filp on a fasync list". -+ */ -+static int fasync_add_entry(int fd, struct file *filp, struct fasync_struct **fapp) -+{ -+ struct fasync_struct *new, *fa, **fp; -+ int result = 0; -+ -+ new = kmem_cache_alloc(fasync_cache, GFP_KERNEL); -+ if (!new) -+ return -ENOMEM; - -- /* -- * We need to take f_lock first since it's not an IRQ-safe -- * lock. -- */ - spin_lock(&filp->f_lock); - write_lock_irq(&fasync_lock); - for (fp = fapp; (fa = *fp) != NULL; fp = &fa->fa_next) { -- if (fa->fa_file == filp) { -- if(on) { -- fa->fa_fd = fd; -- kmem_cache_free(fasync_cache, new); -- } else { -- *fp = fa->fa_next; -- kmem_cache_free(fasync_cache, fa); -- result = 1; -- } -- goto out; -- } -+ if (fa->fa_file != filp) -+ continue; -+ fa->fa_fd = fd; -+ kmem_cache_free(fasync_cache, new); -+ goto out; - } - -- if (on) { -- new->magic = FASYNC_MAGIC; -- new->fa_file = filp; -- new->fa_fd = fd; -- new->fa_next = *fapp; -- *fapp = new; -- result = 1; -- } -+ new->magic = FASYNC_MAGIC; -+ new->fa_file = filp; -+ new->fa_fd = fd; -+ new->fa_next = *fapp; -+ *fapp = new; -+ result = 1; -+ filp->f_flags |= FASYNC; -+ - out: -- if (on) -- filp->f_flags |= FASYNC; -- else -- filp->f_flags &= ~FASYNC; - write_unlock_irq(&fasync_lock); - spin_unlock(&filp->f_lock); - return result; - } - -+/* -+ * fasync_helper() is used by almost all character device drivers -+ * to set up the fasync queue, and for regular files by the file -+ * lease code. It returns negative on error, 0 if it did no changes -+ * and positive if it added/deleted the entry. -+ */ -+int fasync_helper(int fd, struct file * filp, int on, struct fasync_struct **fapp) -+{ -+ if (!on) -+ return fasync_remove_entry(filp, fapp); -+ return fasync_add_entry(fd, filp, fapp); -+} -+ - EXPORT_SYMBOL(fasync_helper); - - void __kill_fasync(struct fasync_struct *fa, int sig, int band) -diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c -index a293f02..570dd1c 100644 ---- a/fs/nfsd/vfs.c -+++ b/fs/nfsd/vfs.c -@@ -774,12 +774,9 @@ static inline int nfsd_dosync(struct file *filp, struct dentry *dp, - int (*fsync) (struct file *, struct dentry *, int); - int err; - -- err = filemap_fdatawrite(inode->i_mapping); -+ err = filemap_write_and_wait(inode->i_mapping); - if (err == 0 && fop && (fsync = fop->fsync)) - err = fsync(filp, dp, 0); -- if (err == 0) -- err = filemap_fdatawait(inode->i_mapping); -- - return err; - } - -diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c -index c4d07a8..2534987 100644 ---- a/fs/quota/dquot.c -+++ b/fs/quota/dquot.c -@@ -1425,6 +1425,9 @@ static void inode_sub_rsv_space(struct inode *inode, qsize_t number) - static qsize_t inode_get_rsv_space(struct inode *inode) - { - qsize_t ret; -+ -+ if (!inode->i_sb->dq_op->get_reserved_space) -+ return 0; - spin_lock(&inode->i_lock); - ret = *inode_reserved_space(inode); - spin_unlock(&inode->i_lock); -diff --git a/include/drm/drmP.h b/include/drm/drmP.h -index 9d3d684..7ad3faa 100644 ---- a/include/drm/drmP.h -+++ b/include/drm/drmP.h -@@ -1402,7 +1402,7 @@ extern int drm_ati_pcigart_cleanup(struct drm_device *dev, - struct drm_ati_pcigart_info * gart_info); - - extern drm_dma_handle_t *drm_pci_alloc(struct drm_device *dev, size_t size, -- size_t align, dma_addr_t maxaddr); -+ size_t align); - extern void __drm_pci_free(struct drm_device *dev, drm_dma_handle_t * dmah); - extern void drm_pci_free(struct drm_device *dev, drm_dma_handle_t * dmah); - -diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h -index a990ace..93515c6 100644 ---- a/include/linux/syscalls.h -+++ b/include/linux/syscalls.h -@@ -879,4 +879,8 @@ int kernel_execve(const char *filename, char *const argv[], char *const envp[]); - asmlinkage long sys_perf_event_open( - struct perf_event_attr __user *attr_uptr, - pid_t pid, int cpu, int group_fd, unsigned long flags); -+ -+asmlinkage long sys_mmap_pgoff(unsigned long addr, unsigned long len, -+ unsigned long prot, unsigned long flags, -+ unsigned long fd, unsigned long pgoff); - #endif -diff --git a/ipc/shm.c b/ipc/shm.c -index 464694e..11bec62 100644 ---- a/ipc/shm.c -+++ b/ipc/shm.c -@@ -290,28 +290,28 @@ static unsigned long shm_get_unmapped_area(struct file *file, - unsigned long flags) - { - struct shm_file_data *sfd = shm_file_data(file); -- return get_unmapped_area(sfd->file, addr, len, pgoff, flags); --} -- --int is_file_shm_hugepages(struct file *file) --{ -- int ret = 0; -- -- if (file->f_op == &shm_file_operations) { -- struct shm_file_data *sfd; -- sfd = shm_file_data(file); -- ret = is_file_hugepages(sfd->file); -- } -- return ret; -+ return sfd->file->f_op->get_unmapped_area(sfd->file, addr, len, -+ pgoff, flags); - } - - static const struct file_operations shm_file_operations = { - .mmap = shm_mmap, - .fsync = shm_fsync, - .release = shm_release, -+}; -+ -+static const struct file_operations shm_file_operations_huge = { -+ .mmap = shm_mmap, -+ .fsync = shm_fsync, -+ .release = shm_release, - .get_unmapped_area = shm_get_unmapped_area, - }; - -+int is_file_shm_hugepages(struct file *file) -+{ -+ return file->f_op == &shm_file_operations_huge; -+} -+ - static const struct vm_operations_struct shm_vm_ops = { - .open = shm_open, /* callback for a new vm-area open */ - .close = shm_close, /* callback for when the vm-area is released */ -@@ -889,7 +889,10 @@ long do_shmat(int shmid, char __user *shmaddr, int shmflg, ulong *raddr) - if (!sfd) - goto out_put_dentry; - -- file = alloc_file(path.mnt, path.dentry, f_mode, &shm_file_operations); -+ file = alloc_file(path.mnt, path.dentry, f_mode, -+ is_file_hugepages(shp->shm_file) ? -+ &shm_file_operations_huge : -+ &shm_file_operations); - if (!file) - goto out_free; - ima_counts_get(file); -diff --git a/kernel/audit_tree.c b/kernel/audit_tree.c -index 2451dc6..4b05bd9 100644 ---- a/kernel/audit_tree.c -+++ b/kernel/audit_tree.c -@@ -277,7 +277,7 @@ static void untag_chunk(struct node *p) - owner->root = NULL; - } - -- for (i = j = 0; i < size; i++, j++) { -+ for (i = j = 0; j <= size; i++, j++) { - struct audit_tree *s; - if (&chunk->owners[j] == p) { - list_del_init(&p->list); -@@ -290,7 +290,7 @@ static void untag_chunk(struct node *p) - if (!s) /* result of earlier fallback */ - continue; - get_tree(s); -- list_replace_init(&chunk->owners[i].list, &new->owners[j].list); -+ list_replace_init(&chunk->owners[j].list, &new->owners[i].list); - } - - list_replace_rcu(&chunk->hash, &new->hash); -@@ -373,15 +373,17 @@ static int tag_chunk(struct inode *inode, struct audit_tree *tree) - for (n = 0; n < old->count; n++) { - if (old->owners[n].owner == tree) { - spin_unlock(&hash_lock); -- put_inotify_watch(watch); -+ put_inotify_watch(&old->watch); - return 0; - } - } - spin_unlock(&hash_lock); - - chunk = alloc_chunk(old->count + 1); -- if (!chunk) -+ if (!chunk) { -+ put_inotify_watch(&old->watch); - return -ENOMEM; -+ } - - mutex_lock(&inode->inotify_mutex); - if (inotify_clone_watch(&old->watch, &chunk->watch) < 0) { -@@ -425,7 +427,8 @@ static int tag_chunk(struct inode *inode, struct audit_tree *tree) - spin_unlock(&hash_lock); - inotify_evict_watch(&old->watch); - mutex_unlock(&inode->inotify_mutex); -- put_inotify_watch(&old->watch); -+ put_inotify_watch(&old->watch); /* pair to inotify_find_watch */ -+ put_inotify_watch(&old->watch); /* and kill it */ - return 0; - } - -diff --git a/kernel/cgroup.c b/kernel/cgroup.c -index 0249f4b..1fbcc74 100644 ---- a/kernel/cgroup.c -+++ b/kernel/cgroup.c -@@ -2468,7 +2468,6 @@ static struct cgroup_pidlist *cgroup_pidlist_find(struct cgroup *cgrp, - /* make sure l doesn't vanish out from under us */ - down_write(&l->mutex); - mutex_unlock(&cgrp->pidlist_mutex); -- l->use_count++; - return l; - } - } -diff --git a/kernel/module.c b/kernel/module.c -index 5842a71..dfa33e8 100644 ---- a/kernel/module.c -+++ b/kernel/module.c -@@ -1030,11 +1030,23 @@ static int try_to_force_load(struct module *mod, const char *reason) - } - - #ifdef CONFIG_MODVERSIONS -+/* If the arch applies (non-zero) relocations to kernel kcrctab, unapply it. */ -+static unsigned long maybe_relocated(unsigned long crc, -+ const struct module *crc_owner) -+{ -+#ifdef ARCH_RELOCATES_KCRCTAB -+ if (crc_owner == NULL) -+ return crc - (unsigned long)reloc_start; -+#endif -+ return crc; -+} -+ - static int check_version(Elf_Shdr *sechdrs, - unsigned int versindex, - const char *symname, - struct module *mod, -- const unsigned long *crc) -+ const unsigned long *crc, -+ const struct module *crc_owner) - { - unsigned int i, num_versions; - struct modversion_info *versions; -@@ -1055,10 +1067,10 @@ static int check_version(Elf_Shdr *sechdrs, - if (strcmp(versions[i].name, symname) != 0) - continue; - -- if (versions[i].crc == *crc) -+ if (versions[i].crc == maybe_relocated(*crc, crc_owner)) - return 1; - DEBUGP("Found checksum %lX vs module %lX\n", -- *crc, versions[i].crc); -+ maybe_relocated(*crc, crc_owner), versions[i].crc); - goto bad_version; - } - -@@ -1081,7 +1093,8 @@ static inline int check_modstruct_version(Elf_Shdr *sechdrs, - if (!find_symbol(MODULE_SYMBOL_PREFIX "module_layout", NULL, - &crc, true, false)) - BUG(); -- return check_version(sechdrs, versindex, "module_layout", mod, crc); -+ return check_version(sechdrs, versindex, "module_layout", mod, crc, -+ NULL); - } - - /* First part is kernel version, which we ignore if module has crcs. */ -@@ -1099,7 +1112,8 @@ static inline int check_version(Elf_Shdr *sechdrs, - unsigned int versindex, - const char *symname, - struct module *mod, -- const unsigned long *crc) -+ const unsigned long *crc, -+ const struct module *crc_owner) - { - return 1; - } -@@ -1134,8 +1148,8 @@ static const struct kernel_symbol *resolve_symbol(Elf_Shdr *sechdrs, - /* use_module can fail due to OOM, - or module initialization or unloading */ - if (sym) { -- if (!check_version(sechdrs, versindex, name, mod, crc) || -- !use_module(mod, owner)) -+ if (!check_version(sechdrs, versindex, name, mod, crc, owner) -+ || !use_module(mod, owner)) - sym = NULL; - } - return sym; -@@ -1146,6 +1160,12 @@ static const struct kernel_symbol *resolve_symbol(Elf_Shdr *sechdrs, - * J. Corbet - */ - #if defined(CONFIG_KALLSYMS) && defined(CONFIG_SYSFS) -+ -+static inline bool sect_empty(const Elf_Shdr *sect) -+{ -+ return !(sect->sh_flags & SHF_ALLOC) || sect->sh_size == 0; -+} -+ - struct module_sect_attr - { - struct module_attribute mattr; -@@ -1187,8 +1207,7 @@ static void add_sect_attrs(struct module *mod, unsigned int nsect, - - /* Count loaded sections and allocate structures */ - for (i = 0; i < nsect; i++) -- if (sechdrs[i].sh_flags & SHF_ALLOC -- && sechdrs[i].sh_size) -+ if (!sect_empty(&sechdrs[i])) - nloaded++; - size[0] = ALIGN(sizeof(*sect_attrs) - + nloaded * sizeof(sect_attrs->attrs[0]), -@@ -1206,9 +1225,7 @@ static void add_sect_attrs(struct module *mod, unsigned int nsect, - sattr = §_attrs->attrs[0]; - gattr = §_attrs->grp.attrs[0]; - for (i = 0; i < nsect; i++) { -- if (! (sechdrs[i].sh_flags & SHF_ALLOC)) -- continue; -- if (!sechdrs[i].sh_size) -+ if (sect_empty(&sechdrs[i])) - continue; - sattr->address = sechdrs[i].sh_addr; - sattr->name = kstrdup(secstrings + sechdrs[i].sh_name, -@@ -1292,7 +1309,7 @@ static void add_notes_attrs(struct module *mod, unsigned int nsect, - /* Count notes sections and allocate structures. */ - notes = 0; - for (i = 0; i < nsect; i++) -- if ((sechdrs[i].sh_flags & SHF_ALLOC) && -+ if (!sect_empty(&sechdrs[i]) && - (sechdrs[i].sh_type == SHT_NOTE)) - ++notes; - -@@ -1308,7 +1325,7 @@ static void add_notes_attrs(struct module *mod, unsigned int nsect, - notes_attrs->notes = notes; - nattr = ¬es_attrs->attrs[0]; - for (loaded = i = 0; i < nsect; ++i) { -- if (!(sechdrs[i].sh_flags & SHF_ALLOC)) -+ if (sect_empty(&sechdrs[i])) - continue; - if (sechdrs[i].sh_type == SHT_NOTE) { - nattr->attr.name = mod->sect_attrs->attrs[loaded].name; -diff --git a/kernel/signal.c b/kernel/signal.c -index 6705320..4d0658d 100644 ---- a/kernel/signal.c -+++ b/kernel/signal.c -@@ -939,7 +939,8 @@ static void print_fatal_signal(struct pt_regs *regs, int signr) - for (i = 0; i < 16; i++) { - unsigned char insn; - -- __get_user(insn, (unsigned char *)(regs->ip + i)); -+ if (get_user(insn, (unsigned char *)(regs->ip + i))) -+ break; - printk("%02x ", insn); - } - } -diff --git a/kernel/sysctl.c b/kernel/sysctl.c -index dd84be9..b8bd058 100644 ---- a/kernel/sysctl.c -+++ b/kernel/sysctl.c -@@ -1200,7 +1200,6 @@ static struct ctl_table vm_table[] = { - .extra2 = (void *)&hugetlb_infinity, - }, - #endif --#ifdef CONFIG_MMU - { - .ctl_name = VM_LOWMEM_RESERVE_RATIO, - .procname = "lowmem_reserve_ratio", -@@ -1346,6 +1345,7 @@ static struct ctl_table vm_table[] = { - .strategy = &sysctl_jiffies, - }, - #endif -+#ifdef CONFIG_MMU - { - .ctl_name = CTL_UNNUMBERED, - .procname = "mmap_min_addr", -diff --git a/lib/dma-debug.c b/lib/dma-debug.c -index 5a77c7c..084e879 100644 ---- a/lib/dma-debug.c -+++ b/lib/dma-debug.c -@@ -913,6 +913,9 @@ static void check_sync(struct device *dev, - ref->size); - } - -+ if (entry->direction == DMA_BIDIRECTIONAL) -+ goto out; -+ - if (ref->direction != entry->direction) { - err_printk(dev, entry, "DMA-API: device driver syncs " - "DMA memory with different direction " -@@ -923,9 +926,6 @@ static void check_sync(struct device *dev, - dir2name[ref->direction]); - } - -- if (entry->direction == DMA_BIDIRECTIONAL) -- goto out; -- - if (to_cpu && !(entry->direction == DMA_FROM_DEVICE) && - !(ref->direction == DMA_TO_DEVICE)) - err_printk(dev, entry, "DMA-API: device driver syncs " -@@ -948,7 +948,6 @@ static void check_sync(struct device *dev, - - out: - put_hash_bucket(bucket, &flags); -- - } - - void debug_dma_map_page(struct device *dev, struct page *page, size_t offset, -diff --git a/lib/rational.c b/lib/rational.c -index b3c099b..3ed247b 100644 ---- a/lib/rational.c -+++ b/lib/rational.c -@@ -7,6 +7,7 @@ - */ - - #include -+#include - - /* - * calculate best rational approximation for a given fraction -diff --git a/mm/mmap.c b/mm/mmap.c -index 73f5e4b..ae19746 100644 ---- a/mm/mmap.c -+++ b/mm/mmap.c -@@ -932,13 +932,9 @@ unsigned long do_mmap_pgoff(struct file *file, unsigned long addr, - if (!(flags & MAP_FIXED)) - addr = round_hint_to_min(addr); - -- error = arch_mmap_check(addr, len, flags); -- if (error) -- return error; -- - /* Careful about overflows.. */ - len = PAGE_ALIGN(len); -- if (!len || len > TASK_SIZE) -+ if (!len) - return -ENOMEM; - - /* offset overflow? */ -@@ -949,24 +945,6 @@ unsigned long do_mmap_pgoff(struct file *file, unsigned long addr, - if (mm->map_count > sysctl_max_map_count) - return -ENOMEM; - -- if (flags & MAP_HUGETLB) { -- struct user_struct *user = NULL; -- if (file) -- return -EINVAL; -- -- /* -- * VM_NORESERVE is used because the reservations will be -- * taken when vm_ops->mmap() is called -- * A dummy user value is used because we are not locking -- * memory so no accounting is necessary -- */ -- len = ALIGN(len, huge_page_size(&default_hstate)); -- file = hugetlb_file_setup(HUGETLB_ANON_FILE, len, VM_NORESERVE, -- &user, HUGETLB_ANONHUGE_INODE); -- if (IS_ERR(file)) -- return PTR_ERR(file); -- } -- - /* Obtain the address to map to. we verify (or select) it and ensure - * that it represents a valid section of the address space. - */ -@@ -1459,6 +1437,14 @@ get_unmapped_area(struct file *file, unsigned long addr, unsigned long len, - unsigned long (*get_area)(struct file *, unsigned long, - unsigned long, unsigned long, unsigned long); - -+ unsigned long error = arch_mmap_check(addr, len, flags); -+ if (error) -+ return error; -+ -+ /* Careful about overflows.. */ -+ if (len > TASK_SIZE) -+ return -ENOMEM; -+ - get_area = current->mm->get_unmapped_area; - if (file && file->f_op && file->f_op->get_unmapped_area) - get_area = file->f_op->get_unmapped_area; -@@ -2003,20 +1989,14 @@ unsigned long do_brk(unsigned long addr, unsigned long len) - if (!len) - return addr; - -- if ((addr + len) > TASK_SIZE || (addr + len) < addr) -- return -EINVAL; -- -- if (is_hugepage_only_range(mm, addr, len)) -- return -EINVAL; -- - error = security_file_mmap(NULL, 0, 0, 0, addr, 1); - if (error) - return error; - - flags = VM_DATA_DEFAULT_FLAGS | VM_ACCOUNT | mm->def_flags; - -- error = arch_mmap_check(addr, len, flags); -- if (error) -+ error = get_unmapped_area(NULL, addr, len, 0, MAP_FIXED); -+ if (error & ~PAGE_MASK) - return error; - - /* -diff --git a/mm/mremap.c b/mm/mremap.c -index 97bff25..8451908 100644 ---- a/mm/mremap.c -+++ b/mm/mremap.c -@@ -261,6 +261,137 @@ static unsigned long move_vma(struct vm_area_struct *vma, - return new_addr; - } - -+static struct vm_area_struct *vma_to_resize(unsigned long addr, -+ unsigned long old_len, unsigned long new_len, unsigned long *p) -+{ -+ struct mm_struct *mm = current->mm; -+ struct vm_area_struct *vma = find_vma(mm, addr); -+ -+ if (!vma || vma->vm_start > addr) -+ goto Efault; -+ -+ if (is_vm_hugetlb_page(vma)) -+ goto Einval; -+ -+ /* We can't remap across vm area boundaries */ -+ if (old_len > vma->vm_end - addr) -+ goto Efault; -+ -+ if (vma->vm_flags & (VM_DONTEXPAND | VM_PFNMAP)) { -+ if (new_len > old_len) -+ goto Efault; -+ } -+ -+ if (vma->vm_flags & VM_LOCKED) { -+ unsigned long locked, lock_limit; -+ locked = mm->locked_vm << PAGE_SHIFT; -+ lock_limit = current->signal->rlim[RLIMIT_MEMLOCK].rlim_cur; -+ locked += new_len - old_len; -+ if (locked > lock_limit && !capable(CAP_IPC_LOCK)) -+ goto Eagain; -+ } -+ -+ if (!may_expand_vm(mm, (new_len - old_len) >> PAGE_SHIFT)) -+ goto Enomem; -+ -+ if (vma->vm_flags & VM_ACCOUNT) { -+ unsigned long charged = (new_len - old_len) >> PAGE_SHIFT; -+ if (security_vm_enough_memory(charged)) -+ goto Efault; -+ *p = charged; -+ } -+ -+ return vma; -+ -+Efault: /* very odd choice for most of the cases, but... */ -+ return ERR_PTR(-EFAULT); -+Einval: -+ return ERR_PTR(-EINVAL); -+Enomem: -+ return ERR_PTR(-ENOMEM); -+Eagain: -+ return ERR_PTR(-EAGAIN); -+} -+ -+static unsigned long mremap_to(unsigned long addr, -+ unsigned long old_len, unsigned long new_addr, -+ unsigned long new_len) -+{ -+ struct mm_struct *mm = current->mm; -+ struct vm_area_struct *vma; -+ unsigned long ret = -EINVAL; -+ unsigned long charged = 0; -+ unsigned long map_flags; -+ -+ if (new_addr & ~PAGE_MASK) -+ goto out; -+ -+ if (new_len > TASK_SIZE || new_addr > TASK_SIZE - new_len) -+ goto out; -+ -+ /* Check if the location we're moving into overlaps the -+ * old location at all, and fail if it does. -+ */ -+ if ((new_addr <= addr) && (new_addr+new_len) > addr) -+ goto out; -+ -+ if ((addr <= new_addr) && (addr+old_len) > new_addr) -+ goto out; -+ -+ ret = security_file_mmap(NULL, 0, 0, 0, new_addr, 1); -+ if (ret) -+ goto out; -+ -+ ret = do_munmap(mm, new_addr, new_len); -+ if (ret) -+ goto out; -+ -+ if (old_len >= new_len) { -+ ret = do_munmap(mm, addr+new_len, old_len - new_len); -+ if (ret && old_len != new_len) -+ goto out; -+ old_len = new_len; -+ } -+ -+ vma = vma_to_resize(addr, old_len, new_len, &charged); -+ if (IS_ERR(vma)) { -+ ret = PTR_ERR(vma); -+ goto out; -+ } -+ -+ map_flags = MAP_FIXED; -+ if (vma->vm_flags & VM_MAYSHARE) -+ map_flags |= MAP_SHARED; -+ -+ ret = get_unmapped_area(vma->vm_file, new_addr, new_len, vma->vm_pgoff + -+ ((addr - vma->vm_start) >> PAGE_SHIFT), -+ map_flags); -+ if (ret & ~PAGE_MASK) -+ goto out1; -+ -+ ret = move_vma(vma, addr, old_len, new_len, new_addr); -+ if (!(ret & ~PAGE_MASK)) -+ goto out; -+out1: -+ vm_unacct_memory(charged); -+ -+out: -+ return ret; -+} -+ -+static int vma_expandable(struct vm_area_struct *vma, unsigned long delta) -+{ -+ unsigned long end = vma->vm_end + delta; -+ if (end < vma->vm_end) /* overflow */ -+ return 0; -+ if (vma->vm_next && vma->vm_next->vm_start < end) /* intersection */ -+ return 0; -+ if (get_unmapped_area(NULL, vma->vm_start, end - vma->vm_start, -+ 0, MAP_FIXED) & ~PAGE_MASK) -+ return 0; -+ return 1; -+} -+ - /* - * Expand (or shrink) an existing mapping, potentially moving it at the - * same time (controlled by the MREMAP_MAYMOVE flag and available VM space) -@@ -294,32 +425,10 @@ unsigned long do_mremap(unsigned long addr, - if (!new_len) - goto out; - -- /* new_addr is only valid if MREMAP_FIXED is specified */ - if (flags & MREMAP_FIXED) { -- if (new_addr & ~PAGE_MASK) -- goto out; -- if (!(flags & MREMAP_MAYMOVE)) -- goto out; -- -- if (new_len > TASK_SIZE || new_addr > TASK_SIZE - new_len) -- goto out; -- -- /* Check if the location we're moving into overlaps the -- * old location at all, and fail if it does. -- */ -- if ((new_addr <= addr) && (new_addr+new_len) > addr) -- goto out; -- -- if ((addr <= new_addr) && (addr+old_len) > new_addr) -- goto out; -- -- ret = security_file_mmap(NULL, 0, 0, 0, new_addr, 1); -- if (ret) -- goto out; -- -- ret = do_munmap(mm, new_addr, new_len); -- if (ret) -- goto out; -+ if (flags & MREMAP_MAYMOVE) -+ ret = mremap_to(addr, old_len, new_addr, new_len); -+ goto out; - } - - /* -@@ -332,60 +441,23 @@ unsigned long do_mremap(unsigned long addr, - if (ret && old_len != new_len) - goto out; - ret = addr; -- if (!(flags & MREMAP_FIXED) || (new_addr == addr)) -- goto out; -- old_len = new_len; -+ goto out; - } - - /* -- * Ok, we need to grow.. or relocate. -+ * Ok, we need to grow.. - */ -- ret = -EFAULT; -- vma = find_vma(mm, addr); -- if (!vma || vma->vm_start > addr) -- goto out; -- if (is_vm_hugetlb_page(vma)) { -- ret = -EINVAL; -- goto out; -- } -- /* We can't remap across vm area boundaries */ -- if (old_len > vma->vm_end - addr) -- goto out; -- if (vma->vm_flags & (VM_DONTEXPAND | VM_PFNMAP)) { -- if (new_len > old_len) -- goto out; -- } -- if (vma->vm_flags & VM_LOCKED) { -- unsigned long locked, lock_limit; -- locked = mm->locked_vm << PAGE_SHIFT; -- lock_limit = current->signal->rlim[RLIMIT_MEMLOCK].rlim_cur; -- locked += new_len - old_len; -- ret = -EAGAIN; -- if (locked > lock_limit && !capable(CAP_IPC_LOCK)) -- goto out; -- } -- if (!may_expand_vm(mm, (new_len - old_len) >> PAGE_SHIFT)) { -- ret = -ENOMEM; -+ vma = vma_to_resize(addr, old_len, new_len, &charged); -+ if (IS_ERR(vma)) { -+ ret = PTR_ERR(vma); - goto out; - } - -- if (vma->vm_flags & VM_ACCOUNT) { -- charged = (new_len - old_len) >> PAGE_SHIFT; -- if (security_vm_enough_memory(charged)) -- goto out_nc; -- } -- - /* old_len exactly to the end of the area.. -- * And we're not relocating the area. - */ -- if (old_len == vma->vm_end - addr && -- !((flags & MREMAP_FIXED) && (addr != new_addr)) && -- (old_len != new_len || !(flags & MREMAP_MAYMOVE))) { -- unsigned long max_addr = TASK_SIZE; -- if (vma->vm_next) -- max_addr = vma->vm_next->vm_start; -+ if (old_len == vma->vm_end - addr) { - /* can we just expand the current mapping? */ -- if (max_addr - addr >= new_len) { -+ if (vma_expandable(vma, new_len - old_len)) { - int pages = (new_len - old_len) >> PAGE_SHIFT; - - vma_adjust(vma, vma->vm_start, -@@ -409,28 +481,27 @@ unsigned long do_mremap(unsigned long addr, - */ - ret = -ENOMEM; - if (flags & MREMAP_MAYMOVE) { -- if (!(flags & MREMAP_FIXED)) { -- unsigned long map_flags = 0; -- if (vma->vm_flags & VM_MAYSHARE) -- map_flags |= MAP_SHARED; -- -- new_addr = get_unmapped_area(vma->vm_file, 0, new_len, -- vma->vm_pgoff, map_flags); -- if (new_addr & ~PAGE_MASK) { -- ret = new_addr; -- goto out; -- } -- -- ret = security_file_mmap(NULL, 0, 0, 0, new_addr, 1); -- if (ret) -- goto out; -+ unsigned long map_flags = 0; -+ if (vma->vm_flags & VM_MAYSHARE) -+ map_flags |= MAP_SHARED; -+ -+ new_addr = get_unmapped_area(vma->vm_file, 0, new_len, -+ vma->vm_pgoff + -+ ((addr - vma->vm_start) >> PAGE_SHIFT), -+ map_flags); -+ if (new_addr & ~PAGE_MASK) { -+ ret = new_addr; -+ goto out; - } -+ -+ ret = security_file_mmap(NULL, 0, 0, 0, new_addr, 1); -+ if (ret) -+ goto out; - ret = move_vma(vma, addr, old_len, new_len, new_addr); - } - out: - if (ret & ~PAGE_MASK) - vm_unacct_memory(charged); --out_nc: - return ret; - } - -diff --git a/mm/util.c b/mm/util.c -index 7c35ad9..b377ce4 100644 ---- a/mm/util.c -+++ b/mm/util.c -@@ -4,6 +4,10 @@ - #include - #include - #include -+#include -+#include -+#include -+#include - #include - - #define CREATE_TRACE_POINTS -@@ -268,6 +272,46 @@ int __attribute__((weak)) get_user_pages_fast(unsigned long start, - } - EXPORT_SYMBOL_GPL(get_user_pages_fast); - -+SYSCALL_DEFINE6(mmap_pgoff, unsigned long, addr, unsigned long, len, -+ unsigned long, prot, unsigned long, flags, -+ unsigned long, fd, unsigned long, pgoff) -+{ -+ struct file * file = NULL; -+ unsigned long retval = -EBADF; -+ -+ if (!(flags & MAP_ANONYMOUS)) { -+ if (unlikely(flags & MAP_HUGETLB)) -+ return -EINVAL; -+ file = fget(fd); -+ if (!file) -+ goto out; -+ } else if (flags & MAP_HUGETLB) { -+ struct user_struct *user = NULL; -+ /* -+ * VM_NORESERVE is used because the reservations will be -+ * taken when vm_ops->mmap() is called -+ * A dummy user value is used because we are not locking -+ * memory so no accounting is necessary -+ */ -+ len = ALIGN(len, huge_page_size(&default_hstate)); -+ file = hugetlb_file_setup(HUGETLB_ANON_FILE, len, VM_NORESERVE, -+ &user, HUGETLB_ANONHUGE_INODE); -+ if (IS_ERR(file)) -+ return PTR_ERR(file); -+ } -+ -+ flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); -+ -+ down_write(¤t->mm->mmap_sem); -+ retval = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); -+ up_write(¤t->mm->mmap_sem); -+ -+ if (file) -+ fput(file); -+out: -+ return retval; -+} -+ - /* Tracepoints definitions. */ - EXPORT_TRACEPOINT_SYMBOL(kmalloc); - EXPORT_TRACEPOINT_SYMBOL(kmem_cache_alloc); -diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c -index bd1c654..0b7f262 100644 ---- a/net/bridge/netfilter/ebtables.c -+++ b/net/bridge/netfilter/ebtables.c -@@ -1406,6 +1406,9 @@ static int do_ebt_set_ctl(struct sock *sk, - { - int ret; - -+ if (!capable(CAP_NET_ADMIN)) -+ return -EPERM; -+ - switch(cmd) { - case EBT_SO_SET_ENTRIES: - ret = do_replace(sock_net(sk), user, len); -@@ -1425,6 +1428,9 @@ static int do_ebt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len) - struct ebt_replace tmp; - struct ebt_table *t; - -+ if (!capable(CAP_NET_ADMIN)) -+ return -EPERM; -+ - if (copy_from_user(&tmp, user, sizeof(tmp))) - return -EFAULT; - -diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c -index df159ff..4bac362 100644 ---- a/net/ipv6/exthdrs.c -+++ b/net/ipv6/exthdrs.c -@@ -559,6 +559,11 @@ static inline struct inet6_dev *ipv6_skb_idev(struct sk_buff *skb) - return skb_dst(skb) ? ip6_dst_idev(skb_dst(skb)) : __in6_dev_get(skb->dev); - } - -+static inline struct net *ipv6_skb_net(struct sk_buff *skb) -+{ -+ return skb_dst(skb) ? dev_net(skb_dst(skb)->dev) : dev_net(skb->dev); -+} -+ - /* Router Alert as of RFC 2711 */ - - static int ipv6_hop_ra(struct sk_buff *skb, int optoff) -@@ -580,8 +585,8 @@ static int ipv6_hop_ra(struct sk_buff *skb, int optoff) - static int ipv6_hop_jumbo(struct sk_buff *skb, int optoff) - { - const unsigned char *nh = skb_network_header(skb); -+ struct net *net = ipv6_skb_net(skb); - u32 pkt_len; -- struct net *net = dev_net(skb_dst(skb)->dev); - - if (nh[optoff + 1] != 4 || (optoff & 3) != 2) { - LIMIT_NETDEBUG(KERN_DEBUG "ipv6_hop_jumbo: wrong jumbo opt length/alignment %d\n", -diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c -index b8295cb..079c500 100644 ---- a/net/mac80211/iface.c -+++ b/net/mac80211/iface.c -@@ -15,12 +15,14 @@ - #include - #include - #include -+#include - #include "ieee80211_i.h" - #include "sta_info.h" - #include "debugfs_netdev.h" - #include "mesh.h" - #include "led.h" - #include "driver-ops.h" -+#include "wme.h" - - /** - * DOC: Interface list locking -@@ -642,6 +644,12 @@ static void ieee80211_teardown_sdata(struct net_device *dev) - WARN_ON(flushed); - } - -+static u16 ieee80211_netdev_select_queue(struct net_device *dev, -+ struct sk_buff *skb) -+{ -+ return ieee80211_select_queue(IEEE80211_DEV_TO_SUB_IF(dev), skb); -+} -+ - static const struct net_device_ops ieee80211_dataif_ops = { - .ndo_open = ieee80211_open, - .ndo_stop = ieee80211_stop, -@@ -650,8 +658,35 @@ static const struct net_device_ops ieee80211_dataif_ops = { - .ndo_set_multicast_list = ieee80211_set_multicast_list, - .ndo_change_mtu = ieee80211_change_mtu, - .ndo_set_mac_address = eth_mac_addr, -+ .ndo_select_queue = ieee80211_netdev_select_queue, - }; - -+static u16 ieee80211_monitor_select_queue(struct net_device *dev, -+ struct sk_buff *skb) -+{ -+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); -+ struct ieee80211_local *local = sdata->local; -+ struct ieee80211_hdr *hdr; -+ struct ieee80211_radiotap_header *rtap = (void *)skb->data; -+ -+ if (local->hw.queues < 4) -+ return 0; -+ -+ if (skb->len < 4 || -+ skb->len < le16_to_cpu(rtap->it_len) + 2 /* frame control */) -+ return 0; /* doesn't matter, frame will be dropped */ -+ -+ hdr = (void *)((u8 *)skb->data + le16_to_cpu(rtap->it_len)); -+ -+ if (!ieee80211_is_data(hdr->frame_control)) { -+ skb->priority = 7; -+ return ieee802_1d_to_ac[skb->priority]; -+ } -+ -+ skb->priority = 0; -+ return ieee80211_downgrade_queue(local, skb); -+} -+ - static const struct net_device_ops ieee80211_monitorif_ops = { - .ndo_open = ieee80211_open, - .ndo_stop = ieee80211_stop, -@@ -660,6 +695,7 @@ static const struct net_device_ops ieee80211_monitorif_ops = { - .ndo_set_multicast_list = ieee80211_set_multicast_list, - .ndo_change_mtu = ieee80211_change_mtu, - .ndo_set_mac_address = eth_mac_addr, -+ .ndo_select_queue = ieee80211_monitor_select_queue, - }; - - static void ieee80211_if_setup(struct net_device *dev) -@@ -768,8 +804,8 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, - - ASSERT_RTNL(); - -- ndev = alloc_netdev(sizeof(*sdata) + local->hw.vif_data_size, -- name, ieee80211_if_setup); -+ ndev = alloc_netdev_mq(sizeof(*sdata) + local->hw.vif_data_size, -+ name, ieee80211_if_setup, local->hw.queues); - if (!ndev) - return -ENOMEM; - dev_net_set(ndev, wiphy_net(local->hw.wiphy)); -diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c -index f13d181..6cae295 100644 ---- a/net/mac80211/mlme.c -+++ b/net/mac80211/mlme.c -@@ -1953,7 +1953,9 @@ static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, - rma = ieee80211_rx_mgmt_disassoc(sdata, mgmt, skb->len); - break; - case IEEE80211_STYPE_ACTION: -- /* XXX: differentiate, can only happen for CSA now! */ -+ if (mgmt->u.action.category != WLAN_CATEGORY_SPECTRUM_MGMT) -+ break; -+ - ieee80211_sta_process_chanswitch(sdata, - &mgmt->u.action.u.chan_switch.sw_elem, - ifmgd->associated); -diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c -index 4e14754..16c6cdc 100644 ---- a/net/mac80211/rx.c -+++ b/net/mac80211/rx.c -@@ -1548,7 +1548,9 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) - memset(info, 0, sizeof(*info)); - info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING; - info->control.vif = &rx->sdata->vif; -- ieee80211_select_queue(local, fwd_skb); -+ skb_set_queue_mapping(skb, -+ ieee80211_select_queue(rx->sdata, fwd_skb)); -+ ieee80211_set_qos_hdr(local, skb); - if (is_multicast_ether_addr(fwd_hdr->addr1)) - IEEE80211_IFSTA_MESH_CTR_INC(&sdata->u.mesh, - fwded_mcast); -@@ -1808,6 +1810,10 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) - } - break; - default: -+ /* do not process rejected action frames */ -+ if (mgmt->u.action.category & 0x80) -+ return RX_DROP_MONITOR; -+ - return RX_CONTINUE; - } - -diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c -index d398197..441f68e 100644 ---- a/net/mac80211/tx.c -+++ b/net/mac80211/tx.c -@@ -1482,7 +1482,7 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, - return; - } - -- ieee80211_select_queue(local, skb); -+ ieee80211_set_qos_hdr(local, skb); - ieee80211_tx(sdata, skb, false); - dev_put(sdata->dev); - } -@@ -2226,6 +2226,9 @@ void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, - if (!encrypt) - info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; - -+ /* send all internal mgmt frames on VO */ -+ skb_set_queue_mapping(skb, 0); -+ - /* - * The other path calling ieee80211_xmit is from the tasklet, - * and while we can handle concurrent transmissions locking -diff --git a/net/mac80211/util.c b/net/mac80211/util.c -index 51e0bd2..553cffe 100644 ---- a/net/mac80211/util.c -+++ b/net/mac80211/util.c -@@ -269,6 +269,7 @@ static void __ieee80211_wake_queue(struct ieee80211_hw *hw, int queue, - enum queue_stop_reason reason) - { - struct ieee80211_local *local = hw_to_local(hw); -+ struct ieee80211_sub_if_data *sdata; - - if (WARN_ON(queue >= hw->queues)) - return; -@@ -281,6 +282,11 @@ static void __ieee80211_wake_queue(struct ieee80211_hw *hw, int queue, - - if (!skb_queue_empty(&local->pending[queue])) - tasklet_schedule(&local->tx_pending_tasklet); -+ -+ rcu_read_lock(); -+ list_for_each_entry_rcu(sdata, &local->interfaces, list) -+ netif_tx_wake_queue(netdev_get_tx_queue(sdata->dev, queue)); -+ rcu_read_unlock(); - } - - void ieee80211_wake_queue_by_reason(struct ieee80211_hw *hw, int queue, -@@ -305,11 +311,17 @@ static void __ieee80211_stop_queue(struct ieee80211_hw *hw, int queue, - enum queue_stop_reason reason) - { - struct ieee80211_local *local = hw_to_local(hw); -+ struct ieee80211_sub_if_data *sdata; - - if (WARN_ON(queue >= hw->queues)) - return; - - __set_bit(reason, &local->queue_stop_reasons[queue]); -+ -+ rcu_read_lock(); -+ list_for_each_entry_rcu(sdata, &local->interfaces, list) -+ netif_tx_stop_queue(netdev_get_tx_queue(sdata->dev, queue)); -+ rcu_read_unlock(); - } - - void ieee80211_stop_queue_by_reason(struct ieee80211_hw *hw, int queue, -diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c -index b19b769..6d32ebf 100644 ---- a/net/mac80211/wme.c -+++ b/net/mac80211/wme.c -@@ -44,22 +44,62 @@ static int wme_downgrade_ac(struct sk_buff *skb) - } - - --/* Indicate which queue to use. */ --static u16 classify80211(struct ieee80211_local *local, struct sk_buff *skb) -+/* Indicate which queue to use. */ -+u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata, -+ struct sk_buff *skb) - { -- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; -+ struct ieee80211_local *local = sdata->local; -+ struct sta_info *sta = NULL; -+ u32 sta_flags = 0; -+ const u8 *ra = NULL; -+ bool qos = false; - -- if (!ieee80211_is_data(hdr->frame_control)) { -- /* management frames go on AC_VO queue, but are sent -- * without QoS control fields */ -- return 0; -+ if (local->hw.queues < 4 || skb->len < 6) { -+ skb->priority = 0; /* required for correct WPA/11i MIC */ -+ return min_t(u16, local->hw.queues - 1, -+ ieee802_1d_to_ac[skb->priority]); - } - -- if (0 /* injected */) { -- /* use AC from radiotap */ -+ rcu_read_lock(); -+ switch (sdata->vif.type) { -+ case NL80211_IFTYPE_AP_VLAN: -+ case NL80211_IFTYPE_AP: -+ ra = skb->data; -+ break; -+ case NL80211_IFTYPE_WDS: -+ ra = sdata->u.wds.remote_addr; -+ break; -+#ifdef CONFIG_MAC80211_MESH -+ case NL80211_IFTYPE_MESH_POINT: -+ /* -+ * XXX: This is clearly broken ... but already was before, -+ * because ieee80211_fill_mesh_addresses() would clear A1 -+ * except for multicast addresses. -+ */ -+ break; -+#endif -+ case NL80211_IFTYPE_STATION: -+ ra = sdata->u.mgd.bssid; -+ break; -+ case NL80211_IFTYPE_ADHOC: -+ ra = skb->data; -+ break; -+ default: -+ break; - } - -- if (!ieee80211_is_data_qos(hdr->frame_control)) { -+ if (!sta && ra && !is_multicast_ether_addr(ra)) { -+ sta = sta_info_get(local, ra); -+ if (sta) -+ sta_flags = get_sta_flags(sta); -+ } -+ -+ if (sta_flags & WLAN_STA_WME) -+ qos = true; -+ -+ rcu_read_unlock(); -+ -+ if (!qos) { - skb->priority = 0; /* required for correct WPA/11i MIC */ - return ieee802_1d_to_ac[skb->priority]; - } -@@ -68,6 +108,12 @@ static u16 classify80211(struct ieee80211_local *local, struct sk_buff *skb) - * data frame has */ - skb->priority = cfg80211_classify8021d(skb); - -+ return ieee80211_downgrade_queue(local, skb); -+} -+ -+u16 ieee80211_downgrade_queue(struct ieee80211_local *local, -+ struct sk_buff *skb) -+{ - /* in case we are a client verify acm is not set for this ac */ - while (unlikely(local->wmm_acm & BIT(skb->priority))) { - if (wme_downgrade_ac(skb)) { -@@ -85,24 +131,17 @@ static u16 classify80211(struct ieee80211_local *local, struct sk_buff *skb) - return ieee802_1d_to_ac[skb->priority]; - } - --void ieee80211_select_queue(struct ieee80211_local *local, struct sk_buff *skb) -+void ieee80211_set_qos_hdr(struct ieee80211_local *local, struct sk_buff *skb) - { -- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; -- u16 queue; -- u8 tid; -- -- queue = classify80211(local, skb); -- if (unlikely(queue >= local->hw.queues)) -- queue = local->hw.queues - 1; -- -- /* -- * Now we know the 1d priority, fill in the QoS header if -- * there is one (and we haven't done this before). -- */ -+ struct ieee80211_hdr *hdr = (void *)skb->data; -+ -+ /* Fill in the QoS header if there is one. */ - if (ieee80211_is_data_qos(hdr->frame_control)) { - u8 *p = ieee80211_get_qos_ctl(hdr); -- u8 ack_policy = 0; -+ u8 ack_policy = 0, tid; -+ - tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK; -+ - if (unlikely(local->wifi_wme_noack_test)) - ack_policy |= QOS_CONTROL_ACK_POLICY_NOACK << - QOS_CONTROL_ACK_POLICY_SHIFT; -@@ -110,6 +149,4 @@ void ieee80211_select_queue(struct ieee80211_local *local, struct sk_buff *skb) - *p++ = ack_policy | tid; - *p = 0; - } -- -- skb_set_queue_mapping(skb, queue); - } -diff --git a/net/mac80211/wme.h b/net/mac80211/wme.h -index d4fd87c..6053b1c 100644 ---- a/net/mac80211/wme.h -+++ b/net/mac80211/wme.h -@@ -20,7 +20,11 @@ - - extern const int ieee802_1d_to_ac[8]; - --void ieee80211_select_queue(struct ieee80211_local *local, -- struct sk_buff *skb); -+u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata, -+ struct sk_buff *skb); -+void ieee80211_set_qos_hdr(struct ieee80211_local *local, struct sk_buff *skb); -+u16 ieee80211_downgrade_queue(struct ieee80211_local *local, -+ struct sk_buff *skb); -+ - - #endif /* _WME_H */ -diff --git a/net/netfilter/nf_conntrack_ftp.c b/net/netfilter/nf_conntrack_ftp.c -index 5509dd1..7dfd469 100644 ---- a/net/netfilter/nf_conntrack_ftp.c -+++ b/net/netfilter/nf_conntrack_ftp.c -@@ -323,24 +323,24 @@ static void update_nl_seq(struct nf_conn *ct, u32 nl_seq, - struct nf_ct_ftp_master *info, int dir, - struct sk_buff *skb) - { -- unsigned int i, oldest = NUM_SEQ_TO_REMEMBER; -+ unsigned int i, oldest; - - /* Look for oldest: if we find exact match, we're done. */ - for (i = 0; i < info->seq_aft_nl_num[dir]; i++) { - if (info->seq_aft_nl[dir][i] == nl_seq) - return; -- -- if (oldest == info->seq_aft_nl_num[dir] || -- before(info->seq_aft_nl[dir][i], -- info->seq_aft_nl[dir][oldest])) -- oldest = i; - } - - if (info->seq_aft_nl_num[dir] < NUM_SEQ_TO_REMEMBER) { - info->seq_aft_nl[dir][info->seq_aft_nl_num[dir]++] = nl_seq; -- } else if (oldest != NUM_SEQ_TO_REMEMBER && -- after(nl_seq, info->seq_aft_nl[dir][oldest])) { -- info->seq_aft_nl[dir][oldest] = nl_seq; -+ } else { -+ if (before(info->seq_aft_nl[dir][0], info->seq_aft_nl[dir][1])) -+ oldest = 0; -+ else -+ oldest = 1; -+ -+ if (after(nl_seq, info->seq_aft_nl[dir][oldest])) -+ info->seq_aft_nl[dir][oldest] = nl_seq; - } - } - -diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c -index 129d75e..9c5a19d 100644 ---- a/net/sunrpc/auth_gss/auth_gss.c -+++ b/net/sunrpc/auth_gss/auth_gss.c -@@ -644,7 +644,22 @@ gss_pipe_downcall(struct file *filp, const char __user *src, size_t mlen) - p = gss_fill_context(p, end, ctx, gss_msg->auth->mech); - if (IS_ERR(p)) { - err = PTR_ERR(p); -- gss_msg->msg.errno = (err == -EAGAIN) ? -EAGAIN : -EACCES; -+ switch (err) { -+ case -EACCES: -+ gss_msg->msg.errno = err; -+ err = mlen; -+ break; -+ case -EFAULT: -+ case -ENOMEM: -+ case -EINVAL: -+ case -ENOSYS: -+ gss_msg->msg.errno = -EAGAIN; -+ break; -+ default: -+ printk(KERN_CRIT "%s: bad return from " -+ "gss_fill_context: %ld\n", __func__, err); -+ BUG(); -+ } - goto err_release_msg; - } - gss_msg->ctx = gss_get_ctx(ctx); -diff --git a/net/sunrpc/auth_gss/gss_krb5_mech.c b/net/sunrpc/auth_gss/gss_krb5_mech.c -index ef45eba..2deb0ed 100644 ---- a/net/sunrpc/auth_gss/gss_krb5_mech.c -+++ b/net/sunrpc/auth_gss/gss_krb5_mech.c -@@ -131,8 +131,10 @@ gss_import_sec_context_kerberos(const void *p, - struct krb5_ctx *ctx; - int tmp; - -- if (!(ctx = kzalloc(sizeof(*ctx), GFP_NOFS))) -+ if (!(ctx = kzalloc(sizeof(*ctx), GFP_NOFS))) { -+ p = ERR_PTR(-ENOMEM); - goto out_err; -+ } - - p = simple_get_bytes(p, end, &ctx->initiate, sizeof(ctx->initiate)); - if (IS_ERR(p)) -diff --git a/net/sunrpc/auth_gss/gss_mech_switch.c b/net/sunrpc/auth_gss/gss_mech_switch.c -index 6efbb0c..76e4c6f 100644 ---- a/net/sunrpc/auth_gss/gss_mech_switch.c -+++ b/net/sunrpc/auth_gss/gss_mech_switch.c -@@ -252,7 +252,7 @@ gss_import_sec_context(const void *input_token, size_t bufsize, - struct gss_ctx **ctx_id) - { - if (!(*ctx_id = kzalloc(sizeof(**ctx_id), GFP_KERNEL))) -- return GSS_S_FAILURE; -+ return -ENOMEM; - (*ctx_id)->mech_type = gss_mech_get(mech); - - return mech->gm_ops -diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c -index df124f7..0266cca 100644 ---- a/net/sunrpc/svc_xprt.c -+++ b/net/sunrpc/svc_xprt.c -@@ -711,7 +711,8 @@ int svc_recv(struct svc_rqst *rqstp, long timeout) - spin_unlock_bh(&pool->sp_lock); - - len = 0; -- if (test_bit(XPT_LISTENER, &xprt->xpt_flags)) { -+ if (test_bit(XPT_LISTENER, &xprt->xpt_flags) && -+ !test_bit(XPT_CLOSE, &xprt->xpt_flags)) { - struct svc_xprt *newxpt; - newxpt = xprt->xpt_ops->xpo_accept(xprt); - if (newxpt) { -diff --git a/net/wireless/reg.c b/net/wireless/reg.c -index f256dff..efd24a7 100644 ---- a/net/wireless/reg.c -+++ b/net/wireless/reg.c -@@ -1714,7 +1714,7 @@ int regulatory_hint_user(const char *alpha2) - request->wiphy_idx = WIPHY_IDX_STALE; - request->alpha2[0] = alpha2[0]; - request->alpha2[1] = alpha2[1]; -- request->initiator = NL80211_REGDOM_SET_BY_USER, -+ request->initiator = NL80211_REGDOM_SET_BY_USER; - - queue_regulatory_request(request); - -diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c -index 7337abd..67ca440 100644 ---- a/sound/pci/ac97/ac97_patch.c -+++ b/sound/pci/ac97/ac97_patch.c -@@ -1870,6 +1870,7 @@ static unsigned int ad1981_jacks_blacklist[] = { - 0x10140554, /* Thinkpad T42p/R50p */ - 0x10140567, /* Thinkpad T43p 2668-G7U */ - 0x10140581, /* Thinkpad X41-2527 */ -+ 0x10280160, /* Dell Dimension 2400 */ - 0x104380b0, /* Asus A7V8X-MX */ - 0x11790241, /* Toshiba Satellite A-15 S127 */ - 0x144dc01a, /* Samsung NP-X20C004/SEG */ -diff --git a/sound/pci/atiixp.c b/sound/pci/atiixp.c -index d6752df..42b4fbb 100644 ---- a/sound/pci/atiixp.c -+++ b/sound/pci/atiixp.c -@@ -297,6 +297,7 @@ static struct pci_device_id snd_atiixp_ids[] = { - MODULE_DEVICE_TABLE(pci, snd_atiixp_ids); - - static struct snd_pci_quirk atiixp_quirks[] __devinitdata = { -+ SND_PCI_QUIRK(0x105b, 0x0c81, "Foxconn RC4107MA-RS2", 0), - SND_PCI_QUIRK(0x15bd, 0x3100, "DFI RS482", 0), - { } /* terminator */ - }; -diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c -index e40d31f..a4cb183 100644 ---- a/sound/pci/hda/patch_realtek.c -+++ b/sound/pci/hda/patch_realtek.c -@@ -15323,7 +15323,7 @@ static struct alc_config_preset alc861vd_presets[] = { - static int alc861vd_auto_create_input_ctls(struct hda_codec *codec, - const struct auto_pin_cfg *cfg) - { -- return alc_auto_create_input_ctls(codec, cfg, 0x15, 0x09, 0); -+ return alc_auto_create_input_ctls(codec, cfg, 0x15, 0x22, 0); - } - - -diff --git a/sound/soc/codecs/wm8350.c b/sound/soc/codecs/wm8350.c -index 593d5b9..2089fe7 100644 ---- a/sound/soc/codecs/wm8350.c -+++ b/sound/soc/codecs/wm8350.c -@@ -925,7 +925,7 @@ static int wm8350_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) - iface |= 0x3 << 8; - break; - case SND_SOC_DAIFMT_DSP_B: -- iface |= 0x3 << 8; /* lg not sure which mode */ -+ iface |= 0x3 << 8 | WM8350_AIF_LRCLK_INV; - break; - default: - return -EINVAL; -diff --git a/sound/soc/codecs/wm8510.c b/sound/soc/codecs/wm8510.c -index 060d5d0..8db62e2 100644 ---- a/sound/soc/codecs/wm8510.c -+++ b/sound/soc/codecs/wm8510.c -@@ -425,23 +425,23 @@ static int wm8510_pcm_hw_params(struct snd_pcm_substream *substream, - - /* filter coefficient */ - switch (params_rate(params)) { -- case SNDRV_PCM_RATE_8000: -+ case 8000: - adn |= 0x5 << 1; - break; -- case SNDRV_PCM_RATE_11025: -+ case 11025: - adn |= 0x4 << 1; - break; -- case SNDRV_PCM_RATE_16000: -+ case 16000: - adn |= 0x3 << 1; - break; -- case SNDRV_PCM_RATE_22050: -+ case 22050: - adn |= 0x2 << 1; - break; -- case SNDRV_PCM_RATE_32000: -+ case 32000: - adn |= 0x1 << 1; - break; -- case SNDRV_PCM_RATE_44100: -- case SNDRV_PCM_RATE_48000: -+ case 44100: -+ case 48000: - break; - } - -diff --git a/sound/soc/codecs/wm8940.c b/sound/soc/codecs/wm8940.c -index 1ef2454..63bc2ae 100644 ---- a/sound/soc/codecs/wm8940.c -+++ b/sound/soc/codecs/wm8940.c -@@ -379,23 +379,23 @@ static int wm8940_i2s_hw_params(struct snd_pcm_substream *substream, - iface |= (1 << 9); - - switch (params_rate(params)) { -- case SNDRV_PCM_RATE_8000: -+ case 8000: - addcntrl |= (0x5 << 1); - break; -- case SNDRV_PCM_RATE_11025: -+ case 11025: - addcntrl |= (0x4 << 1); - break; -- case SNDRV_PCM_RATE_16000: -+ case 16000: - addcntrl |= (0x3 << 1); - break; -- case SNDRV_PCM_RATE_22050: -+ case 22050: - addcntrl |= (0x2 << 1); - break; -- case SNDRV_PCM_RATE_32000: -+ case 32000: - addcntrl |= (0x1 << 1); - break; -- case SNDRV_PCM_RATE_44100: -- case SNDRV_PCM_RATE_48000: -+ case 44100: -+ case 48000: - break; - } - ret = snd_soc_write(codec, WM8940_ADDCNTRL, addcntrl); -diff --git a/sound/soc/codecs/wm8974.c b/sound/soc/codecs/wm8974.c -index b0bd1c0..0dbf6fe 100644 ---- a/sound/soc/codecs/wm8974.c -+++ b/sound/soc/codecs/wm8974.c -@@ -480,23 +480,23 @@ static int wm8974_pcm_hw_params(struct snd_pcm_substream *substream, - - /* filter coefficient */ - switch (params_rate(params)) { -- case SNDRV_PCM_RATE_8000: -+ case 8000: - adn |= 0x5 << 1; - break; -- case SNDRV_PCM_RATE_11025: -+ case 11025: - adn |= 0x4 << 1; - break; -- case SNDRV_PCM_RATE_16000: -+ case 16000: - adn |= 0x3 << 1; - break; -- case SNDRV_PCM_RATE_22050: -+ case 22050: - adn |= 0x2 << 1; - break; -- case SNDRV_PCM_RATE_32000: -+ case 32000: - adn |= 0x1 << 1; - break; -- case SNDRV_PCM_RATE_44100: -- case SNDRV_PCM_RATE_48000: -+ case 44100: -+ case 48000: - break; - } - diff --git a/debian/patches/bugfix/all/stable/2.6.32.5.patch b/debian/patches/bugfix/all/stable/2.6.32.5.patch deleted file mode 100644 index 5857bbe74..000000000 --- a/debian/patches/bugfix/all/stable/2.6.32.5.patch +++ /dev/null @@ -1,1021 +0,0 @@ -diff --git a/Makefile b/Makefile -index 6d13598..4ebd3f1 100644 -diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c -index e8dfdbd..cadbed6 100644 ---- a/arch/powerpc/kernel/pci-common.c -+++ b/arch/powerpc/kernel/pci-common.c -@@ -1107,6 +1107,12 @@ void __devinit pcibios_setup_bus_devices(struct pci_bus *bus) - list_for_each_entry(dev, &bus->devices, bus_list) { - struct dev_archdata *sd = &dev->dev.archdata; - -+ /* Cardbus can call us to add new devices to a bus, so ignore -+ * those who are already fully discovered -+ */ -+ if (dev->is_added) -+ continue; -+ - /* Setup OF node pointer in archdata */ - sd->of_node = pci_device_to_OF_node(dev); - -@@ -1147,6 +1153,13 @@ void __devinit pcibios_fixup_bus(struct pci_bus *bus) - } - EXPORT_SYMBOL(pcibios_fixup_bus); - -+void __devinit pci_fixup_cardbus(struct pci_bus *bus) -+{ -+ /* Now fixup devices on that bus */ -+ pcibios_setup_bus_devices(bus); -+} -+ -+ - static int skip_isa_ioresource_align(struct pci_dev *dev) - { - if ((ppc_pci_flags & PPC_PCI_CAN_SKIP_ISA_ALIGN) && -diff --git a/arch/sparc/kernel/nmi.c b/arch/sparc/kernel/nmi.c -index b129611..4771274 100644 ---- a/arch/sparc/kernel/nmi.c -+++ b/arch/sparc/kernel/nmi.c -@@ -96,7 +96,6 @@ notrace __kprobes void perfctr_irq(int irq, struct pt_regs *regs) - int cpu = smp_processor_id(); - - clear_softint(1 << irq); -- pcr_ops->write(PCR_PIC_PRIV); - - local_cpu_data().__nmi_count++; - -@@ -105,6 +104,8 @@ notrace __kprobes void perfctr_irq(int irq, struct pt_regs *regs) - if (notify_die(DIE_NMI, "nmi", regs, 0, - pt_regs_trap_type(regs), SIGINT) == NOTIFY_STOP) - touched = 1; -+ else -+ pcr_ops->write(PCR_PIC_PRIV); - - sum = kstat_irqs_cpu(0, cpu); - if (__get_cpu_var(nmi_touch)) { -diff --git a/arch/sparc/kernel/perf_event.c b/arch/sparc/kernel/perf_event.c -index fa5936e..198fb4e 100644 ---- a/arch/sparc/kernel/perf_event.c -+++ b/arch/sparc/kernel/perf_event.c -@@ -986,6 +986,17 @@ static int __kprobes perf_event_nmi_handler(struct notifier_block *self, - data.addr = 0; - - cpuc = &__get_cpu_var(cpu_hw_events); -+ -+ /* If the PMU has the TOE IRQ enable bits, we need to do a -+ * dummy write to the %pcr to clear the overflow bits and thus -+ * the interrupt. -+ * -+ * Do this before we peek at the counters to determine -+ * overflow so we don't lose any events. -+ */ -+ if (sparc_pmu->irq_bit) -+ pcr_ops->write(cpuc->pcr); -+ - for (idx = 0; idx < MAX_HWEVENTS; idx++) { - struct perf_event *event = cpuc->events[idx]; - struct hw_perf_event *hwc; -diff --git a/arch/x86/kernel/apic/apic_flat_64.c b/arch/x86/kernel/apic/apic_flat_64.c -index d0c99ab..873f81f 100644 ---- a/arch/x86/kernel/apic/apic_flat_64.c -+++ b/arch/x86/kernel/apic/apic_flat_64.c -@@ -240,6 +240,11 @@ static int physflat_acpi_madt_oem_check(char *oem_id, char *oem_table_id) - printk(KERN_DEBUG "system APIC only can use physical flat"); - return 1; - } -+ -+ if (!strncmp(oem_id, "IBM", 3) && !strncmp(oem_table_id, "EXA", 3)) { -+ printk(KERN_DEBUG "IBM Summit detected, will use apic physical"); -+ return 1; -+ } - #endif - - return 0; -diff --git a/arch/x86/kernel/apic/x2apic_uv_x.c b/arch/x86/kernel/apic/x2apic_uv_x.c -index 2ab3535..9ee87cf 100644 ---- a/arch/x86/kernel/apic/x2apic_uv_x.c -+++ b/arch/x86/kernel/apic/x2apic_uv_x.c -@@ -364,13 +364,13 @@ static __init void get_lowmem_redirect(unsigned long *base, unsigned long *size) - - enum map_type {map_wb, map_uc}; - --static __init void map_high(char *id, unsigned long base, int shift, -- int max_pnode, enum map_type map_type) -+static __init void map_high(char *id, unsigned long base, int pshift, -+ int bshift, int max_pnode, enum map_type map_type) - { - unsigned long bytes, paddr; - -- paddr = base << shift; -- bytes = (1UL << shift) * (max_pnode + 1); -+ paddr = base << pshift; -+ bytes = (1UL << bshift) * (max_pnode + 1); - printk(KERN_INFO "UV: Map %s_HI 0x%lx - 0x%lx\n", id, paddr, - paddr + bytes); - if (map_type == map_uc) -@@ -386,7 +386,7 @@ static __init void map_gru_high(int max_pnode) - - gru.v = uv_read_local_mmr(UVH_RH_GAM_GRU_OVERLAY_CONFIG_MMR); - if (gru.s.enable) -- map_high("GRU", gru.s.base, shift, max_pnode, map_wb); -+ map_high("GRU", gru.s.base, shift, shift, max_pnode, map_wb); - } - - static __init void map_mmr_high(int max_pnode) -@@ -396,7 +396,7 @@ static __init void map_mmr_high(int max_pnode) - - mmr.v = uv_read_local_mmr(UVH_RH_GAM_MMR_OVERLAY_CONFIG_MMR); - if (mmr.s.enable) -- map_high("MMR", mmr.s.base, shift, max_pnode, map_uc); -+ map_high("MMR", mmr.s.base, shift, shift, max_pnode, map_uc); - } - - static __init void map_mmioh_high(int max_pnode) -@@ -406,7 +406,8 @@ static __init void map_mmioh_high(int max_pnode) - - mmioh.v = uv_read_local_mmr(UVH_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR); - if (mmioh.s.enable) -- map_high("MMIOH", mmioh.s.base, shift, max_pnode, map_uc); -+ map_high("MMIOH", mmioh.s.base, shift, mmioh.s.m_io, -+ max_pnode, map_uc); - } - - static __init void uv_rtc_init(void) -diff --git a/arch/x86/kernel/cpu/mcheck/therm_throt.c b/arch/x86/kernel/cpu/mcheck/therm_throt.c -index 4fef985..687638e 100644 ---- a/arch/x86/kernel/cpu/mcheck/therm_throt.c -+++ b/arch/x86/kernel/cpu/mcheck/therm_throt.c -@@ -274,8 +274,9 @@ void intel_init_thermal(struct cpuinfo_x86 *c) - int tm2 = 0; - u32 l, h; - -- /* Thermal monitoring depends on ACPI and clock modulation*/ -- if (!cpu_has(c, X86_FEATURE_ACPI) || !cpu_has(c, X86_FEATURE_ACC)) -+ /* Thermal monitoring depends on APIC, ACPI and clock modulation */ -+ if (!cpu_has_apic || !cpu_has(c, X86_FEATURE_ACPI) || -+ !cpu_has(c, X86_FEATURE_ACC)) - return; - - /* -diff --git a/drivers/edac/i5000_edac.c b/drivers/edac/i5000_edac.c -index 77a9579..adc10a2 100644 ---- a/drivers/edac/i5000_edac.c -+++ b/drivers/edac/i5000_edac.c -@@ -577,7 +577,13 @@ static void i5000_process_nonfatal_error_info(struct mem_ctl_info *mci, - debugf0("\tUncorrected bits= 0x%x\n", ue_errors); - - branch = EXTRACT_FBDCHAN_INDX(info->ferr_nf_fbd); -- channel = branch; -+ -+ /* -+ * According with i5000 datasheet, bit 28 has no significance -+ * for errors M4Err-M12Err and M17Err-M21Err, on FERR_NF_FBD -+ */ -+ channel = branch & 2; -+ - bank = NREC_BANK(info->nrecmema); - rank = NREC_RANK(info->nrecmema); - rdwr = NREC_RDWR(info->nrecmema); -diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c -index aa7fd82..7d1357e 100644 ---- a/drivers/gpu/drm/i915/i915_irq.c -+++ b/drivers/gpu/drm/i915/i915_irq.c -@@ -255,7 +255,6 @@ irqreturn_t igdng_irq_handler(struct drm_device *dev) - drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - int ret = IRQ_NONE; - u32 de_iir, gt_iir, de_ier; -- u32 new_de_iir, new_gt_iir; - struct drm_i915_master_private *master_priv; - - /* disable master interrupt before clearing iir */ -@@ -266,35 +265,29 @@ irqreturn_t igdng_irq_handler(struct drm_device *dev) - de_iir = I915_READ(DEIIR); - gt_iir = I915_READ(GTIIR); - -- for (;;) { -- if (de_iir == 0 && gt_iir == 0) -- break; -- -- ret = IRQ_HANDLED; -- -- I915_WRITE(DEIIR, de_iir); -- new_de_iir = I915_READ(DEIIR); -- I915_WRITE(GTIIR, gt_iir); -- new_gt_iir = I915_READ(GTIIR); -+ if (de_iir == 0 && gt_iir == 0) -+ goto done; - -- if (dev->primary->master) { -- master_priv = dev->primary->master->driver_priv; -- if (master_priv->sarea_priv) -- master_priv->sarea_priv->last_dispatch = -- READ_BREADCRUMB(dev_priv); -- } -+ ret = IRQ_HANDLED; - -- if (gt_iir & GT_USER_INTERRUPT) { -- u32 seqno = i915_get_gem_seqno(dev); -- dev_priv->mm.irq_gem_seqno = seqno; -- trace_i915_gem_request_complete(dev, seqno); -- DRM_WAKEUP(&dev_priv->irq_queue); -- } -+ if (dev->primary->master) { -+ master_priv = dev->primary->master->driver_priv; -+ if (master_priv->sarea_priv) -+ master_priv->sarea_priv->last_dispatch = -+ READ_BREADCRUMB(dev_priv); -+ } - -- de_iir = new_de_iir; -- gt_iir = new_gt_iir; -+ if (gt_iir & GT_USER_INTERRUPT) { -+ u32 seqno = i915_get_gem_seqno(dev); -+ dev_priv->mm.irq_gem_seqno = seqno; -+ trace_i915_gem_request_complete(dev, seqno); -+ DRM_WAKEUP(&dev_priv->irq_queue); - } - -+ I915_WRITE(GTIIR, gt_iir); -+ I915_WRITE(DEIIR, de_iir); -+ -+done: - I915_WRITE(DEIER, de_ier); - (void)I915_READ(DEIER); - -diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c -index 4b96e7a..5b4d66d 100644 ---- a/drivers/hid/hid-apple.c -+++ b/drivers/hid/hid-apple.c -@@ -431,6 +431,13 @@ static const struct hid_device_id apple_devices[] = { - .driver_data = APPLE_HAS_FN | APPLE_ISO_KEYBOARD }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING3_JIS), - .driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS }, -+ { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI), -+ .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN }, -+ { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO), -+ .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN | -+ APPLE_ISO_KEYBOARD }, -+ { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS), -+ .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY), - .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY), -diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c -index 7d05c4b..9678354 100644 ---- a/drivers/hid/hid-core.c -+++ b/drivers/hid/hid-core.c -@@ -1287,6 +1287,9 @@ static const struct hid_device_id hid_blacklist[] = { - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING3_ANSI) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING3_ISO) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING3_JIS) }, -+ { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI) }, -+ { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO) }, -+ { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) }, - { HID_USB_DEVICE(USB_VENDOR_ID_BELKIN, USB_DEVICE_ID_FLIP_KVM) }, -diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h -index adbef5d..e380e7b 100644 ---- a/drivers/hid/hid-ids.h -+++ b/drivers/hid/hid-ids.h -@@ -88,6 +88,9 @@ - #define USB_DEVICE_ID_APPLE_WELLSPRING3_ANSI 0x0236 - #define USB_DEVICE_ID_APPLE_WELLSPRING3_ISO 0x0237 - #define USB_DEVICE_ID_APPLE_WELLSPRING3_JIS 0x0238 -+#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI 0x0239 -+#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO 0x023a -+#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS 0x023b - #define USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY 0x030a - #define USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY 0x030b - #define USB_DEVICE_ID_APPLE_ATV_IRCONTROL 0x8241 -diff --git a/drivers/i2c/busses/i2c-pca-isa.c b/drivers/i2c/busses/i2c-pca-isa.c -index 0ed68e2..f7346a9 100644 ---- a/drivers/i2c/busses/i2c-pca-isa.c -+++ b/drivers/i2c/busses/i2c-pca-isa.c -@@ -75,7 +75,7 @@ static int pca_isa_waitforcompletion(void *pd) - unsigned long timeout; - - if (irq > -1) { -- ret = wait_event_interruptible_timeout(pca_wait, -+ ret = wait_event_timeout(pca_wait, - pca_isa_readbyte(pd, I2C_PCA_CON) - & I2C_PCA_CON_SI, pca_isa_ops.timeout); - } else { -@@ -96,7 +96,7 @@ static void pca_isa_resetchip(void *pd) - } - - static irqreturn_t pca_handler(int this_irq, void *dev_id) { -- wake_up_interruptible(&pca_wait); -+ wake_up(&pca_wait); - return IRQ_HANDLED; - } - -diff --git a/drivers/i2c/busses/i2c-pca-platform.c b/drivers/i2c/busses/i2c-pca-platform.c -index c4df9d4..5b2213d 100644 ---- a/drivers/i2c/busses/i2c-pca-platform.c -+++ b/drivers/i2c/busses/i2c-pca-platform.c -@@ -84,7 +84,7 @@ static int i2c_pca_pf_waitforcompletion(void *pd) - unsigned long timeout; - - if (i2c->irq) { -- ret = wait_event_interruptible_timeout(i2c->wait, -+ ret = wait_event_timeout(i2c->wait, - i2c->algo_data.read_byte(i2c, I2C_PCA_CON) - & I2C_PCA_CON_SI, i2c->adap.timeout); - } else { -@@ -122,7 +122,7 @@ static irqreturn_t i2c_pca_pf_handler(int this_irq, void *dev_id) - if ((i2c->algo_data.read_byte(i2c, I2C_PCA_CON) & I2C_PCA_CON_SI) == 0) - return IRQ_NONE; - -- wake_up_interruptible(&i2c->wait); -+ wake_up(&i2c->wait); - - return IRQ_HANDLED; - } -diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c -index 2965043..3bf7b0a 100644 ---- a/drivers/i2c/i2c-core.c -+++ b/drivers/i2c/i2c-core.c -@@ -801,6 +801,9 @@ int i2c_del_adapter(struct i2c_adapter *adap) - adap->dev.parent); - #endif - -+ /* device name is gone after device_unregister */ -+ dev_dbg(&adap->dev, "adapter [%s] unregistered\n", adap->name); -+ - /* clean up the sysfs representation */ - init_completion(&adap->dev_released); - device_unregister(&adap->dev); -@@ -813,8 +816,6 @@ int i2c_del_adapter(struct i2c_adapter *adap) - idr_remove(&i2c_adapter_idr, adap->nr); - mutex_unlock(&core_lock); - -- dev_dbg(&adap->dev, "adapter [%s] unregistered\n", adap->name); -- - /* Clear the device structure in case this adapter is ever going to be - added again */ - memset(&adap->dev, 0, sizeof(adap->dev)); -diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c -index 07c5379..0876d82 100644 ---- a/drivers/input/mouse/psmouse-base.c -+++ b/drivers/input/mouse/psmouse-base.c -@@ -667,19 +667,6 @@ static int psmouse_extensions(struct psmouse *psmouse, - max_proto = PSMOUSE_IMEX; - } - --/* -- * Try Finger Sensing Pad -- */ -- if (max_proto > PSMOUSE_IMEX) { -- if (fsp_detect(psmouse, set_properties) == 0) { -- if (!set_properties || fsp_init(psmouse) == 0) -- return PSMOUSE_FSP; --/* -- * Init failed, try basic relative protocols -- */ -- max_proto = PSMOUSE_IMEX; -- } -- } - - if (max_proto > PSMOUSE_IMEX) { - if (genius_detect(psmouse, set_properties) == 0) -@@ -696,6 +683,21 @@ static int psmouse_extensions(struct psmouse *psmouse, - } - - /* -+ * Try Finger Sensing Pad. We do it here because its probe upsets -+ * Trackpoint devices (causing TP_READ_ID command to time out). -+ */ -+ if (max_proto > PSMOUSE_IMEX) { -+ if (fsp_detect(psmouse, set_properties) == 0) { -+ if (!set_properties || fsp_init(psmouse) == 0) -+ return PSMOUSE_FSP; -+/* -+ * Init failed, try basic relative protocols -+ */ -+ max_proto = PSMOUSE_IMEX; -+ } -+ } -+ -+/* - * Reset to defaults in case the device got confused by extended - * protocol probes. Note that we follow up with full reset because - * some mice put themselves to sleep when they see PSMOUSE_RESET_DIS. -diff --git a/drivers/media/video/gspca/sn9c20x.c b/drivers/media/video/gspca/sn9c20x.c -index cdad3db..e0a3b75 100644 ---- a/drivers/media/video/gspca/sn9c20x.c -+++ b/drivers/media/video/gspca/sn9c20x.c -@@ -2319,7 +2319,7 @@ static void do_autogain(struct gspca_dev *gspca_dev, u16 avg_lum) - } - } - if (avg_lum > MAX_AVG_LUM) { -- if (sd->gain - 1 >= 0) { -+ if (sd->gain >= 1) { - sd->gain--; - set_gain(gspca_dev); - } -diff --git a/drivers/mfd/wm8350-core.c b/drivers/mfd/wm8350-core.c -index ba27c9d..ca6b098 100644 ---- a/drivers/mfd/wm8350-core.c -+++ b/drivers/mfd/wm8350-core.c -@@ -134,8 +134,7 @@ static inline int is_reg_locked(struct wm8350 *wm8350, u8 reg) - wm8350->reg_cache[WM8350_SECURITY] == WM8350_UNLOCK_KEY) - return 0; - -- if ((reg == WM8350_GPIO_CONFIGURATION_I_O) || -- (reg >= WM8350_GPIO_FUNCTION_SELECT_1 && -+ if ((reg >= WM8350_GPIO_FUNCTION_SELECT_1 && - reg <= WM8350_GPIO_FUNCTION_SELECT_4) || - (reg >= WM8350_BATTERY_CHARGER_CONTROL_1 && - reg <= WM8350_BATTERY_CHARGER_CONTROL_3)) -diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c -index 4e4c295..6477722 100644 ---- a/drivers/pci/pci.c -+++ b/drivers/pci/pci.c -@@ -2723,6 +2723,11 @@ int __attribute__ ((weak)) pci_ext_cfg_avail(struct pci_dev *dev) - return 1; - } - -+void __weak pci_fixup_cardbus(struct pci_bus *bus) -+{ -+} -+EXPORT_SYMBOL(pci_fixup_cardbus); -+ - static int __init pci_setup(char *str) - { - while (str) { -diff --git a/drivers/pcmcia/cardbus.c b/drivers/pcmcia/cardbus.c -index db77e1f..5c26793 100644 ---- a/drivers/pcmcia/cardbus.c -+++ b/drivers/pcmcia/cardbus.c -@@ -214,7 +214,7 @@ int __ref cb_alloc(struct pcmcia_socket * s) - unsigned int max, pass; - - s->functions = pci_scan_slot(bus, PCI_DEVFN(0, 0)); --// pcibios_fixup_bus(bus); -+ pci_fixup_cardbus(bus); - - max = bus->secondary; - for (pass = 0; pass < 2; pass++) -diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c -index 849359a..767cb61 100644 ---- a/drivers/platform/x86/asus-laptop.c -+++ b/drivers/platform/x86/asus-laptop.c -@@ -221,6 +221,7 @@ static struct asus_hotk *hotk; - */ - static const struct acpi_device_id asus_device_ids[] = { - {"ATK0100", 0}, -+ {"ATK0101", 0}, - {"", 0}, - }; - MODULE_DEVICE_TABLE(acpi, asus_device_ids); -@@ -293,6 +294,11 @@ struct key_entry { - enum { KE_KEY, KE_END }; - - static struct key_entry asus_keymap[] = { -+ {KE_KEY, 0x02, KEY_SCREENLOCK}, -+ {KE_KEY, 0x05, KEY_WLAN}, -+ {KE_KEY, 0x08, BTN_TOUCH}, -+ {KE_KEY, 0x17, KEY_ZOOM}, -+ {KE_KEY, 0x1f, KEY_BATTERY}, - {KE_KEY, 0x30, KEY_VOLUMEUP}, - {KE_KEY, 0x31, KEY_VOLUMEDOWN}, - {KE_KEY, 0x32, KEY_MUTE}, -@@ -312,6 +318,8 @@ static struct key_entry asus_keymap[] = { - {KE_KEY, 0x5F, KEY_WLAN}, - {KE_KEY, 0x60, KEY_SWITCHVIDEOMODE}, - {KE_KEY, 0x61, KEY_SWITCHVIDEOMODE}, -+ {KE_KEY, 0x62, KEY_SWITCHVIDEOMODE}, -+ {KE_KEY, 0x63, KEY_SWITCHVIDEOMODE}, - {KE_KEY, 0x6B, BTN_TOUCH}, /* Lock Mouse */ - {KE_KEY, 0x82, KEY_CAMERA}, - {KE_KEY, 0x8A, KEY_PROG1}, -diff --git a/drivers/scsi/megaraid/megaraid_sas.c b/drivers/scsi/megaraid/megaraid_sas.c -index 507ccc6..518712c 100644 ---- a/drivers/scsi/megaraid/megaraid_sas.c -+++ b/drivers/scsi/megaraid/megaraid_sas.c -@@ -3451,7 +3451,7 @@ out: - return retval; - } - --static DRIVER_ATTR(poll_mode_io, S_IRUGO|S_IWUGO, -+static DRIVER_ATTR(poll_mode_io, S_IRUGO|S_IWUSR, - megasas_sysfs_show_poll_mode_io, - megasas_sysfs_set_poll_mode_io); - -diff --git a/drivers/serial/8250_pnp.c b/drivers/serial/8250_pnp.c -index d71dfe3..0cce8a4 100644 ---- a/drivers/serial/8250_pnp.c -+++ b/drivers/serial/8250_pnp.c -@@ -354,6 +354,8 @@ static const struct pnp_device_id pnp_dev_table[] = { - { "FUJ02E5", 0 }, - /* Fujitsu P-series tablet PC device */ - { "FUJ02E6", 0 }, -+ /* Fujitsu Wacom 2FGT Tablet PC device */ -+ { "FUJ02E7", 0 }, - /* - * LG C1 EXPRESS DUAL (C1-PB11A3) touch screen (actually a FUJ02E6 in - * disguise) -diff --git a/drivers/video/s3c-fb.c b/drivers/video/s3c-fb.c -index adf9632..53cb722 100644 ---- a/drivers/video/s3c-fb.c -+++ b/drivers/video/s3c-fb.c -@@ -211,21 +211,23 @@ static int s3c_fb_check_var(struct fb_var_screeninfo *var, - - /** - * s3c_fb_calc_pixclk() - calculate the divider to create the pixel clock. -- * @id: window id. - * @sfb: The hardware state. - * @pixclock: The pixel clock wanted, in picoseconds. - * - * Given the specified pixel clock, work out the necessary divider to get - * close to the output frequency. - */ --static int s3c_fb_calc_pixclk(unsigned char id, struct s3c_fb *sfb, unsigned int pixclk) -+static int s3c_fb_calc_pixclk(struct s3c_fb *sfb, unsigned int pixclk) - { -- struct s3c_fb_pd_win *win = sfb->pdata->win[id]; - unsigned long clk = clk_get_rate(sfb->bus_clk); -+ unsigned long long tmp; - unsigned int result; - -- pixclk *= win->win_mode.refresh; -- result = clk / pixclk; -+ tmp = (unsigned long long)clk; -+ tmp *= pixclk; -+ -+ do_div(tmp, 1000000000UL); -+ result = (unsigned int)tmp / 1000; - - dev_dbg(sfb->dev, "pixclk=%u, clk=%lu, div=%d (%lu)\n", - pixclk, clk, result, clk / result); -@@ -301,7 +303,7 @@ static int s3c_fb_set_par(struct fb_info *info) - /* use window 0 as the basis for the lcd output timings */ - - if (win_no == 0) { -- clkdiv = s3c_fb_calc_pixclk(win_no, sfb, var->pixclock); -+ clkdiv = s3c_fb_calc_pixclk(sfb, var->pixclock); - - data = sfb->pdata->vidcon0; - data &= ~(VIDCON0_CLKVAL_F_MASK | VIDCON0_CLKDIR); -diff --git a/fs/notify/inotify/inotify_fsnotify.c b/fs/notify/inotify/inotify_fsnotify.c -index c9ee67b..1afb0a1 100644 ---- a/fs/notify/inotify/inotify_fsnotify.c -+++ b/fs/notify/inotify/inotify_fsnotify.c -@@ -121,7 +121,7 @@ static int idr_callback(int id, void *p, void *data) - if (warned) - return 0; - -- warned = false; -+ warned = true; - entry = p; - ientry = container_of(entry, struct inotify_inode_mark_entry, fsn_entry); - -diff --git a/fs/notify/inotify/inotify_user.c b/fs/notify/inotify/inotify_user.c -index dcd2040..ca44337 100644 ---- a/fs/notify/inotify/inotify_user.c -+++ b/fs/notify/inotify/inotify_user.c -@@ -558,7 +558,7 @@ retry: - - spin_lock(&group->inotify_data.idr_lock); - ret = idr_get_new_above(&group->inotify_data.idr, &tmp_ientry->fsn_entry, -- group->inotify_data.last_wd, -+ group->inotify_data.last_wd+1, - &tmp_ientry->wd); - spin_unlock(&group->inotify_data.idr_lock); - if (ret) { -@@ -638,7 +638,7 @@ static struct fsnotify_group *inotify_new_group(struct user_struct *user, unsign - - spin_lock_init(&group->inotify_data.idr_lock); - idr_init(&group->inotify_data.idr); -- group->inotify_data.last_wd = 1; -+ group->inotify_data.last_wd = 0; - group->inotify_data.user = user; - group->inotify_data.fa = NULL; - -diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c -index a14d6cd..d240c15 100644 ---- a/fs/reiserfs/inode.c -+++ b/fs/reiserfs/inode.c -@@ -2531,6 +2531,12 @@ static int reiserfs_writepage(struct page *page, struct writeback_control *wbc) - return reiserfs_write_full_page(page, wbc); - } - -+static void reiserfs_truncate_failed_write(struct inode *inode) -+{ -+ truncate_inode_pages(inode->i_mapping, inode->i_size); -+ reiserfs_truncate_file(inode, 0); -+} -+ - static int reiserfs_write_begin(struct file *file, - struct address_space *mapping, - loff_t pos, unsigned len, unsigned flags, -@@ -2597,6 +2603,8 @@ static int reiserfs_write_begin(struct file *file, - if (ret) { - unlock_page(page); - page_cache_release(page); -+ /* Truncate allocated blocks */ -+ reiserfs_truncate_failed_write(inode); - } - return ret; - } -@@ -2689,8 +2697,7 @@ static int reiserfs_write_end(struct file *file, struct address_space *mapping, - ** transaction tracking stuff when the size changes. So, we have - ** to do the i_size updates here. - */ -- pos += copied; -- if (pos > inode->i_size) { -+ if (pos + copied > inode->i_size) { - struct reiserfs_transaction_handle myth; - reiserfs_write_lock(inode->i_sb); - /* If the file have grown beyond the border where it -@@ -2708,7 +2715,7 @@ static int reiserfs_write_end(struct file *file, struct address_space *mapping, - goto journal_error; - } - reiserfs_update_inode_transaction(inode); -- inode->i_size = pos; -+ inode->i_size = pos + copied; - /* - * this will just nest into our transaction. It's important - * to use mark_inode_dirty so the inode gets pushed around on the -@@ -2735,6 +2742,10 @@ static int reiserfs_write_end(struct file *file, struct address_space *mapping, - out: - unlock_page(page); - page_cache_release(page); -+ -+ if (pos + len > inode->i_size) -+ reiserfs_truncate_failed_write(inode); -+ - return ret == 0 ? copied : ret; - - journal_error: -diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h -index 221cecd..adf99c6 100644 ---- a/include/linux/blkdev.h -+++ b/include/linux/blkdev.h -@@ -1114,11 +1114,18 @@ static inline int queue_alignment_offset(struct request_queue *q) - return q->limits.alignment_offset; - } - -+static inline int queue_limit_alignment_offset(struct queue_limits *lim, sector_t offset) -+{ -+ unsigned int granularity = max(lim->physical_block_size, lim->io_min); -+ -+ offset &= granularity - 1; -+ return (granularity + lim->alignment_offset - offset) & (granularity - 1); -+} -+ - static inline int queue_sector_alignment_offset(struct request_queue *q, - sector_t sector) - { -- return ((sector << 9) - q->limits.alignment_offset) -- & (q->limits.io_min - 1); -+ return queue_limit_alignment_offset(&q->limits, sector << 9); - } - - static inline int bdev_alignment_offset(struct block_device *bdev) -diff --git a/include/linux/mfd/wm8350/pmic.h b/include/linux/mfd/wm8350/pmic.h -index be3264e..e786fe9 100644 ---- a/include/linux/mfd/wm8350/pmic.h -+++ b/include/linux/mfd/wm8350/pmic.h -@@ -666,20 +666,20 @@ - #define WM8350_ISINK_FLASH_DUR_64MS (1 << 8) - #define WM8350_ISINK_FLASH_DUR_96MS (2 << 8) - #define WM8350_ISINK_FLASH_DUR_1024MS (3 << 8) --#define WM8350_ISINK_FLASH_ON_INSTANT (0 << 4) --#define WM8350_ISINK_FLASH_ON_0_25S (1 << 4) --#define WM8350_ISINK_FLASH_ON_0_50S (2 << 4) --#define WM8350_ISINK_FLASH_ON_1_00S (3 << 4) --#define WM8350_ISINK_FLASH_ON_1_95S (1 << 4) --#define WM8350_ISINK_FLASH_ON_3_91S (2 << 4) --#define WM8350_ISINK_FLASH_ON_7_80S (3 << 4) --#define WM8350_ISINK_FLASH_OFF_INSTANT (0 << 0) --#define WM8350_ISINK_FLASH_OFF_0_25S (1 << 0) --#define WM8350_ISINK_FLASH_OFF_0_50S (2 << 0) --#define WM8350_ISINK_FLASH_OFF_1_00S (3 << 0) --#define WM8350_ISINK_FLASH_OFF_1_95S (1 << 0) --#define WM8350_ISINK_FLASH_OFF_3_91S (2 << 0) --#define WM8350_ISINK_FLASH_OFF_7_80S (3 << 0) -+#define WM8350_ISINK_FLASH_ON_INSTANT (0 << 0) -+#define WM8350_ISINK_FLASH_ON_0_25S (1 << 0) -+#define WM8350_ISINK_FLASH_ON_0_50S (2 << 0) -+#define WM8350_ISINK_FLASH_ON_1_00S (3 << 0) -+#define WM8350_ISINK_FLASH_ON_1_95S (1 << 0) -+#define WM8350_ISINK_FLASH_ON_3_91S (2 << 0) -+#define WM8350_ISINK_FLASH_ON_7_80S (3 << 0) -+#define WM8350_ISINK_FLASH_OFF_INSTANT (0 << 4) -+#define WM8350_ISINK_FLASH_OFF_0_25S (1 << 4) -+#define WM8350_ISINK_FLASH_OFF_0_50S (2 << 4) -+#define WM8350_ISINK_FLASH_OFF_1_00S (3 << 4) -+#define WM8350_ISINK_FLASH_OFF_1_95S (1 << 4) -+#define WM8350_ISINK_FLASH_OFF_3_91S (2 << 4) -+#define WM8350_ISINK_FLASH_OFF_7_80S (3 << 4) - - /* - * Regulator Interrupts. -diff --git a/include/linux/pci.h b/include/linux/pci.h -index f5c7cd3..2547515 100644 ---- a/include/linux/pci.h -+++ b/include/linux/pci.h -@@ -564,6 +564,9 @@ void pcibios_align_resource(void *, struct resource *, resource_size_t, - resource_size_t); - void pcibios_update_irq(struct pci_dev *, int irq); - -+/* Weak but can be overriden by arch */ -+void pci_fixup_cardbus(struct pci_bus *); -+ - /* Generic PCI functions used internally */ - - extern struct pci_bus *pci_find_bus(int domain, int busnr); -diff --git a/kernel/futex.c b/kernel/futex.c -index d73ef1f..3b74909 100644 ---- a/kernel/futex.c -+++ b/kernel/futex.c -@@ -203,8 +203,6 @@ static void drop_futex_key_refs(union futex_key *key) - * @uaddr: virtual address of the futex - * @fshared: 0 for a PROCESS_PRIVATE futex, 1 for PROCESS_SHARED - * @key: address where result is stored. -- * @rw: mapping needs to be read/write (values: VERIFY_READ, -- * VERIFY_WRITE) - * - * Returns a negative error code or 0 - * The key words are stored in *key on success. -@@ -216,7 +214,7 @@ static void drop_futex_key_refs(union futex_key *key) - * lock_page() might sleep, the caller should not hold a spinlock. - */ - static int --get_futex_key(u32 __user *uaddr, int fshared, union futex_key *key, int rw) -+get_futex_key(u32 __user *uaddr, int fshared, union futex_key *key) - { - unsigned long address = (unsigned long)uaddr; - struct mm_struct *mm = current->mm; -@@ -239,7 +237,7 @@ get_futex_key(u32 __user *uaddr, int fshared, union futex_key *key, int rw) - * but access_ok() should be faster than find_vma() - */ - if (!fshared) { -- if (unlikely(!access_ok(rw, uaddr, sizeof(u32)))) -+ if (unlikely(!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))) - return -EFAULT; - key->private.mm = mm; - key->private.address = address; -@@ -248,7 +246,7 @@ get_futex_key(u32 __user *uaddr, int fshared, union futex_key *key, int rw) - } - - again: -- err = get_user_pages_fast(address, 1, rw == VERIFY_WRITE, &page); -+ err = get_user_pages_fast(address, 1, 1, &page); - if (err < 0) - return err; - -@@ -867,7 +865,7 @@ static int futex_wake(u32 __user *uaddr, int fshared, int nr_wake, u32 bitset) - if (!bitset) - return -EINVAL; - -- ret = get_futex_key(uaddr, fshared, &key, VERIFY_READ); -+ ret = get_futex_key(uaddr, fshared, &key); - if (unlikely(ret != 0)) - goto out; - -@@ -913,10 +911,10 @@ futex_wake_op(u32 __user *uaddr1, int fshared, u32 __user *uaddr2, - int ret, op_ret; - - retry: -- ret = get_futex_key(uaddr1, fshared, &key1, VERIFY_READ); -+ ret = get_futex_key(uaddr1, fshared, &key1); - if (unlikely(ret != 0)) - goto out; -- ret = get_futex_key(uaddr2, fshared, &key2, VERIFY_WRITE); -+ ret = get_futex_key(uaddr2, fshared, &key2); - if (unlikely(ret != 0)) - goto out_put_key1; - -@@ -1175,11 +1173,10 @@ retry: - pi_state = NULL; - } - -- ret = get_futex_key(uaddr1, fshared, &key1, VERIFY_READ); -+ ret = get_futex_key(uaddr1, fshared, &key1); - if (unlikely(ret != 0)) - goto out; -- ret = get_futex_key(uaddr2, fshared, &key2, -- requeue_pi ? VERIFY_WRITE : VERIFY_READ); -+ ret = get_futex_key(uaddr2, fshared, &key2); - if (unlikely(ret != 0)) - goto out_put_key1; - -@@ -1738,7 +1735,7 @@ static int futex_wait_setup(u32 __user *uaddr, u32 val, int fshared, - */ - retry: - q->key = FUTEX_KEY_INIT; -- ret = get_futex_key(uaddr, fshared, &q->key, VERIFY_READ); -+ ret = get_futex_key(uaddr, fshared, &q->key); - if (unlikely(ret != 0)) - return ret; - -@@ -1904,7 +1901,7 @@ static int futex_lock_pi(u32 __user *uaddr, int fshared, - q.requeue_pi_key = NULL; - retry: - q.key = FUTEX_KEY_INIT; -- ret = get_futex_key(uaddr, fshared, &q.key, VERIFY_WRITE); -+ ret = get_futex_key(uaddr, fshared, &q.key); - if (unlikely(ret != 0)) - goto out; - -@@ -2023,7 +2020,7 @@ retry: - if ((uval & FUTEX_TID_MASK) != task_pid_vnr(current)) - return -EPERM; - -- ret = get_futex_key(uaddr, fshared, &key, VERIFY_WRITE); -+ ret = get_futex_key(uaddr, fshared, &key); - if (unlikely(ret != 0)) - goto out; - -@@ -2215,7 +2212,7 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, int fshared, - rt_waiter.task = NULL; - - key2 = FUTEX_KEY_INIT; -- ret = get_futex_key(uaddr2, fshared, &key2, VERIFY_WRITE); -+ ret = get_futex_key(uaddr2, fshared, &key2); - if (unlikely(ret != 0)) - goto out; - -diff --git a/kernel/sched.c b/kernel/sched.c -index dd0dccd..bf841d8 100644 ---- a/kernel/sched.c -+++ b/kernel/sched.c -@@ -3177,10 +3177,6 @@ static void pull_task(struct rq *src_rq, struct task_struct *p, - deactivate_task(src_rq, p, 0); - set_task_cpu(p, this_cpu); - activate_task(this_rq, p, 0); -- /* -- * Note that idle threads have a prio of MAX_PRIO, for this test -- * to be always true for them. -- */ - check_preempt_curr(this_rq, p, 0); - } - -@@ -6982,7 +6978,6 @@ void __cpuinit init_idle(struct task_struct *idle, int cpu) - __sched_fork(idle); - idle->se.exec_start = sched_clock(); - -- idle->prio = idle->normal_prio = MAX_PRIO; - cpumask_copy(&idle->cpus_allowed, cpumask_of(cpu)); - __set_task_cpu(idle, cpu); - -@@ -7686,7 +7681,6 @@ migration_call(struct notifier_block *nfb, unsigned long action, void *hcpu) - spin_lock_irq(&rq->lock); - update_rq_clock(rq); - deactivate_task(rq, rq->idle, 0); -- rq->idle->static_prio = MAX_PRIO; - __setscheduler(rq, rq->idle, SCHED_NORMAL, 0); - rq->idle->sched_class = &idle_sched_class; - migrate_dead_tasks(cpu); -diff --git a/kernel/sched_clock.c b/kernel/sched_clock.c -index 479ce56..5b49613 100644 ---- a/kernel/sched_clock.c -+++ b/kernel/sched_clock.c -@@ -236,6 +236,18 @@ void sched_clock_idle_wakeup_event(u64 delta_ns) - } - EXPORT_SYMBOL_GPL(sched_clock_idle_wakeup_event); - -+unsigned long long cpu_clock(int cpu) -+{ -+ unsigned long long clock; -+ unsigned long flags; -+ -+ local_irq_save(flags); -+ clock = sched_clock_cpu(cpu); -+ local_irq_restore(flags); -+ -+ return clock; -+} -+ - #else /* CONFIG_HAVE_UNSTABLE_SCHED_CLOCK */ - - void sched_clock_init(void) -@@ -251,17 +263,12 @@ u64 sched_clock_cpu(int cpu) - return sched_clock(); - } - --#endif /* CONFIG_HAVE_UNSTABLE_SCHED_CLOCK */ - - unsigned long long cpu_clock(int cpu) - { -- unsigned long long clock; -- unsigned long flags; -+ return sched_clock_cpu(cpu); -+} - -- local_irq_save(flags); -- clock = sched_clock_cpu(cpu); -- local_irq_restore(flags); -+#endif /* CONFIG_HAVE_UNSTABLE_SCHED_CLOCK */ - -- return clock; --} - EXPORT_SYMBOL_GPL(cpu_clock); -diff --git a/mm/memcontrol.c b/mm/memcontrol.c -index 5dc1037..66035bf 100644 ---- a/mm/memcontrol.c -+++ b/mm/memcontrol.c -@@ -2381,7 +2381,7 @@ static int mem_cgroup_force_empty(struct mem_cgroup *mem, bool free_all) - if (free_all) - goto try_to_free; - move_account: -- while (mem->res.usage > 0) { -+ do { - ret = -EBUSY; - if (cgroup_task_count(cgrp) || !list_empty(&cgrp->children)) - goto out; -@@ -2408,8 +2408,8 @@ move_account: - if (ret == -ENOMEM) - goto try_to_free; - cond_resched(); -- } -- ret = 0; -+ /* "ret" should also be checked to ensure all lists are empty. */ -+ } while (mem->res.usage > 0 || ret); - out: - css_put(&mem->css); - return ret; -@@ -2442,10 +2442,7 @@ try_to_free: - } - lru_add_drain(); - /* try move_account...there may be some *locked* pages. */ -- if (mem->res.usage) -- goto move_account; -- ret = 0; -- goto out; -+ goto move_account; - } - - int mem_cgroup_force_empty_write(struct cgroup *cont, unsigned int event) -diff --git a/mm/page_alloc.c b/mm/page_alloc.c -index 2bc2ac6..3a78e2e 100644 ---- a/mm/page_alloc.c -+++ b/mm/page_alloc.c -@@ -1225,10 +1225,10 @@ again: - } - spin_lock_irqsave(&zone->lock, flags); - page = __rmqueue(zone, order, migratetype); -- __mod_zone_page_state(zone, NR_FREE_PAGES, -(1 << order)); - spin_unlock(&zone->lock); - if (!page) - goto failed; -+ __mod_zone_page_state(zone, NR_FREE_PAGES, -(1 << order)); - } - - __count_zone_vm_events(PGALLOC, zone, 1 << order); -diff --git a/mm/truncate.c b/mm/truncate.c -index 450cebd..258bda7 100644 ---- a/mm/truncate.c -+++ b/mm/truncate.c -@@ -516,22 +516,20 @@ EXPORT_SYMBOL_GPL(invalidate_inode_pages2); - */ - void truncate_pagecache(struct inode *inode, loff_t old, loff_t new) - { -- if (new < old) { -- struct address_space *mapping = inode->i_mapping; -- -- /* -- * unmap_mapping_range is called twice, first simply for -- * efficiency so that truncate_inode_pages does fewer -- * single-page unmaps. However after this first call, and -- * before truncate_inode_pages finishes, it is possible for -- * private pages to be COWed, which remain after -- * truncate_inode_pages finishes, hence the second -- * unmap_mapping_range call must be made for correctness. -- */ -- unmap_mapping_range(mapping, new + PAGE_SIZE - 1, 0, 1); -- truncate_inode_pages(mapping, new); -- unmap_mapping_range(mapping, new + PAGE_SIZE - 1, 0, 1); -- } -+ struct address_space *mapping = inode->i_mapping; -+ -+ /* -+ * unmap_mapping_range is called twice, first simply for -+ * efficiency so that truncate_inode_pages does fewer -+ * single-page unmaps. However after this first call, and -+ * before truncate_inode_pages finishes, it is possible for -+ * private pages to be COWed, which remain after -+ * truncate_inode_pages finishes, hence the second -+ * unmap_mapping_range call must be made for correctness. -+ */ -+ unmap_mapping_range(mapping, new + PAGE_SIZE - 1, 0, 1); -+ truncate_inode_pages(mapping, new); -+ unmap_mapping_range(mapping, new + PAGE_SIZE - 1, 0, 1); - } - EXPORT_SYMBOL(truncate_pagecache); - -diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c -index a4cb183..075c3a6 100644 ---- a/sound/pci/hda/patch_realtek.c -+++ b/sound/pci/hda/patch_realtek.c -@@ -14685,6 +14685,8 @@ static int patch_alc861(struct hda_codec *codec) - spec->stream_digital_playback = &alc861_pcm_digital_playback; - spec->stream_digital_capture = &alc861_pcm_digital_capture; - -+ if (!spec->cap_mixer) -+ set_capture_mixer(codec); - set_beep_amp(spec, 0x23, 0, HDA_OUTPUT); - - spec->vmaster_nid = 0x03; diff --git a/debian/patches/bugfix/all/stable/2.6.32.6.patch b/debian/patches/bugfix/all/stable/2.6.32.6.patch deleted file mode 100644 index 705b8bd66..000000000 --- a/debian/patches/bugfix/all/stable/2.6.32.6.patch +++ /dev/null @@ -1,1324 +0,0 @@ -diff --git a/Makefile b/Makefile -index 4ebd3f1..20da312 100644 -diff --git a/arch/x86/kernel/cpuid.c b/arch/x86/kernel/cpuid.c -index 6a52d4b..f8590c5 100644 ---- a/arch/x86/kernel/cpuid.c -+++ b/arch/x86/kernel/cpuid.c -@@ -192,7 +192,8 @@ static int __init cpuid_init(void) - int i, err = 0; - i = 0; - -- if (register_chrdev(CPUID_MAJOR, "cpu/cpuid", &cpuid_fops)) { -+ if (__register_chrdev(CPUID_MAJOR, 0, NR_CPUS, -+ "cpu/cpuid", &cpuid_fops)) { - printk(KERN_ERR "cpuid: unable to get major %d for cpuid\n", - CPUID_MAJOR); - err = -EBUSY; -@@ -221,7 +222,7 @@ out_class: - } - class_destroy(cpuid_class); - out_chrdev: -- unregister_chrdev(CPUID_MAJOR, "cpu/cpuid"); -+ __unregister_chrdev(CPUID_MAJOR, 0, NR_CPUS, "cpu/cpuid"); - out: - return err; - } -diff --git a/arch/x86/kernel/msr.c b/arch/x86/kernel/msr.c -index 6a3cefc..b42e63b 100644 ---- a/arch/x86/kernel/msr.c -+++ b/arch/x86/kernel/msr.c -@@ -251,7 +251,7 @@ static int __init msr_init(void) - int i, err = 0; - i = 0; - -- if (register_chrdev(MSR_MAJOR, "cpu/msr", &msr_fops)) { -+ if (__register_chrdev(MSR_MAJOR, 0, NR_CPUS, "cpu/msr", &msr_fops)) { - printk(KERN_ERR "msr: unable to get major %d for msr\n", - MSR_MAJOR); - err = -EBUSY; -@@ -279,7 +279,7 @@ out_class: - msr_device_destroy(i); - class_destroy(msr_class); - out_chrdev: -- unregister_chrdev(MSR_MAJOR, "cpu/msr"); -+ __unregister_chrdev(MSR_MAJOR, 0, NR_CPUS, "cpu/msr"); - out: - return err; - } -diff --git a/arch/x86/pci/i386.c b/arch/x86/pci/i386.c -index b22d13b..a672f12 100644 ---- a/arch/x86/pci/i386.c -+++ b/arch/x86/pci/i386.c -@@ -282,6 +282,15 @@ int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma, - return -EINVAL; - - prot = pgprot_val(vma->vm_page_prot); -+ -+ /* -+ * Return error if pat is not enabled and write_combine is requested. -+ * Caller can followup with UC MINUS request and add a WC mtrr if there -+ * is a free mtrr slot. -+ */ -+ if (!pat_enabled && write_combine) -+ return -EINVAL; -+ - if (pat_enabled && write_combine) - prot |= _PAGE_CACHE_WC; - else if (pat_enabled || boot_cpu_data.x86 > 3) -diff --git a/block/blk-settings.c b/block/blk-settings.c -index 66d4aa8..d5aa886 100644 ---- a/block/blk-settings.c -+++ b/block/blk-settings.c -@@ -560,6 +560,28 @@ int blk_stack_limits(struct queue_limits *t, struct queue_limits *b, - EXPORT_SYMBOL(blk_stack_limits); - - /** -+ * bdev_stack_limits - adjust queue limits for stacked drivers -+ * @t: the stacking driver limits (top device) -+ * @bdev: the component block_device (bottom) -+ * @start: first data sector within component device -+ * -+ * Description: -+ * Merges queue limits for a top device and a block_device. Returns -+ * 0 if alignment didn't change. Returns -1 if adding the bottom -+ * device caused misalignment. -+ */ -+int bdev_stack_limits(struct queue_limits *t, struct block_device *bdev, -+ sector_t start) -+{ -+ struct request_queue *bq = bdev_get_queue(bdev); -+ -+ start += get_start_sect(bdev); -+ -+ return blk_stack_limits(t, &bq->limits, start << 9); -+} -+EXPORT_SYMBOL(bdev_stack_limits); -+ -+/** - * disk_stack_limits - adjust queue limits for stacked drivers - * @disk: MD/DM gendisk (top) - * @bdev: the underlying block device (bottom) -diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c -index 7511029..f1670e0 100644 ---- a/drivers/acpi/ec.c -+++ b/drivers/acpi/ec.c -@@ -201,14 +201,13 @@ unlock: - spin_unlock_irqrestore(&ec->curr_lock, flags); - } - --static void acpi_ec_gpe_query(void *ec_cxt); -+static int acpi_ec_sync_query(struct acpi_ec *ec); - --static int ec_check_sci(struct acpi_ec *ec, u8 state) -+static int ec_check_sci_sync(struct acpi_ec *ec, u8 state) - { - if (state & ACPI_EC_FLAG_SCI) { - if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) -- return acpi_os_execute(OSL_EC_BURST_HANDLER, -- acpi_ec_gpe_query, ec); -+ return acpi_ec_sync_query(ec); - } - return 0; - } -@@ -249,11 +248,6 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, - { - unsigned long tmp; - int ret = 0; -- pr_debug(PREFIX "transaction start\n"); -- /* disable GPE during transaction if storm is detected */ -- if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) { -- acpi_disable_gpe(NULL, ec->gpe); -- } - if (EC_FLAGS_MSI) - udelay(ACPI_EC_MSI_UDELAY); - /* start transaction */ -@@ -265,20 +259,9 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, - clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags); - spin_unlock_irqrestore(&ec->curr_lock, tmp); - ret = ec_poll(ec); -- pr_debug(PREFIX "transaction end\n"); - spin_lock_irqsave(&ec->curr_lock, tmp); - ec->curr = NULL; - spin_unlock_irqrestore(&ec->curr_lock, tmp); -- if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) { -- /* check if we received SCI during transaction */ -- ec_check_sci(ec, acpi_ec_read_status(ec)); -- /* it is safe to enable GPE outside of transaction */ -- acpi_enable_gpe(NULL, ec->gpe); -- } else if (t->irq_count > ACPI_EC_STORM_THRESHOLD) { -- pr_info(PREFIX "GPE storm detected, " -- "transactions will use polling mode\n"); -- set_bit(EC_FLAGS_GPE_STORM, &ec->flags); -- } - return ret; - } - -@@ -321,7 +304,26 @@ static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t) - status = -ETIME; - goto end; - } -+ pr_debug(PREFIX "transaction start\n"); -+ /* disable GPE during transaction if storm is detected */ -+ if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) { -+ acpi_disable_gpe(NULL, ec->gpe); -+ } -+ - status = acpi_ec_transaction_unlocked(ec, t); -+ -+ /* check if we received SCI during transaction */ -+ ec_check_sci_sync(ec, acpi_ec_read_status(ec)); -+ if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) { -+ msleep(1); -+ /* it is safe to enable GPE outside of transaction */ -+ acpi_enable_gpe(NULL, ec->gpe); -+ } else if (t->irq_count > ACPI_EC_STORM_THRESHOLD) { -+ pr_info(PREFIX "GPE storm detected, " -+ "transactions will use polling mode\n"); -+ set_bit(EC_FLAGS_GPE_STORM, &ec->flags); -+ } -+ pr_debug(PREFIX "transaction end\n"); - end: - if (ec->global_lock) - acpi_release_global_lock(glk); -@@ -443,7 +445,7 @@ int ec_transaction(u8 command, - - EXPORT_SYMBOL(ec_transaction); - --static int acpi_ec_query(struct acpi_ec *ec, u8 * data) -+static int acpi_ec_query_unlocked(struct acpi_ec *ec, u8 * data) - { - int result; - u8 d; -@@ -452,20 +454,16 @@ static int acpi_ec_query(struct acpi_ec *ec, u8 * data) - .wlen = 0, .rlen = 1}; - if (!ec || !data) - return -EINVAL; -- - /* - * Query the EC to find out which _Qxx method we need to evaluate. - * Note that successful completion of the query causes the ACPI_EC_SCI - * bit to be cleared (and thus clearing the interrupt source). - */ -- -- result = acpi_ec_transaction(ec, &t); -+ result = acpi_ec_transaction_unlocked(ec, &t); - if (result) - return result; -- - if (!d) - return -ENODATA; -- - *data = d; - return 0; - } -@@ -509,43 +507,78 @@ void acpi_ec_remove_query_handler(struct acpi_ec *ec, u8 query_bit) - - EXPORT_SYMBOL_GPL(acpi_ec_remove_query_handler); - --static void acpi_ec_gpe_query(void *ec_cxt) -+static void acpi_ec_run(void *cxt) - { -- struct acpi_ec *ec = ec_cxt; -- u8 value = 0; -- struct acpi_ec_query_handler *handler, copy; -- -- if (!ec || acpi_ec_query(ec, &value)) -+ struct acpi_ec_query_handler *handler = cxt; -+ if (!handler) - return; -- mutex_lock(&ec->lock); -+ pr_debug(PREFIX "start query execution\n"); -+ if (handler->func) -+ handler->func(handler->data); -+ else if (handler->handle) -+ acpi_evaluate_object(handler->handle, NULL, NULL, NULL); -+ pr_debug(PREFIX "stop query execution\n"); -+ kfree(handler); -+} -+ -+static int acpi_ec_sync_query(struct acpi_ec *ec) -+{ -+ u8 value = 0; -+ int status; -+ struct acpi_ec_query_handler *handler, *copy; -+ if ((status = acpi_ec_query_unlocked(ec, &value))) -+ return status; - list_for_each_entry(handler, &ec->list, node) { - if (value == handler->query_bit) { - /* have custom handler for this bit */ -- memcpy(©, handler, sizeof(copy)); -- mutex_unlock(&ec->lock); -- if (copy.func) { -- copy.func(copy.data); -- } else if (copy.handle) { -- acpi_evaluate_object(copy.handle, NULL, NULL, NULL); -- } -- return; -+ copy = kmalloc(sizeof(*handler), GFP_KERNEL); -+ if (!copy) -+ return -ENOMEM; -+ memcpy(copy, handler, sizeof(*copy)); -+ pr_debug(PREFIX "push query execution (0x%2x) on queue\n", value); -+ return acpi_os_execute(OSL_GPE_HANDLER, -+ acpi_ec_run, copy); - } - } -+ return 0; -+} -+ -+static void acpi_ec_gpe_query(void *ec_cxt) -+{ -+ struct acpi_ec *ec = ec_cxt; -+ if (!ec) -+ return; -+ mutex_lock(&ec->lock); -+ acpi_ec_sync_query(ec); - mutex_unlock(&ec->lock); - } - -+static void acpi_ec_gpe_query(void *ec_cxt); -+ -+static int ec_check_sci(struct acpi_ec *ec, u8 state) -+{ -+ if (state & ACPI_EC_FLAG_SCI) { -+ if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) { -+ pr_debug(PREFIX "push gpe query to the queue\n"); -+ return acpi_os_execute(OSL_NOTIFY_HANDLER, -+ acpi_ec_gpe_query, ec); -+ } -+ } -+ return 0; -+} -+ - static u32 acpi_ec_gpe_handler(void *data) - { - struct acpi_ec *ec = data; -- u8 status; - - pr_debug(PREFIX "~~~> interrupt\n"); -- status = acpi_ec_read_status(ec); - -- advance_transaction(ec, status); -- if (ec_transaction_done(ec) && (status & ACPI_EC_FLAG_IBF) == 0) -+ advance_transaction(ec, acpi_ec_read_status(ec)); -+ if (ec_transaction_done(ec) && -+ (acpi_ec_read_status(ec) & ACPI_EC_FLAG_IBF) == 0) { - wake_up(&ec->wait); -- ec_check_sci(ec, status); -+ ec_check_sci(ec, acpi_ec_read_status(ec)); -+ } - return ACPI_INTERRUPT_HANDLED; - } - -diff --git a/drivers/char/nozomi.c b/drivers/char/nozomi.c -index d3400b2..dc52f75 100644 ---- a/drivers/char/nozomi.c -+++ b/drivers/char/nozomi.c -@@ -1629,10 +1629,10 @@ static void ntty_close(struct tty_struct *tty, struct file *file) - - dc->open_ttys--; - port->count--; -- tty_port_tty_set(port, NULL); - - if (port->count == 0) { - DBG1("close: %d", nport->token_dl); -+ tty_port_tty_set(port, NULL); - spin_lock_irqsave(&dc->spin_mutex, flags); - dc->last_ier &= ~(nport->token_dl); - writew(dc->last_ier, dc->reg_ier); -diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c -index 59499ee..e919bd9 100644 ---- a/drivers/char/tty_io.c -+++ b/drivers/char/tty_io.c -@@ -1930,8 +1930,8 @@ static int tty_fasync(int fd, struct file *filp, int on) - pid = task_pid(current); - type = PIDTYPE_PID; - } -- spin_unlock_irqrestore(&tty->ctrl_lock, flags); - retval = __f_setown(filp, pid, type, 0); -+ spin_unlock_irqrestore(&tty->ctrl_lock, flags); - if (retval) - goto out; - } else { -diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c -index 083bec2..29e21d3 100644 ---- a/drivers/gpu/drm/i915/intel_sdvo.c -+++ b/drivers/gpu/drm/i915/intel_sdvo.c -@@ -472,14 +472,63 @@ static int intel_sdvo_get_pixel_multiplier(struct drm_display_mode *mode) - } - - /** -- * Don't check status code from this as it switches the bus back to the -- * SDVO chips which defeats the purpose of doing a bus switch in the first -- * place. -+ * Try to read the response after issuie the DDC switch command. But it -+ * is noted that we must do the action of reading response and issuing DDC -+ * switch command in one I2C transaction. Otherwise when we try to start -+ * another I2C transaction after issuing the DDC bus switch, it will be -+ * switched to the internal SDVO register. - */ - static void intel_sdvo_set_control_bus_switch(struct intel_output *intel_output, - u8 target) - { -- intel_sdvo_write_cmd(intel_output, SDVO_CMD_SET_CONTROL_BUS_SWITCH, &target, 1); -+ struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv; -+ u8 out_buf[2], cmd_buf[2], ret_value[2], ret; -+ struct i2c_msg msgs[] = { -+ { -+ .addr = sdvo_priv->slave_addr >> 1, -+ .flags = 0, -+ .len = 2, -+ .buf = out_buf, -+ }, -+ /* the following two are to read the response */ -+ { -+ .addr = sdvo_priv->slave_addr >> 1, -+ .flags = 0, -+ .len = 1, -+ .buf = cmd_buf, -+ }, -+ { -+ .addr = sdvo_priv->slave_addr >> 1, -+ .flags = I2C_M_RD, -+ .len = 1, -+ .buf = ret_value, -+ }, -+ }; -+ -+ intel_sdvo_debug_write(intel_output, SDVO_CMD_SET_CONTROL_BUS_SWITCH, -+ &target, 1); -+ /* write the DDC switch command argument */ -+ intel_sdvo_write_byte(intel_output, SDVO_I2C_ARG_0, target); -+ -+ out_buf[0] = SDVO_I2C_OPCODE; -+ out_buf[1] = SDVO_CMD_SET_CONTROL_BUS_SWITCH; -+ cmd_buf[0] = SDVO_I2C_CMD_STATUS; -+ cmd_buf[1] = 0; -+ ret_value[0] = 0; -+ ret_value[1] = 0; -+ -+ ret = i2c_transfer(intel_output->i2c_bus, msgs, 3); -+ if (ret != 3) { -+ /* failure in I2C transfer */ -+ DRM_DEBUG_KMS("I2c transfer returned %d\n", ret); -+ return; -+ } -+ if (ret_value[0] != SDVO_CMD_STATUS_SUCCESS) { -+ DRM_DEBUG_KMS("DDC switch command returns response %d\n", -+ ret_value[0]); -+ return; -+ } -+ return; - } - - static bool intel_sdvo_set_target_input(struct intel_output *intel_output, bool target_0, bool target_1) -@@ -1589,6 +1638,32 @@ intel_sdvo_hdmi_sink_detect(struct drm_connector *connector, u16 response) - edid = drm_get_edid(&intel_output->base, - intel_output->ddc_bus); - -+ /* This is only applied to SDVO cards with multiple outputs */ -+ if (edid == NULL && intel_sdvo_multifunc_encoder(intel_output)) { -+ uint8_t saved_ddc, temp_ddc; -+ saved_ddc = sdvo_priv->ddc_bus; -+ temp_ddc = sdvo_priv->ddc_bus >> 1; -+ /* -+ * Don't use the 1 as the argument of DDC bus switch to get -+ * the EDID. It is used for SDVO SPD ROM. -+ */ -+ while(temp_ddc > 1) { -+ sdvo_priv->ddc_bus = temp_ddc; -+ edid = drm_get_edid(&intel_output->base, -+ intel_output->ddc_bus); -+ if (edid) { -+ /* -+ * When we can get the EDID, maybe it is the -+ * correct DDC bus. Update it. -+ */ -+ sdvo_priv->ddc_bus = temp_ddc; -+ break; -+ } -+ temp_ddc >>= 1; -+ } -+ if (edid == NULL) -+ sdvo_priv->ddc_bus = saved_ddc; -+ } - /* when there is no edid and no monitor is connected with VGA - * port, try to use the CRT ddc to read the EDID for DVI-connector - */ -diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c -index 1a6cb3c..e869128 100644 ---- a/drivers/md/dm-table.c -+++ b/drivers/md/dm-table.c -@@ -499,16 +499,15 @@ int dm_set_device_limits(struct dm_target *ti, struct dm_dev *dev, - return 0; - } - -- if (blk_stack_limits(limits, &q->limits, start << 9) < 0) -- DMWARN("%s: target device %s is misaligned: " -+ if (bdev_stack_limits(limits, bdev, start) < 0) -+ DMWARN("%s: adding target device %s caused an alignment inconsistency: " - "physical_block_size=%u, logical_block_size=%u, " - "alignment_offset=%u, start=%llu", - dm_device_name(ti->table->md), bdevname(bdev, b), - q->limits.physical_block_size, - q->limits.logical_block_size, - q->limits.alignment_offset, -- (unsigned long long) start << 9); -- -+ (unsigned long long) start << SECTOR_SHIFT); - - /* - * Check if merge fn is supported. -@@ -1025,9 +1024,9 @@ combine_limits: - * for the table. - */ - if (blk_stack_limits(limits, &ti_limits, 0) < 0) -- DMWARN("%s: target device " -+ DMWARN("%s: adding target device " - "(start sect %llu len %llu) " -- "is misaligned", -+ "caused an alignment inconsistency", - dm_device_name(table->md), - (unsigned long long) ti->begin, - (unsigned long long) ti->len); -@@ -1079,15 +1078,6 @@ void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q, - struct queue_limits *limits) - { - /* -- * Each target device in the table has a data area that should normally -- * be aligned such that the DM device's alignment_offset is 0. -- * FIXME: Propagate alignment_offsets up the stack and warn of -- * sub-optimal or inconsistent settings. -- */ -- limits->alignment_offset = 0; -- limits->misaligned = 0; -- -- /* - * Copy table's limits to the DM device's request_queue - */ - q->limits = *limits; -diff --git a/drivers/media/video/gspca/sunplus.c b/drivers/media/video/gspca/sunplus.c -index aa8f995..28b4625 100644 ---- a/drivers/media/video/gspca/sunplus.c -+++ b/drivers/media/video/gspca/sunplus.c -@@ -705,7 +705,7 @@ static void spca504B_SetSizeType(struct gspca_dev *gspca_dev) - rc = spca504B_PollingDataReady(gspca_dev); - - /* Init the cam width height with some values get on init ? */ -- reg_w_riv(dev, 0x31, 0, 0x04); -+ reg_w_riv(dev, 0x31, 0x04, 0); - spca504B_WaitCmdStatus(gspca_dev); - rc = spca504B_PollingDataReady(gspca_dev); - break; -@@ -807,14 +807,14 @@ static void init_ctl_reg(struct gspca_dev *gspca_dev) - default: - /* case BRIDGE_SPCA533: */ - /* case BRIDGE_SPCA504B: */ -- reg_w_riv(dev, 0, 0x00, 0x21ad); /* hue */ -- reg_w_riv(dev, 0, 0x01, 0x21ac); /* sat/hue */ -- reg_w_riv(dev, 0, 0x00, 0x21a3); /* gamma */ -+ reg_w_riv(dev, 0, 0x21ad, 0x00); /* hue */ -+ reg_w_riv(dev, 0, 0x21ac, 0x01); /* sat/hue */ -+ reg_w_riv(dev, 0, 0x21a3, 0x00); /* gamma */ - break; - case BRIDGE_SPCA536: -- reg_w_riv(dev, 0, 0x40, 0x20f5); -- reg_w_riv(dev, 0, 0x01, 0x20f4); -- reg_w_riv(dev, 0, 0x00, 0x2089); -+ reg_w_riv(dev, 0, 0x20f5, 0x40); -+ reg_w_riv(dev, 0, 0x20f4, 0x01); -+ reg_w_riv(dev, 0, 0x2089, 0x00); - break; - } - if (pollreg) -@@ -888,11 +888,11 @@ static int sd_init(struct gspca_dev *gspca_dev) - switch (sd->bridge) { - case BRIDGE_SPCA504B: - reg_w_riv(dev, 0x1d, 0x00, 0); -- reg_w_riv(dev, 0, 0x01, 0x2306); -- reg_w_riv(dev, 0, 0x00, 0x0d04); -- reg_w_riv(dev, 0, 0x00, 0x2000); -- reg_w_riv(dev, 0, 0x13, 0x2301); -- reg_w_riv(dev, 0, 0x00, 0x2306); -+ reg_w_riv(dev, 0, 0x2306, 0x01); -+ reg_w_riv(dev, 0, 0x0d04, 0x00); -+ reg_w_riv(dev, 0, 0x2000, 0x00); -+ reg_w_riv(dev, 0, 0x2301, 0x13); -+ reg_w_riv(dev, 0, 0x2306, 0x00); - /* fall thru */ - case BRIDGE_SPCA533: - spca504B_PollingDataReady(gspca_dev); -@@ -1011,7 +1011,7 @@ static int sd_start(struct gspca_dev *gspca_dev) - spca504B_WaitCmdStatus(gspca_dev); - break; - default: -- reg_w_riv(dev, 0x31, 0, 0x04); -+ reg_w_riv(dev, 0x31, 0x04, 0); - spca504B_WaitCmdStatus(gspca_dev); - spca504B_PollingDataReady(gspca_dev); - break; -diff --git a/drivers/misc/enclosure.c b/drivers/misc/enclosure.c -index e9eae4a..1eac626 100644 ---- a/drivers/misc/enclosure.c -+++ b/drivers/misc/enclosure.c -@@ -391,6 +391,7 @@ static const char *const enclosure_status [] = { - [ENCLOSURE_STATUS_NOT_INSTALLED] = "not installed", - [ENCLOSURE_STATUS_UNKNOWN] = "unknown", - [ENCLOSURE_STATUS_UNAVAILABLE] = "unavailable", -+ [ENCLOSURE_STATUS_MAX] = NULL, - }; - - static const char *const enclosure_type [] = { -diff --git a/drivers/serial/8250_pnp.c b/drivers/serial/8250_pnp.c -index 0cce8a4..deac67e 100644 ---- a/drivers/serial/8250_pnp.c -+++ b/drivers/serial/8250_pnp.c -@@ -328,15 +328,7 @@ static const struct pnp_device_id pnp_dev_table[] = { - /* U.S. Robotics 56K Voice INT PnP*/ - { "USR9190", 0 }, - /* Wacom tablets */ -- { "WACF004", 0 }, -- { "WACF005", 0 }, -- { "WACF006", 0 }, -- { "WACF007", 0 }, -- { "WACF008", 0 }, -- { "WACF009", 0 }, -- { "WACF00A", 0 }, -- { "WACF00B", 0 }, -- { "WACF00C", 0 }, -+ { "WACFXXX", 0 }, - /* Compaq touchscreen */ - { "FPI2002", 0 }, - /* Fujitsu Stylistic touchscreens */ -diff --git a/drivers/staging/asus_oled/asus_oled.c b/drivers/staging/asus_oled/asus_oled.c -index f4c2657..43c57b7 100644 ---- a/drivers/staging/asus_oled/asus_oled.c -+++ b/drivers/staging/asus_oled/asus_oled.c -@@ -194,9 +194,11 @@ static ssize_t set_enabled(struct device *dev, struct device_attribute *attr, - { - struct usb_interface *intf = to_usb_interface(dev); - struct asus_oled_dev *odev = usb_get_intfdata(intf); -- int temp = strict_strtoul(buf, 10, NULL); -+ unsigned long value; -+ if (strict_strtoul(buf, 10, &value)) -+ return -EINVAL; - -- enable_oled(odev, temp); -+ enable_oled(odev, value); - - return count; - } -@@ -207,10 +209,12 @@ static ssize_t class_set_enabled(struct device *device, - { - struct asus_oled_dev *odev = - (struct asus_oled_dev *) dev_get_drvdata(device); -+ unsigned long value; - -- int temp = strict_strtoul(buf, 10, NULL); -+ if (strict_strtoul(buf, 10, &value)) -+ return -EINVAL; - -- enable_oled(odev, temp); -+ enable_oled(odev, value); - - return count; - } -diff --git a/drivers/staging/hv/Hv.c b/drivers/staging/hv/Hv.c -index c5b6613..c2809f2 100644 ---- a/drivers/staging/hv/Hv.c -+++ b/drivers/staging/hv/Hv.c -@@ -386,7 +386,7 @@ u16 HvSignalEvent(void) - * retrieve the initialized message and event pages. Otherwise, we create and - * initialize the message and event pages. - */ --int HvSynicInit(u32 irqVector) -+void HvSynicInit(void *irqarg) - { - u64 version; - union hv_synic_simp simp; -@@ -394,13 +394,14 @@ int HvSynicInit(u32 irqVector) - union hv_synic_sint sharedSint; - union hv_synic_scontrol sctrl; - u64 guestID; -- int ret = 0; -+ u32 irqVector = *((u32 *)(irqarg)); -+ int cpu = smp_processor_id(); - - DPRINT_ENTER(VMBUS); - - if (!gHvContext.HypercallPage) { - DPRINT_EXIT(VMBUS); -- return ret; -+ return; - } - - /* Check the version */ -@@ -425,27 +426,27 @@ int HvSynicInit(u32 irqVector) - */ - rdmsrl(HV_X64_MSR_GUEST_OS_ID, guestID); - if (guestID == HV_LINUX_GUEST_ID) { -- gHvContext.synICMessagePage[0] = -+ gHvContext.synICMessagePage[cpu] = - phys_to_virt(simp.BaseSimpGpa << PAGE_SHIFT); -- gHvContext.synICEventPage[0] = -+ gHvContext.synICEventPage[cpu] = - phys_to_virt(siefp.BaseSiefpGpa << PAGE_SHIFT); - } else { - DPRINT_ERR(VMBUS, "unknown guest id!!"); - goto Cleanup; - } - DPRINT_DBG(VMBUS, "MAPPED: Simp: %p, Sifep: %p", -- gHvContext.synICMessagePage[0], -- gHvContext.synICEventPage[0]); -+ gHvContext.synICMessagePage[cpu], -+ gHvContext.synICEventPage[cpu]); - } else { -- gHvContext.synICMessagePage[0] = osd_PageAlloc(1); -- if (gHvContext.synICMessagePage[0] == NULL) { -+ gHvContext.synICMessagePage[cpu] = (void *)get_zeroed_page(GFP_ATOMIC); -+ if (gHvContext.synICMessagePage[cpu] == NULL) { - DPRINT_ERR(VMBUS, - "unable to allocate SYNIC message page!!"); - goto Cleanup; - } - -- gHvContext.synICEventPage[0] = osd_PageAlloc(1); -- if (gHvContext.synICEventPage[0] == NULL) { -+ gHvContext.synICEventPage[cpu] = (void *)get_zeroed_page(GFP_ATOMIC); -+ if (gHvContext.synICEventPage[cpu] == NULL) { - DPRINT_ERR(VMBUS, - "unable to allocate SYNIC event page!!"); - goto Cleanup; -@@ -454,7 +455,7 @@ int HvSynicInit(u32 irqVector) - /* Setup the Synic's message page */ - rdmsrl(HV_X64_MSR_SIMP, simp.AsUINT64); - simp.SimpEnabled = 1; -- simp.BaseSimpGpa = virt_to_phys(gHvContext.synICMessagePage[0]) -+ simp.BaseSimpGpa = virt_to_phys(gHvContext.synICMessagePage[cpu]) - >> PAGE_SHIFT; - - DPRINT_DBG(VMBUS, "HV_X64_MSR_SIMP msr set to: %llx", -@@ -465,7 +466,7 @@ int HvSynicInit(u32 irqVector) - /* Setup the Synic's event page */ - rdmsrl(HV_X64_MSR_SIEFP, siefp.AsUINT64); - siefp.SiefpEnabled = 1; -- siefp.BaseSiefpGpa = virt_to_phys(gHvContext.synICEventPage[0]) -+ siefp.BaseSiefpGpa = virt_to_phys(gHvContext.synICEventPage[cpu]) - >> PAGE_SHIFT; - - DPRINT_DBG(VMBUS, "HV_X64_MSR_SIEFP msr set to: %llx", -@@ -501,32 +502,30 @@ int HvSynicInit(u32 irqVector) - - DPRINT_EXIT(VMBUS); - -- return ret; -+ return; - - Cleanup: -- ret = -1; -- - if (gHvContext.GuestId == HV_LINUX_GUEST_ID) { -- if (gHvContext.synICEventPage[0]) -- osd_PageFree(gHvContext.synICEventPage[0], 1); -+ if (gHvContext.synICEventPage[cpu]) -+ osd_PageFree(gHvContext.synICEventPage[cpu], 1); - -- if (gHvContext.synICMessagePage[0]) -- osd_PageFree(gHvContext.synICMessagePage[0], 1); -+ if (gHvContext.synICMessagePage[cpu]) -+ osd_PageFree(gHvContext.synICMessagePage[cpu], 1); - } - - DPRINT_EXIT(VMBUS); -- -- return ret; -+ return; - } - - /** - * HvSynicCleanup - Cleanup routine for HvSynicInit(). - */ --void HvSynicCleanup(void) -+void HvSynicCleanup(void *arg) - { - union hv_synic_sint sharedSint; - union hv_synic_simp simp; - union hv_synic_siefp siefp; -+ int cpu = smp_processor_id(); - - DPRINT_ENTER(VMBUS); - -@@ -539,6 +538,7 @@ void HvSynicCleanup(void) - - sharedSint.Masked = 1; - -+ /* Need to correctly cleanup in the case of SMP!!! */ - /* Disable the interrupt */ - wrmsrl(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT, sharedSint.AsUINT64); - -@@ -560,8 +560,8 @@ void HvSynicCleanup(void) - - wrmsrl(HV_X64_MSR_SIEFP, siefp.AsUINT64); - -- osd_PageFree(gHvContext.synICMessagePage[0], 1); -- osd_PageFree(gHvContext.synICEventPage[0], 1); -+ osd_PageFree(gHvContext.synICMessagePage[cpu], 1); -+ osd_PageFree(gHvContext.synICEventPage[cpu], 1); - } - - DPRINT_EXIT(VMBUS); -diff --git a/drivers/staging/hv/Hv.h b/drivers/staging/hv/Hv.h -index 5379e4b..fce4b5c 100644 ---- a/drivers/staging/hv/Hv.h -+++ b/drivers/staging/hv/Hv.h -@@ -93,7 +93,7 @@ static const struct hv_guid VMBUS_SERVICE_ID = { - }, - }; - --#define MAX_NUM_CPUS 1 -+#define MAX_NUM_CPUS 32 - - - struct hv_input_signal_event_buffer { -@@ -137,8 +137,8 @@ extern u16 HvPostMessage(union hv_connection_id connectionId, - - extern u16 HvSignalEvent(void); - --extern int HvSynicInit(u32 irqVector); -+extern void HvSynicInit(void *irqarg); - --extern void HvSynicCleanup(void); -+extern void HvSynicCleanup(void *arg); - - #endif /* __HV_H__ */ -diff --git a/drivers/staging/hv/Vmbus.c b/drivers/staging/hv/Vmbus.c -index a4dd06f..35a023e 100644 ---- a/drivers/staging/hv/Vmbus.c -+++ b/drivers/staging/hv/Vmbus.c -@@ -129,7 +129,7 @@ static int VmbusOnDeviceAdd(struct hv_device *dev, void *AdditionalInfo) - - /* strcpy(dev->name, "vmbus"); */ - /* SynIC setup... */ -- ret = HvSynicInit(*irqvector); -+ on_each_cpu(HvSynicInit, (void *)irqvector, 1); - - /* Connect to VMBus in the root partition */ - ret = VmbusConnect(); -@@ -150,7 +150,7 @@ static int VmbusOnDeviceRemove(struct hv_device *dev) - DPRINT_ENTER(VMBUS); - VmbusChannelReleaseUnattachedChannels(); - VmbusDisconnect(); -- HvSynicCleanup(); -+ on_each_cpu(HvSynicCleanup, NULL, 1); - DPRINT_EXIT(VMBUS); - - return ret; -@@ -173,7 +173,8 @@ static void VmbusOnCleanup(struct hv_driver *drv) - */ - static void VmbusOnMsgDPC(struct hv_driver *drv) - { -- void *page_addr = gHvContext.synICMessagePage[0]; -+ int cpu = smp_processor_id(); -+ void *page_addr = gHvContext.synICMessagePage[cpu]; - struct hv_message *msg = (struct hv_message *)page_addr + - VMBUS_MESSAGE_SINT; - struct hv_message *copied; -@@ -230,11 +231,12 @@ static void VmbusOnEventDPC(struct hv_driver *drv) - static int VmbusOnISR(struct hv_driver *drv) - { - int ret = 0; -+ int cpu = smp_processor_id(); - void *page_addr; - struct hv_message *msg; - union hv_synic_event_flags *event; - -- page_addr = gHvContext.synICMessagePage[0]; -+ page_addr = gHvContext.synICMessagePage[cpu]; - msg = (struct hv_message *)page_addr + VMBUS_MESSAGE_SINT; - - DPRINT_ENTER(VMBUS); -@@ -248,7 +250,7 @@ static int VmbusOnISR(struct hv_driver *drv) - } - - /* TODO: Check if there are events to be process */ -- page_addr = gHvContext.synICEventPage[0]; -+ page_addr = gHvContext.synICEventPage[cpu]; - event = (union hv_synic_event_flags *)page_addr + VMBUS_MESSAGE_SINT; - - /* Since we are a child, we only need to check bit 0 */ -diff --git a/drivers/usb/core/devices.c b/drivers/usb/core/devices.c -index 96f1171..355dffc 100644 ---- a/drivers/usb/core/devices.c -+++ b/drivers/usb/core/devices.c -@@ -494,7 +494,7 @@ static ssize_t usb_device_dump(char __user **buffer, size_t *nbytes, - return 0; - /* allocate 2^1 pages = 8K (on i386); - * should be more than enough for one device */ -- pages_start = (char *)__get_free_pages(GFP_KERNEL, 1); -+ pages_start = (char *)__get_free_pages(GFP_NOIO, 1); - if (!pages_start) - return -ENOMEM; - -diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c -index 8b0c235..1a7d54b 100644 ---- a/drivers/usb/core/hub.c -+++ b/drivers/usb/core/hub.c -@@ -3286,6 +3286,9 @@ static void hub_events(void) - USB_PORT_FEAT_C_SUSPEND); - udev = hdev->children[i-1]; - if (udev) { -+ /* TRSMRCY = 10 msec */ -+ msleep(10); -+ - usb_lock_device(udev); - ret = remote_wakeup(hdev-> - children[i-1]); -diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c -index da718e8..980a8d2 100644 ---- a/drivers/usb/core/message.c -+++ b/drivers/usb/core/message.c -@@ -911,11 +911,11 @@ char *usb_cache_string(struct usb_device *udev, int index) - if (index <= 0) - return NULL; - -- buf = kmalloc(MAX_USB_STRING_SIZE, GFP_KERNEL); -+ buf = kmalloc(MAX_USB_STRING_SIZE, GFP_NOIO); - if (buf) { - len = usb_string(udev, index, buf, MAX_USB_STRING_SIZE); - if (len > 0) { -- smallbuf = kmalloc(++len, GFP_KERNEL); -+ smallbuf = kmalloc(++len, GFP_NOIO); - if (!smallbuf) - return buf; - memcpy(smallbuf, buf, len); -@@ -1682,7 +1682,7 @@ int usb_set_configuration(struct usb_device *dev, int configuration) - if (cp) { - nintf = cp->desc.bNumInterfaces; - new_interfaces = kmalloc(nintf * sizeof(*new_interfaces), -- GFP_KERNEL); -+ GFP_NOIO); - if (!new_interfaces) { - dev_err(&dev->dev, "Out of memory\n"); - return -ENOMEM; -@@ -1691,7 +1691,7 @@ int usb_set_configuration(struct usb_device *dev, int configuration) - for (; n < nintf; ++n) { - new_interfaces[n] = kzalloc( - sizeof(struct usb_interface), -- GFP_KERNEL); -+ GFP_NOIO); - if (!new_interfaces[n]) { - dev_err(&dev->dev, "Out of memory\n"); - ret = -ENOMEM; -diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c -index 8752e55..fcdcad4 100644 ---- a/drivers/usb/core/sysfs.c -+++ b/drivers/usb/core/sysfs.c -@@ -115,6 +115,12 @@ show_speed(struct device *dev, struct device_attribute *attr, char *buf) - case USB_SPEED_HIGH: - speed = "480"; - break; -+ case USB_SPEED_VARIABLE: -+ speed = "480"; -+ break; -+ case USB_SPEED_SUPER: -+ speed = "5000"; -+ break; - default: - speed = "unknown"; - } -diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c -index f5f5601..e18c677 100644 ---- a/drivers/usb/host/ehci-hcd.c -+++ b/drivers/usb/host/ehci-hcd.c -@@ -785,9 +785,10 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd) - - /* start 20 msec resume signaling from this port, - * and make khubd collect PORT_STAT_C_SUSPEND to -- * stop that signaling. -+ * stop that signaling. Use 5 ms extra for safety, -+ * like usb_port_resume() does. - */ -- ehci->reset_done [i] = jiffies + msecs_to_jiffies (20); -+ ehci->reset_done[i] = jiffies + msecs_to_jiffies(25); - ehci_dbg (ehci, "port %d remote wakeup\n", i + 1); - mod_timer(&hcd->rh_timer, ehci->reset_done[i]); - } -diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c -index 1b6f1c0..698f461 100644 ---- a/drivers/usb/host/ehci-hub.c -+++ b/drivers/usb/host/ehci-hub.c -@@ -120,9 +120,26 @@ static int ehci_bus_suspend (struct usb_hcd *hcd) - del_timer_sync(&ehci->watchdog); - del_timer_sync(&ehci->iaa_watchdog); - -- port = HCS_N_PORTS (ehci->hcs_params); - spin_lock_irq (&ehci->lock); - -+ /* Once the controller is stopped, port resumes that are already -+ * in progress won't complete. Hence if remote wakeup is enabled -+ * for the root hub and any ports are in the middle of a resume or -+ * remote wakeup, we must fail the suspend. -+ */ -+ if (hcd->self.root_hub->do_remote_wakeup) { -+ port = HCS_N_PORTS(ehci->hcs_params); -+ while (port--) { -+ if (ehci->reset_done[port] != 0) { -+ spin_unlock_irq(&ehci->lock); -+ ehci_dbg(ehci, "suspend failed because " -+ "port %d is resuming\n", -+ port + 1); -+ return -EBUSY; -+ } -+ } -+ } -+ - /* stop schedules, clean any completed work */ - if (HC_IS_RUNNING(hcd->state)) { - ehci_quiesce (ehci); -@@ -138,6 +155,7 @@ static int ehci_bus_suspend (struct usb_hcd *hcd) - */ - ehci->bus_suspended = 0; - ehci->owned_ports = 0; -+ port = HCS_N_PORTS(ehci->hcs_params); - while (port--) { - u32 __iomem *reg = &ehci->regs->port_status [port]; - u32 t1 = ehci_readl(ehci, reg) & ~PORT_RWC_BITS; -diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c -index 139a2cc..c0d4b39 100644 ---- a/drivers/usb/host/ehci-q.c -+++ b/drivers/usb/host/ehci-q.c -@@ -827,9 +827,10 @@ qh_make ( - * But interval 1 scheduling is simpler, and - * includes high bandwidth. - */ -- dbg ("intr period %d uframes, NYET!", -- urb->interval); -- goto done; -+ urb->interval = 1; -+ } else if (qh->period > ehci->periodic_size) { -+ qh->period = ehci->periodic_size; -+ urb->interval = qh->period << 3; - } - } else { - int think_time; -@@ -852,6 +853,10 @@ qh_make ( - usb_calc_bus_time (urb->dev->speed, - is_input, 0, max_packet (maxp))); - qh->period = urb->interval; -+ if (qh->period > ehci->periodic_size) { -+ qh->period = ehci->periodic_size; -+ urb->interval = qh->period; -+ } - } - } - -diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c -index 5cd0e48..99cd00f 100644 ---- a/drivers/usb/host/uhci-hcd.c -+++ b/drivers/usb/host/uhci-hcd.c -@@ -749,7 +749,20 @@ static int uhci_rh_suspend(struct usb_hcd *hcd) - spin_lock_irq(&uhci->lock); - if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) - rc = -ESHUTDOWN; -- else if (!uhci->dead) -+ else if (uhci->dead) -+ ; /* Dead controllers tell no tales */ -+ -+ /* Once the controller is stopped, port resumes that are already -+ * in progress won't complete. Hence if remote wakeup is enabled -+ * for the root hub and any ports are in the middle of a resume or -+ * remote wakeup, we must fail the suspend. -+ */ -+ else if (hcd->self.root_hub->do_remote_wakeup && -+ uhci->resuming_ports) { -+ dev_dbg(uhci_dev(uhci), "suspend failed because a port " -+ "is resuming\n"); -+ rc = -EBUSY; -+ } else - suspend_rh(uhci, UHCI_RH_SUSPENDED); - spin_unlock_irq(&uhci->lock); - return rc; -diff --git a/drivers/usb/host/uhci-hub.c b/drivers/usb/host/uhci-hub.c -index 885b585..8270055 100644 ---- a/drivers/usb/host/uhci-hub.c -+++ b/drivers/usb/host/uhci-hub.c -@@ -167,7 +167,7 @@ static void uhci_check_ports(struct uhci_hcd *uhci) - /* Port received a wakeup request */ - set_bit(port, &uhci->resuming_ports); - uhci->ports_timeout = jiffies + -- msecs_to_jiffies(20); -+ msecs_to_jiffies(25); - - /* Make sure we see the port again - * after the resuming period is over. */ -diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c -index bbe005c..e0fb294 100644 ---- a/drivers/usb/serial/generic.c -+++ b/drivers/usb/serial/generic.c -@@ -489,6 +489,8 @@ void usb_serial_generic_write_bulk_callback(struct urb *urb) - dbg("%s - port %d", __func__, port->number); - - if (port->serial->type->max_in_flight_urbs) { -+ kfree(urb->transfer_buffer); -+ - spin_lock_irqsave(&port->lock, flags); - --port->urbs_in_flight; - port->tx_bytes_flight -= urb->transfer_buffer_length; -diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h -index 64a0a2c..c932f90 100644 ---- a/drivers/usb/storage/unusual_devs.h -+++ b/drivers/usb/storage/unusual_devs.h -@@ -1807,13 +1807,6 @@ UNUSUAL_DEV( 0x2735, 0x100b, 0x0000, 0x9999, - US_SC_DEVICE, US_PR_DEVICE, NULL, - US_FL_GO_SLOW ), - --/* Reported by Rohan Hart */ --UNUSUAL_DEV( 0x2770, 0x915d, 0x0010, 0x0010, -- "INTOVA", -- "Pixtreme", -- US_SC_DEVICE, US_PR_DEVICE, NULL, -- US_FL_FIX_CAPACITY ), -- - /* Reported by Frederic Marchal - * Mio Moov 330 - */ -diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c -index 716c8d7..33197fa 100644 ---- a/drivers/usb/storage/usb.c -+++ b/drivers/usb/storage/usb.c -@@ -430,7 +430,8 @@ static void adjust_quirks(struct us_data *us) - u16 vid = le16_to_cpu(us->pusb_dev->descriptor.idVendor); - u16 pid = le16_to_cpu(us->pusb_dev->descriptor.idProduct); - unsigned f = 0; -- unsigned int mask = (US_FL_SANE_SENSE | US_FL_FIX_CAPACITY | -+ unsigned int mask = (US_FL_SANE_SENSE | US_FL_BAD_SENSE | -+ US_FL_FIX_CAPACITY | - US_FL_CAPACITY_HEURISTICS | US_FL_IGNORE_DEVICE | - US_FL_NOT_LOCKABLE | US_FL_MAX_SECTORS_64 | - US_FL_CAPACITY_OK | US_FL_IGNORE_RESIDUE | -diff --git a/fs/ecryptfs/crypto.c b/fs/ecryptfs/crypto.c -index fbb6e5e..7cb0a59 100644 ---- a/fs/ecryptfs/crypto.c -+++ b/fs/ecryptfs/crypto.c -@@ -1748,7 +1748,7 @@ ecryptfs_process_key_cipher(struct crypto_blkcipher **key_tfm, - char *cipher_name, size_t *key_size) - { - char dummy_key[ECRYPTFS_MAX_KEY_BYTES]; -- char *full_alg_name; -+ char *full_alg_name = NULL; - int rc; - - *key_tfm = NULL; -@@ -1763,7 +1763,6 @@ ecryptfs_process_key_cipher(struct crypto_blkcipher **key_tfm, - if (rc) - goto out; - *key_tfm = crypto_alloc_blkcipher(full_alg_name, 0, CRYPTO_ALG_ASYNC); -- kfree(full_alg_name); - if (IS_ERR(*key_tfm)) { - rc = PTR_ERR(*key_tfm); - printk(KERN_ERR "Unable to allocate crypto cipher with name " -@@ -1786,6 +1785,7 @@ ecryptfs_process_key_cipher(struct crypto_blkcipher **key_tfm, - goto out; - } - out: -+ kfree(full_alg_name); - return rc; - } - -diff --git a/fs/ecryptfs/file.c b/fs/ecryptfs/file.c -index 9e94405..1744f17 100644 ---- a/fs/ecryptfs/file.c -+++ b/fs/ecryptfs/file.c -@@ -191,13 +191,6 @@ static int ecryptfs_open(struct inode *inode, struct file *file) - | ECRYPTFS_ENCRYPTED); - } - mutex_unlock(&crypt_stat->cs_mutex); -- if ((ecryptfs_inode_to_private(inode)->lower_file->f_flags & O_RDONLY) -- && !(file->f_flags & O_RDONLY)) { -- rc = -EPERM; -- printk(KERN_WARNING "%s: Lower persistent file is RO; eCryptfs " -- "file must hence be opened RO\n", __func__); -- goto out; -- } - if (!ecryptfs_inode_to_private(inode)->lower_file) { - rc = ecryptfs_init_persistent_file(ecryptfs_dentry); - if (rc) { -@@ -208,6 +201,13 @@ static int ecryptfs_open(struct inode *inode, struct file *file) - goto out; - } - } -+ if ((ecryptfs_inode_to_private(inode)->lower_file->f_flags & O_RDONLY) -+ && !(file->f_flags & O_RDONLY)) { -+ rc = -EPERM; -+ printk(KERN_WARNING "%s: Lower persistent file is RO; eCryptfs " -+ "file must hence be opened RO\n", __func__); -+ goto out; -+ } - ecryptfs_set_file_lower( - file, ecryptfs_inode_to_private(inode)->lower_file); - if (S_ISDIR(ecryptfs_dentry->d_inode->i_mode)) { -diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h -index adf99c6..912b8ff 100644 ---- a/include/linux/blkdev.h -+++ b/include/linux/blkdev.h -@@ -942,6 +942,8 @@ extern void blk_queue_io_opt(struct request_queue *q, unsigned int opt); - extern void blk_set_default_limits(struct queue_limits *lim); - extern int blk_stack_limits(struct queue_limits *t, struct queue_limits *b, - sector_t offset); -+extern int bdev_stack_limits(struct queue_limits *t, struct block_device *bdev, -+ sector_t offset); - extern void disk_stack_limits(struct gendisk *disk, struct block_device *bdev, - sector_t offset); - extern void blk_queue_stack_limits(struct request_queue *t, struct request_queue *b); -diff --git a/include/linux/enclosure.h b/include/linux/enclosure.h -index 90d1c21..9a33c5f 100644 ---- a/include/linux/enclosure.h -+++ b/include/linux/enclosure.h -@@ -42,6 +42,8 @@ enum enclosure_status { - ENCLOSURE_STATUS_NOT_INSTALLED, - ENCLOSURE_STATUS_UNKNOWN, - ENCLOSURE_STATUS_UNAVAILABLE, -+ /* last element for counting purposes */ -+ ENCLOSURE_STATUS_MAX - }; - - /* SFF-8485 activity light settings */ -diff --git a/kernel/perf_event.c b/kernel/perf_event.c -index 6eee915..413d101 100644 ---- a/kernel/perf_event.c -+++ b/kernel/perf_event.c -@@ -1359,6 +1359,9 @@ static void perf_ctx_adjust_freq(struct perf_event_context *ctx) - if (event->state != PERF_EVENT_STATE_ACTIVE) - continue; - -+ if (event->cpu != -1 && event->cpu != smp_processor_id()) -+ continue; -+ - hwc = &event->hw; - - interrupts = hwc->interrupts; -@@ -3226,6 +3229,12 @@ static void perf_event_task_output(struct perf_event *event, - - static int perf_event_task_match(struct perf_event *event) - { -+ if (event->state != PERF_EVENT_STATE_ACTIVE) -+ return 0; -+ -+ if (event->cpu != -1 && event->cpu != smp_processor_id()) -+ return 0; -+ - if (event->attr.comm || event->attr.mmap || event->attr.task) - return 1; - -@@ -3255,13 +3264,13 @@ static void perf_event_task_event(struct perf_task_event *task_event) - - cpuctx = &get_cpu_var(perf_cpu_context); - perf_event_task_ctx(&cpuctx->ctx, task_event); -- put_cpu_var(perf_cpu_context); - - rcu_read_lock(); - if (!ctx) - ctx = rcu_dereference(task_event->task->perf_event_ctxp); - if (ctx) - perf_event_task_ctx(ctx, task_event); -+ put_cpu_var(perf_cpu_context); - rcu_read_unlock(); - } - -@@ -3338,6 +3347,12 @@ static void perf_event_comm_output(struct perf_event *event, - - static int perf_event_comm_match(struct perf_event *event) - { -+ if (event->state != PERF_EVENT_STATE_ACTIVE) -+ return 0; -+ -+ if (event->cpu != -1 && event->cpu != smp_processor_id()) -+ return 0; -+ - if (event->attr.comm) - return 1; - -@@ -3378,7 +3393,6 @@ static void perf_event_comm_event(struct perf_comm_event *comm_event) - - cpuctx = &get_cpu_var(perf_cpu_context); - perf_event_comm_ctx(&cpuctx->ctx, comm_event); -- put_cpu_var(perf_cpu_context); - - rcu_read_lock(); - /* -@@ -3388,6 +3402,7 @@ static void perf_event_comm_event(struct perf_comm_event *comm_event) - ctx = rcu_dereference(current->perf_event_ctxp); - if (ctx) - perf_event_comm_ctx(ctx, comm_event); -+ put_cpu_var(perf_cpu_context); - rcu_read_unlock(); - } - -@@ -3462,6 +3477,12 @@ static void perf_event_mmap_output(struct perf_event *event, - static int perf_event_mmap_match(struct perf_event *event, - struct perf_mmap_event *mmap_event) - { -+ if (event->state != PERF_EVENT_STATE_ACTIVE) -+ return 0; -+ -+ if (event->cpu != -1 && event->cpu != smp_processor_id()) -+ return 0; -+ - if (event->attr.mmap) - return 1; - -@@ -3539,7 +3560,6 @@ got_name: - - cpuctx = &get_cpu_var(perf_cpu_context); - perf_event_mmap_ctx(&cpuctx->ctx, mmap_event); -- put_cpu_var(perf_cpu_context); - - rcu_read_lock(); - /* -@@ -3549,6 +3569,7 @@ got_name: - ctx = rcu_dereference(current->perf_event_ctxp); - if (ctx) - perf_event_mmap_ctx(ctx, mmap_event); -+ put_cpu_var(perf_cpu_context); - rcu_read_unlock(); - - kfree(buf); -@@ -3811,6 +3832,9 @@ static int perf_swevent_match(struct perf_event *event, - enum perf_type_id type, - u32 event_id, struct pt_regs *regs) - { -+ if (event->cpu != -1 && event->cpu != smp_processor_id()) -+ return 0; -+ - if (!perf_swevent_is_counting(event)) - return 0; - -diff --git a/mm/vmalloc.c b/mm/vmalloc.c -index 7758726..a3a99d3 100644 ---- a/mm/vmalloc.c -+++ b/mm/vmalloc.c -@@ -555,10 +555,8 @@ static void __purge_vmap_area_lazy(unsigned long *start, unsigned long *end, - } - rcu_read_unlock(); - -- if (nr) { -- BUG_ON(nr > atomic_read(&vmap_lazy_nr)); -+ if (nr) - atomic_sub(nr, &vmap_lazy_nr); -- } - - if (nr || force_flush) - flush_tlb_kernel_range(*start, *end); -diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c -index e8a510d..4101afe 100644 ---- a/tools/perf/builtin-timechart.c -+++ b/tools/perf/builtin-timechart.c -@@ -275,7 +275,7 @@ static u64 cpus_pstate_state[MAX_CPUS]; - static int - process_comm_event(event_t *event) - { -- pid_set_comm(event->comm.pid, event->comm.comm); -+ pid_set_comm(event->comm.tid, event->comm.comm); - return 0; - } - static int diff --git a/debian/patches/bugfix/all/stable/2.6.32.7.patch b/debian/patches/bugfix/all/stable/2.6.32.7.patch deleted file mode 100644 index af74f2838..000000000 --- a/debian/patches/bugfix/all/stable/2.6.32.7.patch +++ /dev/null @@ -1,4403 +0,0 @@ -diff --git a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile -index ab8300f..50075df 100644 ---- a/Documentation/DocBook/Makefile -+++ b/Documentation/DocBook/Makefile -@@ -32,10 +32,10 @@ PS_METHOD = $(prefer-db2x) - - ### - # The targets that may be used. --PHONY += xmldocs sgmldocs psdocs pdfdocs htmldocs mandocs installmandocs cleandocs media -+PHONY += xmldocs sgmldocs psdocs pdfdocs htmldocs mandocs installmandocs cleandocs xmldoclinks - - BOOKS := $(addprefix $(obj)/,$(DOCBOOKS)) --xmldocs: $(BOOKS) -+xmldocs: $(BOOKS) xmldoclinks - sgmldocs: xmldocs - - PS := $(patsubst %.xml, %.ps, $(BOOKS)) -@@ -45,15 +45,24 @@ PDF := $(patsubst %.xml, %.pdf, $(BOOKS)) - pdfdocs: $(PDF) - - HTML := $(sort $(patsubst %.xml, %.html, $(BOOKS))) --htmldocs: media $(HTML) -+htmldocs: $(HTML) - $(call build_main_index) -+ $(call build_images) - - MAN := $(patsubst %.xml, %.9, $(BOOKS)) - mandocs: $(MAN) - --media: -- mkdir -p $(srctree)/Documentation/DocBook/media/ -- cp $(srctree)/Documentation/DocBook/dvb/*.png $(srctree)/Documentation/DocBook/v4l/*.gif $(srctree)/Documentation/DocBook/media/ -+build_images = mkdir -p $(objtree)/Documentation/DocBook/media/ && \ -+ cp $(srctree)/Documentation/DocBook/dvb/*.png $(srctree)/Documentation/DocBook/v4l/*.gif $(objtree)/Documentation/DocBook/media/ -+ -+xmldoclinks: -+ifneq ($(objtree),$(srctree)) -+ for dep in dvb media-entities.tmpl media-indices.tmpl v4l; do \ -+ rm -f $(objtree)/Documentation/DocBook/$$dep \ -+ && ln -s $(srctree)/Documentation/DocBook/$$dep $(objtree)/Documentation/DocBook/ \ -+ || exit; \ -+ done -+endif - - installmandocs: mandocs - mkdir -p /usr/local/man/man9/ -diff --git a/Documentation/video4linux/CARDLIST.saa7134 b/Documentation/video4linux/CARDLIST.saa7134 -index 2620d60..94e255a 100644 ---- a/Documentation/video4linux/CARDLIST.saa7134 -+++ b/Documentation/video4linux/CARDLIST.saa7134 -@@ -172,3 +172,4 @@ - 171 -> Beholder BeholdTV X7 [5ace:7595] - 172 -> RoverMedia TV Link Pro FM [19d1:0138] - 173 -> Zolid Hybrid TV Tuner PCI [1131:2004] -+174 -> Asus Europa Hybrid OEM [1043:4847] -diff --git a/Makefile b/Makefile -index 20da312..07d3c6a 100644 -diff --git a/arch/arm/mach-davinci/dm646x.c b/arch/arm/mach-davinci/dm646x.c -index 0976049..36e4fb4 100644 ---- a/arch/arm/mach-davinci/dm646x.c -+++ b/arch/arm/mach-davinci/dm646x.c -@@ -789,7 +789,14 @@ static struct davinci_id dm646x_ids[] = { - .part_no = 0xb770, - .manufacturer = 0x017, - .cpu_id = DAVINCI_CPU_ID_DM6467, -- .name = "dm6467", -+ .name = "dm6467_rev1.x", -+ }, -+ { -+ .variant = 0x1, -+ .part_no = 0xb770, -+ .manufacturer = 0x017, -+ .cpu_id = DAVINCI_CPU_ID_DM6467, -+ .name = "dm6467_rev3.x", - }, - }; - -diff --git a/arch/powerpc/sysdev/fsl_pci.c b/arch/powerpc/sysdev/fsl_pci.c -index ae88b14..e82749b 100644 ---- a/arch/powerpc/sysdev/fsl_pci.c -+++ b/arch/powerpc/sysdev/fsl_pci.c -@@ -392,8 +392,22 @@ DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8536, quirk_fsl_pcie_header); - DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8641, quirk_fsl_pcie_header); - DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8641D, quirk_fsl_pcie_header); - DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8610, quirk_fsl_pcie_header); -+DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P1011E, quirk_fsl_pcie_header); -+DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P1011, quirk_fsl_pcie_header); -+DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P1013E, quirk_fsl_pcie_header); -+DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P1013, quirk_fsl_pcie_header); -+DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P1020E, quirk_fsl_pcie_header); -+DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P1020, quirk_fsl_pcie_header); -+DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P1022E, quirk_fsl_pcie_header); -+DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P1022, quirk_fsl_pcie_header); -+DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P2010E, quirk_fsl_pcie_header); -+DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P2010, quirk_fsl_pcie_header); - DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P2020E, quirk_fsl_pcie_header); - DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P2020, quirk_fsl_pcie_header); -+DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P4040E, quirk_fsl_pcie_header); -+DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P4040, quirk_fsl_pcie_header); -+DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P4080E, quirk_fsl_pcie_header); -+DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P4080, quirk_fsl_pcie_header); - #endif /* CONFIG_PPC_85xx || CONFIG_PPC_86xx */ - - #if defined(CONFIG_PPC_83xx) || defined(CONFIG_PPC_MPC512x) -diff --git a/arch/s390/kvm/intercept.c b/arch/s390/kvm/intercept.c -index ba9d8a7..b400964 100644 ---- a/arch/s390/kvm/intercept.c -+++ b/arch/s390/kvm/intercept.c -@@ -213,7 +213,7 @@ static int handle_instruction_and_prog(struct kvm_vcpu *vcpu) - return rc2; - } - --static const intercept_handler_t intercept_funcs[0x48 >> 2] = { -+static const intercept_handler_t intercept_funcs[] = { - [0x00 >> 2] = handle_noop, - [0x04 >> 2] = handle_instruction, - [0x08 >> 2] = handle_prog, -@@ -230,7 +230,7 @@ int kvm_handle_sie_intercept(struct kvm_vcpu *vcpu) - intercept_handler_t func; - u8 code = vcpu->arch.sie_block->icptcode; - -- if (code & 3 || code > 0x48) -+ if (code & 3 || (code >> 2) >= ARRAY_SIZE(intercept_funcs)) - return -ENOTSUPP; - func = intercept_funcs[code >> 2]; - if (func) -diff --git a/arch/x86/kernel/cpu/intel.c b/arch/x86/kernel/cpu/intel.c -index 40e1835..a2a03cf 100644 ---- a/arch/x86/kernel/cpu/intel.c -+++ b/arch/x86/kernel/cpu/intel.c -@@ -70,7 +70,6 @@ static void __cpuinit early_init_intel(struct cpuinfo_x86 *c) - if (c->x86_power & (1 << 8)) { - set_cpu_cap(c, X86_FEATURE_CONSTANT_TSC); - set_cpu_cap(c, X86_FEATURE_NONSTOP_TSC); -- set_cpu_cap(c, X86_FEATURE_TSC_RELIABLE); - sched_clock_stable = 1; - } - -diff --git a/arch/x86/kernel/cpuid.c b/arch/x86/kernel/cpuid.c -index f8590c5..0c91110 100644 ---- a/arch/x86/kernel/cpuid.c -+++ b/arch/x86/kernel/cpuid.c -@@ -234,7 +234,7 @@ static void __exit cpuid_exit(void) - for_each_online_cpu(cpu) - cpuid_device_destroy(cpu); - class_destroy(cpuid_class); -- unregister_chrdev(CPUID_MAJOR, "cpu/cpuid"); -+ __unregister_chrdev(CPUID_MAJOR, 0, NR_CPUS, "cpu/cpuid"); - unregister_hotcpu_notifier(&cpuid_class_cpu_notifier); - } - -diff --git a/arch/x86/kernel/msr.c b/arch/x86/kernel/msr.c -index b42e63b..5eaeb5e 100644 ---- a/arch/x86/kernel/msr.c -+++ b/arch/x86/kernel/msr.c -@@ -290,7 +290,7 @@ static void __exit msr_exit(void) - for_each_online_cpu(cpu) - msr_device_destroy(cpu); - class_destroy(msr_class); -- unregister_chrdev(MSR_MAJOR, "cpu/msr"); -+ __unregister_chrdev(MSR_MAJOR, 0, NR_CPUS, "cpu/msr"); - unregister_hotcpu_notifier(&msr_class_cpu_notifier); - } - -diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c -index cd982f4..597683a 100644 ---- a/arch/x86/kernel/tsc.c -+++ b/arch/x86/kernel/tsc.c -@@ -763,6 +763,7 @@ void mark_tsc_unstable(char *reason) - { - if (!tsc_unstable) { - tsc_unstable = 1; -+ sched_clock_stable = 0; - printk(KERN_INFO "Marking TSC unstable due to %s\n", reason); - /* Change only the rating, when not registered */ - if (clocksource_tsc.mult) -diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c -index 41659fb..8dfeaaa 100644 ---- a/arch/x86/kvm/lapic.c -+++ b/arch/x86/kvm/lapic.c -@@ -374,6 +374,12 @@ static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode, - if (unlikely(!apic_enabled(apic))) - break; - -+ if (trig_mode) { -+ apic_debug("level trig mode for vector %d", vector); -+ apic_set_vector(vector, apic->regs + APIC_TMR); -+ } else -+ apic_clear_vector(vector, apic->regs + APIC_TMR); -+ - result = !apic_test_and_set_irr(vector, apic); - trace_kvm_apic_accept_irq(vcpu->vcpu_id, delivery_mode, - trig_mode, vector, !result); -@@ -384,11 +390,6 @@ static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode, - break; - } - -- if (trig_mode) { -- apic_debug("level trig mode for vector %d", vector); -- apic_set_vector(vector, apic->regs + APIC_TMR); -- } else -- apic_clear_vector(vector, apic->regs + APIC_TMR); - kvm_vcpu_kick(vcpu); - break; - -diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c -index 818b92a..3a01519 100644 ---- a/arch/x86/kvm/mmu.c -+++ b/arch/x86/kvm/mmu.c -@@ -477,7 +477,7 @@ static int host_mapping_level(struct kvm *kvm, gfn_t gfn) - - addr = gfn_to_hva(kvm, gfn); - if (kvm_is_error_hva(addr)) -- return page_size; -+ return PT_PAGE_TABLE_LEVEL; - - down_read(¤t->mm->mmap_sem); - vma = find_vma(current->mm, addr); -@@ -515,11 +515,9 @@ static int mapping_level(struct kvm_vcpu *vcpu, gfn_t large_gfn) - if (host_level == PT_PAGE_TABLE_LEVEL) - return host_level; - -- for (level = PT_DIRECTORY_LEVEL; level <= host_level; ++level) { -- -+ for (level = PT_DIRECTORY_LEVEL; level <= host_level; ++level) - if (has_wrprotected_page(vcpu->kvm, large_gfn, level)) - break; -- } - - return level - 1; - } -diff --git a/arch/x86/kvm/paging_tmpl.h b/arch/x86/kvm/paging_tmpl.h -index 85e12cd..5fa3325 100644 ---- a/arch/x86/kvm/paging_tmpl.h -+++ b/arch/x86/kvm/paging_tmpl.h -@@ -150,7 +150,9 @@ walk: - walker->table_gfn[walker->level - 1] = table_gfn; - walker->pte_gpa[walker->level - 1] = pte_gpa; - -- kvm_read_guest(vcpu->kvm, pte_gpa, &pte, sizeof(pte)); -+ if (kvm_read_guest(vcpu->kvm, pte_gpa, &pte, sizeof(pte))) -+ goto not_present; -+ - trace_kvm_mmu_paging_element(pte, walker->level); - - if (!is_present_gpte(pte)) -diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c -index 97b31fa..6378e07 100644 ---- a/arch/x86/kvm/x86.c -+++ b/arch/x86/kvm/x86.c -@@ -4766,12 +4766,13 @@ int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu) - GFP_KERNEL); - if (!vcpu->arch.mce_banks) { - r = -ENOMEM; -- goto fail_mmu_destroy; -+ goto fail_free_lapic; - } - vcpu->arch.mcg_cap = KVM_MAX_MCE_BANKS; - - return 0; -- -+fail_free_lapic: -+ kvm_free_lapic(vcpu); - fail_mmu_destroy: - kvm_mmu_destroy(vcpu); - fail_free_pio_data: -@@ -4782,6 +4783,7 @@ fail: - - void kvm_arch_vcpu_uninit(struct kvm_vcpu *vcpu) - { -+ kfree(vcpu->arch.mce_banks); - kvm_free_lapic(vcpu); - down_read(&vcpu->kvm->slots_lock); - kvm_mmu_destroy(vcpu); -diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c -index bbd066e..a8f3ca6 100644 ---- a/drivers/acpi/processor_idle.c -+++ b/drivers/acpi/processor_idle.c -@@ -299,6 +299,17 @@ static int acpi_processor_get_power_info_fadt(struct acpi_processor *pr) - pr->power.states[ACPI_STATE_C2].latency = acpi_gbl_FADT.C2latency; - pr->power.states[ACPI_STATE_C3].latency = acpi_gbl_FADT.C3latency; - -+ /* -+ * FADT specified C2 latency must be less than or equal to -+ * 100 microseconds. -+ */ -+ if (acpi_gbl_FADT.C2latency > ACPI_PROCESSOR_MAX_C2_LATENCY) { -+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, -+ "C2 latency too large [%d]\n", acpi_gbl_FADT.C2latency)); -+ /* invalidate C2 */ -+ pr->power.states[ACPI_STATE_C2].address = 0; -+ } -+ - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "lvl2[0x%08x] lvl3[0x%08x]\n", - pr->power.states[ACPI_STATE_C2].address, -@@ -495,16 +506,6 @@ static void acpi_processor_power_verify_c2(struct acpi_processor_cx *cx) - return; - - /* -- * C2 latency must be less than or equal to 100 -- * microseconds. -- */ -- else if (cx->latency > ACPI_PROCESSOR_MAX_C2_LATENCY) { -- ACPI_DEBUG_PRINT((ACPI_DB_INFO, -- "latency too large [%d]\n", cx->latency)); -- return; -- } -- -- /* - * Otherwise we've met all of our C2 requirements. - * Normalize the C2 latency to expidite policy - */ -diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c -index a3241a1..9519c77 100644 ---- a/drivers/ata/ahci.c -+++ b/drivers/ata/ahci.c -@@ -113,6 +113,7 @@ enum { - board_ahci_mcp65 = 6, - board_ahci_nopmp = 7, - board_ahci_yesncq = 8, -+ board_ahci_nosntf = 9, - - /* global controller registers */ - HOST_CAP = 0x00, /* host capabilities */ -@@ -235,6 +236,7 @@ enum { - AHCI_HFLAG_NO_SUSPEND = (1 << 10), /* don't suspend */ - AHCI_HFLAG_SRST_TOUT_IS_OFFLINE = (1 << 11), /* treat SRST timeout as - link offline */ -+ AHCI_HFLAG_NO_SNTF = (1 << 12), /* no sntf */ - - /* ap->flags bits */ - -@@ -508,7 +510,7 @@ static const struct ata_port_info ahci_port_info[] = { - .udma_mask = ATA_UDMA6, - .port_ops = &ahci_ops, - }, -- /* board_ahci_yesncq */ -+ [board_ahci_yesncq] = - { - AHCI_HFLAGS (AHCI_HFLAG_YES_NCQ), - .flags = AHCI_FLAG_COMMON, -@@ -516,6 +518,14 @@ static const struct ata_port_info ahci_port_info[] = { - .udma_mask = ATA_UDMA6, - .port_ops = &ahci_ops, - }, -+ [board_ahci_nosntf] = -+ { -+ AHCI_HFLAGS (AHCI_HFLAG_NO_SNTF), -+ .flags = AHCI_FLAG_COMMON, -+ .pio_mask = ATA_PIO4, -+ .udma_mask = ATA_UDMA6, -+ .port_ops = &ahci_ops, -+ }, - }; - - static const struct pci_device_id ahci_pci_tbl[] = { -@@ -531,7 +541,7 @@ static const struct pci_device_id ahci_pci_tbl[] = { - { PCI_VDEVICE(INTEL, 0x2683), board_ahci }, /* ESB2 */ - { PCI_VDEVICE(INTEL, 0x27c6), board_ahci }, /* ICH7-M DH */ - { PCI_VDEVICE(INTEL, 0x2821), board_ahci }, /* ICH8 */ -- { PCI_VDEVICE(INTEL, 0x2822), board_ahci }, /* ICH8 */ -+ { PCI_VDEVICE(INTEL, 0x2822), board_ahci_nosntf }, /* ICH8 */ - { PCI_VDEVICE(INTEL, 0x2824), board_ahci }, /* ICH8 */ - { PCI_VDEVICE(INTEL, 0x2829), board_ahci }, /* ICH8M */ - { PCI_VDEVICE(INTEL, 0x282a), board_ahci }, /* ICH8M */ -@@ -849,6 +859,12 @@ static void ahci_save_initial_config(struct pci_dev *pdev, - cap &= ~HOST_CAP_PMP; - } - -+ if ((cap & HOST_CAP_SNTF) && (hpriv->flags & AHCI_HFLAG_NO_SNTF)) { -+ dev_printk(KERN_INFO, &pdev->dev, -+ "controller can't do SNTF, turning off CAP_SNTF\n"); -+ cap &= ~HOST_CAP_SNTF; -+ } -+ - if (pdev->vendor == PCI_VENDOR_ID_JMICRON && pdev->device == 0x2361 && - port_map != 1) { - dev_printk(KERN_INFO, &pdev->dev, -diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c -index 9ac4e37..0c6155f 100644 ---- a/drivers/ata/ata_piix.c -+++ b/drivers/ata/ata_piix.c -@@ -869,10 +869,10 @@ static void do_pata_set_dmamode(struct ata_port *ap, struct ata_device *adev, in - (timings[pio][1] << 8); - } - -- if (ap->udma_mask) { -+ if (ap->udma_mask) - udma_enable &= ~(1 << devid); -- pci_write_config_word(dev, master_port, master_data); -- } -+ -+ pci_write_config_word(dev, master_port, master_data); - } - /* Don't scribble on 0x48 if the controller does not support UDMA */ - if (ap->udma_mask) -diff --git a/drivers/base/devtmpfs.c b/drivers/base/devtmpfs.c -index a1cb5af..33faaa2 100644 ---- a/drivers/base/devtmpfs.c -+++ b/drivers/base/devtmpfs.c -@@ -353,6 +353,7 @@ int __init devtmpfs_init(void) - { - int err; - struct vfsmount *mnt; -+ char options[] = "mode=0755"; - - err = register_filesystem(&dev_fs_type); - if (err) { -@@ -361,7 +362,7 @@ int __init devtmpfs_init(void) - return err; - } - -- mnt = kern_mount(&dev_fs_type); -+ mnt = kern_mount_data(&dev_fs_type, options); - if (IS_ERR(mnt)) { - err = PTR_ERR(mnt); - printk(KERN_ERR "devtmpfs: unable to create devtmpfs %i\n", err); -diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c -index 938100f..3a2ccb0 100644 ---- a/drivers/firmware/dmi_scan.c -+++ b/drivers/firmware/dmi_scan.c -@@ -429,7 +429,7 @@ static bool dmi_matches(const struct dmi_system_id *dmi) - for (i = 0; i < ARRAY_SIZE(dmi->matches); i++) { - int s = dmi->matches[i].slot; - if (s == DMI_NONE) -- continue; -+ break; - if (dmi_ident[s] - && strstr(dmi_ident[s], dmi->matches[i].substr)) - continue; -@@ -440,6 +440,15 @@ static bool dmi_matches(const struct dmi_system_id *dmi) - } - - /** -+ * dmi_is_end_of_table - check for end-of-table marker -+ * @dmi: pointer to the dmi_system_id structure to check -+ */ -+static bool dmi_is_end_of_table(const struct dmi_system_id *dmi) -+{ -+ return dmi->matches[0].slot == DMI_NONE; -+} -+ -+/** - * dmi_check_system - check system DMI data - * @list: array of dmi_system_id structures to match against - * All non-null elements of the list must match -@@ -457,7 +466,7 @@ int dmi_check_system(const struct dmi_system_id *list) - int count = 0; - const struct dmi_system_id *d; - -- for (d = list; d->ident; d++) -+ for (d = list; !dmi_is_end_of_table(d); d++) - if (dmi_matches(d)) { - count++; - if (d->callback && d->callback(d)) -@@ -484,7 +493,7 @@ const struct dmi_system_id *dmi_first_match(const struct dmi_system_id *list) - { - const struct dmi_system_id *d; - -- for (d = list; d->ident; d++) -+ for (d = list; !dmi_is_end_of_table(d); d++) - if (dmi_matches(d)) - return d; - -diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c -index 03bd703..5d901f6 100644 ---- a/drivers/hid/usbhid/hid-core.c -+++ b/drivers/hid/usbhid/hid-core.c -@@ -998,7 +998,8 @@ static int usbhid_start(struct hid_device *hid) - usbhid->urbctrl->transfer_dma = usbhid->ctrlbuf_dma; - usbhid->urbctrl->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP); - -- usbhid_init_reports(hid); -+ if (!(hid->quirks & HID_QUIRK_NO_INIT_REPORTS)) -+ usbhid_init_reports(hid); - - set_bit(HID_STARTED, &usbhid->iofl); - -diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c -index 0d9045a..5713b93 100644 ---- a/drivers/hid/usbhid/hid-quirks.c -+++ b/drivers/hid/usbhid/hid-quirks.c -@@ -280,7 +280,7 @@ u32 usbhid_lookup_quirk(const u16 idVendor, const u16 idProduct) - if (idVendor == USB_VENDOR_ID_NCR && - idProduct >= USB_DEVICE_ID_NCR_FIRST && - idProduct <= USB_DEVICE_ID_NCR_LAST) -- return HID_QUIRK_NOGET; -+ return HID_QUIRK_NO_INIT_REPORTS; - - down_read(&dquirks_rwsem); - bl_entry = usbhid_exists_dquirk(idVendor, idProduct); -diff --git a/drivers/hwmon/fschmd.c b/drivers/hwmon/fschmd.c -index da1b1f9..f600813 100644 ---- a/drivers/hwmon/fschmd.c -+++ b/drivers/hwmon/fschmd.c -@@ -767,6 +767,7 @@ leave: - static int watchdog_open(struct inode *inode, struct file *filp) - { - struct fschmd_data *pos, *data = NULL; -+ int watchdog_is_open; - - /* We get called from drivers/char/misc.c with misc_mtx hold, and we - call misc_register() from fschmd_probe() with watchdog_data_mutex -@@ -781,10 +782,12 @@ static int watchdog_open(struct inode *inode, struct file *filp) - } - } - /* Note we can never not have found data, so we don't check for this */ -- kref_get(&data->kref); -+ watchdog_is_open = test_and_set_bit(0, &data->watchdog_is_open); -+ if (!watchdog_is_open) -+ kref_get(&data->kref); - mutex_unlock(&watchdog_data_mutex); - -- if (test_and_set_bit(0, &data->watchdog_is_open)) -+ if (watchdog_is_open) - return -EBUSY; - - /* Start the watchdog */ -diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c -index 2bf5116..df3eb8c 100644 ---- a/drivers/infiniband/ulp/ipoib/ipoib_main.c -+++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c -@@ -884,6 +884,7 @@ struct ipoib_neigh *ipoib_neigh_alloc(struct neighbour *neighbour, - - neigh->neighbour = neighbour; - neigh->dev = dev; -+ memset(&neigh->dgid.raw, 0, sizeof (union ib_gid)); - *to_ipoib_neigh(neighbour) = neigh; - skb_queue_head_init(&neigh->queue); - ipoib_cm_set(neigh, NULL); -diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c -index f361106..fc8823b 100644 ---- a/drivers/input/mouse/alps.c -+++ b/drivers/input/mouse/alps.c -@@ -5,6 +5,7 @@ - * Copyright (c) 2003-2005 Peter Osterlund - * Copyright (c) 2004 Dmitry Torokhov - * Copyright (c) 2005 Vojtech Pavlik -+ * Copyright (c) 2009 Sebastian Kapfer - * - * ALPS detection, tap switching and status querying info is taken from - * tpconfig utility (by C. Scott Ananian and Bruce Kall). -@@ -35,6 +36,8 @@ - #define ALPS_OLDPROTO 0x10 - #define ALPS_PASS 0x20 - #define ALPS_FW_BK_2 0x40 -+#define ALPS_PS2_INTERLEAVED 0x80 /* 3-byte PS/2 packet interleaved with -+ 6-byte ALPS packet */ - - static const struct alps_model_info alps_model_data[] = { - { { 0x32, 0x02, 0x14 }, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* Toshiba Salellite Pro M10 */ -@@ -55,7 +58,9 @@ static const struct alps_model_info alps_model_data[] = { - { { 0x20, 0x02, 0x0e }, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* XXX */ - { { 0x22, 0x02, 0x0a }, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, - { { 0x22, 0x02, 0x14 }, 0xff, 0xff, ALPS_PASS | ALPS_DUALPOINT }, /* Dell Latitude D600 */ -- { { 0x62, 0x02, 0x14 }, 0xcf, 0xcf, ALPS_PASS | ALPS_DUALPOINT }, /* Dell Latitude E6500 */ -+ /* Dell Latitude E5500, E6400, E6500, Precision M4400 */ -+ { { 0x62, 0x02, 0x14 }, 0xcf, 0xcf, -+ ALPS_PASS | ALPS_DUALPOINT | ALPS_PS2_INTERLEAVED }, - { { 0x73, 0x02, 0x50 }, 0xcf, 0xcf, ALPS_FW_BK_1 }, /* Dell Vostro 1400 */ - }; - -@@ -66,20 +71,88 @@ static const struct alps_model_info alps_model_data[] = { - */ - - /* -- * ALPS abolute Mode - new format -+ * PS/2 packet format -+ * -+ * byte 0: 0 0 YSGN XSGN 1 M R L -+ * byte 1: X7 X6 X5 X4 X3 X2 X1 X0 -+ * byte 2: Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0 -+ * -+ * Note that the device never signals overflow condition. -+ * -+ * ALPS absolute Mode - new format - * - * byte 0: 1 ? ? ? 1 ? ? ? - * byte 1: 0 x6 x5 x4 x3 x2 x1 x0 -- * byte 2: 0 x10 x9 x8 x7 ? fin ges -+ * byte 2: 0 x10 x9 x8 x7 ? fin ges - * byte 3: 0 y9 y8 y7 1 M R L - * byte 4: 0 y6 y5 y4 y3 y2 y1 y0 - * byte 5: 0 z6 z5 z4 z3 z2 z1 z0 - * -+ * Dualpoint device -- interleaved packet format -+ * -+ * byte 0: 1 1 0 0 1 1 1 1 -+ * byte 1: 0 x6 x5 x4 x3 x2 x1 x0 -+ * byte 2: 0 x10 x9 x8 x7 0 fin ges -+ * byte 3: 0 0 YSGN XSGN 1 1 1 1 -+ * byte 4: X7 X6 X5 X4 X3 X2 X1 X0 -+ * byte 5: Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0 -+ * byte 6: 0 y9 y8 y7 1 m r l -+ * byte 7: 0 y6 y5 y4 y3 y2 y1 y0 -+ * byte 8: 0 z6 z5 z4 z3 z2 z1 z0 -+ * -+ * CAPITALS = stick, miniscules = touchpad -+ * - * ?'s can have different meanings on different models, - * such as wheel rotation, extra buttons, stick buttons - * on a dualpoint, etc. - */ - -+static bool alps_is_valid_first_byte(const struct alps_model_info *model, -+ unsigned char data) -+{ -+ return (data & model->mask0) == model->byte0; -+} -+ -+static void alps_report_buttons(struct psmouse *psmouse, -+ struct input_dev *dev1, struct input_dev *dev2, -+ int left, int right, int middle) -+{ -+ struct alps_data *priv = psmouse->private; -+ const struct alps_model_info *model = priv->i; -+ -+ if (model->flags & ALPS_PS2_INTERLEAVED) { -+ struct input_dev *dev; -+ -+ /* -+ * If shared button has already been reported on the -+ * other device (dev2) then this event should be also -+ * sent through that device. -+ */ -+ dev = test_bit(BTN_LEFT, dev2->key) ? dev2 : dev1; -+ input_report_key(dev, BTN_LEFT, left); -+ -+ dev = test_bit(BTN_RIGHT, dev2->key) ? dev2 : dev1; -+ input_report_key(dev, BTN_RIGHT, right); -+ -+ dev = test_bit(BTN_MIDDLE, dev2->key) ? dev2 : dev1; -+ input_report_key(dev, BTN_MIDDLE, middle); -+ -+ /* -+ * Sync the _other_ device now, we'll do the first -+ * device later once we report the rest of the events. -+ */ -+ input_sync(dev2); -+ } else { -+ /* -+ * For devices with non-interleaved packets we know what -+ * device buttons belong to so we can simply report them. -+ */ -+ input_report_key(dev1, BTN_LEFT, left); -+ input_report_key(dev1, BTN_RIGHT, right); -+ input_report_key(dev1, BTN_MIDDLE, middle); -+ } -+} -+ - static void alps_process_packet(struct psmouse *psmouse) - { - struct alps_data *priv = psmouse->private; -@@ -89,18 +162,6 @@ static void alps_process_packet(struct psmouse *psmouse) - int x, y, z, ges, fin, left, right, middle; - int back = 0, forward = 0; - -- if ((packet[0] & 0xc8) == 0x08) { /* 3-byte PS/2 packet */ -- input_report_key(dev2, BTN_LEFT, packet[0] & 1); -- input_report_key(dev2, BTN_RIGHT, packet[0] & 2); -- input_report_key(dev2, BTN_MIDDLE, packet[0] & 4); -- input_report_rel(dev2, REL_X, -- packet[1] ? packet[1] - ((packet[0] << 4) & 0x100) : 0); -- input_report_rel(dev2, REL_Y, -- packet[2] ? ((packet[0] << 3) & 0x100) - packet[2] : 0); -- input_sync(dev2); -- return; -- } -- - if (priv->i->flags & ALPS_OLDPROTO) { - left = packet[2] & 0x10; - right = packet[2] & 0x08; -@@ -136,18 +197,13 @@ static void alps_process_packet(struct psmouse *psmouse) - input_report_rel(dev2, REL_X, (x > 383 ? (x - 768) : x)); - input_report_rel(dev2, REL_Y, -(y > 255 ? (y - 512) : y)); - -- input_report_key(dev2, BTN_LEFT, left); -- input_report_key(dev2, BTN_RIGHT, right); -- input_report_key(dev2, BTN_MIDDLE, middle); -+ alps_report_buttons(psmouse, dev2, dev, left, right, middle); - -- input_sync(dev); - input_sync(dev2); - return; - } - -- input_report_key(dev, BTN_LEFT, left); -- input_report_key(dev, BTN_RIGHT, right); -- input_report_key(dev, BTN_MIDDLE, middle); -+ alps_report_buttons(psmouse, dev, dev2, left, right, middle); - - /* Convert hardware tap to a reasonable Z value */ - if (ges && !fin) z = 40; -@@ -188,25 +244,168 @@ static void alps_process_packet(struct psmouse *psmouse) - input_sync(dev); - } - -+static void alps_report_bare_ps2_packet(struct psmouse *psmouse, -+ unsigned char packet[], -+ bool report_buttons) -+{ -+ struct alps_data *priv = psmouse->private; -+ struct input_dev *dev2 = priv->dev2; -+ -+ if (report_buttons) -+ alps_report_buttons(psmouse, dev2, psmouse->dev, -+ packet[0] & 1, packet[0] & 2, packet[0] & 4); -+ -+ input_report_rel(dev2, REL_X, -+ packet[1] ? packet[1] - ((packet[0] << 4) & 0x100) : 0); -+ input_report_rel(dev2, REL_Y, -+ packet[2] ? ((packet[0] << 3) & 0x100) - packet[2] : 0); -+ -+ input_sync(dev2); -+} -+ -+static psmouse_ret_t alps_handle_interleaved_ps2(struct psmouse *psmouse) -+{ -+ struct alps_data *priv = psmouse->private; -+ -+ if (psmouse->pktcnt < 6) -+ return PSMOUSE_GOOD_DATA; -+ -+ if (psmouse->pktcnt == 6) { -+ /* -+ * Start a timer to flush the packet if it ends up last -+ * 6-byte packet in the stream. Timer needs to fire -+ * psmouse core times out itself. 20 ms should be enough -+ * to decide if we are getting more data or not. -+ */ -+ mod_timer(&priv->timer, jiffies + msecs_to_jiffies(20)); -+ return PSMOUSE_GOOD_DATA; -+ } -+ -+ del_timer(&priv->timer); -+ -+ if (psmouse->packet[6] & 0x80) { -+ -+ /* -+ * Highest bit is set - that means we either had -+ * complete ALPS packet and this is start of the -+ * next packet or we got garbage. -+ */ -+ -+ if (((psmouse->packet[3] | -+ psmouse->packet[4] | -+ psmouse->packet[5]) & 0x80) || -+ (!alps_is_valid_first_byte(priv->i, psmouse->packet[6]))) { -+ dbg("refusing packet %x %x %x %x " -+ "(suspected interleaved ps/2)\n", -+ psmouse->packet[3], psmouse->packet[4], -+ psmouse->packet[5], psmouse->packet[6]); -+ return PSMOUSE_BAD_DATA; -+ } -+ -+ alps_process_packet(psmouse); -+ -+ /* Continue with the next packet */ -+ psmouse->packet[0] = psmouse->packet[6]; -+ psmouse->pktcnt = 1; -+ -+ } else { -+ -+ /* -+ * High bit is 0 - that means that we indeed got a PS/2 -+ * packet in the middle of ALPS packet. -+ * -+ * There is also possibility that we got 6-byte ALPS -+ * packet followed by 3-byte packet from trackpoint. We -+ * can not distinguish between these 2 scenarios but -+ * becase the latter is unlikely to happen in course of -+ * normal operation (user would need to press all -+ * buttons on the pad and start moving trackpoint -+ * without touching the pad surface) we assume former. -+ * Even if we are wrong the wost thing that would happen -+ * the cursor would jump but we should not get protocol -+ * desynchronization. -+ */ -+ -+ alps_report_bare_ps2_packet(psmouse, &psmouse->packet[3], -+ false); -+ -+ /* -+ * Continue with the standard ALPS protocol handling, -+ * but make sure we won't process it as an interleaved -+ * packet again, which may happen if all buttons are -+ * pressed. To avoid this let's reset the 4th bit which -+ * is normally 1. -+ */ -+ psmouse->packet[3] = psmouse->packet[6] & 0xf7; -+ psmouse->pktcnt = 4; -+ } -+ -+ return PSMOUSE_GOOD_DATA; -+} -+ -+static void alps_flush_packet(unsigned long data) -+{ -+ struct psmouse *psmouse = (struct psmouse *)data; -+ -+ serio_pause_rx(psmouse->ps2dev.serio); -+ -+ if (psmouse->pktcnt == 6) { -+ -+ /* -+ * We did not any more data in reasonable amount of time. -+ * Validate the last 3 bytes and process as a standard -+ * ALPS packet. -+ */ -+ if ((psmouse->packet[3] | -+ psmouse->packet[4] | -+ psmouse->packet[5]) & 0x80) { -+ dbg("refusing packet %x %x %x " -+ "(suspected interleaved ps/2)\n", -+ psmouse->packet[3], psmouse->packet[4], -+ psmouse->packet[5]); -+ } else { -+ alps_process_packet(psmouse); -+ } -+ psmouse->pktcnt = 0; -+ } -+ -+ serio_continue_rx(psmouse->ps2dev.serio); -+} -+ - static psmouse_ret_t alps_process_byte(struct psmouse *psmouse) - { - struct alps_data *priv = psmouse->private; -+ const struct alps_model_info *model = priv->i; - - if ((psmouse->packet[0] & 0xc8) == 0x08) { /* PS/2 packet */ - if (psmouse->pktcnt == 3) { -- alps_process_packet(psmouse); -+ alps_report_bare_ps2_packet(psmouse, psmouse->packet, -+ true); - return PSMOUSE_FULL_PACKET; - } - return PSMOUSE_GOOD_DATA; - } - -- if ((psmouse->packet[0] & priv->i->mask0) != priv->i->byte0) -+ /* Check for PS/2 packet stuffed in the middle of ALPS packet. */ -+ -+ if ((model->flags & ALPS_PS2_INTERLEAVED) && -+ psmouse->pktcnt >= 4 && (psmouse->packet[3] & 0x0f) == 0x0f) { -+ return alps_handle_interleaved_ps2(psmouse); -+ } -+ -+ if (!alps_is_valid_first_byte(model, psmouse->packet[0])) { -+ dbg("refusing packet[0] = %x (mask0 = %x, byte0 = %x)\n", -+ psmouse->packet[0], model->mask0, model->byte0); - return PSMOUSE_BAD_DATA; -+ } - - /* Bytes 2 - 6 should have 0 in the highest bit */ - if (psmouse->pktcnt >= 2 && psmouse->pktcnt <= 6 && -- (psmouse->packet[psmouse->pktcnt - 1] & 0x80)) -+ (psmouse->packet[psmouse->pktcnt - 1] & 0x80)) { -+ dbg("refusing packet[%i] = %x\n", -+ psmouse->pktcnt - 1, psmouse->packet[psmouse->pktcnt - 1]); - return PSMOUSE_BAD_DATA; -+ } - - if (psmouse->pktcnt == 6) { - alps_process_packet(psmouse); -@@ -445,6 +644,7 @@ static void alps_disconnect(struct psmouse *psmouse) - struct alps_data *priv = psmouse->private; - - psmouse_reset(psmouse); -+ del_timer_sync(&priv->timer); - input_unregister_device(priv->dev2); - kfree(priv); - } -@@ -461,6 +661,8 @@ int alps_init(struct psmouse *psmouse) - goto init_fail; - - priv->dev2 = dev2; -+ setup_timer(&priv->timer, alps_flush_packet, (unsigned long)psmouse); -+ - psmouse->private = priv; - - if (alps_hw_init(psmouse, &version)) -diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h -index bc87936..904ed8b 100644 ---- a/drivers/input/mouse/alps.h -+++ b/drivers/input/mouse/alps.h -@@ -23,6 +23,7 @@ struct alps_data { - char phys[32]; /* Phys */ - const struct alps_model_info *i;/* Info */ - int prev_fin; /* Finger bit from previous packet */ -+ struct timer_list timer; - }; - - #ifdef CONFIG_MOUSE_PS2_ALPS -diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h -index 2bcf1ac..2a5982e 100644 ---- a/drivers/input/serio/i8042-x86ia64io.h -+++ b/drivers/input/serio/i8042-x86ia64io.h -@@ -67,10 +67,12 @@ static inline void i8042_write_command(int val) - - #include - --static struct dmi_system_id __initdata i8042_dmi_noloop_table[] = { -+static const struct dmi_system_id __initconst i8042_dmi_noloop_table[] = { - { -- /* AUX LOOP command does not raise AUX IRQ */ -- .ident = "Arima-Rioworks HDAMB", -+ /* -+ * Arima-Rioworks HDAMB - -+ * AUX LOOP command does not raise AUX IRQ -+ */ - .matches = { - DMI_MATCH(DMI_BOARD_VENDOR, "RIOWORKS"), - DMI_MATCH(DMI_BOARD_NAME, "HDAMB"), -@@ -78,7 +80,7 @@ static struct dmi_system_id __initdata i8042_dmi_noloop_table[] = { - }, - }, - { -- .ident = "ASUS G1S", -+ /* ASUS G1S */ - .matches = { - DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer Inc."), - DMI_MATCH(DMI_BOARD_NAME, "G1S"), -@@ -86,8 +88,7 @@ static struct dmi_system_id __initdata i8042_dmi_noloop_table[] = { - }, - }, - { -- /* AUX LOOP command does not raise AUX IRQ */ -- .ident = "ASUS P65UP5", -+ /* ASUS P65UP5 - AUX LOOP command does not raise AUX IRQ */ - .matches = { - DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."), - DMI_MATCH(DMI_BOARD_NAME, "P/I-P65UP5"), -@@ -95,7 +96,6 @@ static struct dmi_system_id __initdata i8042_dmi_noloop_table[] = { - }, - }, - { -- .ident = "Compaq Proliant 8500", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Compaq"), - DMI_MATCH(DMI_PRODUCT_NAME , "ProLiant"), -@@ -103,7 +103,6 @@ static struct dmi_system_id __initdata i8042_dmi_noloop_table[] = { - }, - }, - { -- .ident = "Compaq Proliant DL760", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Compaq"), - DMI_MATCH(DMI_PRODUCT_NAME , "ProLiant"), -@@ -111,7 +110,7 @@ static struct dmi_system_id __initdata i8042_dmi_noloop_table[] = { - }, - }, - { -- .ident = "OQO Model 01", -+ /* OQO Model 01 */ - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "OQO"), - DMI_MATCH(DMI_PRODUCT_NAME, "ZEPTO"), -@@ -119,8 +118,7 @@ static struct dmi_system_id __initdata i8042_dmi_noloop_table[] = { - }, - }, - { -- /* AUX LOOP does not work properly */ -- .ident = "ULI EV4873", -+ /* ULI EV4873 - AUX LOOP does not work properly */ - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "ULI"), - DMI_MATCH(DMI_PRODUCT_NAME, "EV4873"), -@@ -128,7 +126,7 @@ static struct dmi_system_id __initdata i8042_dmi_noloop_table[] = { - }, - }, - { -- .ident = "Microsoft Virtual Machine", -+ /* Microsoft Virtual Machine */ - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), - DMI_MATCH(DMI_PRODUCT_NAME, "Virtual Machine"), -@@ -136,7 +134,7 @@ static struct dmi_system_id __initdata i8042_dmi_noloop_table[] = { - }, - }, - { -- .ident = "Medion MAM 2070", -+ /* Medion MAM 2070 */ - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Notebook"), - DMI_MATCH(DMI_PRODUCT_NAME, "MAM 2070"), -@@ -144,7 +142,7 @@ static struct dmi_system_id __initdata i8042_dmi_noloop_table[] = { - }, - }, - { -- .ident = "Blue FB5601", -+ /* Blue FB5601 */ - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "blue"), - DMI_MATCH(DMI_PRODUCT_NAME, "FB5601"), -@@ -152,7 +150,7 @@ static struct dmi_system_id __initdata i8042_dmi_noloop_table[] = { - }, - }, - { -- .ident = "Gigabyte M912", -+ /* Gigabyte M912 */ - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "GIGABYTE"), - DMI_MATCH(DMI_PRODUCT_NAME, "M912"), -@@ -160,7 +158,14 @@ static struct dmi_system_id __initdata i8042_dmi_noloop_table[] = { - }, - }, - { -- .ident = "HP DV9700", -+ /* Gigabyte M1022M netbook */ -+ .matches = { -+ DMI_MATCH(DMI_BOARD_VENDOR, "Gigabyte Technology Co.,Ltd."), -+ DMI_MATCH(DMI_BOARD_NAME, "M1022E"), -+ DMI_MATCH(DMI_BOARD_VERSION, "1.02"), -+ }, -+ }, -+ { - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), - DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion dv9700"), -@@ -177,72 +182,72 @@ static struct dmi_system_id __initdata i8042_dmi_noloop_table[] = { - * ... apparently some Toshibas don't like MUX mode either and - * die horrible death on reboot. - */ --static struct dmi_system_id __initdata i8042_dmi_nomux_table[] = { -+static const struct dmi_system_id __initconst i8042_dmi_nomux_table[] = { - { -- .ident = "Fujitsu Lifebook P7010/P7010D", -+ /* Fujitsu Lifebook P7010/P7010D */ - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), - DMI_MATCH(DMI_PRODUCT_NAME, "P7010"), - }, - }, - { -- .ident = "Fujitsu Lifebook P7010", -+ /* Fujitsu Lifebook P7010 */ - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), - DMI_MATCH(DMI_PRODUCT_NAME, "0000000000"), - }, - }, - { -- .ident = "Fujitsu Lifebook P5020D", -+ /* Fujitsu Lifebook P5020D */ - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), - DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook P Series"), - }, - }, - { -- .ident = "Fujitsu Lifebook S2000", -+ /* Fujitsu Lifebook S2000 */ - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), - DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook S Series"), - }, - }, - { -- .ident = "Fujitsu Lifebook S6230", -+ /* Fujitsu Lifebook S6230 */ - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), - DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook S6230"), - }, - }, - { -- .ident = "Fujitsu T70H", -+ /* Fujitsu T70H */ - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), - DMI_MATCH(DMI_PRODUCT_NAME, "FMVLT70H"), - }, - }, - { -- .ident = "Fujitsu-Siemens Lifebook T3010", -+ /* Fujitsu-Siemens Lifebook T3010 */ - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), - DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK T3010"), - }, - }, - { -- .ident = "Fujitsu-Siemens Lifebook E4010", -+ /* Fujitsu-Siemens Lifebook E4010 */ - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), - DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK E4010"), - }, - }, - { -- .ident = "Fujitsu-Siemens Amilo Pro 2010", -+ /* Fujitsu-Siemens Amilo Pro 2010 */ - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), - DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pro V2010"), - }, - }, - { -- .ident = "Fujitsu-Siemens Amilo Pro 2030", -+ /* Fujitsu-Siemens Amilo Pro 2030 */ - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), - DMI_MATCH(DMI_PRODUCT_NAME, "AMILO PRO V2030"), -@@ -253,7 +258,7 @@ static struct dmi_system_id __initdata i8042_dmi_nomux_table[] = { - * No data is coming from the touchscreen unless KBC - * is in legacy mode. - */ -- .ident = "Panasonic CF-29", -+ /* Panasonic CF-29 */ - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Matsushita"), - DMI_MATCH(DMI_PRODUCT_NAME, "CF-29"), -@@ -261,10 +266,10 @@ static struct dmi_system_id __initdata i8042_dmi_nomux_table[] = { - }, - { - /* -- * Errors on MUX ports are reported without raising AUXDATA -+ * HP Pavilion DV4017EA - -+ * errors on MUX ports are reported without raising AUXDATA - * causing "spurious NAK" messages. - */ -- .ident = "HP Pavilion DV4017EA", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), - DMI_MATCH(DMI_PRODUCT_NAME, "Pavilion dv4000 (EA032EA#ABF)"), -@@ -272,9 +277,9 @@ static struct dmi_system_id __initdata i8042_dmi_nomux_table[] = { - }, - { - /* -- * Like DV4017EA does not raise AUXERR for errors on MUX ports. -+ * HP Pavilion ZT1000 - -+ * like DV4017EA does not raise AUXERR for errors on MUX ports. - */ -- .ident = "HP Pavilion ZT1000", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), - DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion Notebook PC"), -@@ -283,44 +288,41 @@ static struct dmi_system_id __initdata i8042_dmi_nomux_table[] = { - }, - { - /* -- * Like DV4017EA does not raise AUXERR for errors on MUX ports. -+ * HP Pavilion DV4270ca - -+ * like DV4017EA does not raise AUXERR for errors on MUX ports. - */ -- .ident = "HP Pavilion DV4270ca", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), - DMI_MATCH(DMI_PRODUCT_NAME, "Pavilion dv4000 (EH476UA#ABL)"), - }, - }, - { -- .ident = "Toshiba P10", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), - DMI_MATCH(DMI_PRODUCT_NAME, "Satellite P10"), - }, - }, - { -- .ident = "Toshiba Equium A110", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), - DMI_MATCH(DMI_PRODUCT_NAME, "EQUIUM A110"), - }, - }, - { -- .ident = "Alienware Sentia", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "ALIENWARE"), - DMI_MATCH(DMI_PRODUCT_NAME, "Sentia"), - }, - }, - { -- .ident = "Sharp Actius MM20", -+ /* Sharp Actius MM20 */ - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "SHARP"), - DMI_MATCH(DMI_PRODUCT_NAME, "PC-MM20 Series"), - }, - }, - { -- .ident = "Sony Vaio FS-115b", -+ /* Sony Vaio FS-115b */ - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), - DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FS115B"), -@@ -328,73 +330,72 @@ static struct dmi_system_id __initdata i8042_dmi_nomux_table[] = { - }, - { - /* -- * Reset and GET ID commands issued via KBD port are -+ * Sony Vaio FZ-240E - -+ * reset and GET ID commands issued via KBD port are - * sometimes being delivered to AUX3. - */ -- .ident = "Sony Vaio FZ-240E", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), - DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FZ240E"), - }, - }, - { -- .ident = "Amoi M636/A737", -+ /* Amoi M636/A737 */ - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Amoi Electronics CO.,LTD."), - DMI_MATCH(DMI_PRODUCT_NAME, "M636/A737 platform"), - }, - }, - { -- .ident = "Lenovo 3000 n100", -+ /* Lenovo 3000 n100 */ - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), - DMI_MATCH(DMI_PRODUCT_NAME, "076804U"), - }, - }, - { -- .ident = "Acer Aspire 1360", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Acer"), - DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 1360"), - }, - }, - { -- .ident = "Gericom Bellagio", -+ /* Gericom Bellagio */ - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Gericom"), - DMI_MATCH(DMI_PRODUCT_NAME, "N34AS6"), - }, - }, - { -- .ident = "IBM 2656", -+ /* IBM 2656 */ - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "IBM"), - DMI_MATCH(DMI_PRODUCT_NAME, "2656"), - }, - }, - { -- .ident = "Dell XPS M1530", -+ /* Dell XPS M1530 */ - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "XPS M1530"), - }, - }, - { -- .ident = "Compal HEL80I", -+ /* Compal HEL80I */ - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "COMPAL"), - DMI_MATCH(DMI_PRODUCT_NAME, "HEL80I"), - }, - }, - { -- .ident = "Dell Vostro 1510", -+ /* Dell Vostro 1510 */ - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "Vostro1510"), - }, - }, - { -- .ident = "Acer Aspire 5536", -+ /* Acer Aspire 5536 */ - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Acer"), - DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5536"), -@@ -404,65 +405,65 @@ static struct dmi_system_id __initdata i8042_dmi_nomux_table[] = { - { } - }; - --static struct dmi_system_id __initdata i8042_dmi_reset_table[] = { -+static const struct dmi_system_id __initconst i8042_dmi_reset_table[] = { - { -- .ident = "MSI Wind U-100", -+ /* MSI Wind U-100 */ - .matches = { - DMI_MATCH(DMI_BOARD_NAME, "U-100"), - DMI_MATCH(DMI_BOARD_VENDOR, "MICRO-STAR INTERNATIONAL CO., LTD"), - }, - }, - { -- .ident = "LG Electronics X110", -+ /* LG Electronics X110 */ - .matches = { - DMI_MATCH(DMI_BOARD_NAME, "X110"), - DMI_MATCH(DMI_BOARD_VENDOR, "LG Electronics Inc."), - }, - }, - { -- .ident = "Acer Aspire One 150", -+ /* Acer Aspire One 150 */ - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Acer"), - DMI_MATCH(DMI_PRODUCT_NAME, "AOA150"), - }, - }, - { -- .ident = "Advent 4211", -+ /* Advent 4211 */ - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "DIXONSXP"), - DMI_MATCH(DMI_PRODUCT_NAME, "Advent 4211"), - }, - }, - { -- .ident = "Medion Akoya Mini E1210", -+ /* Medion Akoya Mini E1210 */ - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "MEDION"), - DMI_MATCH(DMI_PRODUCT_NAME, "E1210"), - }, - }, - { -- .ident = "Mivvy M310", -+ /* Mivvy M310 */ - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "VIOOO"), - DMI_MATCH(DMI_PRODUCT_NAME, "N10"), - }, - }, - { -- .ident = "Dell Vostro 1320", -+ /* Dell Vostro 1320 */ - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 1320"), - }, - }, - { -- .ident = "Dell Vostro 1520", -+ /* Dell Vostro 1520 */ - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 1520"), - }, - }, - { -- .ident = "Dell Vostro 1720", -+ /* Dell Vostro 1720 */ - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 1720"), -@@ -472,16 +473,16 @@ static struct dmi_system_id __initdata i8042_dmi_reset_table[] = { - }; - - #ifdef CONFIG_PNP --static struct dmi_system_id __initdata i8042_dmi_nopnp_table[] = { -+static const struct dmi_system_id __initconst i8042_dmi_nopnp_table[] = { - { -- .ident = "Intel MBO Desktop D845PESV", -+ /* Intel MBO Desktop D845PESV */ - .matches = { - DMI_MATCH(DMI_BOARD_NAME, "D845PESV"), - DMI_MATCH(DMI_BOARD_VENDOR, "Intel Corporation"), - }, - }, - { -- .ident = "MSI Wind U-100", -+ /* MSI Wind U-100 */ - .matches = { - DMI_MATCH(DMI_BOARD_NAME, "U-100"), - DMI_MATCH(DMI_BOARD_VENDOR, "MICRO-STAR INTERNATIONAL CO., LTD"), -@@ -490,27 +491,23 @@ static struct dmi_system_id __initdata i8042_dmi_nopnp_table[] = { - { } - }; - --static struct dmi_system_id __initdata i8042_dmi_laptop_table[] = { -+static const struct dmi_system_id __initconst i8042_dmi_laptop_table[] = { - { -- .ident = "Portable", - .matches = { - DMI_MATCH(DMI_CHASSIS_TYPE, "8"), /* Portable */ - }, - }, - { -- .ident = "Laptop", - .matches = { - DMI_MATCH(DMI_CHASSIS_TYPE, "9"), /* Laptop */ - }, - }, - { -- .ident = "Notebook", - .matches = { - DMI_MATCH(DMI_CHASSIS_TYPE, "10"), /* Notebook */ - }, - }, - { -- .ident = "Sub-Notebook", - .matches = { - DMI_MATCH(DMI_CHASSIS_TYPE, "14"), /* Sub-Notebook */ - }, -@@ -525,58 +522,65 @@ static struct dmi_system_id __initdata i8042_dmi_laptop_table[] = { - * Originally, this was just confined to older laptops, but a few Acer laptops - * have turned up in 2007 that also need this again. - */ --static struct dmi_system_id __initdata i8042_dmi_dritek_table[] = { -+static const struct dmi_system_id __initconst i8042_dmi_dritek_table[] = { -+ { -+ /* Acer Aspire 5610 */ -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "Acer"), -+ DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5610"), -+ }, -+ }, - { -- .ident = "Acer Aspire 5630", -+ /* Acer Aspire 5630 */ - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Acer"), - DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5630"), - }, - }, - { -- .ident = "Acer Aspire 5650", -+ /* Acer Aspire 5650 */ - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Acer"), - DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5650"), - }, - }, - { -- .ident = "Acer Aspire 5680", -+ /* Acer Aspire 5680 */ - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Acer"), - DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5680"), - }, - }, - { -- .ident = "Acer Aspire 5720", -+ /* Acer Aspire 5720 */ - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Acer"), - DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5720"), - }, - }, - { -- .ident = "Acer Aspire 9110", -+ /* Acer Aspire 9110 */ - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Acer"), - DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 9110"), - }, - }, - { -- .ident = "Acer TravelMate 660", -+ /* Acer TravelMate 660 */ - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Acer"), - DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 660"), - }, - }, - { -- .ident = "Acer TravelMate 2490", -+ /* Acer TravelMate 2490 */ - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Acer"), - DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 2490"), - }, - }, - { -- .ident = "Acer TravelMate 4280", -+ /* Acer TravelMate 4280 */ - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Acer"), - DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 4280"), -diff --git a/drivers/md/md.c b/drivers/md/md.c -index c6a6685..08f7471 100644 ---- a/drivers/md/md.c -+++ b/drivers/md/md.c -@@ -4173,7 +4173,7 @@ static int do_md_run(mddev_t * mddev) - mddev->barriers_work = 1; - mddev->ok_start_degraded = start_dirty_degraded; - -- if (start_readonly) -+ if (start_readonly && mddev->ro == 0) - mddev->ro = 2; /* read-only, but switch on first write */ - - err = mddev->pers->run(mddev); -diff --git a/drivers/media/dvb/siano/smsusb.c b/drivers/media/dvb/siano/smsusb.c -index 8f88a58..6b03dbf 100644 ---- a/drivers/media/dvb/siano/smsusb.c -+++ b/drivers/media/dvb/siano/smsusb.c -@@ -533,8 +533,18 @@ struct usb_device_id smsusb_id_table[] = { - .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, - { USB_DEVICE(0x2040, 0xb910), - .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, -+ { USB_DEVICE(0x2040, 0xb980), -+ .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, -+ { USB_DEVICE(0x2040, 0xb990), -+ .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, - { USB_DEVICE(0x2040, 0xc000), - .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, -+ { USB_DEVICE(0x2040, 0xc010), -+ .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, -+ { USB_DEVICE(0x2040, 0xc080), -+ .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, -+ { USB_DEVICE(0x2040, 0xc090), -+ .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, - { } /* Terminating entry */ - }; - -diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c -index 0901322..6781a07 100644 ---- a/drivers/media/video/saa7134/saa7134-cards.c -+++ b/drivers/media/video/saa7134/saa7134-cards.c -@@ -5279,6 +5279,30 @@ struct saa7134_board saa7134_boards[] = { - .amux = TV, - }, - }, -+ [SAA7134_BOARD_ASUS_EUROPA_HYBRID] = { -+ .name = "Asus Europa Hybrid OEM", -+ .audio_clock = 0x00187de7, -+ .tuner_type = TUNER_PHILIPS_TD1316, -+ .radio_type = UNSET, -+ .tuner_addr = 0x61, -+ .radio_addr = ADDR_UNSET, -+ .tda9887_conf = TDA9887_PRESENT | TDA9887_PORT1_ACTIVE, -+ .mpeg = SAA7134_MPEG_DVB, -+ .inputs = { { -+ .name = name_tv, -+ .vmux = 3, -+ .amux = TV, -+ .tv = 1, -+ }, { -+ .name = name_comp1, -+ .vmux = 4, -+ .amux = LINE2, -+ }, { -+ .name = name_svideo, -+ .vmux = 8, -+ .amux = LINE2, -+ } }, -+ }, - - }; - -@@ -6418,6 +6442,12 @@ struct pci_device_id saa7134_pci_tbl[] = { - .subdevice = 0x2004, - .driver_data = SAA7134_BOARD_ZOLID_HYBRID_PCI, - }, { -+ .vendor = PCI_VENDOR_ID_PHILIPS, -+ .device = PCI_DEVICE_ID_PHILIPS_SAA7134, -+ .subvendor = 0x1043, -+ .subdevice = 0x4847, -+ .driver_data = SAA7134_BOARD_ASUS_EUROPA_HYBRID, -+ }, { - /* --- boards without eeprom + subsystem ID --- */ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, -@@ -7079,6 +7109,7 @@ int saa7134_board_init2(struct saa7134_dev *dev) - /* break intentionally omitted */ - case SAA7134_BOARD_VIDEOMATE_DVBT_300: - case SAA7134_BOARD_ASUS_EUROPA2_HYBRID: -+ case SAA7134_BOARD_ASUS_EUROPA_HYBRID: - { - - /* The Philips EUROPA based hybrid boards have the tuner -diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c -index a26e997..b8a805c 100644 ---- a/drivers/media/video/saa7134/saa7134-dvb.c -+++ b/drivers/media/video/saa7134/saa7134-dvb.c -@@ -1116,6 +1116,7 @@ static int dvb_init(struct saa7134_dev *dev) - break; - case SAA7134_BOARD_PHILIPS_EUROPA: - case SAA7134_BOARD_VIDEOMATE_DVBT_300: -+ case SAA7134_BOARD_ASUS_EUROPA_HYBRID: - fe0->dvb.frontend = dvb_attach(tda10046_attach, - &philips_europa_config, - &dev->i2c_adap); -diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h -index f8697d4..94e1a3b 100644 ---- a/drivers/media/video/saa7134/saa7134.h -+++ b/drivers/media/video/saa7134/saa7134.h -@@ -297,6 +297,7 @@ struct saa7134_format { - #define SAA7134_BOARD_BEHOLD_X7 171 - #define SAA7134_BOARD_ROVERMEDIA_LINK_PRO_FM 172 - #define SAA7134_BOARD_ZOLID_HYBRID_PCI 173 -+#define SAA7134_BOARD_ASUS_EUROPA_HYBRID 174 - - #define SAA7134_MAXBOARDS 32 - #define SAA7134_INPUT_MAX 8 -diff --git a/drivers/media/video/uvc/uvc_ctrl.c b/drivers/media/video/uvc/uvc_ctrl.c -index 1b89735..4a293b4 100644 ---- a/drivers/media/video/uvc/uvc_ctrl.c -+++ b/drivers/media/video/uvc/uvc_ctrl.c -@@ -1405,7 +1405,7 @@ uvc_ctrl_prune_entity(struct uvc_device *dev, struct uvc_entity *entity) - size = entity->processing.bControlSize; - - for (i = 0; i < ARRAY_SIZE(blacklist); ++i) { -- if (!usb_match_id(dev->intf, &blacklist[i].id)) -+ if (!usb_match_one_id(dev->intf, &blacklist[i].id)) - continue; - - if (blacklist[i].index >= 8 * size || -diff --git a/drivers/mtd/ubi/upd.c b/drivers/mtd/ubi/upd.c -index c1d7b88..425bf5a 100644 ---- a/drivers/mtd/ubi/upd.c -+++ b/drivers/mtd/ubi/upd.c -@@ -155,6 +155,7 @@ int ubi_start_update(struct ubi_device *ubi, struct ubi_volume *vol, - if (err) - return err; - vol->updating = 0; -+ return 0; - } - - vol->upd_buf = vmalloc(ubi->leb_size); -diff --git a/drivers/mtd/ubi/vtbl.c b/drivers/mtd/ubi/vtbl.c -index 1afc61e..4004402 100644 ---- a/drivers/mtd/ubi/vtbl.c -+++ b/drivers/mtd/ubi/vtbl.c -@@ -566,6 +566,7 @@ static int init_volumes(struct ubi_device *ubi, const struct ubi_scan_info *si, - vol->reserved_pebs = be32_to_cpu(vtbl[i].reserved_pebs); - vol->alignment = be32_to_cpu(vtbl[i].alignment); - vol->data_pad = be32_to_cpu(vtbl[i].data_pad); -+ vol->upd_marker = vtbl[i].upd_marker; - vol->vol_type = vtbl[i].vol_type == UBI_VID_DYNAMIC ? - UBI_DYNAMIC_VOLUME : UBI_STATIC_VOLUME; - vol->name_len = be16_to_cpu(vtbl[i].name_len); -diff --git a/drivers/net/atl1c/atl1c.h b/drivers/net/atl1c/atl1c.h -index 2a1120a..790e55b 100644 ---- a/drivers/net/atl1c/atl1c.h -+++ b/drivers/net/atl1c/atl1c.h -@@ -534,6 +534,9 @@ struct atl1c_adapter { - #define __AT_TESTING 0x0001 - #define __AT_RESETTING 0x0002 - #define __AT_DOWN 0x0003 -+ u8 work_event; -+#define ATL1C_WORK_EVENT_RESET 0x01 -+#define ATL1C_WORK_EVENT_LINK_CHANGE 0x02 - u32 msg_enable; - - bool have_msi; -@@ -545,8 +548,7 @@ struct atl1c_adapter { - spinlock_t tx_lock; - atomic_t irq_sem; - -- struct work_struct reset_task; -- struct work_struct link_chg_task; -+ struct work_struct common_task; - struct timer_list watchdog_timer; - struct timer_list phy_config_timer; - -diff --git a/drivers/net/atl1c/atl1c_main.c b/drivers/net/atl1c/atl1c_main.c -index 1372e9a..be00ee9 100644 ---- a/drivers/net/atl1c/atl1c_main.c -+++ b/drivers/net/atl1c/atl1c_main.c -@@ -198,27 +198,12 @@ static void atl1c_phy_config(unsigned long data) - - void atl1c_reinit_locked(struct atl1c_adapter *adapter) - { -- - WARN_ON(in_interrupt()); - atl1c_down(adapter); - atl1c_up(adapter); - clear_bit(__AT_RESETTING, &adapter->flags); - } - --static void atl1c_reset_task(struct work_struct *work) --{ -- struct atl1c_adapter *adapter; -- struct net_device *netdev; -- -- adapter = container_of(work, struct atl1c_adapter, reset_task); -- netdev = adapter->netdev; -- -- netif_device_detach(netdev); -- atl1c_down(adapter); -- atl1c_up(adapter); -- netif_device_attach(netdev); --} -- - static void atl1c_check_link_status(struct atl1c_adapter *adapter) - { - struct atl1c_hw *hw = &adapter->hw; -@@ -275,18 +260,6 @@ static void atl1c_check_link_status(struct atl1c_adapter *adapter) - } - } - --/* -- * atl1c_link_chg_task - deal with link change event Out of interrupt context -- * @netdev: network interface device structure -- */ --static void atl1c_link_chg_task(struct work_struct *work) --{ -- struct atl1c_adapter *adapter; -- -- adapter = container_of(work, struct atl1c_adapter, link_chg_task); -- atl1c_check_link_status(adapter); --} -- - static void atl1c_link_chg_event(struct atl1c_adapter *adapter) - { - struct net_device *netdev = adapter->netdev; -@@ -311,20 +284,40 @@ static void atl1c_link_chg_event(struct atl1c_adapter *adapter) - adapter->link_speed = SPEED_0; - } - } -- schedule_work(&adapter->link_chg_task); -+ -+ adapter->work_event |= ATL1C_WORK_EVENT_LINK_CHANGE; -+ schedule_work(&adapter->common_task); - } - --static void atl1c_del_timer(struct atl1c_adapter *adapter) -+static void atl1c_common_task(struct work_struct *work) - { -- del_timer_sync(&adapter->phy_config_timer); -+ struct atl1c_adapter *adapter; -+ struct net_device *netdev; -+ -+ adapter = container_of(work, struct atl1c_adapter, common_task); -+ netdev = adapter->netdev; -+ -+ if (adapter->work_event & ATL1C_WORK_EVENT_RESET) { -+ netif_device_detach(netdev); -+ atl1c_down(adapter); -+ atl1c_up(adapter); -+ netif_device_attach(netdev); -+ return; -+ } -+ -+ if (adapter->work_event & ATL1C_WORK_EVENT_LINK_CHANGE) -+ atl1c_check_link_status(adapter); -+ -+ return; - } - --static void atl1c_cancel_work(struct atl1c_adapter *adapter) -+ -+static void atl1c_del_timer(struct atl1c_adapter *adapter) - { -- cancel_work_sync(&adapter->reset_task); -- cancel_work_sync(&adapter->link_chg_task); -+ del_timer_sync(&adapter->phy_config_timer); - } - -+ - /* - * atl1c_tx_timeout - Respond to a Tx Hang - * @netdev: network interface device structure -@@ -334,7 +327,8 @@ static void atl1c_tx_timeout(struct net_device *netdev) - struct atl1c_adapter *adapter = netdev_priv(netdev); - - /* Do the reset outside of interrupt context */ -- schedule_work(&adapter->reset_task); -+ adapter->work_event |= ATL1C_WORK_EVENT_RESET; -+ schedule_work(&adapter->common_task); - } - - /* -@@ -1536,7 +1530,8 @@ static irqreturn_t atl1c_intr(int irq, void *data) - /* reset MAC */ - hw->intr_mask &= ~ISR_ERROR; - AT_WRITE_REG(hw, REG_IMR, hw->intr_mask); -- schedule_work(&adapter->reset_task); -+ adapter->work_event |= ATL1C_WORK_EVENT_RESET; -+ schedule_work(&adapter->common_task); - break; - } - -@@ -2200,8 +2195,7 @@ void atl1c_down(struct atl1c_adapter *adapter) - struct net_device *netdev = adapter->netdev; - - atl1c_del_timer(adapter); -- atl1c_cancel_work(adapter); -- -+ adapter->work_event = 0; /* clear all event */ - /* signal that we're down so the interrupt handler does not - * reschedule our watchdog timer */ - set_bit(__AT_DOWN, &adapter->flags); -@@ -2601,8 +2595,8 @@ static int __devinit atl1c_probe(struct pci_dev *pdev, - adapter->hw.mac_addr[4], adapter->hw.mac_addr[5]); - - atl1c_hw_set_mac_addr(&adapter->hw); -- INIT_WORK(&adapter->reset_task, atl1c_reset_task); -- INIT_WORK(&adapter->link_chg_task, atl1c_link_chg_task); -+ INIT_WORK(&adapter->common_task, atl1c_common_task); -+ adapter->work_event = 0; - err = register_netdev(netdev); - if (err) { - dev_err(&pdev->dev, "register netdevice failed\n"); -diff --git a/drivers/net/atl1e/atl1e_main.c b/drivers/net/atl1e/atl1e_main.c -index 955da73..1b5facf 100644 ---- a/drivers/net/atl1e/atl1e_main.c -+++ b/drivers/net/atl1e/atl1e_main.c -@@ -1666,41 +1666,6 @@ static int atl1e_tso_csum(struct atl1e_adapter *adapter, - } - return 0; - } -- -- if (offload_type & SKB_GSO_TCPV6) { -- real_len = (((unsigned char *)ipv6_hdr(skb) - skb->data) -- + ntohs(ipv6_hdr(skb)->payload_len)); -- if (real_len < skb->len) -- pskb_trim(skb, real_len); -- -- /* check payload == 0 byte ? */ -- hdr_len = (skb_transport_offset(skb) + tcp_hdrlen(skb)); -- if (unlikely(skb->len == hdr_len)) { -- /* only xsum need */ -- dev_warn(&pdev->dev, -- "IPV6 tso with zero data??\n"); -- goto check_sum; -- } else { -- tcp_hdr(skb)->check = ~csum_ipv6_magic( -- &ipv6_hdr(skb)->saddr, -- &ipv6_hdr(skb)->daddr, -- 0, IPPROTO_TCP, 0); -- tpd->word3 |= 1 << TPD_IP_VERSION_SHIFT; -- hdr_len >>= 1; -- tpd->word3 |= (hdr_len & TPD_V6_IPHLLO_MASK) << -- TPD_V6_IPHLLO_SHIFT; -- tpd->word3 |= ((hdr_len >> 3) & -- TPD_V6_IPHLHI_MASK) << -- TPD_V6_IPHLHI_SHIFT; -- tpd->word3 |= (tcp_hdrlen(skb) >> 2 & -- TPD_TCPHDRLEN_MASK) << -- TPD_TCPHDRLEN_SHIFT; -- tpd->word3 |= ((skb_shinfo(skb)->gso_size) & -- TPD_MSS_MASK) << TPD_MSS_SHIFT; -- tpd->word3 |= 1 << TPD_SEGMENT_EN_SHIFT; -- } -- } -- return 0; - } - - check_sum: -@@ -2289,7 +2254,6 @@ static int atl1e_init_netdev(struct net_device *netdev, struct pci_dev *pdev) - NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; - netdev->features |= NETIF_F_LLTX; - netdev->features |= NETIF_F_TSO; -- netdev->features |= NETIF_F_TSO6; - - return 0; - } -diff --git a/drivers/net/benet/be.h b/drivers/net/benet/be.h -index 3b79a22..a84f1c5 100644 ---- a/drivers/net/benet/be.h -+++ b/drivers/net/benet/be.h -@@ -35,20 +35,31 @@ - #define DRV_VER "2.101.205" - #define DRV_NAME "be2net" - #define BE_NAME "ServerEngines BladeEngine2 10Gbps NIC" -+#define BE3_NAME "ServerEngines BladeEngine3 10Gbps NIC" - #define OC_NAME "Emulex OneConnect 10Gbps NIC" -+#define OC_NAME1 "Emulex OneConnect 10Gbps NIC (be3)" - #define DRV_DESC BE_NAME "Driver" - - #define BE_VENDOR_ID 0x19a2 - #define BE_DEVICE_ID1 0x211 -+#define BE_DEVICE_ID2 0x221 - #define OC_DEVICE_ID1 0x700 - #define OC_DEVICE_ID2 0x701 -+#define OC_DEVICE_ID3 0x710 - - static inline char *nic_name(struct pci_dev *pdev) - { -- if (pdev->device == OC_DEVICE_ID1 || pdev->device == OC_DEVICE_ID2) -+ switch (pdev->device) { -+ case OC_DEVICE_ID1: -+ case OC_DEVICE_ID2: - return OC_NAME; -- else -+ case OC_DEVICE_ID3: -+ return OC_NAME1; -+ case BE_DEVICE_ID2: -+ return BE3_NAME; -+ default: - return BE_NAME; -+ } - } - - /* Number of bytes of an RX frame that are copied to skb->data */ -diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c -index 876b357..3749bb1 100644 ---- a/drivers/net/benet/be_main.c -+++ b/drivers/net/benet/be_main.c -@@ -31,8 +31,10 @@ MODULE_PARM_DESC(rx_frag_size, "Size of a fragment that holds rcvd data."); - - static DEFINE_PCI_DEVICE_TABLE(be_dev_ids) = { - { PCI_DEVICE(BE_VENDOR_ID, BE_DEVICE_ID1) }, -+ { PCI_DEVICE(BE_VENDOR_ID, BE_DEVICE_ID2) }, - { PCI_DEVICE(BE_VENDOR_ID, OC_DEVICE_ID1) }, - { PCI_DEVICE(BE_VENDOR_ID, OC_DEVICE_ID2) }, -+ { PCI_DEVICE(BE_VENDOR_ID, OC_DEVICE_ID3) }, - { 0 } - }; - MODULE_DEVICE_TABLE(pci, be_dev_ids); -diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c -index a2fc70a..35d896b 100644 ---- a/drivers/net/qlge/qlge_main.c -+++ b/drivers/net/qlge/qlge_main.c -@@ -3310,10 +3310,8 @@ static int ql_adapter_initialize(struct ql_adapter *qdev) - - /* Initialize the port and set the max framesize. */ - status = qdev->nic_ops->port_initialize(qdev); -- if (status) { -- QPRINTK(qdev, IFUP, ERR, "Failed to start port.\n"); -- return status; -- } -+ if (status) -+ QPRINTK(qdev, IFUP, ERR, "Failed to start port.\n"); - - /* Set up the MAC address and frame routing filter. */ - status = ql_cam_route_initialize(qdev); -@@ -3714,9 +3712,6 @@ static int qlge_set_mac_address(struct net_device *ndev, void *p) - struct sockaddr *addr = p; - int status; - -- if (netif_running(ndev)) -- return -EBUSY; -- - if (!is_valid_ether_addr(addr->sa_data)) - return -EADDRNOTAVAIL; - memcpy(ndev->dev_addr, addr->sa_data, ndev->addr_len); -@@ -3868,8 +3863,7 @@ static int __devinit ql_init_device(struct pci_dev *pdev, - struct net_device *ndev, int cards_found) - { - struct ql_adapter *qdev = netdev_priv(ndev); -- int pos, err = 0; -- u16 val16; -+ int err = 0; - - memset((void *)qdev, 0, sizeof(*qdev)); - err = pci_enable_device(pdev); -@@ -3881,18 +3875,12 @@ static int __devinit ql_init_device(struct pci_dev *pdev, - qdev->ndev = ndev; - qdev->pdev = pdev; - pci_set_drvdata(pdev, ndev); -- pos = pci_find_capability(pdev, PCI_CAP_ID_EXP); -- if (pos <= 0) { -- dev_err(&pdev->dev, PFX "Cannot find PCI Express capability, " -- "aborting.\n"); -- return pos; -- } else { -- pci_read_config_word(pdev, pos + PCI_EXP_DEVCTL, &val16); -- val16 &= ~PCI_EXP_DEVCTL_NOSNOOP_EN; -- val16 |= (PCI_EXP_DEVCTL_CERE | -- PCI_EXP_DEVCTL_NFERE | -- PCI_EXP_DEVCTL_FERE | PCI_EXP_DEVCTL_URRE); -- pci_write_config_word(pdev, pos + PCI_EXP_DEVCTL, val16); -+ -+ /* Set PCIe read request size */ -+ err = pcie_set_readrq(pdev, 4096); -+ if (err) { -+ dev_err(&pdev->dev, "Set readrq failed.\n"); -+ goto err_out; - } - - err = pci_request_regions(pdev, DRV_NAME); -diff --git a/drivers/net/qlge/qlge_mpi.c b/drivers/net/qlge/qlge_mpi.c -index aec05f2..32b1e1f 100644 ---- a/drivers/net/qlge/qlge_mpi.c -+++ b/drivers/net/qlge/qlge_mpi.c -@@ -446,6 +446,9 @@ static int ql_mpi_handler(struct ql_adapter *qdev, struct mbox_params *mbcp) - ql_aen_lost(qdev, mbcp); - break; - -+ case AEN_DCBX_CHG: -+ /* Need to support AEN 8110 */ -+ break; - default: - QPRINTK(qdev, DRV, ERR, - "Unsupported AE %.08x.\n", mbcp->mbox_out[0]); -diff --git a/drivers/net/sfc/tx.c b/drivers/net/sfc/tx.c -index 489c4de..d443ad7 100644 ---- a/drivers/net/sfc/tx.c -+++ b/drivers/net/sfc/tx.c -@@ -821,8 +821,6 @@ static void efx_enqueue_unwind(struct efx_tx_queue *tx_queue) - tx_queue->efx->type->txd_ring_mask]; - efx_tsoh_free(tx_queue, buffer); - EFX_BUG_ON_PARANOID(buffer->skb); -- buffer->len = 0; -- buffer->continuation = true; - if (buffer->unmap_len) { - unmap_addr = (buffer->dma_addr + buffer->len - - buffer->unmap_len); -@@ -836,6 +834,8 @@ static void efx_enqueue_unwind(struct efx_tx_queue *tx_queue) - PCI_DMA_TODEVICE); - buffer->unmap_len = 0; - } -+ buffer->len = 0; -+ buffer->continuation = true; - } - } - -diff --git a/drivers/net/wireless/ath/ar9170/usb.c b/drivers/net/wireless/ath/ar9170/usb.c -index e974e58..f141a4f 100644 ---- a/drivers/net/wireless/ath/ar9170/usb.c -+++ b/drivers/net/wireless/ath/ar9170/usb.c -@@ -68,8 +68,10 @@ static struct usb_device_id ar9170_usb_ids[] = { - { USB_DEVICE(0x0cf3, 0x1002) }, - /* Cace Airpcap NX */ - { USB_DEVICE(0xcace, 0x0300) }, -- /* D-Link DWA 160A */ -+ /* D-Link DWA 160 A1 */ - { USB_DEVICE(0x07d1, 0x3c10) }, -+ /* D-Link DWA 160 A2 */ -+ { USB_DEVICE(0x07d1, 0x3a09) }, - /* Netgear WNDA3100 */ - { USB_DEVICE(0x0846, 0x9010) }, - /* Netgear WN111 v2 */ -diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c -index 94a1225..133df70 100644 ---- a/drivers/net/wireless/iwlwifi/iwl-5000.c -+++ b/drivers/net/wireless/iwlwifi/iwl-5000.c -@@ -1666,6 +1666,7 @@ struct iwl_cfg iwl5300_agn_cfg = { - .valid_rx_ant = ANT_ABC, - .need_pll_cfg = true, - .ht_greenfield_support = true, -+ .use_rts_for_ht = true, /* use rts/cts protection */ - }; - - struct iwl_cfg iwl5100_bg_cfg = { -@@ -1717,6 +1718,7 @@ struct iwl_cfg iwl5100_agn_cfg = { - .valid_rx_ant = ANT_AB, - .need_pll_cfg = true, - .ht_greenfield_support = true, -+ .use_rts_for_ht = true, /* use rts/cts protection */ - }; - - struct iwl_cfg iwl5350_agn_cfg = { -@@ -1734,6 +1736,7 @@ struct iwl_cfg iwl5350_agn_cfg = { - .valid_rx_ant = ANT_ABC, - .need_pll_cfg = true, - .ht_greenfield_support = true, -+ .use_rts_for_ht = true, /* use rts/cts protection */ - }; - - struct iwl_cfg iwl5150_agn_cfg = { -@@ -1751,6 +1754,7 @@ struct iwl_cfg iwl5150_agn_cfg = { - .valid_rx_ant = ANT_AB, - .need_pll_cfg = true, - .ht_greenfield_support = true, -+ .use_rts_for_ht = true, /* use rts/cts protection */ - }; - - MODULE_FIRMWARE(IWL5000_MODULE_FIRMWARE(IWL5000_UCODE_API_MAX)); -diff --git a/drivers/pci/pcie/aer/aer_inject.c b/drivers/pci/pcie/aer/aer_inject.c -index 62d15f6..0d91a8a 100644 ---- a/drivers/pci/pcie/aer/aer_inject.c -+++ b/drivers/pci/pcie/aer/aer_inject.c -@@ -392,8 +392,14 @@ static int aer_inject(struct aer_error_inj *einj) - if (ret) - goto out_put; - -- if (find_aer_device(rpdev, &edev)) -+ if (find_aer_device(rpdev, &edev)) { -+ if (!get_service_data(edev)) { -+ printk(KERN_WARNING "AER service is not initialized\n"); -+ ret = -EINVAL; -+ goto out_put; -+ } - aer_irq(-1, edev); -+ } - else - ret = -EINVAL; - out_put: -diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c -index cb1a027..dd58c6a 100644 ---- a/drivers/pci/setup-bus.c -+++ b/drivers/pci/setup-bus.c -@@ -142,7 +142,6 @@ static void pci_setup_bridge(struct pci_bus *bus) - struct pci_dev *bridge = bus->self; - struct pci_bus_region region; - u32 l, bu, lu, io_upper16; -- int pref_mem64; - - if (pci_is_enabled(bridge)) - return; -@@ -198,7 +197,6 @@ static void pci_setup_bridge(struct pci_bus *bus) - pci_write_config_dword(bridge, PCI_PREF_LIMIT_UPPER32, 0); - - /* Set up PREF base/limit. */ -- pref_mem64 = 0; - bu = lu = 0; - pcibios_resource_to_bus(bridge, ®ion, bus->resource[2]); - if (bus->resource[2]->flags & IORESOURCE_PREFETCH) { -@@ -206,7 +204,6 @@ static void pci_setup_bridge(struct pci_bus *bus) - l = (region.start >> 16) & 0xfff0; - l |= region.end & 0xfff00000; - if (bus->resource[2]->flags & IORESOURCE_MEM_64) { -- pref_mem64 = 1; - bu = upper_32_bits(region.start); - lu = upper_32_bits(region.end); - width = 16; -@@ -221,11 +218,9 @@ static void pci_setup_bridge(struct pci_bus *bus) - } - pci_write_config_dword(bridge, PCI_PREF_MEMORY_BASE, l); - -- if (pref_mem64) { -- /* Set the upper 32 bits of PREF base & limit. */ -- pci_write_config_dword(bridge, PCI_PREF_BASE_UPPER32, bu); -- pci_write_config_dword(bridge, PCI_PREF_LIMIT_UPPER32, lu); -- } -+ /* Set the upper 32 bits of PREF base & limit. */ -+ pci_write_config_dword(bridge, PCI_PREF_BASE_UPPER32, bu); -+ pci_write_config_dword(bridge, PCI_PREF_LIMIT_UPPER32, lu); - - pci_write_config_word(bridge, PCI_BRIDGE_CONTROL, bus->bridge_ctl); - } -diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c -index 2490b74..55f9973 100644 ---- a/drivers/s390/cio/device.c -+++ b/drivers/s390/cio/device.c -@@ -1292,7 +1292,7 @@ static int io_subchannel_probe(struct subchannel *sch) - sch->private = kzalloc(sizeof(struct io_subchannel_private), - GFP_KERNEL | GFP_DMA); - if (!sch->private) -- goto out_err; -+ goto out_schedule; - /* - * First check if a fitting device may be found amongst the - * disconnected devices or in the orphanage. -@@ -1317,7 +1317,7 @@ static int io_subchannel_probe(struct subchannel *sch) - } - cdev = io_subchannel_create_ccwdev(sch); - if (IS_ERR(cdev)) -- goto out_err; -+ goto out_schedule; - rc = io_subchannel_recog(cdev, sch); - if (rc) { - spin_lock_irqsave(sch->lock, flags); -@@ -1325,9 +1325,7 @@ static int io_subchannel_probe(struct subchannel *sch) - spin_unlock_irqrestore(sch->lock, flags); - } - return 0; --out_err: -- kfree(sch->private); -- sysfs_remove_group(&sch->dev.kobj, &io_subchannel_attr_group); -+ - out_schedule: - io_subchannel_schedule_removal(sch); - return 0; -@@ -1341,13 +1339,14 @@ io_subchannel_remove (struct subchannel *sch) - - cdev = sch_get_cdev(sch); - if (!cdev) -- return 0; -+ goto out_free; - /* Set ccw device to not operational and drop reference. */ - spin_lock_irqsave(cdev->ccwlock, flags); - sch_set_cdev(sch, NULL); - cdev->private->state = DEV_STATE_NOT_OPER; - spin_unlock_irqrestore(cdev->ccwlock, flags); - ccw_device_unregister(cdev); -+out_free: - kfree(sch->private); - sysfs_remove_group(&sch->dev.kobj, &io_subchannel_attr_group); - return 0; -diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c -index b9613d7..13b703a 100644 ---- a/drivers/s390/cio/device_fsm.c -+++ b/drivers/s390/cio/device_fsm.c -@@ -1080,14 +1080,14 @@ void ccw_device_trigger_reprobe(struct ccw_device *cdev) - ccw_device_start_id(cdev, 0); - } - --static void --ccw_device_offline_irq(struct ccw_device *cdev, enum dev_event dev_event) -+static void ccw_device_disabled_irq(struct ccw_device *cdev, -+ enum dev_event dev_event) - { - struct subchannel *sch; - - sch = to_subchannel(cdev->dev.parent); - /* -- * An interrupt in state offline means a previous disable was not -+ * An interrupt in a disabled state means a previous disable was not - * successful - should not happen, but we try to disable again. - */ - cio_disable_subchannel(sch); -@@ -1150,25 +1150,12 @@ ccw_device_nop(struct ccw_device *cdev, enum dev_event dev_event) - } - - /* -- * Bug operation action. -- */ --static void --ccw_device_bug(struct ccw_device *cdev, enum dev_event dev_event) --{ -- CIO_MSG_EVENT(0, "Internal state [%i][%i] not handled for device " -- "0.%x.%04x\n", cdev->private->state, dev_event, -- cdev->private->dev_id.ssid, -- cdev->private->dev_id.devno); -- BUG(); --} -- --/* - * device statemachine - */ - fsm_func_t *dev_jumptable[NR_DEV_STATES][NR_DEV_EVENTS] = { - [DEV_STATE_NOT_OPER] = { - [DEV_EVENT_NOTOPER] = ccw_device_nop, -- [DEV_EVENT_INTERRUPT] = ccw_device_bug, -+ [DEV_EVENT_INTERRUPT] = ccw_device_disabled_irq, - [DEV_EVENT_TIMEOUT] = ccw_device_nop, - [DEV_EVENT_VERIFY] = ccw_device_nop, - }, -@@ -1186,7 +1173,7 @@ fsm_func_t *dev_jumptable[NR_DEV_STATES][NR_DEV_EVENTS] = { - }, - [DEV_STATE_OFFLINE] = { - [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper, -- [DEV_EVENT_INTERRUPT] = ccw_device_offline_irq, -+ [DEV_EVENT_INTERRUPT] = ccw_device_disabled_irq, - [DEV_EVENT_TIMEOUT] = ccw_device_nop, - [DEV_EVENT_VERIFY] = ccw_device_offline_verify, - }, -@@ -1243,7 +1230,7 @@ fsm_func_t *dev_jumptable[NR_DEV_STATES][NR_DEV_EVENTS] = { - [DEV_STATE_DISCONNECTED] = { - [DEV_EVENT_NOTOPER] = ccw_device_nop, - [DEV_EVENT_INTERRUPT] = ccw_device_start_id, -- [DEV_EVENT_TIMEOUT] = ccw_device_bug, -+ [DEV_EVENT_TIMEOUT] = ccw_device_nop, - [DEV_EVENT_VERIFY] = ccw_device_start_id, - }, - [DEV_STATE_DISCONNECTED_SENSE_ID] = { -diff --git a/drivers/s390/net/netiucv.c b/drivers/s390/net/netiucv.c -index c84eadd..395c04c 100644 ---- a/drivers/s390/net/netiucv.c -+++ b/drivers/s390/net/netiucv.c -@@ -741,13 +741,13 @@ static void conn_action_txdone(fsm_instance *fi, int event, void *arg) - if (single_flag) { - if ((skb = skb_dequeue(&conn->commit_queue))) { - atomic_dec(&skb->users); -- dev_kfree_skb_any(skb); - if (privptr) { - privptr->stats.tx_packets++; - privptr->stats.tx_bytes += - (skb->len - NETIUCV_HDRLEN -- - NETIUCV_HDRLEN); -+ - NETIUCV_HDRLEN); - } -+ dev_kfree_skb_any(skb); - } - } - conn->tx_buff->data = conn->tx_buff->head; -diff --git a/drivers/scsi/device_handler/scsi_dh.c b/drivers/scsi/device_handler/scsi_dh.c -index 3ee1cbc..bfec4fa 100644 ---- a/drivers/scsi/device_handler/scsi_dh.c -+++ b/drivers/scsi/device_handler/scsi_dh.c -@@ -304,18 +304,15 @@ static int scsi_dh_notifier(struct notifier_block *nb, - sdev = to_scsi_device(dev); - - if (action == BUS_NOTIFY_ADD_DEVICE) { -+ err = device_create_file(dev, &scsi_dh_state_attr); -+ /* don't care about err */ - devinfo = device_handler_match(NULL, sdev); -- if (!devinfo) -- goto out; -- -- err = scsi_dh_handler_attach(sdev, devinfo); -- if (!err) -- err = device_create_file(dev, &scsi_dh_state_attr); -+ if (devinfo) -+ err = scsi_dh_handler_attach(sdev, devinfo); - } else if (action == BUS_NOTIFY_DEL_DEVICE) { - device_remove_file(dev, &scsi_dh_state_attr); - scsi_dh_handler_detach(sdev, NULL); - } --out: - return err; - } - -diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c -index 704b8e0..70ab5d0 100644 ---- a/drivers/scsi/fcoe/fcoe.c -+++ b/drivers/scsi/fcoe/fcoe.c -@@ -137,7 +137,7 @@ static struct scsi_host_template fcoe_shost_template = { - .change_queue_depth = fc_change_queue_depth, - .change_queue_type = fc_change_queue_type, - .this_id = -1, -- .cmd_per_lun = 32, -+ .cmd_per_lun = 3, - .can_queue = FCOE_MAX_OUTSTANDING_COMMANDS, - .use_clustering = ENABLE_CLUSTERING, - .sg_tablesize = SG_ALL, -@@ -160,6 +160,7 @@ static int fcoe_interface_setup(struct fcoe_interface *fcoe, - { - struct fcoe_ctlr *fip = &fcoe->ctlr; - struct netdev_hw_addr *ha; -+ struct net_device *real_dev; - u8 flogi_maddr[ETH_ALEN]; - - fcoe->netdev = netdev; -@@ -173,10 +174,12 @@ static int fcoe_interface_setup(struct fcoe_interface *fcoe, - - /* look for SAN MAC address, if multiple SAN MACs exist, only - * use the first one for SPMA */ -+ real_dev = (netdev->priv_flags & IFF_802_1Q_VLAN) ? -+ vlan_dev_real_dev(netdev) : netdev; - rcu_read_lock(); -- for_each_dev_addr(netdev, ha) { -+ for_each_dev_addr(real_dev, ha) { - if ((ha->type == NETDEV_HW_ADDR_T_SAN) && -- (is_valid_ether_addr(fip->ctl_src_addr))) { -+ (is_valid_ether_addr(ha->addr))) { - memcpy(fip->ctl_src_addr, ha->addr, ETH_ALEN); - fip->spma = 1; - break; -@@ -664,7 +667,7 @@ static int fcoe_ddp_setup(struct fc_lport *lp, u16 xid, - { - struct net_device *n = fcoe_netdev(lp); - -- if (n->netdev_ops && n->netdev_ops->ndo_fcoe_ddp_setup) -+ if (n->netdev_ops->ndo_fcoe_ddp_setup) - return n->netdev_ops->ndo_fcoe_ddp_setup(n, xid, sgl, sgc); - - return 0; -@@ -681,7 +684,7 @@ static int fcoe_ddp_done(struct fc_lport *lp, u16 xid) - { - struct net_device *n = fcoe_netdev(lp); - -- if (n->netdev_ops && n->netdev_ops->ndo_fcoe_ddp_done) -+ if (n->netdev_ops->ndo_fcoe_ddp_done) - return n->netdev_ops->ndo_fcoe_ddp_done(n, xid); - return 0; - } -@@ -1631,7 +1634,7 @@ static int fcoe_destroy(const char *buffer, struct kernel_param *kp) - { - struct fcoe_interface *fcoe; - struct net_device *netdev; -- int rc; -+ int rc = 0; - - mutex_lock(&fcoe_config_mutex); - #ifdef CONFIG_FCOE_MODULE -diff --git a/drivers/scsi/libfc/fc_disc.c b/drivers/scsi/libfc/fc_disc.c -index c48799e..d4cb3f9 100644 ---- a/drivers/scsi/libfc/fc_disc.c -+++ b/drivers/scsi/libfc/fc_disc.c -@@ -371,7 +371,7 @@ static void fc_disc_gpn_ft_req(struct fc_disc *disc) - disc, lport->e_d_tov)) - return; - err: -- fc_disc_error(disc, fp); -+ fc_disc_error(disc, NULL); - } - - /** -diff --git a/drivers/scsi/libfc/fc_elsct.c b/drivers/scsi/libfc/fc_elsct.c -index 5cfa687..9298458 100644 ---- a/drivers/scsi/libfc/fc_elsct.c -+++ b/drivers/scsi/libfc/fc_elsct.c -@@ -53,8 +53,10 @@ static struct fc_seq *fc_elsct_send(struct fc_lport *lport, - did = FC_FID_DIR_SERV; - } - -- if (rc) -+ if (rc) { -+ fc_frame_free(fp); - return NULL; -+ } - - fc_fill_fc_hdr(fp, r_ctl, did, fc_host_port_id(lport->host), fh_type, - FC_FC_FIRST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT, 0); -diff --git a/drivers/scsi/libfc/fc_fcp.c b/drivers/scsi/libfc/fc_fcp.c -index 59a4408..7a14402 100644 ---- a/drivers/scsi/libfc/fc_fcp.c -+++ b/drivers/scsi/libfc/fc_fcp.c -@@ -302,10 +302,13 @@ static void fc_fcp_ddp_done(struct fc_fcp_pkt *fsp) - if (!fsp) - return; - -+ if (fsp->xfer_ddp == FC_XID_UNKNOWN) -+ return; -+ - lp = fsp->lp; -- if (fsp->xfer_ddp && lp->tt.ddp_done) { -+ if (lp->tt.ddp_done) { - fsp->xfer_len = lp->tt.ddp_done(lp, fsp->xfer_ddp); -- fsp->xfer_ddp = 0; -+ fsp->xfer_ddp = FC_XID_UNKNOWN; - } - } - -@@ -572,7 +575,8 @@ static int fc_fcp_send_data(struct fc_fcp_pkt *fsp, struct fc_seq *seq, - tlen -= sg_bytes; - remaining -= sg_bytes; - -- if (tlen) -+ if ((skb_shinfo(fp_skb(fp))->nr_frags < FC_FRAME_SG_LEN) && -+ (tlen)) - continue; - - /* -@@ -1048,7 +1052,6 @@ static int fc_fcp_cmd_send(struct fc_lport *lp, struct fc_fcp_pkt *fsp, - - seq = lp->tt.exch_seq_send(lp, fp, resp, fc_fcp_pkt_destroy, fsp, 0); - if (!seq) { -- fc_frame_free(fp); - rc = -1; - goto unlock; - } -@@ -1313,7 +1316,6 @@ static void fc_fcp_rec(struct fc_fcp_pkt *fsp) - fc_fcp_pkt_hold(fsp); /* hold while REC outstanding */ - return; - } -- fc_frame_free(fp); - retry: - if (fsp->recov_retry++ < FC_MAX_RECOV_RETRY) - fc_fcp_timer_set(fsp, FC_SCSI_REC_TOV); -@@ -1561,10 +1563,9 @@ static void fc_fcp_srr(struct fc_fcp_pkt *fsp, enum fc_rctl r_ctl, u32 offset) - - seq = lp->tt.exch_seq_send(lp, fp, fc_fcp_srr_resp, NULL, - fsp, jiffies_to_msecs(FC_SCSI_REC_TOV)); -- if (!seq) { -- fc_frame_free(fp); -+ if (!seq) - goto retry; -- } -+ - fsp->recov_seq = seq; - fsp->xfer_len = offset; - fsp->xfer_contig_end = offset; -@@ -1708,6 +1709,7 @@ int fc_queuecommand(struct scsi_cmnd *sc_cmd, void (*done)(struct scsi_cmnd *)) - fsp->cmd = sc_cmd; /* save the cmd */ - fsp->lp = lp; /* save the softc ptr */ - fsp->rport = rport; /* set the remote port ptr */ -+ fsp->xfer_ddp = FC_XID_UNKNOWN; - sc_cmd->scsi_done = done; - - /* -@@ -1846,7 +1848,8 @@ static void fc_io_compl(struct fc_fcp_pkt *fsp) - * scsi status is good but transport level - * underrun. - */ -- sc_cmd->result = DID_OK << 16; -+ sc_cmd->result = (fsp->state & FC_SRB_RCV_STATUS ? -+ DID_OK : DID_ERROR) << 16; - } else { - /* - * scsi got underrun, this is an error -@@ -2046,18 +2049,16 @@ EXPORT_SYMBOL(fc_eh_host_reset); - int fc_slave_alloc(struct scsi_device *sdev) - { - struct fc_rport *rport = starget_to_rport(scsi_target(sdev)); -- int queue_depth; - - if (!rport || fc_remote_port_chkready(rport)) - return -ENXIO; - -- if (sdev->tagged_supported) { -- if (sdev->host->hostt->cmd_per_lun) -- queue_depth = sdev->host->hostt->cmd_per_lun; -- else -- queue_depth = FC_FCP_DFLT_QUEUE_DEPTH; -- scsi_activate_tcq(sdev, queue_depth); -- } -+ if (sdev->tagged_supported) -+ scsi_activate_tcq(sdev, FC_FCP_DFLT_QUEUE_DEPTH); -+ else -+ scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), -+ FC_FCP_DFLT_QUEUE_DEPTH); -+ - return 0; - } - EXPORT_SYMBOL(fc_slave_alloc); -diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c -index bd2f771..536492a 100644 ---- a/drivers/scsi/libfc/fc_lport.c -+++ b/drivers/scsi/libfc/fc_lport.c -@@ -329,7 +329,7 @@ static void fc_lport_add_fc4_type(struct fc_lport *lport, enum fc_fh_type type) - * @sp: current sequence in the RLIR exchange - * @fp: RLIR request frame - * -- * Locking Note: The lport lock is exected to be held before calling -+ * Locking Note: The lport lock is expected to be held before calling - * this function. - */ - static void fc_lport_recv_rlir_req(struct fc_seq *sp, struct fc_frame *fp, -@@ -348,7 +348,7 @@ static void fc_lport_recv_rlir_req(struct fc_seq *sp, struct fc_frame *fp, - * @sp: current sequence in the ECHO exchange - * @fp: ECHO request frame - * -- * Locking Note: The lport lock is exected to be held before calling -+ * Locking Note: The lport lock is expected to be held before calling - * this function. - */ - static void fc_lport_recv_echo_req(struct fc_seq *sp, struct fc_frame *in_fp, -@@ -361,7 +361,7 @@ static void fc_lport_recv_echo_req(struct fc_seq *sp, struct fc_frame *in_fp, - void *dp; - u32 f_ctl; - -- FC_LPORT_DBG(lport, "Received RLIR request while in state %s\n", -+ FC_LPORT_DBG(lport, "Received ECHO request while in state %s\n", - fc_lport_state(lport)); - - len = fr_len(in_fp) - sizeof(struct fc_frame_header); -@@ -374,7 +374,7 @@ static void fc_lport_recv_echo_req(struct fc_seq *sp, struct fc_frame *in_fp, - if (fp) { - dp = fc_frame_payload_get(fp, len); - memcpy(dp, pp, len); -- *((u32 *)dp) = htonl(ELS_LS_ACC << 24); -+ *((__be32 *)dp) = htonl(ELS_LS_ACC << 24); - sp = lport->tt.seq_start_next(sp); - f_ctl = FC_FC_EX_CTX | FC_FC_LAST_SEQ | FC_FC_END_SEQ; - fc_fill_fc_hdr(fp, FC_RCTL_ELS_REP, ep->did, ep->sid, -@@ -385,12 +385,12 @@ static void fc_lport_recv_echo_req(struct fc_seq *sp, struct fc_frame *in_fp, - } - - /** -- * fc_lport_recv_echo_req() - Handle received Request Node ID data request -- * @lport: Fibre Channel local port recieving the RNID -- * @sp: current sequence in the RNID exchange -- * @fp: RNID request frame -+ * fc_lport_recv_rnid_req() - Handle received Request Node ID data request -+ * @sp: The sequence in the RNID exchange -+ * @fp: The RNID request frame -+ * @lport: The local port recieving the RNID - * -- * Locking Note: The lport lock is exected to be held before calling -+ * Locking Note: The lport lock is expected to be held before calling - * this function. - */ - static void fc_lport_recv_rnid_req(struct fc_seq *sp, struct fc_frame *in_fp, -@@ -667,7 +667,7 @@ static void fc_lport_enter_ready(struct fc_lport *lport) - * Accept it with the common service parameters indicating our N port. - * Set up to do a PLOGI if we have the higher-number WWPN. - * -- * Locking Note: The lport lock is exected to be held before calling -+ * Locking Note: The lport lock is expected to be held before calling - * this function. - */ - static void fc_lport_recv_flogi_req(struct fc_seq *sp_in, -@@ -1115,7 +1115,7 @@ static void fc_lport_enter_scr(struct fc_lport *lport) - - if (!lport->tt.elsct_send(lport, FC_FID_FCTRL, fp, ELS_SCR, - fc_lport_scr_resp, lport, lport->e_d_tov)) -- fc_lport_error(lport, fp); -+ fc_lport_error(lport, NULL); - } - - /** -@@ -1186,7 +1186,7 @@ static void fc_lport_enter_rpn_id(struct fc_lport *lport) - if (!lport->tt.elsct_send(lport, FC_FID_DIR_SERV, fp, FC_NS_RPN_ID, - fc_lport_rpn_id_resp, - lport, lport->e_d_tov)) -- fc_lport_error(lport, fp); -+ fc_lport_error(lport, NULL); - } - - static struct fc_rport_operations fc_lport_rport_ops = { -@@ -1237,10 +1237,13 @@ static void fc_lport_timeout(struct work_struct *work) - - switch (lport->state) { - case LPORT_ST_DISABLED: -+ WARN_ON(1); -+ break; - case LPORT_ST_READY: -- case LPORT_ST_RESET: - WARN_ON(1); - break; -+ case LPORT_ST_RESET: -+ break; - case LPORT_ST_FLOGI: - fc_lport_enter_flogi(lport); - break; -@@ -1337,7 +1340,7 @@ static void fc_lport_enter_logo(struct fc_lport *lport) - - if (!lport->tt.elsct_send(lport, FC_FID_FLOGI, fp, ELS_LOGO, - fc_lport_logo_resp, lport, lport->e_d_tov)) -- fc_lport_error(lport, fp); -+ fc_lport_error(lport, NULL); - } - - /** -@@ -1453,7 +1456,7 @@ void fc_lport_enter_flogi(struct fc_lport *lport) - - if (!lport->tt.elsct_send(lport, FC_FID_FLOGI, fp, ELS_FLOGI, - fc_lport_flogi_resp, lport, lport->e_d_tov)) -- fc_lport_error(lport, fp); -+ fc_lport_error(lport, NULL); - } - - /* Configure a fc_lport */ -diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c -index 03ea674..ff558a6 100644 ---- a/drivers/scsi/libfc/fc_rport.c -+++ b/drivers/scsi/libfc/fc_rport.c -@@ -86,6 +86,7 @@ static const char *fc_rport_state_names[] = { - [RPORT_ST_LOGO] = "LOGO", - [RPORT_ST_ADISC] = "ADISC", - [RPORT_ST_DELETE] = "Delete", -+ [RPORT_ST_RESTART] = "Restart", - }; - - /** -@@ -99,8 +100,7 @@ static struct fc_rport_priv *fc_rport_lookup(const struct fc_lport *lport, - struct fc_rport_priv *rdata; - - list_for_each_entry(rdata, &lport->disc.rports, peers) -- if (rdata->ids.port_id == port_id && -- rdata->rp_state != RPORT_ST_DELETE) -+ if (rdata->ids.port_id == port_id) - return rdata; - return NULL; - } -@@ -235,6 +235,7 @@ static void fc_rport_work(struct work_struct *work) - struct fc_rport_operations *rport_ops; - struct fc_rport_identifiers ids; - struct fc_rport *rport; -+ int restart = 0; - - mutex_lock(&rdata->rp_mutex); - event = rdata->event; -@@ -287,8 +288,20 @@ static void fc_rport_work(struct work_struct *work) - mutex_unlock(&rdata->rp_mutex); - - if (port_id != FC_FID_DIR_SERV) { -+ /* -+ * We must drop rp_mutex before taking disc_mutex. -+ * Re-evaluate state to allow for restart. -+ * A transition to RESTART state must only happen -+ * while disc_mutex is held and rdata is on the list. -+ */ - mutex_lock(&lport->disc.disc_mutex); -- list_del(&rdata->peers); -+ mutex_lock(&rdata->rp_mutex); -+ if (rdata->rp_state == RPORT_ST_RESTART) -+ restart = 1; -+ else -+ list_del(&rdata->peers); -+ rdata->event = RPORT_EV_NONE; -+ mutex_unlock(&rdata->rp_mutex); - mutex_unlock(&lport->disc.disc_mutex); - } - -@@ -312,7 +325,13 @@ static void fc_rport_work(struct work_struct *work) - mutex_unlock(&rdata->rp_mutex); - fc_remote_port_delete(rport); - } -- kref_put(&rdata->kref, lport->tt.rport_destroy); -+ if (restart) { -+ mutex_lock(&rdata->rp_mutex); -+ FC_RPORT_DBG(rdata, "work restart\n"); -+ fc_rport_enter_plogi(rdata); -+ mutex_unlock(&rdata->rp_mutex); -+ } else -+ kref_put(&rdata->kref, lport->tt.rport_destroy); - break; - - default: -@@ -342,6 +361,12 @@ int fc_rport_login(struct fc_rport_priv *rdata) - FC_RPORT_DBG(rdata, "ADISC port\n"); - fc_rport_enter_adisc(rdata); - break; -+ case RPORT_ST_RESTART: -+ break; -+ case RPORT_ST_DELETE: -+ FC_RPORT_DBG(rdata, "Restart deleted port\n"); -+ fc_rport_state_enter(rdata, RPORT_ST_RESTART); -+ break; - default: - FC_RPORT_DBG(rdata, "Login to port\n"); - fc_rport_enter_plogi(rdata); -@@ -397,20 +422,21 @@ int fc_rport_logoff(struct fc_rport_priv *rdata) - - if (rdata->rp_state == RPORT_ST_DELETE) { - FC_RPORT_DBG(rdata, "Port in Delete state, not removing\n"); -- mutex_unlock(&rdata->rp_mutex); - goto out; - } - -- fc_rport_enter_logo(rdata); -+ if (rdata->rp_state == RPORT_ST_RESTART) -+ FC_RPORT_DBG(rdata, "Port in Restart state, deleting\n"); -+ else -+ fc_rport_enter_logo(rdata); - - /* - * Change the state to Delete so that we discard - * the response. - */ - fc_rport_enter_delete(rdata, RPORT_EV_STOP); -- mutex_unlock(&rdata->rp_mutex); -- - out: -+ mutex_unlock(&rdata->rp_mutex); - return 0; - } - -@@ -466,6 +492,7 @@ static void fc_rport_timeout(struct work_struct *work) - case RPORT_ST_READY: - case RPORT_ST_INIT: - case RPORT_ST_DELETE: -+ case RPORT_ST_RESTART: - break; - } - -@@ -499,6 +526,7 @@ static void fc_rport_error(struct fc_rport_priv *rdata, struct fc_frame *fp) - fc_rport_enter_logo(rdata); - break; - case RPORT_ST_DELETE: -+ case RPORT_ST_RESTART: - case RPORT_ST_READY: - case RPORT_ST_INIT: - break; -@@ -632,7 +660,7 @@ static void fc_rport_enter_plogi(struct fc_rport_priv *rdata) - - if (!lport->tt.elsct_send(lport, rdata->ids.port_id, fp, ELS_PLOGI, - fc_rport_plogi_resp, rdata, lport->e_d_tov)) -- fc_rport_error_retry(rdata, fp); -+ fc_rport_error_retry(rdata, NULL); - else - kref_get(&rdata->kref); - } -@@ -793,7 +821,7 @@ static void fc_rport_enter_prli(struct fc_rport_priv *rdata) - - if (!lport->tt.elsct_send(lport, rdata->ids.port_id, fp, ELS_PRLI, - fc_rport_prli_resp, rdata, lport->e_d_tov)) -- fc_rport_error_retry(rdata, fp); -+ fc_rport_error_retry(rdata, NULL); - else - kref_get(&rdata->kref); - } -@@ -889,7 +917,7 @@ static void fc_rport_enter_rtv(struct fc_rport_priv *rdata) - - if (!lport->tt.elsct_send(lport, rdata->ids.port_id, fp, ELS_RTV, - fc_rport_rtv_resp, rdata, lport->e_d_tov)) -- fc_rport_error_retry(rdata, fp); -+ fc_rport_error_retry(rdata, NULL); - else - kref_get(&rdata->kref); - } -@@ -919,7 +947,7 @@ static void fc_rport_enter_logo(struct fc_rport_priv *rdata) - - if (!lport->tt.elsct_send(lport, rdata->ids.port_id, fp, ELS_LOGO, - fc_rport_logo_resp, rdata, lport->e_d_tov)) -- fc_rport_error_retry(rdata, fp); -+ fc_rport_error_retry(rdata, NULL); - else - kref_get(&rdata->kref); - } -@@ -1006,7 +1034,7 @@ static void fc_rport_enter_adisc(struct fc_rport_priv *rdata) - } - if (!lport->tt.elsct_send(lport, rdata->ids.port_id, fp, ELS_ADISC, - fc_rport_adisc_resp, rdata, lport->e_d_tov)) -- fc_rport_error_retry(rdata, fp); -+ fc_rport_error_retry(rdata, NULL); - else - kref_get(&rdata->kref); - } -@@ -1248,6 +1276,7 @@ static void fc_rport_recv_plogi_req(struct fc_lport *lport, - } - break; - case RPORT_ST_PRLI: -+ case RPORT_ST_RTV: - case RPORT_ST_READY: - case RPORT_ST_ADISC: - FC_RPORT_DBG(rdata, "Received PLOGI in logged-in state %d " -@@ -1255,11 +1284,14 @@ static void fc_rport_recv_plogi_req(struct fc_lport *lport, - /* XXX TBD - should reset */ - break; - case RPORT_ST_DELETE: -- default: -- FC_RPORT_DBG(rdata, "Received PLOGI in unexpected state %d\n", -- rdata->rp_state); -- fc_frame_free(rx_fp); -- goto out; -+ case RPORT_ST_LOGO: -+ case RPORT_ST_RESTART: -+ FC_RPORT_DBG(rdata, "Received PLOGI in state %s - send busy\n", -+ fc_rport_state(rdata)); -+ mutex_unlock(&rdata->rp_mutex); -+ rjt_data.reason = ELS_RJT_BUSY; -+ rjt_data.explan = ELS_EXPL_NONE; -+ goto reject; - } - - /* -@@ -1402,7 +1434,7 @@ static void fc_rport_recv_prli_req(struct fc_rport_priv *rdata, - break; - case FC_TYPE_FCP: - fcp_parm = ntohl(rspp->spp_params); -- if (fcp_parm * FCP_SPPF_RETRY) -+ if (fcp_parm & FCP_SPPF_RETRY) - rdata->flags |= FC_RP_FLAGS_RETRY; - rdata->supported_classes = FC_COS_CLASS3; - if (fcp_parm & FCP_SPPF_INIT_FCN) -@@ -1510,14 +1542,14 @@ static void fc_rport_recv_logo_req(struct fc_lport *lport, - FC_RPORT_DBG(rdata, "Received LOGO request while in state %s\n", - fc_rport_state(rdata)); - -+ fc_rport_enter_delete(rdata, RPORT_EV_LOGO); -+ - /* -- * If the remote port was created due to discovery, -- * log back in. It may have seen a stale RSCN about us. -+ * If the remote port was created due to discovery, set state -+ * to log back in. It may have seen a stale RSCN about us. - */ -- if (rdata->rp_state != RPORT_ST_DELETE && rdata->disc_id) -- fc_rport_enter_plogi(rdata); -- else -- fc_rport_enter_delete(rdata, RPORT_EV_LOGO); -+ if (rdata->disc_id) -+ fc_rport_state_enter(rdata, RPORT_ST_RESTART); - mutex_unlock(&rdata->rp_mutex); - } else - FC_RPORT_ID_DBG(lport, sid, -diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c -index f913f1e..549bc7d 100644 ---- a/drivers/scsi/lpfc/lpfc_init.c -+++ b/drivers/scsi/lpfc/lpfc_init.c -@@ -4384,9 +4384,13 @@ lpfc_sli_pci_mem_setup(struct lpfc_hba *phba) - pdev = phba->pcidev; - - /* Set the device DMA mask size */ -- if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) != 0) -- if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) != 0) -+ if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) != 0 -+ || pci_set_consistent_dma_mask(pdev,DMA_BIT_MASK(64)) != 0) { -+ if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) != 0 -+ || pci_set_consistent_dma_mask(pdev,DMA_BIT_MASK(32)) != 0) { - return error; -+ } -+ } - - /* Get the bus address of Bar0 and Bar2 and the number of bytes - * required by each mapping. -@@ -5940,9 +5944,13 @@ lpfc_sli4_pci_mem_setup(struct lpfc_hba *phba) - pdev = phba->pcidev; - - /* Set the device DMA mask size */ -- if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) != 0) -- if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) != 0) -+ if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) != 0 -+ || pci_set_consistent_dma_mask(pdev,DMA_BIT_MASK(64)) != 0) { -+ if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) != 0 -+ || pci_set_consistent_dma_mask(pdev,DMA_BIT_MASK(32)) != 0) { - return error; -+ } -+ } - - /* Get the bus address of SLI4 device Bar0, Bar1, and Bar2 and the - * number of bytes required by each mapping. They are actually -diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h b/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h -index ab47c46..5af66db 100644 ---- a/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h -+++ b/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h -@@ -348,6 +348,14 @@ typedef struct _MPI2_CONFIG_REPLY - #define MPI2_MFGPAGE_DEVID_SAS2108_3 (0x0077) - #define MPI2_MFGPAGE_DEVID_SAS2116_1 (0x0064) - #define MPI2_MFGPAGE_DEVID_SAS2116_2 (0x0065) -+#define MPI2_MFGPAGE_DEVID_SAS2208_1 (0x0080) -+#define MPI2_MFGPAGE_DEVID_SAS2208_2 (0x0081) -+#define MPI2_MFGPAGE_DEVID_SAS2208_3 (0x0082) -+#define MPI2_MFGPAGE_DEVID_SAS2208_4 (0x0083) -+#define MPI2_MFGPAGE_DEVID_SAS2208_5 (0x0084) -+#define MPI2_MFGPAGE_DEVID_SAS2208_6 (0x0085) -+#define MPI2_MFGPAGE_DEVID_SAS2208_7 (0x0086) -+#define MPI2_MFGPAGE_DEVID_SAS2208_8 (0x0087) - - - /* Manufacturing Page 0 */ -diff --git a/drivers/scsi/mpt2sas/mpt2sas_scsih.c b/drivers/scsi/mpt2sas/mpt2sas_scsih.c -index 86ab32d..1743640 100644 ---- a/drivers/scsi/mpt2sas/mpt2sas_scsih.c -+++ b/drivers/scsi/mpt2sas/mpt2sas_scsih.c -@@ -196,10 +196,28 @@ static struct pci_device_id scsih_pci_table[] = { - PCI_ANY_ID, PCI_ANY_ID }, - { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2108_3, - PCI_ANY_ID, PCI_ANY_ID }, -+ /* Meteor ~ 2116 */ - { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2116_1, - PCI_ANY_ID, PCI_ANY_ID }, - { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2116_2, - PCI_ANY_ID, PCI_ANY_ID }, -+ /* Thunderbolt ~ 2208 */ -+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_1, -+ PCI_ANY_ID, PCI_ANY_ID }, -+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_2, -+ PCI_ANY_ID, PCI_ANY_ID }, -+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_3, -+ PCI_ANY_ID, PCI_ANY_ID }, -+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_4, -+ PCI_ANY_ID, PCI_ANY_ID }, -+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_5, -+ PCI_ANY_ID, PCI_ANY_ID }, -+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_6, -+ PCI_ANY_ID, PCI_ANY_ID }, -+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_7, -+ PCI_ANY_ID, PCI_ANY_ID }, -+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_8, -+ PCI_ANY_ID, PCI_ANY_ID }, - {0} /* Terminating entry */ - }; - MODULE_DEVICE_TABLE(pci, scsih_pci_table); -diff --git a/drivers/scsi/scsi_devinfo.c b/drivers/scsi/scsi_devinfo.c -index 93c2622..802e91c 100644 ---- a/drivers/scsi/scsi_devinfo.c -+++ b/drivers/scsi/scsi_devinfo.c -@@ -168,11 +168,10 @@ static struct { - {"Generic", "USB SD Reader", "1.00", BLIST_FORCELUN | BLIST_INQUIRY_36}, - {"Generic", "USB Storage-SMC", "0180", BLIST_FORCELUN | BLIST_INQUIRY_36}, - {"Generic", "USB Storage-SMC", "0207", BLIST_FORCELUN | BLIST_INQUIRY_36}, -- {"HITACHI", "DF400", "*", BLIST_SPARSELUN}, -- {"HITACHI", "DF500", "*", BLIST_SPARSELUN}, -- {"HITACHI", "DF600", "*", BLIST_SPARSELUN}, -- {"HITACHI", "DISK-SUBSYSTEM", "*", BLIST_ATTACH_PQ3 | BLIST_SPARSELUN | BLIST_LARGELUN}, -- {"HITACHI", "OPEN-E", "*", BLIST_ATTACH_PQ3 | BLIST_SPARSELUN | BLIST_LARGELUN}, -+ {"HITACHI", "DF400", "*", BLIST_REPORTLUN2}, -+ {"HITACHI", "DF500", "*", BLIST_REPORTLUN2}, -+ {"HITACHI", "DISK-SUBSYSTEM", "*", BLIST_REPORTLUN2}, -+ {"HITACHI", "OPEN-", "*", BLIST_REPORTLUN2}, - {"HITACHI", "OP-C-", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, - {"HITACHI", "3380-", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, - {"HITACHI", "3390-", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, -diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c -index 45be82f..bf52dec 100644 ---- a/drivers/scsi/scsi_transport_fc.c -+++ b/drivers/scsi/scsi_transport_fc.c -@@ -2395,6 +2395,7 @@ fc_rport_final_delete(struct work_struct *work) - struct Scsi_Host *shost = rport_to_shost(rport); - struct fc_internal *i = to_fc_internal(shost->transportt); - unsigned long flags; -+ int do_callback = 0; - - /* - * if a scan is pending, flush the SCSI Host work_q so that -@@ -2433,8 +2434,15 @@ fc_rport_final_delete(struct work_struct *work) - * Avoid this call if we already called it when we preserved the - * rport for the binding. - */ -+ spin_lock_irqsave(shost->host_lock, flags); - if (!(rport->flags & FC_RPORT_DEVLOSS_CALLBK_DONE) && -- (i->f->dev_loss_tmo_callbk)) -+ (i->f->dev_loss_tmo_callbk)) { -+ rport->flags |= FC_RPORT_DEVLOSS_CALLBK_DONE; -+ do_callback = 1; -+ } -+ spin_unlock_irqrestore(shost->host_lock, flags); -+ -+ if (do_callback) - i->f->dev_loss_tmo_callbk(rport); - - fc_bsg_remove(rport->rqst_q); -@@ -2981,6 +2989,7 @@ fc_timeout_deleted_rport(struct work_struct *work) - struct fc_internal *i = to_fc_internal(shost->transportt); - struct fc_host_attrs *fc_host = shost_to_fc_host(shost); - unsigned long flags; -+ int do_callback = 0; - - spin_lock_irqsave(shost->host_lock, flags); - -@@ -3046,7 +3055,6 @@ fc_timeout_deleted_rport(struct work_struct *work) - rport->roles = FC_PORT_ROLE_UNKNOWN; - rport->port_state = FC_PORTSTATE_NOTPRESENT; - rport->flags &= ~FC_RPORT_FAST_FAIL_TIMEDOUT; -- rport->flags |= FC_RPORT_DEVLOSS_CALLBK_DONE; - - /* - * Pre-emptively kill I/O rather than waiting for the work queue -@@ -3056,32 +3064,40 @@ fc_timeout_deleted_rport(struct work_struct *work) - spin_unlock_irqrestore(shost->host_lock, flags); - fc_terminate_rport_io(rport); - -- BUG_ON(rport->port_state != FC_PORTSTATE_NOTPRESENT); -+ spin_lock_irqsave(shost->host_lock, flags); - -- /* remove the identifiers that aren't used in the consisting binding */ -- switch (fc_host->tgtid_bind_type) { -- case FC_TGTID_BIND_BY_WWPN: -- rport->node_name = -1; -- rport->port_id = -1; -- break; -- case FC_TGTID_BIND_BY_WWNN: -- rport->port_name = -1; -- rport->port_id = -1; -- break; -- case FC_TGTID_BIND_BY_ID: -- rport->node_name = -1; -- rport->port_name = -1; -- break; -- case FC_TGTID_BIND_NONE: /* to keep compiler happy */ -- break; -+ if (rport->port_state == FC_PORTSTATE_NOTPRESENT) { /* still missing */ -+ -+ /* remove the identifiers that aren't used in the consisting binding */ -+ switch (fc_host->tgtid_bind_type) { -+ case FC_TGTID_BIND_BY_WWPN: -+ rport->node_name = -1; -+ rport->port_id = -1; -+ break; -+ case FC_TGTID_BIND_BY_WWNN: -+ rport->port_name = -1; -+ rport->port_id = -1; -+ break; -+ case FC_TGTID_BIND_BY_ID: -+ rport->node_name = -1; -+ rport->port_name = -1; -+ break; -+ case FC_TGTID_BIND_NONE: /* to keep compiler happy */ -+ break; -+ } -+ -+ /* -+ * As this only occurs if the remote port (scsi target) -+ * went away and didn't come back - we'll remove -+ * all attached scsi devices. -+ */ -+ rport->flags |= FC_RPORT_DEVLOSS_CALLBK_DONE; -+ fc_queue_work(shost, &rport->stgt_delete_work); -+ -+ do_callback = 1; - } - -- /* -- * As this only occurs if the remote port (scsi target) -- * went away and didn't come back - we'll remove -- * all attached scsi devices. -- */ -- fc_queue_work(shost, &rport->stgt_delete_work); -+ spin_unlock_irqrestore(shost->host_lock, flags); - - /* - * Notify the driver that the rport is now dead. The LLDD will -@@ -3089,7 +3105,7 @@ fc_timeout_deleted_rport(struct work_struct *work) - * - * Note: we set the CALLBK_DONE flag above to correspond - */ -- if (i->f->dev_loss_tmo_callbk) -+ if (do_callback && i->f->dev_loss_tmo_callbk) - i->f->dev_loss_tmo_callbk(rport); - } - -diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c -index ad897df..de2f8c4 100644 ---- a/drivers/scsi/scsi_transport_iscsi.c -+++ b/drivers/scsi/scsi_transport_iscsi.c -@@ -627,8 +627,10 @@ static void __iscsi_block_session(struct work_struct *work) - spin_unlock_irqrestore(&session->lock, flags); - scsi_target_block(&session->dev); - ISCSI_DBG_TRANS_SESSION(session, "Completed SCSI target blocking\n"); -- queue_delayed_work(iscsi_eh_timer_workq, &session->recovery_work, -- session->recovery_tmo * HZ); -+ if (session->recovery_tmo >= 0) -+ queue_delayed_work(iscsi_eh_timer_workq, -+ &session->recovery_work, -+ session->recovery_tmo * HZ); - } - - void iscsi_block_session(struct iscsi_cls_session *session) -@@ -1348,8 +1350,7 @@ iscsi_set_param(struct iscsi_transport *transport, struct iscsi_uevent *ev) - switch (ev->u.set_param.param) { - case ISCSI_PARAM_SESS_RECOVERY_TMO: - sscanf(data, "%d", &value); -- if (value != 0) -- session->recovery_tmo = value; -+ session->recovery_tmo = value; - break; - default: - err = transport->set_param(conn, ev->u.set_param.param, -diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c -index ebcc6d0..13a1b39 100644 ---- a/drivers/usb/serial/ftdi_sio.c -+++ b/drivers/usb/serial/ftdi_sio.c -@@ -598,6 +598,20 @@ static struct usb_device_id id_table_combined [] = { - { USB_DEVICE(BANDB_VID, BANDB_USOTL4_PID) }, - { USB_DEVICE(BANDB_VID, BANDB_USTL4_PID) }, - { USB_DEVICE(BANDB_VID, BANDB_USO9ML2_PID) }, -+ { USB_DEVICE(BANDB_VID, BANDB_USOPTL4_PID) }, -+ { USB_DEVICE(BANDB_VID, BANDB_USPTL4_PID) }, -+ { USB_DEVICE(BANDB_VID, BANDB_USO9ML2DR_2_PID) }, -+ { USB_DEVICE(BANDB_VID, BANDB_USO9ML2DR_PID) }, -+ { USB_DEVICE(BANDB_VID, BANDB_USOPTL4DR2_PID) }, -+ { USB_DEVICE(BANDB_VID, BANDB_USOPTL4DR_PID) }, -+ { USB_DEVICE(BANDB_VID, BANDB_485USB9F_2W_PID) }, -+ { USB_DEVICE(BANDB_VID, BANDB_485USB9F_4W_PID) }, -+ { USB_DEVICE(BANDB_VID, BANDB_232USB9M_PID) }, -+ { USB_DEVICE(BANDB_VID, BANDB_485USBTB_2W_PID) }, -+ { USB_DEVICE(BANDB_VID, BANDB_485USBTB_4W_PID) }, -+ { USB_DEVICE(BANDB_VID, BANDB_TTL5USB9M_PID) }, -+ { USB_DEVICE(BANDB_VID, BANDB_TTL3USB9M_PID) }, -+ { USB_DEVICE(BANDB_VID, BANDB_ZZ_PROG1_USB_PID) }, - { USB_DEVICE(FTDI_VID, EVER_ECO_PRO_CDS) }, - { USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_1_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_2_PID) }, -diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h -index 6f31e0d..4586a24 100644 ---- a/drivers/usb/serial/ftdi_sio.h -+++ b/drivers/usb/serial/ftdi_sio.h -@@ -662,6 +662,20 @@ - #define BANDB_USOTL4_PID 0xAC01 /* USOTL4 Isolated RS-485 Converter */ - #define BANDB_USTL4_PID 0xAC02 /* USTL4 RS-485 Converter */ - #define BANDB_USO9ML2_PID 0xAC03 /* USO9ML2 Isolated RS-232 Converter */ -+#define BANDB_USOPTL4_PID 0xAC11 -+#define BANDB_USPTL4_PID 0xAC12 -+#define BANDB_USO9ML2DR_2_PID 0xAC16 -+#define BANDB_USO9ML2DR_PID 0xAC17 -+#define BANDB_USOPTL4DR2_PID 0xAC18 /* USOPTL4R-2 2-port Isolated RS-232 Converter */ -+#define BANDB_USOPTL4DR_PID 0xAC19 -+#define BANDB_485USB9F_2W_PID 0xAC25 -+#define BANDB_485USB9F_4W_PID 0xAC26 -+#define BANDB_232USB9M_PID 0xAC27 -+#define BANDB_485USBTB_2W_PID 0xAC33 -+#define BANDB_485USBTB_4W_PID 0xAC34 -+#define BANDB_TTL5USB9M_PID 0xAC49 -+#define BANDB_TTL3USB9M_PID 0xAC50 -+#define BANDB_ZZ_PROG1_USB_PID 0xBA02 - - /* - * RM Michaelides CANview USB (http://www.rmcan.com) -diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c -index f11abf5..485fa9c 100644 ---- a/drivers/usb/serial/mos7840.c -+++ b/drivers/usb/serial/mos7840.c -@@ -121,8 +121,14 @@ - * moschip_id_table_combined - */ - #define USB_VENDOR_ID_BANDB 0x0856 --#define BANDB_DEVICE_ID_USOPTL4_4 0xAC44 -+#define BANDB_DEVICE_ID_USO9ML2_2 0xAC22 -+#define BANDB_DEVICE_ID_USO9ML2_4 0xAC24 -+#define BANDB_DEVICE_ID_US9ML2_2 0xAC29 -+#define BANDB_DEVICE_ID_US9ML2_4 0xAC30 -+#define BANDB_DEVICE_ID_USPTL4_2 0xAC31 -+#define BANDB_DEVICE_ID_USPTL4_4 0xAC32 - #define BANDB_DEVICE_ID_USOPTL4_2 0xAC42 -+#define BANDB_DEVICE_ID_USOPTL4_4 0xAC44 - - /* This driver also supports - * ATEN UC2324 device using Moschip MCS7840 -@@ -177,8 +183,14 @@ - static struct usb_device_id moschip_port_id_table[] = { - {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7840)}, - {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7820)}, -- {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_4)}, -+ {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_2)}, -+ {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_4)}, -+ {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_US9ML2_2)}, -+ {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_US9ML2_4)}, -+ {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USPTL4_2)}, -+ {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USPTL4_4)}, - {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_2)}, -+ {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_4)}, - {USB_DEVICE(USB_VENDOR_ID_ATENINTL, ATENINTL_DEVICE_ID_UC2324)}, - {USB_DEVICE(USB_VENDOR_ID_ATENINTL, ATENINTL_DEVICE_ID_UC2322)}, - {} /* terminating entry */ -@@ -187,8 +199,14 @@ static struct usb_device_id moschip_port_id_table[] = { - static __devinitdata struct usb_device_id moschip_id_table_combined[] = { - {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7840)}, - {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7820)}, -- {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_4)}, -+ {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_2)}, -+ {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_4)}, -+ {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_US9ML2_2)}, -+ {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_US9ML2_4)}, -+ {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USPTL4_2)}, -+ {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USPTL4_4)}, - {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_2)}, -+ {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_4)}, - {USB_DEVICE(USB_VENDOR_ID_ATENINTL, ATENINTL_DEVICE_ID_UC2324)}, - {USB_DEVICE(USB_VENDOR_ID_ATENINTL, ATENINTL_DEVICE_ID_UC2322)}, - {} /* terminating entry */ -diff --git a/drivers/watchdog/iTCO_wdt.c b/drivers/watchdog/iTCO_wdt.c -index 6a51edd..4bdb7f1 100644 ---- a/drivers/watchdog/iTCO_wdt.c -+++ b/drivers/watchdog/iTCO_wdt.c -@@ -1,5 +1,5 @@ - /* -- * intel TCO Watchdog Driver (Used in i82801 and i63xxESB chipsets) -+ * intel TCO Watchdog Driver - * - * (c) Copyright 2006-2009 Wim Van Sebroeck . - * -@@ -14,47 +14,24 @@ - * - * The TCO watchdog is implemented in the following I/O controller hubs: - * (See the intel documentation on http://developer.intel.com.) -- * 82801AA (ICH) : document number 290655-003, 290677-014, -- * 82801AB (ICHO) : document number 290655-003, 290677-014, -- * 82801BA (ICH2) : document number 290687-002, 298242-027, -- * 82801BAM (ICH2-M) : document number 290687-002, 298242-027, -- * 82801CA (ICH3-S) : document number 290733-003, 290739-013, -- * 82801CAM (ICH3-M) : document number 290716-001, 290718-007, -- * 82801DB (ICH4) : document number 290744-001, 290745-025, -- * 82801DBM (ICH4-M) : document number 252337-001, 252663-008, -- * 82801E (C-ICH) : document number 273599-001, 273645-002, -- * 82801EB (ICH5) : document number 252516-001, 252517-028, -- * 82801ER (ICH5R) : document number 252516-001, 252517-028, -- * 6300ESB (6300ESB) : document number 300641-004, 300884-013, -- * 82801FB (ICH6) : document number 301473-002, 301474-026, -- * 82801FR (ICH6R) : document number 301473-002, 301474-026, -- * 82801FBM (ICH6-M) : document number 301473-002, 301474-026, -- * 82801FW (ICH6W) : document number 301473-001, 301474-026, -- * 82801FRW (ICH6RW) : document number 301473-001, 301474-026, -- * 631xESB (631xESB) : document number 313082-001, 313075-006, -- * 632xESB (632xESB) : document number 313082-001, 313075-006, -- * 82801GB (ICH7) : document number 307013-003, 307014-024, -- * 82801GR (ICH7R) : document number 307013-003, 307014-024, -- * 82801GDH (ICH7DH) : document number 307013-003, 307014-024, -- * 82801GBM (ICH7-M) : document number 307013-003, 307014-024, -- * 82801GHM (ICH7-M DH) : document number 307013-003, 307014-024, -- * 82801GU (ICH7-U) : document number 307013-003, 307014-024, -- * 82801HB (ICH8) : document number 313056-003, 313057-017, -- * 82801HR (ICH8R) : document number 313056-003, 313057-017, -- * 82801HBM (ICH8M) : document number 313056-003, 313057-017, -- * 82801HH (ICH8DH) : document number 313056-003, 313057-017, -- * 82801HO (ICH8DO) : document number 313056-003, 313057-017, -- * 82801HEM (ICH8M-E) : document number 313056-003, 313057-017, -- * 82801IB (ICH9) : document number 316972-004, 316973-012, -- * 82801IR (ICH9R) : document number 316972-004, 316973-012, -- * 82801IH (ICH9DH) : document number 316972-004, 316973-012, -- * 82801IO (ICH9DO) : document number 316972-004, 316973-012, -- * 82801IBM (ICH9M) : document number 316972-004, 316973-012, -- * 82801IEM (ICH9M-E) : document number 316972-004, 316973-012, -- * 82801JIB (ICH10) : document number 319973-002, 319974-002, -- * 82801JIR (ICH10R) : document number 319973-002, 319974-002, -- * 82801JD (ICH10D) : document number 319973-002, 319974-002, -- * 82801JDO (ICH10DO) : document number 319973-002, 319974-002 -+ * document number 290655-003, 290677-014: 82801AA (ICH), 82801AB (ICHO) -+ * document number 290687-002, 298242-027: 82801BA (ICH2) -+ * document number 290733-003, 290739-013: 82801CA (ICH3-S) -+ * document number 290716-001, 290718-007: 82801CAM (ICH3-M) -+ * document number 290744-001, 290745-025: 82801DB (ICH4) -+ * document number 252337-001, 252663-008: 82801DBM (ICH4-M) -+ * document number 273599-001, 273645-002: 82801E (C-ICH) -+ * document number 252516-001, 252517-028: 82801EB (ICH5), 82801ER (ICH5R) -+ * document number 300641-004, 300884-013: 6300ESB -+ * document number 301473-002, 301474-026: 82801F (ICH6) -+ * document number 313082-001, 313075-006: 631xESB, 632xESB -+ * document number 307013-003, 307014-024: 82801G (ICH7) -+ * document number 313056-003, 313057-017: 82801H (ICH8) -+ * document number 316972-004, 316973-012: 82801I (ICH9) -+ * document number 319973-002, 319974-002: 82801J (ICH10) -+ * document number 322169-001, 322170-003: 5 Series, 3400 Series (PCH) -+ * document number 320066-003, 320257-008: EP80597 (IICH) -+ * document number TBD : Cougar Point (CPT) - */ - - /* -@@ -122,6 +99,24 @@ enum iTCO_chipsets { - TCO_ICH10R, /* ICH10R */ - TCO_ICH10D, /* ICH10D */ - TCO_ICH10DO, /* ICH10DO */ -+ TCO_PCH, /* PCH Desktop Full Featured */ -+ TCO_PCHM, /* PCH Mobile Full Featured */ -+ TCO_P55, /* P55 */ -+ TCO_PM55, /* PM55 */ -+ TCO_H55, /* H55 */ -+ TCO_QM57, /* QM57 */ -+ TCO_H57, /* H57 */ -+ TCO_HM55, /* HM55 */ -+ TCO_Q57, /* Q57 */ -+ TCO_HM57, /* HM57 */ -+ TCO_PCHMSFF, /* PCH Mobile SFF Full Featured */ -+ TCO_QS57, /* QS57 */ -+ TCO_3400, /* 3400 */ -+ TCO_3420, /* 3420 */ -+ TCO_3450, /* 3450 */ -+ TCO_EP80579, /* EP80579 */ -+ TCO_CPTD, /* CPT Desktop */ -+ TCO_CPTM, /* CPT Mobile */ - }; - - static struct { -@@ -162,6 +157,24 @@ static struct { - {"ICH10R", 2}, - {"ICH10D", 2}, - {"ICH10DO", 2}, -+ {"PCH Desktop Full Featured", 2}, -+ {"PCH Mobile Full Featured", 2}, -+ {"P55", 2}, -+ {"PM55", 2}, -+ {"H55", 2}, -+ {"QM57", 2}, -+ {"H57", 2}, -+ {"HM55", 2}, -+ {"Q57", 2}, -+ {"HM57", 2}, -+ {"PCH Mobile SFF Full Featured", 2}, -+ {"QS57", 2}, -+ {"3400", 2}, -+ {"3420", 2}, -+ {"3450", 2}, -+ {"EP80579", 2}, -+ {"CPT Desktop", 2}, -+ {"CPT Mobile", 2}, - {NULL, 0} - }; - -@@ -230,6 +243,24 @@ static struct pci_device_id iTCO_wdt_pci_tbl[] = { - { ITCO_PCI_DEVICE(0x3a16, TCO_ICH10R)}, - { ITCO_PCI_DEVICE(0x3a1a, TCO_ICH10D)}, - { ITCO_PCI_DEVICE(0x3a14, TCO_ICH10DO)}, -+ { ITCO_PCI_DEVICE(0x3b00, TCO_PCH)}, -+ { ITCO_PCI_DEVICE(0x3b01, TCO_PCHM)}, -+ { ITCO_PCI_DEVICE(0x3b02, TCO_P55)}, -+ { ITCO_PCI_DEVICE(0x3b03, TCO_PM55)}, -+ { ITCO_PCI_DEVICE(0x3b06, TCO_H55)}, -+ { ITCO_PCI_DEVICE(0x3b07, TCO_QM57)}, -+ { ITCO_PCI_DEVICE(0x3b08, TCO_H57)}, -+ { ITCO_PCI_DEVICE(0x3b09, TCO_HM55)}, -+ { ITCO_PCI_DEVICE(0x3b0a, TCO_Q57)}, -+ { ITCO_PCI_DEVICE(0x3b0b, TCO_HM57)}, -+ { ITCO_PCI_DEVICE(0x3b0d, TCO_PCHMSFF)}, -+ { ITCO_PCI_DEVICE(0x3b0f, TCO_QS57)}, -+ { ITCO_PCI_DEVICE(0x3b12, TCO_3400)}, -+ { ITCO_PCI_DEVICE(0x3b14, TCO_3420)}, -+ { ITCO_PCI_DEVICE(0x3b16, TCO_3450)}, -+ { ITCO_PCI_DEVICE(0x5031, TCO_EP80579)}, -+ { ITCO_PCI_DEVICE(0x1c42, TCO_CPTD)}, -+ { ITCO_PCI_DEVICE(0x1c43, TCO_CPTM)}, - { 0, }, /* End of list */ - }; - MODULE_DEVICE_TABLE(pci, iTCO_wdt_pci_tbl); -diff --git a/fs/fcntl.c b/fs/fcntl.c -index 97e01dc..5ef953e 100644 ---- a/fs/fcntl.c -+++ b/fs/fcntl.c -@@ -199,7 +199,9 @@ static int setfl(int fd, struct file * filp, unsigned long arg) - static void f_modown(struct file *filp, struct pid *pid, enum pid_type type, - int force) - { -- write_lock_irq(&filp->f_owner.lock); -+ unsigned long flags; -+ -+ write_lock_irqsave(&filp->f_owner.lock, flags); - if (force || !filp->f_owner.pid) { - put_pid(filp->f_owner.pid); - filp->f_owner.pid = get_pid(pid); -@@ -211,7 +213,7 @@ static void f_modown(struct file *filp, struct pid *pid, enum pid_type type, - filp->f_owner.euid = cred->euid; - } - } -- write_unlock_irq(&filp->f_owner.lock); -+ write_unlock_irqrestore(&filp->f_owner.lock, flags); - } - - int __f_setown(struct file *filp, struct pid *pid, enum pid_type type, -diff --git a/fs/nfs/super.c b/fs/nfs/super.c -index 90be551..e71f0fd 100644 ---- a/fs/nfs/super.c -+++ b/fs/nfs/super.c -@@ -734,8 +734,6 @@ static struct nfs_parsed_mount_data *nfs_alloc_parsed_mount_data(unsigned int ve - - data = kzalloc(sizeof(*data), GFP_KERNEL); - if (data) { -- data->rsize = NFS_MAX_FILE_IO_SIZE; -- data->wsize = NFS_MAX_FILE_IO_SIZE; - data->acregmin = NFS_DEF_ACREGMIN; - data->acregmax = NFS_DEF_ACREGMAX; - data->acdirmin = NFS_DEF_ACDIRMIN; -diff --git a/fs/nfsd/nfs4acl.c b/fs/nfsd/nfs4acl.c -index 725d02f..6d9c6aa 100644 ---- a/fs/nfsd/nfs4acl.c -+++ b/fs/nfsd/nfs4acl.c -@@ -389,7 +389,7 @@ sort_pacl(struct posix_acl *pacl) - sort_pacl_range(pacl, 1, i-1); - - BUG_ON(pacl->a_entries[i].e_tag != ACL_GROUP_OBJ); -- j = i++; -+ j = ++i; - while (pacl->a_entries[j].e_tag == ACL_GROUP) - j++; - sort_pacl_range(pacl, i, j-1); -diff --git a/fs/partitions/efi.c b/fs/partitions/efi.c -index 038a602..49cfd5f 100644 ---- a/fs/partitions/efi.c -+++ b/fs/partitions/efi.c -@@ -1,7 +1,9 @@ - /************************************************************ - * EFI GUID Partition Table handling -- * Per Intel EFI Specification v1.02 -- * http://developer.intel.com/technology/efi/efi.htm -+ * -+ * http://www.uefi.org/specs/ -+ * http://www.intel.com/technology/efi/ -+ * - * efi.[ch] by Matt Domsch - * Copyright 2000,2001,2002,2004 Dell Inc. - * -@@ -92,6 +94,7 @@ - * - ************************************************************/ - #include -+#include - #include "check.h" - #include "efi.h" - -@@ -141,7 +144,8 @@ last_lba(struct block_device *bdev) - { - if (!bdev || !bdev->bd_inode) - return 0; -- return (bdev->bd_inode->i_size >> 9) - 1ULL; -+ return div_u64(bdev->bd_inode->i_size, -+ bdev_logical_block_size(bdev)) - 1ULL; - } - - static inline int -@@ -188,6 +192,7 @@ static size_t - read_lba(struct block_device *bdev, u64 lba, u8 * buffer, size_t count) - { - size_t totalreadcount = 0; -+ sector_t n = lba * (bdev_logical_block_size(bdev) / 512); - - if (!bdev || !buffer || lba > last_lba(bdev)) - return 0; -@@ -195,7 +200,7 @@ read_lba(struct block_device *bdev, u64 lba, u8 * buffer, size_t count) - while (count) { - int copied = 512; - Sector sect; -- unsigned char *data = read_dev_sector(bdev, lba++, §); -+ unsigned char *data = read_dev_sector(bdev, n++, §); - if (!data) - break; - if (copied > count) -@@ -257,15 +262,16 @@ static gpt_header * - alloc_read_gpt_header(struct block_device *bdev, u64 lba) - { - gpt_header *gpt; -+ unsigned ssz = bdev_logical_block_size(bdev); -+ - if (!bdev) - return NULL; - -- gpt = kzalloc(sizeof (gpt_header), GFP_KERNEL); -+ gpt = kzalloc(ssz, GFP_KERNEL); - if (!gpt) - return NULL; - -- if (read_lba(bdev, lba, (u8 *) gpt, -- sizeof (gpt_header)) < sizeof (gpt_header)) { -+ if (read_lba(bdev, lba, (u8 *) gpt, ssz) < ssz) { - kfree(gpt); - gpt=NULL; - return NULL; -@@ -601,6 +607,7 @@ efi_partition(struct parsed_partitions *state, struct block_device *bdev) - gpt_header *gpt = NULL; - gpt_entry *ptes = NULL; - u32 i; -+ unsigned ssz = bdev_logical_block_size(bdev) / 512; - - if (!find_valid_gpt(bdev, &gpt, &ptes) || !gpt || !ptes) { - kfree(gpt); -@@ -611,13 +618,14 @@ efi_partition(struct parsed_partitions *state, struct block_device *bdev) - pr_debug("GUID Partition Table is valid! Yea!\n"); - - for (i = 0; i < le32_to_cpu(gpt->num_partition_entries) && i < state->limit-1; i++) { -+ u64 start = le64_to_cpu(ptes[i].starting_lba); -+ u64 size = le64_to_cpu(ptes[i].ending_lba) - -+ le64_to_cpu(ptes[i].starting_lba) + 1ULL; -+ - if (!is_pte_valid(&ptes[i], last_lba(bdev))) - continue; - -- put_partition(state, i+1, le64_to_cpu(ptes[i].starting_lba), -- (le64_to_cpu(ptes[i].ending_lba) - -- le64_to_cpu(ptes[i].starting_lba) + -- 1ULL)); -+ put_partition(state, i+1, start * ssz, size * ssz); - - /* If this is a RAID volume, tell md */ - if (!efi_guidcmp(ptes[i].partition_type_guid, -diff --git a/fs/partitions/efi.h b/fs/partitions/efi.h -index 2cc89d0..6998b58 100644 ---- a/fs/partitions/efi.h -+++ b/fs/partitions/efi.h -@@ -37,7 +37,6 @@ - #define EFI_PMBR_OSTYPE_EFI 0xEF - #define EFI_PMBR_OSTYPE_EFI_GPT 0xEE - --#define GPT_BLOCK_SIZE 512 - #define GPT_HEADER_SIGNATURE 0x5452415020494645ULL - #define GPT_HEADER_REVISION_V1 0x00010000 - #define GPT_PRIMARY_PARTITION_TABLE_LBA 1 -@@ -79,7 +78,12 @@ typedef struct _gpt_header { - __le32 num_partition_entries; - __le32 sizeof_partition_entry; - __le32 partition_entry_array_crc32; -- u8 reserved2[GPT_BLOCK_SIZE - 92]; -+ -+ /* The rest of the logical block is reserved by UEFI and must be zero. -+ * EFI standard handles this by: -+ * -+ * uint8_t reserved2[ BlockSize - 92 ]; -+ */ - } __attribute__ ((packed)) gpt_header; - - typedef struct _gpt_entry_attributes { -diff --git a/fs/super.c b/fs/super.c -index 19eb70b..aff046b 100644 ---- a/fs/super.c -+++ b/fs/super.c -@@ -901,8 +901,9 @@ int get_sb_single(struct file_system_type *fs_type, - return error; - } - s->s_flags |= MS_ACTIVE; -+ } else { -+ do_remount_sb(s, flags, data, 0); - } -- do_remount_sb(s, flags, data, 0); - simple_set_mnt(mnt, s); - return 0; - } -diff --git a/include/acpi/platform/aclinux.h b/include/acpi/platform/aclinux.h -index 9d7febd..0946997 100644 ---- a/include/acpi/platform/aclinux.h -+++ b/include/acpi/platform/aclinux.h -@@ -152,7 +152,7 @@ static inline void *acpi_os_acquire_object(acpi_cache_t * cache) - #include - #define ACPI_PREEMPTION_POINT() \ - do { \ -- if (!in_atomic_preempt_off()) \ -+ if (!in_atomic_preempt_off() && !irqs_disabled()) \ - cond_resched(); \ - } while (0) - -diff --git a/include/linux/clocksource.h b/include/linux/clocksource.h -index 83d2fbd..64b1a4c 100644 ---- a/include/linux/clocksource.h -+++ b/include/linux/clocksource.h -@@ -151,6 +151,7 @@ extern u64 timecounter_cyc2time(struct timecounter *tc, - * subtraction of non 64 bit counters - * @mult: cycle to nanosecond multiplier - * @shift: cycle to nanosecond divisor (power of two) -+ * @max_idle_ns: max idle time permitted by the clocksource (nsecs) - * @flags: flags describing special properties - * @vread: vsyscall based read - * @resume: resume function for the clocksource, if necessary -@@ -168,6 +169,7 @@ struct clocksource { - cycle_t mask; - u32 mult; - u32 shift; -+ u64 max_idle_ns; - unsigned long flags; - cycle_t (*vread)(void); - void (*resume)(void); -diff --git a/include/linux/hid.h b/include/linux/hid.h -index 10f6284..8709365 100644 ---- a/include/linux/hid.h -+++ b/include/linux/hid.h -@@ -312,6 +312,7 @@ struct hid_item { - #define HID_QUIRK_MULTI_INPUT 0x00000040 - #define HID_QUIRK_SKIP_OUTPUT_REPORTS 0x00010000 - #define HID_QUIRK_FULLSPEED_INTERVAL 0x10000000 -+#define HID_QUIRK_NO_INIT_REPORTS 0x20000000 - - /* - * This is the global environment of the parser. This information is -diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h -index 84cf1f3..1b7f2a7 100644 ---- a/include/linux/pci_ids.h -+++ b/include/linux/pci_ids.h -@@ -2290,6 +2290,20 @@ - #define PCI_DEVICE_ID_MPC8536 0x0051 - #define PCI_DEVICE_ID_P2020E 0x0070 - #define PCI_DEVICE_ID_P2020 0x0071 -+#define PCI_DEVICE_ID_P2010E 0x0078 -+#define PCI_DEVICE_ID_P2010 0x0079 -+#define PCI_DEVICE_ID_P1020E 0x0100 -+#define PCI_DEVICE_ID_P1020 0x0101 -+#define PCI_DEVICE_ID_P1011E 0x0108 -+#define PCI_DEVICE_ID_P1011 0x0109 -+#define PCI_DEVICE_ID_P1022E 0x0110 -+#define PCI_DEVICE_ID_P1022 0x0111 -+#define PCI_DEVICE_ID_P1013E 0x0118 -+#define PCI_DEVICE_ID_P1013 0x0119 -+#define PCI_DEVICE_ID_P4080E 0x0400 -+#define PCI_DEVICE_ID_P4080 0x0401 -+#define PCI_DEVICE_ID_P4040E 0x0408 -+#define PCI_DEVICE_ID_P4040 0x0409 - #define PCI_DEVICE_ID_MPC8641 0x7010 - #define PCI_DEVICE_ID_MPC8641D 0x7011 - #define PCI_DEVICE_ID_MPC8610 0x7018 -diff --git a/include/linux/time.h b/include/linux/time.h -index fe04e5e..6e026e4 100644 ---- a/include/linux/time.h -+++ b/include/linux/time.h -@@ -148,6 +148,7 @@ extern void monotonic_to_bootbased(struct timespec *ts); - - extern struct timespec timespec_trunc(struct timespec t, unsigned gran); - extern int timekeeping_valid_for_hres(void); -+extern u64 timekeeping_max_deferment(void); - extern void update_wall_time(void); - extern void update_xtime_cache(u64 nsec); - extern void timekeeping_leap_insert(int leapsecond); -diff --git a/include/scsi/fc_frame.h b/include/scsi/fc_frame.h -index c35d238..148126d 100644 ---- a/include/scsi/fc_frame.h -+++ b/include/scsi/fc_frame.h -@@ -37,6 +37,9 @@ - #define FC_FRAME_HEADROOM 32 /* headroom for VLAN + FCoE headers */ - #define FC_FRAME_TAILROOM 8 /* trailer space for FCoE */ - -+/* Max number of skb frags allowed, reserving one for fcoe_crc_eof page */ -+#define FC_FRAME_SG_LEN (MAX_SKB_FRAGS - 1) -+ - #define fp_skb(fp) (&((fp)->skb)) - #define fr_hdr(fp) ((fp)->skb.data) - #define fr_len(fp) ((fp)->skb.len) -diff --git a/include/scsi/libfc.h b/include/scsi/libfc.h -index 65dc9aa..09a124b 100644 ---- a/include/scsi/libfc.h -+++ b/include/scsi/libfc.h -@@ -145,6 +145,7 @@ enum fc_rport_state { - RPORT_ST_LOGO, /* port logout sent */ - RPORT_ST_ADISC, /* Discover Address sent */ - RPORT_ST_DELETE, /* port being deleted */ -+ RPORT_ST_RESTART, /* remote port being deleted and will restart */ - }; - - /** -diff --git a/init/calibrate.c b/init/calibrate.c -index a379c90..6eb48e5 100644 ---- a/init/calibrate.c -+++ b/init/calibrate.c -@@ -123,23 +123,26 @@ void __cpuinit calibrate_delay(void) - { - unsigned long ticks, loopbit; - int lps_precision = LPS_PREC; -+ static bool printed; - - if (preset_lpj) { - loops_per_jiffy = preset_lpj; -- printk(KERN_INFO -- "Calibrating delay loop (skipped) preset value.. "); -- } else if ((smp_processor_id() == 0) && lpj_fine) { -+ if (!printed) -+ pr_info("Calibrating delay loop (skipped) " -+ "preset value.. "); -+ } else if ((!printed) && lpj_fine) { - loops_per_jiffy = lpj_fine; -- printk(KERN_INFO -- "Calibrating delay loop (skipped), " -+ pr_info("Calibrating delay loop (skipped), " - "value calculated using timer frequency.. "); - } else if ((loops_per_jiffy = calibrate_delay_direct()) != 0) { -- printk(KERN_INFO -- "Calibrating delay using timer specific routine.. "); -+ if (!printed) -+ pr_info("Calibrating delay using timer " -+ "specific routine.. "); - } else { - loops_per_jiffy = (1<<12); - -- printk(KERN_INFO "Calibrating delay loop... "); -+ if (!printed) -+ pr_info("Calibrating delay loop... "); - while ((loops_per_jiffy <<= 1) != 0) { - /* wait for "start of" clock tick */ - ticks = jiffies; -@@ -170,7 +173,10 @@ void __cpuinit calibrate_delay(void) - loops_per_jiffy &= ~loopbit; - } - } -- printk(KERN_CONT "%lu.%02lu BogoMIPS (lpj=%lu)\n", -+ if (!printed) -+ pr_cont("%lu.%02lu BogoMIPS (lpj=%lu)\n", - loops_per_jiffy/(500000/HZ), - (loops_per_jiffy/(5000/HZ)) % 100, loops_per_jiffy); -+ -+ printed = true; - } -diff --git a/ipc/msg.c b/ipc/msg.c -index 2ceab7f..779f762 100644 ---- a/ipc/msg.c -+++ b/ipc/msg.c -@@ -125,6 +125,7 @@ void msg_init_ns(struct ipc_namespace *ns) - void msg_exit_ns(struct ipc_namespace *ns) - { - free_ipcs(ns, &msg_ids(ns), freeque); -+ idr_destroy(&ns->ids[IPC_MSG_IDS].ipcs_idr); - } - #endif - -diff --git a/ipc/sem.c b/ipc/sem.c -index 87c2b64..2f2a479 100644 ---- a/ipc/sem.c -+++ b/ipc/sem.c -@@ -129,6 +129,7 @@ void sem_init_ns(struct ipc_namespace *ns) - void sem_exit_ns(struct ipc_namespace *ns) - { - free_ipcs(ns, &sem_ids(ns), freeary); -+ idr_destroy(&ns->ids[IPC_SEM_IDS].ipcs_idr); - } - #endif - -diff --git a/ipc/shm.c b/ipc/shm.c -index 11bec62..e9b039f 100644 ---- a/ipc/shm.c -+++ b/ipc/shm.c -@@ -101,6 +101,7 @@ static void do_shm_rmid(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp) - void shm_exit_ns(struct ipc_namespace *ns) - { - free_ipcs(ns, &shm_ids(ns), do_shm_rmid); -+ idr_destroy(&ns->ids[IPC_SHM_IDS].ipcs_idr); - } - #endif - -diff --git a/kernel/cpu.c b/kernel/cpu.c -index b216886..291ac58 100644 ---- a/kernel/cpu.c -+++ b/kernel/cpu.c -@@ -400,10 +400,9 @@ int disable_nonboot_cpus(void) - if (cpu == first_cpu) - continue; - error = _cpu_down(cpu, 1); -- if (!error) { -+ if (!error) - cpumask_set_cpu(cpu, frozen_cpus); -- printk("CPU%d is down\n", cpu); -- } else { -+ else { - printk(KERN_ERR "Error taking CPU%d down: %d\n", - cpu, error); - break; -diff --git a/kernel/sched.c b/kernel/sched.c -index bf841d8..60d74cc 100644 ---- a/kernel/sched.c -+++ b/kernel/sched.c -@@ -816,6 +816,7 @@ const_debug unsigned int sysctl_sched_nr_migrate = 32; - * default: 0.25ms - */ - unsigned int sysctl_sched_shares_ratelimit = 250000; -+unsigned int normalized_sysctl_sched_shares_ratelimit = 250000; - - /* - * Inject some fuzzyness into changing the per-cpu group shares -@@ -1812,6 +1813,7 @@ static void cfs_rq_set_shares(struct cfs_rq *cfs_rq, unsigned long shares) - #endif - - static void calc_load_account_active(struct rq *this_rq); -+static void update_sysctl(void); - - #include "sched_stats.h" - #include "sched_idletask.c" -@@ -7018,22 +7020,23 @@ cpumask_var_t nohz_cpu_mask; - * - * This idea comes from the SD scheduler of Con Kolivas: - */ --static inline void sched_init_granularity(void) -+static void update_sysctl(void) - { -- unsigned int factor = 1 + ilog2(num_online_cpus()); -- const unsigned long limit = 200000000; -- -- sysctl_sched_min_granularity *= factor; -- if (sysctl_sched_min_granularity > limit) -- sysctl_sched_min_granularity = limit; -- -- sysctl_sched_latency *= factor; -- if (sysctl_sched_latency > limit) -- sysctl_sched_latency = limit; -+ unsigned int cpus = min(num_online_cpus(), 8U); -+ unsigned int factor = 1 + ilog2(cpus); - -- sysctl_sched_wakeup_granularity *= factor; -+#define SET_SYSCTL(name) \ -+ (sysctl_##name = (factor) * normalized_sysctl_##name) -+ SET_SYSCTL(sched_min_granularity); -+ SET_SYSCTL(sched_latency); -+ SET_SYSCTL(sched_wakeup_granularity); -+ SET_SYSCTL(sched_shares_ratelimit); -+#undef SET_SYSCTL -+} - -- sysctl_sched_shares_ratelimit *= factor; -+static inline void sched_init_granularity(void) -+{ -+ update_sysctl(); - } - - #ifdef CONFIG_SMP -@@ -8061,6 +8064,7 @@ static cpumask_var_t cpu_isolated_map; - /* Setup the mask of cpus configured for isolated domains */ - static int __init isolated_cpu_setup(char *str) - { -+ alloc_bootmem_cpumask_var(&cpu_isolated_map); - cpulist_parse(str, cpu_isolated_map); - return 1; - } -@@ -9591,7 +9595,9 @@ void __init sched_init(void) - zalloc_cpumask_var(&nohz.cpu_mask, GFP_NOWAIT); - alloc_cpumask_var(&nohz.ilb_grp_nohz_mask, GFP_NOWAIT); - #endif -- zalloc_cpumask_var(&cpu_isolated_map, GFP_NOWAIT); -+ /* May be allocated at isolcpus cmdline parse time */ -+ if (cpu_isolated_map == NULL) -+ zalloc_cpumask_var(&cpu_isolated_map, GFP_NOWAIT); - #endif /* SMP */ - - perf_event_init(); -diff --git a/kernel/sched_fair.c b/kernel/sched_fair.c -index 199228b..d80812d 100644 ---- a/kernel/sched_fair.c -+++ b/kernel/sched_fair.c -@@ -35,12 +35,14 @@ - * run vmstat and monitor the context-switches (cs) field) - */ - unsigned int sysctl_sched_latency = 5000000ULL; -+unsigned int normalized_sysctl_sched_latency = 5000000ULL; - - /* - * Minimal preemption granularity for CPU-bound tasks: - * (default: 1 msec * (1 + ilog(ncpus)), units: nanoseconds) - */ - unsigned int sysctl_sched_min_granularity = 1000000ULL; -+unsigned int normalized_sysctl_sched_min_granularity = 1000000ULL; - - /* - * is kept at sysctl_sched_latency / sysctl_sched_min_granularity -@@ -70,6 +72,7 @@ unsigned int __read_mostly sysctl_sched_compat_yield; - * have immediate wakeup/sleep latencies. - */ - unsigned int sysctl_sched_wakeup_granularity = 1000000UL; -+unsigned int normalized_sysctl_sched_wakeup_granularity = 1000000UL; - - const_debug unsigned int sysctl_sched_migration_cost = 500000UL; - -@@ -1880,6 +1883,17 @@ move_one_task_fair(struct rq *this_rq, int this_cpu, struct rq *busiest, - - return 0; - } -+ -+static void rq_online_fair(struct rq *rq) -+{ -+ update_sysctl(); -+} -+ -+static void rq_offline_fair(struct rq *rq) -+{ -+ update_sysctl(); -+} -+ - #endif /* CONFIG_SMP */ - - /* -@@ -2027,6 +2041,8 @@ static const struct sched_class fair_sched_class = { - - .load_balance = load_balance_fair, - .move_one_task = move_one_task_fair, -+ .rq_online = rq_online_fair, -+ .rq_offline = rq_offline_fair, - #endif - - .set_curr_task = set_curr_task_fair, -diff --git a/kernel/time/clockevents.c b/kernel/time/clockevents.c -index 9484be4..0d809ae 100644 ---- a/kernel/time/clockevents.c -+++ b/kernel/time/clockevents.c -@@ -20,6 +20,8 @@ - #include - #include - -+#include "tick-internal.h" -+ - /* The registered clock event devices */ - static LIST_HEAD(clockevent_devices); - static LIST_HEAD(clockevents_released); -@@ -258,7 +260,8 @@ void clockevents_notify(unsigned long reason, void *arg) - cpu = *((int *)arg); - list_for_each_entry_safe(dev, tmp, &clockevent_devices, list) { - if (cpumask_test_cpu(cpu, dev->cpumask) && -- cpumask_weight(dev->cpumask) == 1) { -+ cpumask_weight(dev->cpumask) == 1 && -+ !tick_is_broadcast_device(dev)) { - BUG_ON(dev->mode != CLOCK_EVT_MODE_UNUSED); - list_del(&dev->list); - } -diff --git a/kernel/time/clocksource.c b/kernel/time/clocksource.c -index 5e18c6a..5155dc3 100644 ---- a/kernel/time/clocksource.c -+++ b/kernel/time/clocksource.c -@@ -416,6 +416,47 @@ void clocksource_touch_watchdog(void) - #ifdef CONFIG_GENERIC_TIME - - /** -+ * clocksource_max_deferment - Returns max time the clocksource can be deferred -+ * @cs: Pointer to clocksource -+ * -+ */ -+static u64 clocksource_max_deferment(struct clocksource *cs) -+{ -+ u64 max_nsecs, max_cycles; -+ -+ /* -+ * Calculate the maximum number of cycles that we can pass to the -+ * cyc2ns function without overflowing a 64-bit signed result. The -+ * maximum number of cycles is equal to ULLONG_MAX/cs->mult which -+ * is equivalent to the below. -+ * max_cycles < (2^63)/cs->mult -+ * max_cycles < 2^(log2((2^63)/cs->mult)) -+ * max_cycles < 2^(log2(2^63) - log2(cs->mult)) -+ * max_cycles < 2^(63 - log2(cs->mult)) -+ * max_cycles < 1 << (63 - log2(cs->mult)) -+ * Please note that we add 1 to the result of the log2 to account for -+ * any rounding errors, ensure the above inequality is satisfied and -+ * no overflow will occur. -+ */ -+ max_cycles = 1ULL << (63 - (ilog2(cs->mult) + 1)); -+ -+ /* -+ * The actual maximum number of cycles we can defer the clocksource is -+ * determined by the minimum of max_cycles and cs->mask. -+ */ -+ max_cycles = min_t(u64, max_cycles, (u64) cs->mask); -+ max_nsecs = clocksource_cyc2ns(max_cycles, cs->mult, cs->shift); -+ -+ /* -+ * To ensure that the clocksource does not wrap whilst we are idle, -+ * limit the time the clocksource can be deferred by 12.5%. Please -+ * note a margin of 12.5% is used because this can be computed with -+ * a shift, versus say 10% which would require division. -+ */ -+ return max_nsecs - (max_nsecs >> 5); -+} -+ -+/** - * clocksource_select - Select the best clocksource available - * - * Private function. Must hold clocksource_mutex when called. -@@ -511,6 +552,9 @@ static void clocksource_enqueue(struct clocksource *cs) - */ - int clocksource_register(struct clocksource *cs) - { -+ /* calculate max idle time permitted for this clocksource */ -+ cs->max_idle_ns = clocksource_max_deferment(cs); -+ - mutex_lock(&clocksource_mutex); - clocksource_enqueue(cs); - clocksource_select(); -diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c -index 89aed59..44320b1 100644 ---- a/kernel/time/tick-sched.c -+++ b/kernel/time/tick-sched.c -@@ -216,6 +216,7 @@ void tick_nohz_stop_sched_tick(int inidle) - struct tick_sched *ts; - ktime_t last_update, expires, now; - struct clock_event_device *dev = __get_cpu_var(tick_cpu_device).evtdev; -+ u64 time_delta; - int cpu; - - local_irq_save(flags); -@@ -275,6 +276,17 @@ void tick_nohz_stop_sched_tick(int inidle) - seq = read_seqbegin(&xtime_lock); - last_update = last_jiffies_update; - last_jiffies = jiffies; -+ -+ /* -+ * On SMP we really should only care for the CPU which -+ * has the do_timer duty assigned. All other CPUs can -+ * sleep as long as they want. -+ */ -+ if (cpu == tick_do_timer_cpu || -+ tick_do_timer_cpu == TICK_DO_TIMER_NONE) -+ time_delta = timekeeping_max_deferment(); -+ else -+ time_delta = KTIME_MAX; - } while (read_seqretry(&xtime_lock, seq)); - - /* Get the next timer wheel timer */ -@@ -294,11 +306,26 @@ void tick_nohz_stop_sched_tick(int inidle) - if ((long)delta_jiffies >= 1) { - - /* -- * calculate the expiry time for the next timer wheel -- * timer -- */ -- expires = ktime_add_ns(last_update, tick_period.tv64 * -- delta_jiffies); -+ * calculate the expiry time for the next timer wheel -+ * timer. delta_jiffies >= NEXT_TIMER_MAX_DELTA signals -+ * that there is no timer pending or at least extremely -+ * far into the future (12 days for HZ=1000). In this -+ * case we set the expiry to the end of time. -+ */ -+ if (likely(delta_jiffies < NEXT_TIMER_MAX_DELTA)) { -+ /* -+ * Calculate the time delta for the next timer event. -+ * If the time delta exceeds the maximum time delta -+ * permitted by the current clocksource then adjust -+ * the time delta accordingly to ensure the -+ * clocksource does not wrap. -+ */ -+ time_delta = min_t(u64, time_delta, -+ tick_period.tv64 * delta_jiffies); -+ expires = ktime_add_ns(last_update, time_delta); -+ } else { -+ expires.tv64 = KTIME_MAX; -+ } - - /* - * If this cpu is the one which updates jiffies, then -@@ -342,22 +369,19 @@ void tick_nohz_stop_sched_tick(int inidle) - - ts->idle_sleeps++; - -+ /* Mark expires */ -+ ts->idle_expires = expires; -+ - /* -- * delta_jiffies >= NEXT_TIMER_MAX_DELTA signals that -- * there is no timer pending or at least extremly far -- * into the future (12 days for HZ=1000). In this case -- * we simply stop the tick timer: -+ * If the expiration time == KTIME_MAX, then -+ * in this case we simply stop the tick timer. - */ -- if (unlikely(delta_jiffies >= NEXT_TIMER_MAX_DELTA)) { -- ts->idle_expires.tv64 = KTIME_MAX; -+ if (unlikely(expires.tv64 == KTIME_MAX)) { - if (ts->nohz_mode == NOHZ_MODE_HIGHRES) - hrtimer_cancel(&ts->sched_timer); - goto out; - } - -- /* Mark expiries */ -- ts->idle_expires = expires; -- - if (ts->nohz_mode == NOHZ_MODE_HIGHRES) { - hrtimer_start(&ts->sched_timer, expires, - HRTIMER_MODE_ABS_PINNED); -diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c -index c3a4e29..66d090e 100644 ---- a/kernel/time/timekeeping.c -+++ b/kernel/time/timekeeping.c -@@ -488,6 +488,17 @@ int timekeeping_valid_for_hres(void) - } - - /** -+ * timekeeping_max_deferment - Returns max time the clocksource can be deferred -+ * -+ * Caller must observe xtime_lock via read_seqbegin/read_seqretry to -+ * ensure that the clocksource does not change! -+ */ -+u64 timekeeping_max_deferment(void) -+{ -+ return timekeeper.clock->max_idle_ns; -+} -+ -+/** - * read_persistent_clock - Return time from the persistent clock. - * - * Weak dummy function for arches that do not yet support it. -diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c -index cca675e..fe2d3f8 100644 ---- a/net/mac80211/cfg.c -+++ b/net/mac80211/cfg.c -@@ -1306,6 +1306,9 @@ static int ieee80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_conf *conf = &local->hw.conf; - -+ if (sdata->vif.type != NL80211_IFTYPE_STATION) -+ return -EOPNOTSUPP; -+ - if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_PS)) - return -EOPNOTSUPP; - -diff --git a/net/netfilter/xt_conntrack.c b/net/netfilter/xt_conntrack.c -index 6dc4652..ae66305 100644 ---- a/net/netfilter/xt_conntrack.c -+++ b/net/netfilter/xt_conntrack.c -@@ -113,7 +113,8 @@ ct_proto_port_check(const struct xt_conntrack_mtinfo2 *info, - } - - static bool --conntrack_mt(const struct sk_buff *skb, const struct xt_match_param *par) -+conntrack_mt(const struct sk_buff *skb, const struct xt_match_param *par, -+ u16 state_mask, u16 status_mask) - { - const struct xt_conntrack_mtinfo2 *info = par->matchinfo; - enum ip_conntrack_info ctinfo; -@@ -136,7 +137,7 @@ conntrack_mt(const struct sk_buff *skb, const struct xt_match_param *par) - if (test_bit(IPS_DST_NAT_BIT, &ct->status)) - statebit |= XT_CONNTRACK_STATE_DNAT; - } -- if (!!(info->state_mask & statebit) ^ -+ if (!!(state_mask & statebit) ^ - !(info->invert_flags & XT_CONNTRACK_STATE)) - return false; - } -@@ -172,7 +173,7 @@ conntrack_mt(const struct sk_buff *skb, const struct xt_match_param *par) - return false; - - if ((info->match_flags & XT_CONNTRACK_STATUS) && -- (!!(info->status_mask & ct->status) ^ -+ (!!(status_mask & ct->status) ^ - !(info->invert_flags & XT_CONNTRACK_STATUS))) - return false; - -@@ -192,11 +193,17 @@ conntrack_mt(const struct sk_buff *skb, const struct xt_match_param *par) - static bool - conntrack_mt_v1(const struct sk_buff *skb, const struct xt_match_param *par) - { -- const struct xt_conntrack_mtinfo2 *const *info = par->matchinfo; -- struct xt_match_param newpar = *par; -+ const struct xt_conntrack_mtinfo1 *info = par->matchinfo; - -- newpar.matchinfo = *info; -- return conntrack_mt(skb, &newpar); -+ return conntrack_mt(skb, par, info->state_mask, info->status_mask); -+} -+ -+static bool -+conntrack_mt_v2(const struct sk_buff *skb, const struct xt_match_param *par) -+{ -+ const struct xt_conntrack_mtinfo2 *info = par->matchinfo; -+ -+ return conntrack_mt(skb, par, info->state_mask, info->status_mask); - } - - static bool conntrack_mt_check(const struct xt_mtchk_param *par) -@@ -209,45 +216,11 @@ static bool conntrack_mt_check(const struct xt_mtchk_param *par) - return true; - } - --static bool conntrack_mt_check_v1(const struct xt_mtchk_param *par) --{ -- struct xt_conntrack_mtinfo1 *info = par->matchinfo; -- struct xt_conntrack_mtinfo2 *up; -- int ret = conntrack_mt_check(par); -- -- if (ret < 0) -- return ret; -- -- up = kmalloc(sizeof(*up), GFP_KERNEL); -- if (up == NULL) { -- nf_ct_l3proto_module_put(par->family); -- return -ENOMEM; -- } -- -- /* -- * The strategy here is to minimize the overhead of v1 matching, -- * by prebuilding a v2 struct and putting the pointer into the -- * v1 dataspace. -- */ -- memcpy(up, info, offsetof(typeof(*info), state_mask)); -- up->state_mask = info->state_mask; -- up->status_mask = info->status_mask; -- *(void **)info = up; -- return true; --} -- - static void conntrack_mt_destroy(const struct xt_mtdtor_param *par) - { - nf_ct_l3proto_module_put(par->family); - } - --static void conntrack_mt_destroy_v1(const struct xt_mtdtor_param *par) --{ -- struct xt_conntrack_mtinfo2 **info = par->matchinfo; -- kfree(*info); -- conntrack_mt_destroy(par); --} -- - static struct xt_match conntrack_mt_reg[] __read_mostly = { - { - .name = "conntrack", -@@ -255,8 +228,8 @@ static struct xt_match conntrack_mt_reg[] __read_mostly = { - .family = NFPROTO_UNSPEC, - .matchsize = sizeof(struct xt_conntrack_mtinfo1), - .match = conntrack_mt_v1, -- .checkentry = conntrack_mt_check_v1, -- .destroy = conntrack_mt_destroy_v1, -+ .checkentry = conntrack_mt_check, -+ .destroy = conntrack_mt_destroy, - .me = THIS_MODULE, - }, - { -@@ -264,7 +237,7 @@ static struct xt_match conntrack_mt_reg[] __read_mostly = { - .revision = 2, - .family = NFPROTO_UNSPEC, - .matchsize = sizeof(struct xt_conntrack_mtinfo2), -- .match = conntrack_mt, -+ .match = conntrack_mt_v2, - .checkentry = conntrack_mt_check, - .destroy = conntrack_mt_destroy, - .me = THIS_MODULE, -diff --git a/net/wireless/sme.c b/net/wireless/sme.c -index 9f0b280..b2930e3 100644 ---- a/net/wireless/sme.c -+++ b/net/wireless/sme.c -@@ -655,6 +655,7 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie, - memset(&wrqu, 0, sizeof(wrqu)); - wrqu.ap_addr.sa_family = ARPHRD_ETHER; - wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL); -+ wdev->wext.connect.ssid_len = 0; - #endif - } - -diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c -index 7e4ee4e..03784da 100644 ---- a/sound/pci/hda/hda_intel.c -+++ b/sound/pci/hda/hda_intel.c -@@ -2694,6 +2694,9 @@ static struct pci_device_id azx_ids[] = { - { PCI_DEVICE(0x10de, 0x0ac1), .driver_data = AZX_DRIVER_NVIDIA }, - { PCI_DEVICE(0x10de, 0x0ac2), .driver_data = AZX_DRIVER_NVIDIA }, - { PCI_DEVICE(0x10de, 0x0ac3), .driver_data = AZX_DRIVER_NVIDIA }, -+ { PCI_DEVICE(0x10de, 0x0be2), .driver_data = AZX_DRIVER_NVIDIA }, -+ { PCI_DEVICE(0x10de, 0x0be3), .driver_data = AZX_DRIVER_NVIDIA }, -+ { PCI_DEVICE(0x10de, 0x0be4), .driver_data = AZX_DRIVER_NVIDIA }, - { PCI_DEVICE(0x10de, 0x0d94), .driver_data = AZX_DRIVER_NVIDIA }, - { PCI_DEVICE(0x10de, 0x0d95), .driver_data = AZX_DRIVER_NVIDIA }, - { PCI_DEVICE(0x10de, 0x0d96), .driver_data = AZX_DRIVER_NVIDIA }, -diff --git a/sound/pci/hda/patch_intelhdmi.c b/sound/pci/hda/patch_intelhdmi.c -index 01a18ed..7c23016 100644 ---- a/sound/pci/hda/patch_intelhdmi.c -+++ b/sound/pci/hda/patch_intelhdmi.c -@@ -684,7 +684,7 @@ static struct hda_codec_preset snd_hda_preset_intelhdmi[] = { - { .id = 0x80862801, .name = "G45 DEVBLC", .patch = patch_intel_hdmi }, - { .id = 0x80862802, .name = "G45 DEVCTG", .patch = patch_intel_hdmi }, - { .id = 0x80862803, .name = "G45 DEVELK", .patch = patch_intel_hdmi }, -- { .id = 0x80862804, .name = "G45 DEVIBX", .patch = patch_intel_hdmi }, -+ { .id = 0x80862804, .name = "G45 DEVIBX", .patch = patch_intel_hdmi_ibexpeak }, - { .id = 0x80860054, .name = "Q57 DEVIBX", .patch = patch_intel_hdmi_ibexpeak }, - { .id = 0x10951392, .name = "SiI1392 HDMI", .patch = patch_intel_hdmi }, - {} /* terminator */ -diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c -index 075c3a6..c2e9370 100644 ---- a/sound/pci/hda/patch_realtek.c -+++ b/sound/pci/hda/patch_realtek.c -@@ -2401,6 +2401,8 @@ static const char *alc_slave_sws[] = { - "Speaker Playback Switch", - "Mono Playback Switch", - "IEC958 Playback Switch", -+ "Line-Out Playback Switch", -+ "PCM Playback Switch", - NULL, - }; - -@@ -8839,7 +8841,7 @@ static struct snd_pci_quirk alc882_cfg_tbl[] = { - SND_PCI_QUIRK(0x1462, 0x040d, "MSI", ALC883_TARGA_2ch_DIG), - SND_PCI_QUIRK(0x1462, 0x0579, "MSI", ALC883_TARGA_2ch_DIG), - SND_PCI_QUIRK(0x1462, 0x28fb, "Targa T8", ALC882_TARGA), /* MSI-1049 T8 */ -- SND_PCI_QUIRK(0x1462, 0x2fb3, "MSI", ALC883_TARGA_2ch_DIG), -+ SND_PCI_QUIRK(0x1462, 0x2fb3, "MSI", ALC882_AUTO), - SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC882_6ST_DIG), - SND_PCI_QUIRK(0x1462, 0x3729, "MSI S420", ALC883_TARGA_DIG), - SND_PCI_QUIRK(0x1462, 0x3783, "NEC S970", ALC883_TARGA_DIG), -@@ -10152,7 +10154,7 @@ static void alc262_hp_t5735_setup(struct hda_codec *codec) - struct alc_spec *spec = codec->spec; - - spec->autocfg.hp_pins[0] = 0x15; -- spec->autocfg.speaker_pins[0] = 0x0c; /* HACK: not actually a pin */ -+ spec->autocfg.speaker_pins[0] = 0x14; - } - - static struct snd_kcontrol_new alc262_hp_t5735_mixer[] = { -@@ -11586,9 +11588,9 @@ static struct alc_config_preset alc262_presets[] = { - .num_channel_mode = ARRAY_SIZE(alc262_modes), - .channel_mode = alc262_modes, - .input_mux = &alc262_capture_source, -- .unsol_event = alc_automute_amp_unsol_event, -+ .unsol_event = alc_sku_unsol_event, - .setup = alc262_hp_t5735_setup, -- .init_hook = alc_automute_amp, -+ .init_hook = alc_inithook, - }, - [ALC262_HP_RP5700] = { - .mixers = { alc262_hp_rp5700_mixer }, -diff --git a/sound/pci/ice1712/juli.c b/sound/pci/ice1712/juli.c -index fd948bf..f5020ad 100644 ---- a/sound/pci/ice1712/juli.c -+++ b/sound/pci/ice1712/juli.c -@@ -504,6 +504,31 @@ static int __devinit juli_add_controls(struct snd_ice1712 *ice) - } - - /* -+ * suspend/resume -+ * */ -+ -+#ifdef CONFIG_PM -+static int juli_resume(struct snd_ice1712 *ice) -+{ -+ struct snd_akm4xxx *ak = ice->akm; -+ struct juli_spec *spec = ice->spec; -+ /* akm4358 un-reset, un-mute */ -+ snd_akm4xxx_reset(ak, 0); -+ /* reinit ak4114 */ -+ snd_ak4114_reinit(spec->ak4114); -+ return 0; -+} -+ -+static int juli_suspend(struct snd_ice1712 *ice) -+{ -+ struct snd_akm4xxx *ak = ice->akm; -+ /* akm4358 reset and soft-mute */ -+ snd_akm4xxx_reset(ak, 1); -+ return 0; -+} -+#endif -+ -+/* - * initialize the chip - */ - -@@ -646,6 +671,13 @@ static int __devinit juli_init(struct snd_ice1712 *ice) - ice->set_spdif_clock = juli_set_spdif_clock; - - ice->spdif.ops.open = juli_spdif_in_open; -+ -+#ifdef CONFIG_PM -+ ice->pm_resume = juli_resume; -+ ice->pm_suspend = juli_suspend; -+ ice->pm_suspend_enabled = 1; -+#endif -+ - return 0; - } - -diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c -index fe1307b..eedf33c 100644 ---- a/sound/soc/codecs/wm8903.c -+++ b/sound/soc/codecs/wm8903.c -@@ -1506,7 +1506,7 @@ static int wm8903_resume(struct platform_device *pdev) - struct i2c_client *i2c = codec->control_data; - int i; - u16 *reg_cache = codec->reg_cache; -- u16 *tmp_cache = kmemdup(codec->reg_cache, sizeof(wm8903_reg_defaults), -+ u16 *tmp_cache = kmemdup(reg_cache, sizeof(wm8903_reg_defaults), - GFP_KERNEL); - - /* Bring the codec back up to standby first to minimise pop/clicks */ -@@ -1518,6 +1518,7 @@ static int wm8903_resume(struct platform_device *pdev) - for (i = 2; i < ARRAY_SIZE(wm8903_reg_defaults); i++) - if (tmp_cache[i] != reg_cache[i]) - snd_soc_write(codec, i, tmp_cache[i]); -+ kfree(tmp_cache); - } else { - dev_err(&i2c->dev, "Failed to allocate temporary cache\n"); - } -diff --git a/virt/kvm/eventfd.c b/virt/kvm/eventfd.c -index bb4ebd8..251282c 100644 ---- a/virt/kvm/eventfd.c -+++ b/virt/kvm/eventfd.c -@@ -168,7 +168,7 @@ irqfd_ptable_queue_proc(struct file *file, wait_queue_head_t *wqh, - static int - kvm_irqfd_assign(struct kvm *kvm, int fd, int gsi) - { -- struct _irqfd *irqfd; -+ struct _irqfd *irqfd, *tmp; - struct file *file = NULL; - struct eventfd_ctx *eventfd = NULL; - int ret; -@@ -205,9 +205,20 @@ kvm_irqfd_assign(struct kvm *kvm, int fd, int gsi) - init_waitqueue_func_entry(&irqfd->wait, irqfd_wakeup); - init_poll_funcptr(&irqfd->pt, irqfd_ptable_queue_proc); - -+ spin_lock_irq(&kvm->irqfds.lock); -+ -+ ret = 0; -+ list_for_each_entry(tmp, &kvm->irqfds.items, list) { -+ if (irqfd->eventfd != tmp->eventfd) -+ continue; -+ /* This fd is used for another irq already. */ -+ ret = -EBUSY; -+ spin_unlock_irq(&kvm->irqfds.lock); -+ goto fail; -+ } -+ - events = file->f_op->poll(file, &irqfd->pt); - -- spin_lock_irq(&kvm->irqfds.lock); - list_add_tail(&irqfd->list, &kvm->irqfds.items); - spin_unlock_irq(&kvm->irqfds.lock); - -diff --git a/virt/kvm/irq_comm.c b/virt/kvm/irq_comm.c -index 03e5b21..5288885 100644 ---- a/virt/kvm/irq_comm.c -+++ b/virt/kvm/irq_comm.c -@@ -209,11 +209,13 @@ int kvm_request_irq_source_id(struct kvm *kvm) - - if (irq_source_id >= BITS_PER_LONG) { - printk(KERN_WARNING "kvm: exhaust allocatable IRQ sources!\n"); -- return -EFAULT; -+ irq_source_id = -EFAULT; -+ goto unlock; - } - - ASSERT(irq_source_id != KVM_USERSPACE_IRQ_SOURCE_ID); - set_bit(irq_source_id, bitmap); -+unlock: - mutex_unlock(&kvm->irq_lock); - - return irq_source_id; -@@ -229,11 +231,15 @@ void kvm_free_irq_source_id(struct kvm *kvm, int irq_source_id) - if (irq_source_id < 0 || - irq_source_id >= BITS_PER_LONG) { - printk(KERN_ERR "kvm: IRQ source ID out of range!\n"); -- return; -+ goto unlock; - } -+ clear_bit(irq_source_id, &kvm->arch.irq_sources_bitmap); -+ if (!irqchip_in_kernel(kvm)) -+ goto unlock; -+ - for (i = 0; i < KVM_IOAPIC_NUM_PINS; i++) - clear_bit(irq_source_id, &kvm->arch.irq_states[i]); -- clear_bit(irq_source_id, &kvm->arch.irq_sources_bitmap); -+unlock: - mutex_unlock(&kvm->irq_lock); - } - diff --git a/debian/patches/bugfix/all/stable/2.6.32.8.patch b/debian/patches/bugfix/all/stable/2.6.32.8.patch deleted file mode 100644 index 5e51b6327..000000000 --- a/debian/patches/bugfix/all/stable/2.6.32.8.patch +++ /dev/null @@ -1,4706 +0,0 @@ -diff --git a/Documentation/kvm/api.txt b/Documentation/kvm/api.txt -index 5a4bc8c..db3a706 100644 ---- a/Documentation/kvm/api.txt -+++ b/Documentation/kvm/api.txt -@@ -593,6 +593,42 @@ struct kvm_irqchip { - } chip; - }; - -+4.27 KVM_GET_CLOCK -+ -+Capability: KVM_CAP_ADJUST_CLOCK -+Architectures: x86 -+Type: vm ioctl -+Parameters: struct kvm_clock_data (out) -+Returns: 0 on success, -1 on error -+ -+Gets the current timestamp of kvmclock as seen by the current guest. In -+conjunction with KVM_SET_CLOCK, it is used to ensure monotonicity on scenarios -+such as migration. -+ -+struct kvm_clock_data { -+ __u64 clock; /* kvmclock current value */ -+ __u32 flags; -+ __u32 pad[9]; -+}; -+ -+4.28 KVM_SET_CLOCK -+ -+Capability: KVM_CAP_ADJUST_CLOCK -+Architectures: x86 -+Type: vm ioctl -+Parameters: struct kvm_clock_data (in) -+Returns: 0 on success, -1 on error -+ -+Sets the current timestamp of kvmclock to the valued specific in its parameter. -+In conjunction with KVM_GET_CLOCK, it is used to ensure monotonicity on scenarios -+such as migration. -+ -+struct kvm_clock_data { -+ __u64 clock; /* kvmclock current value */ -+ __u32 flags; -+ __u32 pad[9]; -+}; -+ - 5. The kvm_run structure - - Application code obtains a pointer to the kvm_run structure by -diff --git a/Makefile b/Makefile -index 07d3c6a..f282cab 100644 -diff --git a/arch/blackfin/include/asm/page.h b/arch/blackfin/include/asm/page.h -index 944a07c..1d04e40 100644 ---- a/arch/blackfin/include/asm/page.h -+++ b/arch/blackfin/include/asm/page.h -@@ -10,4 +10,9 @@ - #include - #define MAP_NR(addr) (((unsigned long)(addr)-PAGE_OFFSET) >> PAGE_SHIFT) - -+#define VM_DATA_DEFAULT_FLAGS \ -+ (VM_READ | VM_WRITE | \ -+ ((current->personality & READ_IMPLIES_EXEC) ? VM_EXEC : 0 ) | \ -+ VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC) -+ - #endif -diff --git a/arch/frv/include/asm/page.h b/arch/frv/include/asm/page.h -index 25c6a50..8c97068 100644 ---- a/arch/frv/include/asm/page.h -+++ b/arch/frv/include/asm/page.h -@@ -63,12 +63,10 @@ extern unsigned long max_pfn; - #define virt_addr_valid(kaddr) pfn_valid(__pa(kaddr) >> PAGE_SHIFT) - - --#ifdef CONFIG_MMU - #define VM_DATA_DEFAULT_FLAGS \ - (VM_READ | VM_WRITE | \ - ((current->personality & READ_IMPLIES_EXEC) ? VM_EXEC : 0 ) | \ - VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC) --#endif - - #endif /* __ASSEMBLY__ */ - -diff --git a/arch/powerpc/include/asm/elf.h b/arch/powerpc/include/asm/elf.h -index 014a624..5698502 100644 ---- a/arch/powerpc/include/asm/elf.h -+++ b/arch/powerpc/include/asm/elf.h -@@ -236,14 +236,10 @@ typedef elf_vrregset_t elf_fpxregset_t; - #ifdef __powerpc64__ - # define SET_PERSONALITY(ex) \ - do { \ -- unsigned long new_flags = 0; \ - if ((ex).e_ident[EI_CLASS] == ELFCLASS32) \ -- new_flags = _TIF_32BIT; \ -- if ((current_thread_info()->flags & _TIF_32BIT) \ -- != new_flags) \ -- set_thread_flag(TIF_ABI_PENDING); \ -+ set_thread_flag(TIF_32BIT); \ - else \ -- clear_thread_flag(TIF_ABI_PENDING); \ -+ clear_thread_flag(TIF_32BIT); \ - if (personality(current->personality) != PER_LINUX32) \ - set_personality(PER_LINUX | \ - (current->personality & (~PER_MASK))); \ -diff --git a/arch/powerpc/include/asm/thread_info.h b/arch/powerpc/include/asm/thread_info.h -index c8b3292..aa9d383 100644 ---- a/arch/powerpc/include/asm/thread_info.h -+++ b/arch/powerpc/include/asm/thread_info.h -@@ -111,7 +111,6 @@ static inline struct thread_info *current_thread_info(void) - #define TIF_NOTIFY_RESUME 13 /* callback before returning to user */ - #define TIF_FREEZE 14 /* Freezing for suspend */ - #define TIF_RUNLATCH 15 /* Is the runlatch enabled? */ --#define TIF_ABI_PENDING 16 /* 32/64 bit switch needed */ - - /* as above, but as bit values */ - #define _TIF_SYSCALL_TRACE (1<thread.dabr) { -diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S -index 48215d1..e8ef21c 100644 ---- a/arch/s390/kernel/entry.S -+++ b/arch/s390/kernel/entry.S -@@ -571,6 +571,7 @@ pgm_svcper: - mvc __THREAD_per+__PER_access_id(1,%r8),__LC_PER_ACCESS_ID - oi __TI_flags+3(%r9),_TIF_SINGLE_STEP # set TIF_SINGLE_STEP - TRACE_IRQS_ON -+ lm %r2,%r6,SP_R2(%r15) # load svc arguments - stosm __SF_EMPTY(%r15),0x03 # reenable interrupts - b BASED(sysc_do_svc) - -diff --git a/arch/s390/kernel/entry64.S b/arch/s390/kernel/entry64.S -index 9aff1d4..f33658f 100644 ---- a/arch/s390/kernel/entry64.S -+++ b/arch/s390/kernel/entry64.S -@@ -549,6 +549,7 @@ pgm_svcper: - mvc __THREAD_per+__PER_access_id(1,%r8),__LC_PER_ACCESS_ID - oi __TI_flags+7(%r9),_TIF_SINGLE_STEP # set TIF_SINGLE_STEP - TRACE_IRQS_ON -+ lmg %r2,%r6,SP_R2(%r15) # load svc arguments - stosm __SF_EMPTY(%r15),0x03 # reenable interrupts - j sysc_do_svc - -diff --git a/arch/sh/kernel/process_64.c b/arch/sh/kernel/process_64.c -index 1192398..44aa119 100644 ---- a/arch/sh/kernel/process_64.c -+++ b/arch/sh/kernel/process_64.c -@@ -367,7 +367,7 @@ void exit_thread(void) - void flush_thread(void) - { - -- /* Called by fs/exec.c (flush_old_exec) to remove traces of a -+ /* Called by fs/exec.c (setup_new_exec) to remove traces of a - * previously running executable. */ - #ifdef CONFIG_SH_FPU - if (last_task_used_math == current) { -diff --git a/arch/sparc/include/asm/elf_64.h b/arch/sparc/include/asm/elf_64.h -index d42e393..9968085 100644 ---- a/arch/sparc/include/asm/elf_64.h -+++ b/arch/sparc/include/asm/elf_64.h -@@ -196,17 +196,10 @@ static inline unsigned int sparc64_elf_hwcap(void) - #define ELF_PLATFORM (NULL) - - #define SET_PERSONALITY(ex) \ --do { unsigned long new_flags = current_thread_info()->flags; \ -- new_flags &= _TIF_32BIT; \ -- if ((ex).e_ident[EI_CLASS] == ELFCLASS32) \ -- new_flags |= _TIF_32BIT; \ -+do { if ((ex).e_ident[EI_CLASS] == ELFCLASS32) \ -+ set_thread_flag(TIF_32BIT); \ - else \ -- new_flags &= ~_TIF_32BIT; \ -- if ((current_thread_info()->flags & _TIF_32BIT) \ -- != new_flags) \ -- set_thread_flag(TIF_ABI_PENDING); \ -- else \ -- clear_thread_flag(TIF_ABI_PENDING); \ -+ clear_thread_flag(TIF_32BIT); \ - /* flush_thread will update pgd cache */ \ - if (personality(current->personality) != PER_LINUX32) \ - set_personality(PER_LINUX | \ -diff --git a/arch/sparc/include/asm/thread_info_64.h b/arch/sparc/include/asm/thread_info_64.h -index 1b45a7b..f78ad9a 100644 ---- a/arch/sparc/include/asm/thread_info_64.h -+++ b/arch/sparc/include/asm/thread_info_64.h -@@ -227,12 +227,11 @@ register struct thread_info *current_thread_info_reg asm("g6"); - /* flag bit 8 is available */ - #define TIF_SECCOMP 9 /* secure computing */ - #define TIF_SYSCALL_AUDIT 10 /* syscall auditing active */ --/* flag bit 11 is available */ - /* NOTE: Thread flags >= 12 should be ones we have no interest - * in using in assembly, else we can't use the mask as - * an immediate value in instructions such as andcc. - */ --#define TIF_ABI_PENDING 12 -+/* flag bit 12 is available */ - #define TIF_MEMDIE 13 - #define TIF_POLLING_NRFLAG 14 - #define TIF_FREEZE 15 /* is freezing for suspend */ -@@ -246,7 +245,6 @@ register struct thread_info *current_thread_info_reg asm("g6"); - #define _TIF_32BIT (1<task->mm; - if (mm) - tsb_context_switch(mm); -diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig -index 72ace95..4fdb669 100644 ---- a/arch/x86/Kconfig -+++ b/arch/x86/Kconfig -@@ -984,12 +984,6 @@ config X86_CPUID - with major 203 and minors 0 to 31 for /dev/cpu/0/cpuid to - /dev/cpu/31/cpuid. - --config X86_CPU_DEBUG -- tristate "/sys/kernel/debug/x86/cpu/* - CPU Debug support" -- ---help--- -- If you select this option, this will provide various x86 CPUs -- information through debugfs. -- - choice - prompt "High Memory Support" - default HIGHMEM4G if !X86_NUMAQ -diff --git a/arch/x86/ia32/ia32_aout.c b/arch/x86/ia32/ia32_aout.c -index 2a4d073..f9f4724 100644 ---- a/arch/x86/ia32/ia32_aout.c -+++ b/arch/x86/ia32/ia32_aout.c -@@ -308,14 +308,15 @@ static int load_aout_binary(struct linux_binprm *bprm, struct pt_regs *regs) - if (retval) - return retval; - -- regs->cs = __USER32_CS; -- regs->r8 = regs->r9 = regs->r10 = regs->r11 = regs->r12 = -- regs->r13 = regs->r14 = regs->r15 = 0; -- - /* OK, This is the point of no return */ - set_personality(PER_LINUX); - set_thread_flag(TIF_IA32); -- clear_thread_flag(TIF_ABI_PENDING); -+ -+ setup_new_exec(bprm); -+ -+ regs->cs = __USER32_CS; -+ regs->r8 = regs->r9 = regs->r10 = regs->r11 = regs->r12 = -+ regs->r13 = regs->r14 = regs->r15 = 0; - - current->mm->end_code = ex.a_text + - (current->mm->start_code = N_TXTADDR(ex)); -diff --git a/arch/x86/include/asm/cpu_debug.h b/arch/x86/include/asm/cpu_debug.h -deleted file mode 100644 -index d96c1ee..0000000 ---- a/arch/x86/include/asm/cpu_debug.h -+++ /dev/null -@@ -1,127 +0,0 @@ --#ifndef _ASM_X86_CPU_DEBUG_H --#define _ASM_X86_CPU_DEBUG_H -- --/* -- * CPU x86 architecture debug -- * -- * Copyright(C) 2009 Jaswinder Singh Rajput -- */ -- --/* Register flags */ --enum cpu_debug_bit { --/* Model Specific Registers (MSRs) */ -- CPU_MC_BIT, /* Machine Check */ -- CPU_MONITOR_BIT, /* Monitor */ -- CPU_TIME_BIT, /* Time */ -- CPU_PMC_BIT, /* Performance Monitor */ -- CPU_PLATFORM_BIT, /* Platform */ -- CPU_APIC_BIT, /* APIC */ -- CPU_POWERON_BIT, /* Power-on */ -- CPU_CONTROL_BIT, /* Control */ -- CPU_FEATURES_BIT, /* Features control */ -- CPU_LBRANCH_BIT, /* Last Branch */ -- CPU_BIOS_BIT, /* BIOS */ -- CPU_FREQ_BIT, /* Frequency */ -- CPU_MTTR_BIT, /* MTRR */ -- CPU_PERF_BIT, /* Performance */ -- CPU_CACHE_BIT, /* Cache */ -- CPU_SYSENTER_BIT, /* Sysenter */ -- CPU_THERM_BIT, /* Thermal */ -- CPU_MISC_BIT, /* Miscellaneous */ -- CPU_DEBUG_BIT, /* Debug */ -- CPU_PAT_BIT, /* PAT */ -- CPU_VMX_BIT, /* VMX */ -- CPU_CALL_BIT, /* System Call */ -- CPU_BASE_BIT, /* BASE Address */ -- CPU_VER_BIT, /* Version ID */ -- CPU_CONF_BIT, /* Configuration */ -- CPU_SMM_BIT, /* System mgmt mode */ -- CPU_SVM_BIT, /*Secure Virtual Machine*/ -- CPU_OSVM_BIT, /* OS-Visible Workaround*/ --/* Standard Registers */ -- CPU_TSS_BIT, /* Task Stack Segment */ -- CPU_CR_BIT, /* Control Registers */ -- CPU_DT_BIT, /* Descriptor Table */ --/* End of Registers flags */ -- CPU_REG_ALL_BIT, /* Select all Registers */ --}; -- --#define CPU_REG_ALL (~0) /* Select all Registers */ -- --#define CPU_MC (1 << CPU_MC_BIT) --#define CPU_MONITOR (1 << CPU_MONITOR_BIT) --#define CPU_TIME (1 << CPU_TIME_BIT) --#define CPU_PMC (1 << CPU_PMC_BIT) --#define CPU_PLATFORM (1 << CPU_PLATFORM_BIT) --#define CPU_APIC (1 << CPU_APIC_BIT) --#define CPU_POWERON (1 << CPU_POWERON_BIT) --#define CPU_CONTROL (1 << CPU_CONTROL_BIT) --#define CPU_FEATURES (1 << CPU_FEATURES_BIT) --#define CPU_LBRANCH (1 << CPU_LBRANCH_BIT) --#define CPU_BIOS (1 << CPU_BIOS_BIT) --#define CPU_FREQ (1 << CPU_FREQ_BIT) --#define CPU_MTRR (1 << CPU_MTTR_BIT) --#define CPU_PERF (1 << CPU_PERF_BIT) --#define CPU_CACHE (1 << CPU_CACHE_BIT) --#define CPU_SYSENTER (1 << CPU_SYSENTER_BIT) --#define CPU_THERM (1 << CPU_THERM_BIT) --#define CPU_MISC (1 << CPU_MISC_BIT) --#define CPU_DEBUG (1 << CPU_DEBUG_BIT) --#define CPU_PAT (1 << CPU_PAT_BIT) --#define CPU_VMX (1 << CPU_VMX_BIT) --#define CPU_CALL (1 << CPU_CALL_BIT) --#define CPU_BASE (1 << CPU_BASE_BIT) --#define CPU_VER (1 << CPU_VER_BIT) --#define CPU_CONF (1 << CPU_CONF_BIT) --#define CPU_SMM (1 << CPU_SMM_BIT) --#define CPU_SVM (1 << CPU_SVM_BIT) --#define CPU_OSVM (1 << CPU_OSVM_BIT) --#define CPU_TSS (1 << CPU_TSS_BIT) --#define CPU_CR (1 << CPU_CR_BIT) --#define CPU_DT (1 << CPU_DT_BIT) -- --/* Register file flags */ --enum cpu_file_bit { -- CPU_INDEX_BIT, /* index */ -- CPU_VALUE_BIT, /* value */ --}; -- --#define CPU_FILE_VALUE (1 << CPU_VALUE_BIT) -- --#define MAX_CPU_FILES 512 -- --struct cpu_private { -- unsigned cpu; -- unsigned type; -- unsigned reg; -- unsigned file; --}; -- --struct cpu_debug_base { -- char *name; /* Register name */ -- unsigned flag; /* Register flag */ -- unsigned write; /* Register write flag */ --}; -- --/* -- * Currently it looks similar to cpu_debug_base but once we add more files -- * cpu_file_base will go in different direction -- */ --struct cpu_file_base { -- char *name; /* Register file name */ -- unsigned flag; /* Register file flag */ -- unsigned write; /* Register write flag */ --}; -- --struct cpu_cpuX_base { -- struct dentry *dentry; /* Register dentry */ -- int init; /* Register index file */ --}; -- --struct cpu_debug_range { -- unsigned min; /* Register range min */ -- unsigned max; /* Register range max */ -- unsigned flag; /* Supported flags */ --}; -- --#endif /* _ASM_X86_CPU_DEBUG_H */ -diff --git a/arch/x86/include/asm/elf.h b/arch/x86/include/asm/elf.h -index 456a304..8ac9d9a 100644 ---- a/arch/x86/include/asm/elf.h -+++ b/arch/x86/include/asm/elf.h -@@ -197,14 +197,8 @@ do { \ - set_fs(USER_DS); \ - } while (0) - --#define COMPAT_SET_PERSONALITY(ex) \ --do { \ -- if (test_thread_flag(TIF_IA32)) \ -- clear_thread_flag(TIF_ABI_PENDING); \ -- else \ -- set_thread_flag(TIF_ABI_PENDING); \ -- current->personality |= force_personality32; \ --} while (0) -+void set_personality_ia32(void); -+#define COMPAT_SET_PERSONALITY(ex) set_personality_ia32() - - #define COMPAT_ELF_PLATFORM ("i686") - -diff --git a/arch/x86/include/asm/hpet.h b/arch/x86/include/asm/hpet.h -index 1c22cb0..3251e23 100644 ---- a/arch/x86/include/asm/hpet.h -+++ b/arch/x86/include/asm/hpet.h -@@ -66,6 +66,7 @@ - extern unsigned long hpet_address; - extern unsigned long force_hpet_address; - extern int hpet_force_user; -+extern u8 hpet_msi_disable; - extern int is_hpet_enabled(void); - extern int hpet_enable(void); - extern void hpet_disable(void); -diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h -index d838922..d759a1f 100644 ---- a/arch/x86/include/asm/kvm_host.h -+++ b/arch/x86/include/asm/kvm_host.h -@@ -412,6 +412,7 @@ struct kvm_arch{ - unsigned long irq_sources_bitmap; - unsigned long irq_states[KVM_IOAPIC_NUM_PINS]; - u64 vm_init_tsc; -+ s64 kvmclock_offset; - }; - - struct kvm_vm_stat { -diff --git a/arch/x86/include/asm/thread_info.h b/arch/x86/include/asm/thread_info.h -index d27d0a2..19c3ce4 100644 ---- a/arch/x86/include/asm/thread_info.h -+++ b/arch/x86/include/asm/thread_info.h -@@ -86,7 +86,6 @@ struct thread_info { - #define TIF_NOTSC 16 /* TSC is not accessible in userland */ - #define TIF_IA32 17 /* 32bit process */ - #define TIF_FORK 18 /* ret_from_fork */ --#define TIF_ABI_PENDING 19 - #define TIF_MEMDIE 20 - #define TIF_DEBUG 21 /* uses debug registers */ - #define TIF_IO_BITMAP 22 /* uses I/O bitmap */ -@@ -110,7 +109,6 @@ struct thread_info { - #define _TIF_NOTSC (1 << TIF_NOTSC) - #define _TIF_IA32 (1 << TIF_IA32) - #define _TIF_FORK (1 << TIF_FORK) --#define _TIF_ABI_PENDING (1 << TIF_ABI_PENDING) - #define _TIF_DEBUG (1 << TIF_DEBUG) - #define _TIF_IO_BITMAP (1 << TIF_IO_BITMAP) - #define _TIF_FREEZE (1 << TIF_FREEZE) -diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c -index 90b9b55..e3f85fe 100644 ---- a/arch/x86/kernel/amd_iommu.c -+++ b/arch/x86/kernel/amd_iommu.c -@@ -540,7 +540,7 @@ static void flush_all_devices_for_iommu(struct amd_iommu *iommu) - static void flush_devices_by_domain(struct protection_domain *domain) - { - struct amd_iommu *iommu; -- int i; -+ unsigned long i; - - for (i = 0; i <= amd_iommu_last_bdf; ++i) { - if ((domain == NULL && amd_iommu_pd_table[i] == NULL) || -diff --git a/arch/x86/kernel/cpu/Makefile b/arch/x86/kernel/cpu/Makefile -index 68537e9..ff502cc 100644 ---- a/arch/x86/kernel/cpu/Makefile -+++ b/arch/x86/kernel/cpu/Makefile -@@ -18,8 +18,6 @@ obj-y += vmware.o hypervisor.o sched.o - obj-$(CONFIG_X86_32) += bugs.o cmpxchg.o - obj-$(CONFIG_X86_64) += bugs_64.o - --obj-$(CONFIG_X86_CPU_DEBUG) += cpu_debug.o -- - obj-$(CONFIG_CPU_SUP_INTEL) += intel.o - obj-$(CONFIG_CPU_SUP_AMD) += amd.o - obj-$(CONFIG_CPU_SUP_CYRIX_32) += cyrix.o -diff --git a/arch/x86/kernel/cpu/cpu_debug.c b/arch/x86/kernel/cpu/cpu_debug.c -deleted file mode 100644 -index dca325c..0000000 ---- a/arch/x86/kernel/cpu/cpu_debug.c -+++ /dev/null -@@ -1,688 +0,0 @@ --/* -- * CPU x86 architecture debug code -- * -- * Copyright(C) 2009 Jaswinder Singh Rajput -- * -- * For licencing details see kernel-base/COPYING -- */ -- --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include -- --#include --#include --#include --#include --#include --#include -- --static DEFINE_PER_CPU(struct cpu_cpuX_base [CPU_REG_ALL_BIT], cpu_arr); --static DEFINE_PER_CPU(struct cpu_private * [MAX_CPU_FILES], priv_arr); --static DEFINE_PER_CPU(int, cpu_priv_count); -- --static DEFINE_MUTEX(cpu_debug_lock); -- --static struct dentry *cpu_debugfs_dir; -- --static struct cpu_debug_base cpu_base[] = { -- { "mc", CPU_MC, 0 }, -- { "monitor", CPU_MONITOR, 0 }, -- { "time", CPU_TIME, 0 }, -- { "pmc", CPU_PMC, 1 }, -- { "platform", CPU_PLATFORM, 0 }, -- { "apic", CPU_APIC, 0 }, -- { "poweron", CPU_POWERON, 0 }, -- { "control", CPU_CONTROL, 0 }, -- { "features", CPU_FEATURES, 0 }, -- { "lastbranch", CPU_LBRANCH, 0 }, -- { "bios", CPU_BIOS, 0 }, -- { "freq", CPU_FREQ, 0 }, -- { "mtrr", CPU_MTRR, 0 }, -- { "perf", CPU_PERF, 0 }, -- { "cache", CPU_CACHE, 0 }, -- { "sysenter", CPU_SYSENTER, 0 }, -- { "therm", CPU_THERM, 0 }, -- { "misc", CPU_MISC, 0 }, -- { "debug", CPU_DEBUG, 0 }, -- { "pat", CPU_PAT, 0 }, -- { "vmx", CPU_VMX, 0 }, -- { "call", CPU_CALL, 0 }, -- { "base", CPU_BASE, 0 }, -- { "ver", CPU_VER, 0 }, -- { "conf", CPU_CONF, 0 }, -- { "smm", CPU_SMM, 0 }, -- { "svm", CPU_SVM, 0 }, -- { "osvm", CPU_OSVM, 0 }, -- { "tss", CPU_TSS, 0 }, -- { "cr", CPU_CR, 0 }, -- { "dt", CPU_DT, 0 }, -- { "registers", CPU_REG_ALL, 0 }, --}; -- --static struct cpu_file_base cpu_file[] = { -- { "index", CPU_REG_ALL, 0 }, -- { "value", CPU_REG_ALL, 1 }, --}; -- --/* CPU Registers Range */ --static struct cpu_debug_range cpu_reg_range[] = { -- { 0x00000000, 0x00000001, CPU_MC, }, -- { 0x00000006, 0x00000007, CPU_MONITOR, }, -- { 0x00000010, 0x00000010, CPU_TIME, }, -- { 0x00000011, 0x00000013, CPU_PMC, }, -- { 0x00000017, 0x00000017, CPU_PLATFORM, }, -- { 0x0000001B, 0x0000001B, CPU_APIC, }, -- { 0x0000002A, 0x0000002B, CPU_POWERON, }, -- { 0x0000002C, 0x0000002C, CPU_FREQ, }, -- { 0x0000003A, 0x0000003A, CPU_CONTROL, }, -- { 0x00000040, 0x00000047, CPU_LBRANCH, }, -- { 0x00000060, 0x00000067, CPU_LBRANCH, }, -- { 0x00000079, 0x00000079, CPU_BIOS, }, -- { 0x00000088, 0x0000008A, CPU_CACHE, }, -- { 0x0000008B, 0x0000008B, CPU_BIOS, }, -- { 0x0000009B, 0x0000009B, CPU_MONITOR, }, -- { 0x000000C1, 0x000000C4, CPU_PMC, }, -- { 0x000000CD, 0x000000CD, CPU_FREQ, }, -- { 0x000000E7, 0x000000E8, CPU_PERF, }, -- { 0x000000FE, 0x000000FE, CPU_MTRR, }, -- -- { 0x00000116, 0x0000011E, CPU_CACHE, }, -- { 0x00000174, 0x00000176, CPU_SYSENTER, }, -- { 0x00000179, 0x0000017B, CPU_MC, }, -- { 0x00000186, 0x00000189, CPU_PMC, }, -- { 0x00000198, 0x00000199, CPU_PERF, }, -- { 0x0000019A, 0x0000019A, CPU_TIME, }, -- { 0x0000019B, 0x0000019D, CPU_THERM, }, -- { 0x000001A0, 0x000001A0, CPU_MISC, }, -- { 0x000001C9, 0x000001C9, CPU_LBRANCH, }, -- { 0x000001D7, 0x000001D8, CPU_LBRANCH, }, -- { 0x000001D9, 0x000001D9, CPU_DEBUG, }, -- { 0x000001DA, 0x000001E0, CPU_LBRANCH, }, -- -- { 0x00000200, 0x0000020F, CPU_MTRR, }, -- { 0x00000250, 0x00000250, CPU_MTRR, }, -- { 0x00000258, 0x00000259, CPU_MTRR, }, -- { 0x00000268, 0x0000026F, CPU_MTRR, }, -- { 0x00000277, 0x00000277, CPU_PAT, }, -- { 0x000002FF, 0x000002FF, CPU_MTRR, }, -- -- { 0x00000300, 0x00000311, CPU_PMC, }, -- { 0x00000345, 0x00000345, CPU_PMC, }, -- { 0x00000360, 0x00000371, CPU_PMC, }, -- { 0x0000038D, 0x00000390, CPU_PMC, }, -- { 0x000003A0, 0x000003BE, CPU_PMC, }, -- { 0x000003C0, 0x000003CD, CPU_PMC, }, -- { 0x000003E0, 0x000003E1, CPU_PMC, }, -- { 0x000003F0, 0x000003F2, CPU_PMC, }, -- -- { 0x00000400, 0x00000417, CPU_MC, }, -- { 0x00000480, 0x0000048B, CPU_VMX, }, -- -- { 0x00000600, 0x00000600, CPU_DEBUG, }, -- { 0x00000680, 0x0000068F, CPU_LBRANCH, }, -- { 0x000006C0, 0x000006CF, CPU_LBRANCH, }, -- -- { 0x000107CC, 0x000107D3, CPU_PMC, }, -- -- { 0xC0000080, 0xC0000080, CPU_FEATURES, }, -- { 0xC0000081, 0xC0000084, CPU_CALL, }, -- { 0xC0000100, 0xC0000102, CPU_BASE, }, -- { 0xC0000103, 0xC0000103, CPU_TIME, }, -- -- { 0xC0010000, 0xC0010007, CPU_PMC, }, -- { 0xC0010010, 0xC0010010, CPU_CONF, }, -- { 0xC0010015, 0xC0010015, CPU_CONF, }, -- { 0xC0010016, 0xC001001A, CPU_MTRR, }, -- { 0xC001001D, 0xC001001D, CPU_MTRR, }, -- { 0xC001001F, 0xC001001F, CPU_CONF, }, -- { 0xC0010030, 0xC0010035, CPU_BIOS, }, -- { 0xC0010044, 0xC0010048, CPU_MC, }, -- { 0xC0010050, 0xC0010056, CPU_SMM, }, -- { 0xC0010058, 0xC0010058, CPU_CONF, }, -- { 0xC0010060, 0xC0010060, CPU_CACHE, }, -- { 0xC0010061, 0xC0010068, CPU_SMM, }, -- { 0xC0010069, 0xC001006B, CPU_SMM, }, -- { 0xC0010070, 0xC0010071, CPU_SMM, }, -- { 0xC0010111, 0xC0010113, CPU_SMM, }, -- { 0xC0010114, 0xC0010118, CPU_SVM, }, -- { 0xC0010140, 0xC0010141, CPU_OSVM, }, -- { 0xC0011022, 0xC0011023, CPU_CONF, }, --}; -- --static int is_typeflag_valid(unsigned cpu, unsigned flag) --{ -- int i; -- -- /* Standard Registers should be always valid */ -- if (flag >= CPU_TSS) -- return 1; -- -- for (i = 0; i < ARRAY_SIZE(cpu_reg_range); i++) { -- if (cpu_reg_range[i].flag == flag) -- return 1; -- } -- -- /* Invalid */ -- return 0; --} -- --static unsigned get_cpu_range(unsigned cpu, unsigned *min, unsigned *max, -- int index, unsigned flag) --{ -- if (cpu_reg_range[index].flag == flag) { -- *min = cpu_reg_range[index].min; -- *max = cpu_reg_range[index].max; -- } else -- *max = 0; -- -- return *max; --} -- --/* This function can also be called with seq = NULL for printk */ --static void print_cpu_data(struct seq_file *seq, unsigned type, -- u32 low, u32 high) --{ -- struct cpu_private *priv; -- u64 val = high; -- -- if (seq) { -- priv = seq->private; -- if (priv->file) { -- val = (val << 32) | low; -- seq_printf(seq, "0x%llx\n", val); -- } else -- seq_printf(seq, " %08x: %08x_%08x\n", -- type, high, low); -- } else -- printk(KERN_INFO " %08x: %08x_%08x\n", type, high, low); --} -- --/* This function can also be called with seq = NULL for printk */ --static void print_msr(struct seq_file *seq, unsigned cpu, unsigned flag) --{ -- unsigned msr, msr_min, msr_max; -- struct cpu_private *priv; -- u32 low, high; -- int i; -- -- if (seq) { -- priv = seq->private; -- if (priv->file) { -- if (!rdmsr_safe_on_cpu(priv->cpu, priv->reg, -- &low, &high)) -- print_cpu_data(seq, priv->reg, low, high); -- return; -- } -- } -- -- for (i = 0; i < ARRAY_SIZE(cpu_reg_range); i++) { -- if (!get_cpu_range(cpu, &msr_min, &msr_max, i, flag)) -- continue; -- -- for (msr = msr_min; msr <= msr_max; msr++) { -- if (rdmsr_safe_on_cpu(cpu, msr, &low, &high)) -- continue; -- print_cpu_data(seq, msr, low, high); -- } -- } --} -- --static void print_tss(void *arg) --{ -- struct pt_regs *regs = task_pt_regs(current); -- struct seq_file *seq = arg; -- unsigned int seg; -- -- seq_printf(seq, " RAX\t: %016lx\n", regs->ax); -- seq_printf(seq, " RBX\t: %016lx\n", regs->bx); -- seq_printf(seq, " RCX\t: %016lx\n", regs->cx); -- seq_printf(seq, " RDX\t: %016lx\n", regs->dx); -- -- seq_printf(seq, " RSI\t: %016lx\n", regs->si); -- seq_printf(seq, " RDI\t: %016lx\n", regs->di); -- seq_printf(seq, " RBP\t: %016lx\n", regs->bp); -- seq_printf(seq, " ESP\t: %016lx\n", regs->sp); -- --#ifdef CONFIG_X86_64 -- seq_printf(seq, " R08\t: %016lx\n", regs->r8); -- seq_printf(seq, " R09\t: %016lx\n", regs->r9); -- seq_printf(seq, " R10\t: %016lx\n", regs->r10); -- seq_printf(seq, " R11\t: %016lx\n", regs->r11); -- seq_printf(seq, " R12\t: %016lx\n", regs->r12); -- seq_printf(seq, " R13\t: %016lx\n", regs->r13); -- seq_printf(seq, " R14\t: %016lx\n", regs->r14); -- seq_printf(seq, " R15\t: %016lx\n", regs->r15); --#endif -- -- asm("movl %%cs,%0" : "=r" (seg)); -- seq_printf(seq, " CS\t: %04x\n", seg); -- asm("movl %%ds,%0" : "=r" (seg)); -- seq_printf(seq, " DS\t: %04x\n", seg); -- seq_printf(seq, " SS\t: %04lx\n", regs->ss & 0xffff); -- asm("movl %%es,%0" : "=r" (seg)); -- seq_printf(seq, " ES\t: %04x\n", seg); -- asm("movl %%fs,%0" : "=r" (seg)); -- seq_printf(seq, " FS\t: %04x\n", seg); -- asm("movl %%gs,%0" : "=r" (seg)); -- seq_printf(seq, " GS\t: %04x\n", seg); -- -- seq_printf(seq, " EFLAGS\t: %016lx\n", regs->flags); -- -- seq_printf(seq, " EIP\t: %016lx\n", regs->ip); --} -- --static void print_cr(void *arg) --{ -- struct seq_file *seq = arg; -- -- seq_printf(seq, " cr0\t: %016lx\n", read_cr0()); -- seq_printf(seq, " cr2\t: %016lx\n", read_cr2()); -- seq_printf(seq, " cr3\t: %016lx\n", read_cr3()); -- seq_printf(seq, " cr4\t: %016lx\n", read_cr4_safe()); --#ifdef CONFIG_X86_64 -- seq_printf(seq, " cr8\t: %016lx\n", read_cr8()); --#endif --} -- --static void print_desc_ptr(char *str, struct seq_file *seq, struct desc_ptr dt) --{ -- seq_printf(seq, " %s\t: %016llx\n", str, (u64)(dt.address | dt.size)); --} -- --static void print_dt(void *seq) --{ -- struct desc_ptr dt; -- unsigned long ldt; -- -- /* IDT */ -- store_idt((struct desc_ptr *)&dt); -- print_desc_ptr("IDT", seq, dt); -- -- /* GDT */ -- store_gdt((struct desc_ptr *)&dt); -- print_desc_ptr("GDT", seq, dt); -- -- /* LDT */ -- store_ldt(ldt); -- seq_printf(seq, " LDT\t: %016lx\n", ldt); -- -- /* TR */ -- store_tr(ldt); -- seq_printf(seq, " TR\t: %016lx\n", ldt); --} -- --static void print_dr(void *arg) --{ -- struct seq_file *seq = arg; -- unsigned long dr; -- int i; -- -- for (i = 0; i < 8; i++) { -- /* Ignore db4, db5 */ -- if ((i == 4) || (i == 5)) -- continue; -- get_debugreg(dr, i); -- seq_printf(seq, " dr%d\t: %016lx\n", i, dr); -- } -- -- seq_printf(seq, "\n MSR\t:\n"); --} -- --static void print_apic(void *arg) --{ -- struct seq_file *seq = arg; -- --#ifdef CONFIG_X86_LOCAL_APIC -- seq_printf(seq, " LAPIC\t:\n"); -- seq_printf(seq, " ID\t\t: %08x\n", apic_read(APIC_ID) >> 24); -- seq_printf(seq, " LVR\t\t: %08x\n", apic_read(APIC_LVR)); -- seq_printf(seq, " TASKPRI\t: %08x\n", apic_read(APIC_TASKPRI)); -- seq_printf(seq, " ARBPRI\t\t: %08x\n", apic_read(APIC_ARBPRI)); -- seq_printf(seq, " PROCPRI\t: %08x\n", apic_read(APIC_PROCPRI)); -- seq_printf(seq, " LDR\t\t: %08x\n", apic_read(APIC_LDR)); -- seq_printf(seq, " DFR\t\t: %08x\n", apic_read(APIC_DFR)); -- seq_printf(seq, " SPIV\t\t: %08x\n", apic_read(APIC_SPIV)); -- seq_printf(seq, " ISR\t\t: %08x\n", apic_read(APIC_ISR)); -- seq_printf(seq, " ESR\t\t: %08x\n", apic_read(APIC_ESR)); -- seq_printf(seq, " ICR\t\t: %08x\n", apic_read(APIC_ICR)); -- seq_printf(seq, " ICR2\t\t: %08x\n", apic_read(APIC_ICR2)); -- seq_printf(seq, " LVTT\t\t: %08x\n", apic_read(APIC_LVTT)); -- seq_printf(seq, " LVTTHMR\t: %08x\n", apic_read(APIC_LVTTHMR)); -- seq_printf(seq, " LVTPC\t\t: %08x\n", apic_read(APIC_LVTPC)); -- seq_printf(seq, " LVT0\t\t: %08x\n", apic_read(APIC_LVT0)); -- seq_printf(seq, " LVT1\t\t: %08x\n", apic_read(APIC_LVT1)); -- seq_printf(seq, " LVTERR\t\t: %08x\n", apic_read(APIC_LVTERR)); -- seq_printf(seq, " TMICT\t\t: %08x\n", apic_read(APIC_TMICT)); -- seq_printf(seq, " TMCCT\t\t: %08x\n", apic_read(APIC_TMCCT)); -- seq_printf(seq, " TDCR\t\t: %08x\n", apic_read(APIC_TDCR)); -- if (boot_cpu_has(X86_FEATURE_EXTAPIC)) { -- unsigned int i, v, maxeilvt; -- -- v = apic_read(APIC_EFEAT); -- maxeilvt = (v >> 16) & 0xff; -- seq_printf(seq, " EFEAT\t\t: %08x\n", v); -- seq_printf(seq, " ECTRL\t\t: %08x\n", apic_read(APIC_ECTRL)); -- -- for (i = 0; i < maxeilvt; i++) { -- v = apic_read(APIC_EILVTn(i)); -- seq_printf(seq, " EILVT%d\t\t: %08x\n", i, v); -- } -- } --#endif /* CONFIG_X86_LOCAL_APIC */ -- seq_printf(seq, "\n MSR\t:\n"); --} -- --static int cpu_seq_show(struct seq_file *seq, void *v) --{ -- struct cpu_private *priv = seq->private; -- -- if (priv == NULL) -- return -EINVAL; -- -- switch (cpu_base[priv->type].flag) { -- case CPU_TSS: -- smp_call_function_single(priv->cpu, print_tss, seq, 1); -- break; -- case CPU_CR: -- smp_call_function_single(priv->cpu, print_cr, seq, 1); -- break; -- case CPU_DT: -- smp_call_function_single(priv->cpu, print_dt, seq, 1); -- break; -- case CPU_DEBUG: -- if (priv->file == CPU_INDEX_BIT) -- smp_call_function_single(priv->cpu, print_dr, seq, 1); -- print_msr(seq, priv->cpu, cpu_base[priv->type].flag); -- break; -- case CPU_APIC: -- if (priv->file == CPU_INDEX_BIT) -- smp_call_function_single(priv->cpu, print_apic, seq, 1); -- print_msr(seq, priv->cpu, cpu_base[priv->type].flag); -- break; -- -- default: -- print_msr(seq, priv->cpu, cpu_base[priv->type].flag); -- break; -- } -- seq_printf(seq, "\n"); -- -- return 0; --} -- --static void *cpu_seq_start(struct seq_file *seq, loff_t *pos) --{ -- if (*pos == 0) /* One time is enough ;-) */ -- return seq; -- -- return NULL; --} -- --static void *cpu_seq_next(struct seq_file *seq, void *v, loff_t *pos) --{ -- (*pos)++; -- -- return cpu_seq_start(seq, pos); --} -- --static void cpu_seq_stop(struct seq_file *seq, void *v) --{ --} -- --static const struct seq_operations cpu_seq_ops = { -- .start = cpu_seq_start, -- .next = cpu_seq_next, -- .stop = cpu_seq_stop, -- .show = cpu_seq_show, --}; -- --static int cpu_seq_open(struct inode *inode, struct file *file) --{ -- struct cpu_private *priv = inode->i_private; -- struct seq_file *seq; -- int err; -- -- err = seq_open(file, &cpu_seq_ops); -- if (!err) { -- seq = file->private_data; -- seq->private = priv; -- } -- -- return err; --} -- --static int write_msr(struct cpu_private *priv, u64 val) --{ -- u32 low, high; -- -- high = (val >> 32) & 0xffffffff; -- low = val & 0xffffffff; -- -- if (!wrmsr_safe_on_cpu(priv->cpu, priv->reg, low, high)) -- return 0; -- -- return -EPERM; --} -- --static int write_cpu_register(struct cpu_private *priv, const char *buf) --{ -- int ret = -EPERM; -- u64 val; -- -- ret = strict_strtoull(buf, 0, &val); -- if (ret < 0) -- return ret; -- -- /* Supporting only MSRs */ -- if (priv->type < CPU_TSS_BIT) -- return write_msr(priv, val); -- -- return ret; --} -- --static ssize_t cpu_write(struct file *file, const char __user *ubuf, -- size_t count, loff_t *off) --{ -- struct seq_file *seq = file->private_data; -- struct cpu_private *priv = seq->private; -- char buf[19]; -- -- if ((priv == NULL) || (count >= sizeof(buf))) -- return -EINVAL; -- -- if (copy_from_user(&buf, ubuf, count)) -- return -EFAULT; -- -- buf[count] = 0; -- -- if ((cpu_base[priv->type].write) && (cpu_file[priv->file].write)) -- if (!write_cpu_register(priv, buf)) -- return count; -- -- return -EACCES; --} -- --static const struct file_operations cpu_fops = { -- .owner = THIS_MODULE, -- .open = cpu_seq_open, -- .read = seq_read, -- .write = cpu_write, -- .llseek = seq_lseek, -- .release = seq_release, --}; -- --static int cpu_create_file(unsigned cpu, unsigned type, unsigned reg, -- unsigned file, struct dentry *dentry) --{ -- struct cpu_private *priv = NULL; -- -- /* Already intialized */ -- if (file == CPU_INDEX_BIT) -- if (per_cpu(cpu_arr[type].init, cpu)) -- return 0; -- -- priv = kzalloc(sizeof(*priv), GFP_KERNEL); -- if (priv == NULL) -- return -ENOMEM; -- -- priv->cpu = cpu; -- priv->type = type; -- priv->reg = reg; -- priv->file = file; -- mutex_lock(&cpu_debug_lock); -- per_cpu(priv_arr[type], cpu) = priv; -- per_cpu(cpu_priv_count, cpu)++; -- mutex_unlock(&cpu_debug_lock); -- -- if (file) -- debugfs_create_file(cpu_file[file].name, S_IRUGO, -- dentry, (void *)priv, &cpu_fops); -- else { -- debugfs_create_file(cpu_base[type].name, S_IRUGO, -- per_cpu(cpu_arr[type].dentry, cpu), -- (void *)priv, &cpu_fops); -- mutex_lock(&cpu_debug_lock); -- per_cpu(cpu_arr[type].init, cpu) = 1; -- mutex_unlock(&cpu_debug_lock); -- } -- -- return 0; --} -- --static int cpu_init_regfiles(unsigned cpu, unsigned int type, unsigned reg, -- struct dentry *dentry) --{ -- unsigned file; -- int err = 0; -- -- for (file = 0; file < ARRAY_SIZE(cpu_file); file++) { -- err = cpu_create_file(cpu, type, reg, file, dentry); -- if (err) -- return err; -- } -- -- return err; --} -- --static int cpu_init_msr(unsigned cpu, unsigned type, struct dentry *dentry) --{ -- struct dentry *cpu_dentry = NULL; -- unsigned reg, reg_min, reg_max; -- int i, err = 0; -- char reg_dir[12]; -- u32 low, high; -- -- for (i = 0; i < ARRAY_SIZE(cpu_reg_range); i++) { -- if (!get_cpu_range(cpu, ®_min, ®_max, i, -- cpu_base[type].flag)) -- continue; -- -- for (reg = reg_min; reg <= reg_max; reg++) { -- if (rdmsr_safe_on_cpu(cpu, reg, &low, &high)) -- continue; -- -- sprintf(reg_dir, "0x%x", reg); -- cpu_dentry = debugfs_create_dir(reg_dir, dentry); -- err = cpu_init_regfiles(cpu, type, reg, cpu_dentry); -- if (err) -- return err; -- } -- } -- -- return err; --} -- --static int cpu_init_allreg(unsigned cpu, struct dentry *dentry) --{ -- struct dentry *cpu_dentry = NULL; -- unsigned type; -- int err = 0; -- -- for (type = 0; type < ARRAY_SIZE(cpu_base) - 1; type++) { -- if (!is_typeflag_valid(cpu, cpu_base[type].flag)) -- continue; -- cpu_dentry = debugfs_create_dir(cpu_base[type].name, dentry); -- per_cpu(cpu_arr[type].dentry, cpu) = cpu_dentry; -- -- if (type < CPU_TSS_BIT) -- err = cpu_init_msr(cpu, type, cpu_dentry); -- else -- err = cpu_create_file(cpu, type, 0, CPU_INDEX_BIT, -- cpu_dentry); -- if (err) -- return err; -- } -- -- return err; --} -- --static int cpu_init_cpu(void) --{ -- struct dentry *cpu_dentry = NULL; -- struct cpuinfo_x86 *cpui; -- char cpu_dir[12]; -- unsigned cpu; -- int err = 0; -- -- for (cpu = 0; cpu < nr_cpu_ids; cpu++) { -- cpui = &cpu_data(cpu); -- if (!cpu_has(cpui, X86_FEATURE_MSR)) -- continue; -- -- sprintf(cpu_dir, "cpu%d", cpu); -- cpu_dentry = debugfs_create_dir(cpu_dir, cpu_debugfs_dir); -- err = cpu_init_allreg(cpu, cpu_dentry); -- -- pr_info("cpu%d(%d) debug files %d\n", -- cpu, nr_cpu_ids, per_cpu(cpu_priv_count, cpu)); -- if (per_cpu(cpu_priv_count, cpu) > MAX_CPU_FILES) { -- pr_err("Register files count %d exceeds limit %d\n", -- per_cpu(cpu_priv_count, cpu), MAX_CPU_FILES); -- per_cpu(cpu_priv_count, cpu) = MAX_CPU_FILES; -- err = -ENFILE; -- } -- if (err) -- return err; -- } -- -- return err; --} -- --static int __init cpu_debug_init(void) --{ -- cpu_debugfs_dir = debugfs_create_dir("cpu", arch_debugfs_dir); -- -- return cpu_init_cpu(); --} -- --static void __exit cpu_debug_exit(void) --{ -- int i, cpu; -- -- if (cpu_debugfs_dir) -- debugfs_remove_recursive(cpu_debugfs_dir); -- -- for (cpu = 0; cpu < nr_cpu_ids; cpu++) -- for (i = 0; i < per_cpu(cpu_priv_count, cpu); i++) -- kfree(per_cpu(priv_arr[i], cpu)); --} -- --module_init(cpu_debug_init); --module_exit(cpu_debug_exit); -- --MODULE_AUTHOR("Jaswinder Singh Rajput"); --MODULE_DESCRIPTION("CPU Debug module"); --MODULE_LICENSE("GPL"); -diff --git a/arch/x86/kernel/hpet.c b/arch/x86/kernel/hpet.c -index dedc2bd..5877873 100644 ---- a/arch/x86/kernel/hpet.c -+++ b/arch/x86/kernel/hpet.c -@@ -33,6 +33,8 @@ - * HPET address is set in acpi/boot.c, when an ACPI entry exists - */ - unsigned long hpet_address; -+u8 hpet_msi_disable; -+ - #ifdef CONFIG_PCI_MSI - static unsigned long hpet_num_timers; - #endif -@@ -584,6 +586,9 @@ static void hpet_msi_capability_lookup(unsigned int start_timer) - unsigned int num_timers_used = 0; - int i; - -+ if (hpet_msi_disable) -+ return; -+ - id = hpet_readl(HPET_ID); - - num_timers = ((id & HPET_ID_NUMBER) >> HPET_ID_NUMBER_SHIFT); -@@ -911,6 +916,9 @@ static __init int hpet_late_init(void) - hpet_reserve_platform_timers(hpet_readl(HPET_ID)); - hpet_print_config(); - -+ if (hpet_msi_disable) -+ return 0; -+ - for_each_online_cpu(cpu) { - hpet_cpuhp_notify(NULL, CPU_ONLINE, (void *)(long)cpu); - } -diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c -index 5284cd2..f010ab4 100644 ---- a/arch/x86/kernel/process.c -+++ b/arch/x86/kernel/process.c -@@ -91,18 +91,6 @@ void flush_thread(void) - { - struct task_struct *tsk = current; - --#ifdef CONFIG_X86_64 -- if (test_tsk_thread_flag(tsk, TIF_ABI_PENDING)) { -- clear_tsk_thread_flag(tsk, TIF_ABI_PENDING); -- if (test_tsk_thread_flag(tsk, TIF_IA32)) { -- clear_tsk_thread_flag(tsk, TIF_IA32); -- } else { -- set_tsk_thread_flag(tsk, TIF_IA32); -- current_thread_info()->status |= TS_COMPAT; -- } -- } --#endif -- - clear_tsk_thread_flag(tsk, TIF_DEBUG); - - tsk->thread.debugreg0 = 0; -diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c -index eb62cbc..f9ce04f 100644 ---- a/arch/x86/kernel/process_64.c -+++ b/arch/x86/kernel/process_64.c -@@ -540,6 +540,17 @@ sys_clone(unsigned long clone_flags, unsigned long newsp, - return do_fork(clone_flags, newsp, regs, 0, parent_tid, child_tid); - } - -+void set_personality_ia32(void) -+{ -+ /* inherit personality from parent */ -+ -+ /* Make sure to be in 32bit mode */ -+ set_thread_flag(TIF_IA32); -+ -+ /* Prepare the first "return" to user space */ -+ current_thread_info()->status |= TS_COMPAT; -+} -+ - unsigned long get_wchan(struct task_struct *p) - { - unsigned long stack; -diff --git a/arch/x86/kernel/quirks.c b/arch/x86/kernel/quirks.c -index 6c3b2c6..0040164 100644 ---- a/arch/x86/kernel/quirks.c -+++ b/arch/x86/kernel/quirks.c -@@ -491,6 +491,19 @@ void force_hpet_resume(void) - break; - } - } -+ -+/* -+ * HPET MSI on some boards (ATI SB700/SB800) has side effect on -+ * floppy DMA. Disable HPET MSI on such platforms. -+ */ -+static void force_disable_hpet_msi(struct pci_dev *unused) -+{ -+ hpet_msi_disable = 1; -+} -+ -+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_SBX00_SMBUS, -+ force_disable_hpet_msi); -+ - #endif - - #if defined(CONFIG_PCI) && defined(CONFIG_NUMA) -diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c -index 6caf260..bff34d6 100644 ---- a/arch/x86/kernel/reboot.c -+++ b/arch/x86/kernel/reboot.c -@@ -203,6 +203,15 @@ static struct dmi_system_id __initdata reboot_dmi_table[] = { - DMI_MATCH(DMI_BOARD_NAME, "0T656F"), - }, - }, -+ { /* Handle problems with rebooting on Dell OptiPlex 760 with 0G919G*/ -+ .callback = set_bios_reboot, -+ .ident = "Dell OptiPlex 760", -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), -+ DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 760"), -+ DMI_MATCH(DMI_BOARD_NAME, "0G919G"), -+ }, -+ }, - { /* Handle problems with rebooting on Dell 2400's */ - .callback = set_bios_reboot, - .ident = "Dell PowerEdge 2400", -diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c -index 51aa5b2..8425f7e 100644 ---- a/arch/x86/kernel/setup.c -+++ b/arch/x86/kernel/setup.c -@@ -667,19 +667,27 @@ static struct dmi_system_id __initdata bad_bios_dmi_table[] = { - DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix/MSC"), - }, - }, -- { - /* -- * AMI BIOS with low memory corruption was found on Intel DG45ID board. -- * It hase different DMI_BIOS_VENDOR = "Intel Corp.", for now we will -+ * AMI BIOS with low memory corruption was found on Intel DG45ID and -+ * DG45FC boards. -+ * It has a different DMI_BIOS_VENDOR = "Intel Corp.", for now we will - * match only DMI_BOARD_NAME and see if there is more bad products - * with this vendor. - */ -+ { - .callback = dmi_low_memory_corruption, - .ident = "AMI BIOS", - .matches = { - DMI_MATCH(DMI_BOARD_NAME, "DG45ID"), - }, - }, -+ { -+ .callback = dmi_low_memory_corruption, -+ .ident = "AMI BIOS", -+ .matches = { -+ DMI_MATCH(DMI_BOARD_NAME, "DG45FC"), -+ }, -+ }, - #endif - {} - }; -diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c -index 6378e07..145741c 100644 ---- a/arch/x86/kvm/x86.c -+++ b/arch/x86/kvm/x86.c -@@ -680,7 +680,8 @@ static void kvm_write_guest_time(struct kvm_vcpu *v) - /* With all the info we got, fill in the values */ - - vcpu->hv_clock.system_time = ts.tv_nsec + -- (NSEC_PER_SEC * (u64)ts.tv_sec); -+ (NSEC_PER_SEC * (u64)ts.tv_sec) + v->kvm->arch.kvmclock_offset; -+ - /* - * The interface expects us to write an even number signaling that the - * update is finished. Since the guest won't see the intermediate -@@ -1227,6 +1228,7 @@ int kvm_dev_ioctl_check_extension(long ext) - case KVM_CAP_PIT2: - case KVM_CAP_PIT_STATE2: - case KVM_CAP_SET_IDENTITY_MAP_ADDR: -+ case KVM_CAP_ADJUST_CLOCK: - r = 1; - break; - case KVM_CAP_COALESCED_MMIO: -@@ -2424,6 +2426,44 @@ long kvm_arch_vm_ioctl(struct file *filp, - r = 0; - break; - } -+ case KVM_SET_CLOCK: { -+ struct timespec now; -+ struct kvm_clock_data user_ns; -+ u64 now_ns; -+ s64 delta; -+ -+ r = -EFAULT; -+ if (copy_from_user(&user_ns, argp, sizeof(user_ns))) -+ goto out; -+ -+ r = -EINVAL; -+ if (user_ns.flags) -+ goto out; -+ -+ r = 0; -+ ktime_get_ts(&now); -+ now_ns = timespec_to_ns(&now); -+ delta = user_ns.clock - now_ns; -+ kvm->arch.kvmclock_offset = delta; -+ break; -+ } -+ case KVM_GET_CLOCK: { -+ struct timespec now; -+ struct kvm_clock_data user_ns; -+ u64 now_ns; -+ -+ ktime_get_ts(&now); -+ now_ns = timespec_to_ns(&now); -+ user_ns.clock = kvm->arch.kvmclock_offset + now_ns; -+ user_ns.flags = 0; -+ -+ r = -EFAULT; -+ if (copy_to_user(argp, &user_ns, sizeof(user_ns))) -+ goto out; -+ r = 0; -+ break; -+ } -+ - default: - ; - } -diff --git a/arch/x86/mm/srat_64.c b/arch/x86/mm/srat_64.c -index dbb5381..3871c60 100644 ---- a/arch/x86/mm/srat_64.c -+++ b/arch/x86/mm/srat_64.c -@@ -229,9 +229,11 @@ update_nodes_add(int node, unsigned long start, unsigned long end) - printk(KERN_ERR "SRAT: Hotplug zone not continuous. Partly ignored\n"); - } - -- if (changed) -+ if (changed) { -+ node_set(node, cpu_nodes_parsed); - printk(KERN_INFO "SRAT: hot plug zone found %Lx - %Lx\n", - nd->start, nd->end); -+ } - } - - /* Callback for parsing of the Proximity Domain <-> Memory Area mappings */ -diff --git a/arch/x86/oprofile/nmi_int.c b/arch/x86/oprofile/nmi_int.c -index cb88b1a..3347f69 100644 ---- a/arch/x86/oprofile/nmi_int.c -+++ b/arch/x86/oprofile/nmi_int.c -@@ -222,7 +222,7 @@ static void nmi_cpu_switch(void *dummy) - - /* move to next set */ - si += model->num_counters; -- if ((si > model->num_virt_counters) || (counter_config[si].count == 0)) -+ if ((si >= model->num_virt_counters) || (counter_config[si].count == 0)) - per_cpu(switch_index, cpu) = 0; - else - per_cpu(switch_index, cpu) = si; -@@ -598,6 +598,7 @@ static int __init ppro_init(char **cpu_type) - case 15: case 23: - *cpu_type = "i386/core_2"; - break; -+ case 0x2e: - case 26: - spec = &op_arch_perfmon_spec; - *cpu_type = "i386/core_i7"; -diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c -index 7411915..49f6ede 100644 ---- a/drivers/acpi/bus.c -+++ b/drivers/acpi/bus.c -@@ -344,6 +344,167 @@ bool acpi_bus_can_wakeup(acpi_handle handle) - - EXPORT_SYMBOL(acpi_bus_can_wakeup); - -+static void acpi_print_osc_error(acpi_handle handle, -+ struct acpi_osc_context *context, char *error) -+{ -+ struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER}; -+ int i; -+ -+ if (ACPI_FAILURE(acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer))) -+ printk(KERN_DEBUG "%s\n", error); -+ else { -+ printk(KERN_DEBUG "%s:%s\n", (char *)buffer.pointer, error); -+ kfree(buffer.pointer); -+ } -+ printk(KERN_DEBUG"_OSC request data:"); -+ for (i = 0; i < context->cap.length; i += sizeof(u32)) -+ printk("%x ", *((u32 *)(context->cap.pointer + i))); -+ printk("\n"); -+} -+ -+static u8 hex_val(unsigned char c) -+{ -+ return isdigit(c) ? c - '0' : toupper(c) - 'A' + 10; -+} -+ -+static acpi_status acpi_str_to_uuid(char *str, u8 *uuid) -+{ -+ int i; -+ static int opc_map_to_uuid[16] = {6, 4, 2, 0, 11, 9, 16, 14, 19, 21, -+ 24, 26, 28, 30, 32, 34}; -+ -+ if (strlen(str) != 36) -+ return AE_BAD_PARAMETER; -+ for (i = 0; i < 36; i++) { -+ if (i == 8 || i == 13 || i == 18 || i == 23) { -+ if (str[i] != '-') -+ return AE_BAD_PARAMETER; -+ } else if (!isxdigit(str[i])) -+ return AE_BAD_PARAMETER; -+ } -+ for (i = 0; i < 16; i++) { -+ uuid[i] = hex_val(str[opc_map_to_uuid[i]]) << 4; -+ uuid[i] |= hex_val(str[opc_map_to_uuid[i] + 1]); -+ } -+ return AE_OK; -+} -+ -+acpi_status acpi_run_osc(acpi_handle handle, struct acpi_osc_context *context) -+{ -+ acpi_status status; -+ struct acpi_object_list input; -+ union acpi_object in_params[4]; -+ union acpi_object *out_obj; -+ u8 uuid[16]; -+ u32 errors; -+ struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL}; -+ -+ if (!context) -+ return AE_ERROR; -+ if (ACPI_FAILURE(acpi_str_to_uuid(context->uuid_str, uuid))) -+ return AE_ERROR; -+ context->ret.length = ACPI_ALLOCATE_BUFFER; -+ context->ret.pointer = NULL; -+ -+ /* Setting up input parameters */ -+ input.count = 4; -+ input.pointer = in_params; -+ in_params[0].type = ACPI_TYPE_BUFFER; -+ in_params[0].buffer.length = 16; -+ in_params[0].buffer.pointer = uuid; -+ in_params[1].type = ACPI_TYPE_INTEGER; -+ in_params[1].integer.value = context->rev; -+ in_params[2].type = ACPI_TYPE_INTEGER; -+ in_params[2].integer.value = context->cap.length/sizeof(u32); -+ in_params[3].type = ACPI_TYPE_BUFFER; -+ in_params[3].buffer.length = context->cap.length; -+ in_params[3].buffer.pointer = context->cap.pointer; -+ -+ status = acpi_evaluate_object(handle, "_OSC", &input, &output); -+ if (ACPI_FAILURE(status)) -+ return status; -+ -+ if (!output.length) -+ return AE_NULL_OBJECT; -+ -+ out_obj = output.pointer; -+ if (out_obj->type != ACPI_TYPE_BUFFER -+ || out_obj->buffer.length != context->cap.length) { -+ acpi_print_osc_error(handle, context, -+ "_OSC evaluation returned wrong type"); -+ status = AE_TYPE; -+ goto out_kfree; -+ } -+ /* Need to ignore the bit0 in result code */ -+ errors = *((u32 *)out_obj->buffer.pointer) & ~(1 << 0); -+ if (errors) { -+ if (errors & OSC_REQUEST_ERROR) -+ acpi_print_osc_error(handle, context, -+ "_OSC request failed"); -+ if (errors & OSC_INVALID_UUID_ERROR) -+ acpi_print_osc_error(handle, context, -+ "_OSC invalid UUID"); -+ if (errors & OSC_INVALID_REVISION_ERROR) -+ acpi_print_osc_error(handle, context, -+ "_OSC invalid revision"); -+ if (errors & OSC_CAPABILITIES_MASK_ERROR) { -+ if (((u32 *)context->cap.pointer)[OSC_QUERY_TYPE] -+ & OSC_QUERY_ENABLE) -+ goto out_success; -+ status = AE_SUPPORT; -+ goto out_kfree; -+ } -+ status = AE_ERROR; -+ goto out_kfree; -+ } -+out_success: -+ context->ret.length = out_obj->buffer.length; -+ context->ret.pointer = kmalloc(context->ret.length, GFP_KERNEL); -+ if (!context->ret.pointer) { -+ status = AE_NO_MEMORY; -+ goto out_kfree; -+ } -+ memcpy(context->ret.pointer, out_obj->buffer.pointer, -+ context->ret.length); -+ status = AE_OK; -+ -+out_kfree: -+ kfree(output.pointer); -+ if (status != AE_OK) -+ context->ret.pointer = NULL; -+ return status; -+} -+EXPORT_SYMBOL(acpi_run_osc); -+ -+static u8 sb_uuid_str[] = "0811B06E-4A27-44F9-8D60-3CBBC22E7B48"; -+static void acpi_bus_osc_support(void) -+{ -+ u32 capbuf[2]; -+ struct acpi_osc_context context = { -+ .uuid_str = sb_uuid_str, -+ .rev = 1, -+ .cap.length = 8, -+ .cap.pointer = capbuf, -+ }; -+ acpi_handle handle; -+ -+ capbuf[OSC_QUERY_TYPE] = OSC_QUERY_ENABLE; -+ capbuf[OSC_SUPPORT_TYPE] = OSC_SB_PR3_SUPPORT; /* _PR3 is in use */ -+#if defined(CONFIG_ACPI_PROCESSOR_AGGREGATOR) ||\ -+ defined(CONFIG_ACPI_PROCESSOR_AGGREGATOR_MODULE) -+ capbuf[OSC_SUPPORT_TYPE] |= OSC_SB_PAD_SUPPORT; -+#endif -+ -+#if defined(CONFIG_ACPI_PROCESSOR) || defined(CONFIG_ACPI_PROCESSOR_MODULE) -+ capbuf[OSC_SUPPORT_TYPE] |= OSC_SB_PPC_OST_SUPPORT; -+#endif -+ if (ACPI_FAILURE(acpi_get_handle(NULL, "\\_SB", &handle))) -+ return; -+ if (ACPI_SUCCESS(acpi_run_osc(handle, &context))) -+ kfree(context.ret.pointer); -+ /* do we need to check the returned cap? Sounds no */ -+} -+ - /* -------------------------------------------------------------------------- - Event Management - -------------------------------------------------------------------------- */ -@@ -734,6 +895,8 @@ static int __init acpi_bus_init(void) - status = acpi_ec_ecdt_probe(); - /* Ignore result. Not having an ECDT is not fatal. */ - -+ acpi_bus_osc_support(); -+ - status = acpi_initialize_objects(ACPI_FULL_INITIALIZATION); - if (ACPI_FAILURE(status)) { - printk(KERN_ERR PREFIX "Unable to initialize ACPI objects\n"); -diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c -index dc72690..91fed3c 100644 ---- a/drivers/ata/libata-core.c -+++ b/drivers/ata/libata-core.c -@@ -3790,21 +3790,45 @@ int sata_link_debounce(struct ata_link *link, const unsigned long *params, - int sata_link_resume(struct ata_link *link, const unsigned long *params, - unsigned long deadline) - { -+ int tries = ATA_LINK_RESUME_TRIES; - u32 scontrol, serror; - int rc; - - if ((rc = sata_scr_read(link, SCR_CONTROL, &scontrol))) - return rc; - -- scontrol = (scontrol & 0x0f0) | 0x300; -+ /* -+ * Writes to SControl sometimes get ignored under certain -+ * controllers (ata_piix SIDPR). Make sure DET actually is -+ * cleared. -+ */ -+ do { -+ scontrol = (scontrol & 0x0f0) | 0x300; -+ if ((rc = sata_scr_write(link, SCR_CONTROL, scontrol))) -+ return rc; -+ /* -+ * Some PHYs react badly if SStatus is pounded -+ * immediately after resuming. Delay 200ms before -+ * debouncing. -+ */ -+ msleep(200); - -- if ((rc = sata_scr_write(link, SCR_CONTROL, scontrol))) -- return rc; -+ /* is SControl restored correctly? */ -+ if ((rc = sata_scr_read(link, SCR_CONTROL, &scontrol))) -+ return rc; -+ } while ((scontrol & 0xf0f) != 0x300 && --tries); - -- /* Some PHYs react badly if SStatus is pounded immediately -- * after resuming. Delay 200ms before debouncing. -- */ -- msleep(200); -+ if ((scontrol & 0xf0f) != 0x300) { -+ ata_link_printk(link, KERN_ERR, -+ "failed to resume link (SControl %X)\n", -+ scontrol); -+ return 0; -+ } -+ -+ if (tries < ATA_LINK_RESUME_TRIES) -+ ata_link_printk(link, KERN_WARNING, -+ "link resume succeeded after %d retries\n", -+ ATA_LINK_RESUME_TRIES - tries); - - if ((rc = sata_link_debounce(link, params, deadline))) - return rc; -diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c -index bba2ae5..7d8d3c3 100644 ---- a/drivers/ata/libata-eh.c -+++ b/drivers/ata/libata-eh.c -@@ -2019,8 +2019,9 @@ static void ata_eh_link_autopsy(struct ata_link *link) - qc->err_mask &= ~(AC_ERR_DEV | AC_ERR_OTHER); - - /* determine whether the command is worth retrying */ -- if (!(qc->err_mask & AC_ERR_INVALID) && -- ((qc->flags & ATA_QCFLAG_IO) || qc->err_mask != AC_ERR_DEV)) -+ if (qc->flags & ATA_QCFLAG_IO || -+ (!(qc->err_mask & AC_ERR_INVALID) && -+ qc->err_mask != AC_ERR_DEV)) - qc->flags |= ATA_QCFLAG_RETRY; - - /* accumulate error info */ -diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c -index 2ddf03a..68b5957 100644 ---- a/drivers/block/pktcdvd.c -+++ b/drivers/block/pktcdvd.c -@@ -322,7 +322,7 @@ static void pkt_sysfs_dev_remove(struct pktcdvd_device *pd) - pkt_kobj_remove(pd->kobj_stat); - pkt_kobj_remove(pd->kobj_wqueue); - if (class_pktcdvd) -- device_destroy(class_pktcdvd, pd->pkt_dev); -+ device_unregister(pd->dev); - } - - -diff --git a/drivers/char/random.c b/drivers/char/random.c -index 04b505e..908ac1f 100644 ---- a/drivers/char/random.c -+++ b/drivers/char/random.c -@@ -1051,12 +1051,6 @@ random_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos) - /* like a named pipe */ - } - -- /* -- * If we gave the user some bytes, update the access time. -- */ -- if (count) -- file_accessed(file); -- - return (count ? count : retval); - } - -@@ -1107,7 +1101,6 @@ static ssize_t random_write(struct file *file, const char __user *buffer, - size_t count, loff_t *ppos) - { - size_t ret; -- struct inode *inode = file->f_path.dentry->d_inode; - - ret = write_pool(&blocking_pool, buffer, count); - if (ret) -@@ -1116,8 +1109,6 @@ static ssize_t random_write(struct file *file, const char __user *buffer, - if (ret) - return ret; - -- inode->i_mtime = current_fs_time(inode->i_sb); -- mark_inode_dirty(inode); - return (ssize_t)count; - } - -diff --git a/drivers/connector/connector.c b/drivers/connector/connector.c -index f060246..537c29a 100644 ---- a/drivers/connector/connector.c -+++ b/drivers/connector/connector.c -@@ -36,17 +36,6 @@ MODULE_LICENSE("GPL"); - MODULE_AUTHOR("Evgeniy Polyakov "); - MODULE_DESCRIPTION("Generic userspace <-> kernelspace connector."); - --static u32 cn_idx = CN_IDX_CONNECTOR; --static u32 cn_val = CN_VAL_CONNECTOR; -- --module_param(cn_idx, uint, 0); --module_param(cn_val, uint, 0); --MODULE_PARM_DESC(cn_idx, "Connector's main device idx."); --MODULE_PARM_DESC(cn_val, "Connector's main device val."); -- --static DEFINE_MUTEX(notify_lock); --static LIST_HEAD(notify_list); -- - static struct cn_dev cdev; - - static int cn_already_initialized; -@@ -210,54 +199,6 @@ static void cn_rx_skb(struct sk_buff *__skb) - } - - /* -- * Notification routing. -- * -- * Gets id and checks if there are notification request for it's idx -- * and val. If there are such requests notify the listeners with the -- * given notify event. -- * -- */ --static void cn_notify(struct cb_id *id, u32 notify_event) --{ -- struct cn_ctl_entry *ent; -- -- mutex_lock(¬ify_lock); -- list_for_each_entry(ent, ¬ify_list, notify_entry) { -- int i; -- struct cn_notify_req *req; -- struct cn_ctl_msg *ctl = ent->msg; -- int idx_found, val_found; -- -- idx_found = val_found = 0; -- -- req = (struct cn_notify_req *)ctl->data; -- for (i = 0; i < ctl->idx_notify_num; ++i, ++req) { -- if (id->idx >= req->first && -- id->idx < req->first + req->range) { -- idx_found = 1; -- break; -- } -- } -- -- for (i = 0; i < ctl->val_notify_num; ++i, ++req) { -- if (id->val >= req->first && -- id->val < req->first + req->range) { -- val_found = 1; -- break; -- } -- } -- -- if (idx_found && val_found) { -- struct cn_msg m = { .ack = notify_event, }; -- -- memcpy(&m.id, id, sizeof(m.id)); -- cn_netlink_send(&m, ctl->group, GFP_KERNEL); -- } -- } -- mutex_unlock(¬ify_lock); --} -- --/* - * Callback add routing - adds callback with given ID and name. - * If there is registered callback with the same ID it will not be added. - * -@@ -276,8 +217,6 @@ int cn_add_callback(struct cb_id *id, char *name, - if (err) - return err; - -- cn_notify(id, 0); -- - return 0; - } - EXPORT_SYMBOL_GPL(cn_add_callback); -@@ -295,111 +234,9 @@ void cn_del_callback(struct cb_id *id) - struct cn_dev *dev = &cdev; - - cn_queue_del_callback(dev->cbdev, id); -- cn_notify(id, 1); - } - EXPORT_SYMBOL_GPL(cn_del_callback); - --/* -- * Checks two connector's control messages to be the same. -- * Returns 1 if they are the same or if the first one is corrupted. -- */ --static int cn_ctl_msg_equals(struct cn_ctl_msg *m1, struct cn_ctl_msg *m2) --{ -- int i; -- struct cn_notify_req *req1, *req2; -- -- if (m1->idx_notify_num != m2->idx_notify_num) -- return 0; -- -- if (m1->val_notify_num != m2->val_notify_num) -- return 0; -- -- if (m1->len != m2->len) -- return 0; -- -- if ((m1->idx_notify_num + m1->val_notify_num) * sizeof(*req1) != -- m1->len) -- return 1; -- -- req1 = (struct cn_notify_req *)m1->data; -- req2 = (struct cn_notify_req *)m2->data; -- -- for (i = 0; i < m1->idx_notify_num; ++i) { -- if (req1->first != req2->first || req1->range != req2->range) -- return 0; -- req1++; -- req2++; -- } -- -- for (i = 0; i < m1->val_notify_num; ++i) { -- if (req1->first != req2->first || req1->range != req2->range) -- return 0; -- req1++; -- req2++; -- } -- -- return 1; --} -- --/* -- * Main connector device's callback. -- * -- * Used for notification of a request's processing. -- */ --static void cn_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp) --{ -- struct cn_ctl_msg *ctl; -- struct cn_ctl_entry *ent; -- u32 size; -- -- if (msg->len < sizeof(*ctl)) -- return; -- -- ctl = (struct cn_ctl_msg *)msg->data; -- -- size = (sizeof(*ctl) + ((ctl->idx_notify_num + -- ctl->val_notify_num) * -- sizeof(struct cn_notify_req))); -- -- if (msg->len != size) -- return; -- -- if (ctl->len + sizeof(*ctl) != msg->len) -- return; -- -- /* -- * Remove notification. -- */ -- if (ctl->group == 0) { -- struct cn_ctl_entry *n; -- -- mutex_lock(¬ify_lock); -- list_for_each_entry_safe(ent, n, ¬ify_list, notify_entry) { -- if (cn_ctl_msg_equals(ent->msg, ctl)) { -- list_del(&ent->notify_entry); -- kfree(ent); -- } -- } -- mutex_unlock(¬ify_lock); -- -- return; -- } -- -- size += sizeof(*ent); -- -- ent = kzalloc(size, GFP_KERNEL); -- if (!ent) -- return; -- -- ent->msg = (struct cn_ctl_msg *)(ent + 1); -- -- memcpy(ent->msg, ctl, size - sizeof(*ent)); -- -- mutex_lock(¬ify_lock); -- list_add(&ent->notify_entry, ¬ify_list); -- mutex_unlock(¬ify_lock); --} -- - static int cn_proc_show(struct seq_file *m, void *v) - { - struct cn_queue_dev *dev = cdev.cbdev; -@@ -437,11 +274,8 @@ static const struct file_operations cn_file_ops = { - static int __devinit cn_init(void) - { - struct cn_dev *dev = &cdev; -- int err; - - dev->input = cn_rx_skb; -- dev->id.idx = cn_idx; -- dev->id.val = cn_val; - - dev->nls = netlink_kernel_create(&init_net, NETLINK_CONNECTOR, - CN_NETLINK_USERS + 0xf, -@@ -457,14 +291,6 @@ static int __devinit cn_init(void) - - cn_already_initialized = 1; - -- err = cn_add_callback(&dev->id, "connector", &cn_callback); -- if (err) { -- cn_already_initialized = 0; -- cn_queue_free_dev(dev->cbdev); -- netlink_kernel_release(dev->nls); -- return -EINVAL; -- } -- - proc_net_fops_create(&init_net, "connector", S_IRUGO, &cn_file_ops); - - return 0; -@@ -478,7 +304,6 @@ static void __devexit cn_fini(void) - - proc_net_remove(&init_net, "connector"); - -- cn_del_callback(&dev->id); - cn_queue_free_dev(dev->cbdev); - netlink_kernel_release(dev->nls); - } -diff --git a/drivers/firewire/core-card.c b/drivers/firewire/core-card.c -index e4864e8..ed635ae 100644 ---- a/drivers/firewire/core-card.c -+++ b/drivers/firewire/core-card.c -@@ -57,6 +57,9 @@ static LIST_HEAD(card_list); - static LIST_HEAD(descriptor_list); - static int descriptor_count; - -+/* ROM header, bus info block, root dir header, capabilities = 7 quadlets */ -+static size_t config_rom_length = 1 + 4 + 1 + 1; -+ - #define BIB_CRC(v) ((v) << 0) - #define BIB_CRC_LENGTH(v) ((v) << 16) - #define BIB_INFO_LENGTH(v) ((v) << 24) -@@ -72,7 +75,7 @@ static int descriptor_count; - #define BIB_CMC ((1) << 30) - #define BIB_IMC ((1) << 31) - --static u32 *generate_config_rom(struct fw_card *card, size_t *config_rom_length) -+static u32 *generate_config_rom(struct fw_card *card) - { - struct fw_descriptor *desc; - static u32 config_rom[256]; -@@ -131,7 +134,7 @@ static u32 *generate_config_rom(struct fw_card *card, size_t *config_rom_length) - for (i = 0; i < j; i += length + 1) - length = fw_compute_block_crc(config_rom + i); - -- *config_rom_length = j; -+ WARN_ON(j != config_rom_length); - - return config_rom; - } -@@ -140,17 +143,24 @@ static void update_config_roms(void) - { - struct fw_card *card; - u32 *config_rom; -- size_t length; - - list_for_each_entry (card, &card_list, link) { -- config_rom = generate_config_rom(card, &length); -- card->driver->set_config_rom(card, config_rom, length); -+ config_rom = generate_config_rom(card); -+ card->driver->set_config_rom(card, config_rom, -+ config_rom_length); - } - } - -+static size_t required_space(struct fw_descriptor *desc) -+{ -+ /* descriptor + entry into root dir + optional immediate entry */ -+ return desc->length + 1 + (desc->immediate > 0 ? 1 : 0); -+} -+ - int fw_core_add_descriptor(struct fw_descriptor *desc) - { - size_t i; -+ int ret; - - /* - * Check descriptor is valid; the length of all blocks in the -@@ -166,15 +176,21 @@ int fw_core_add_descriptor(struct fw_descriptor *desc) - - mutex_lock(&card_mutex); - -- list_add_tail(&desc->link, &descriptor_list); -- descriptor_count++; -- if (desc->immediate > 0) -+ if (config_rom_length + required_space(desc) > 256) { -+ ret = -EBUSY; -+ } else { -+ list_add_tail(&desc->link, &descriptor_list); -+ config_rom_length += required_space(desc); - descriptor_count++; -- update_config_roms(); -+ if (desc->immediate > 0) -+ descriptor_count++; -+ update_config_roms(); -+ ret = 0; -+ } - - mutex_unlock(&card_mutex); - -- return 0; -+ return ret; - } - EXPORT_SYMBOL(fw_core_add_descriptor); - -@@ -183,6 +199,7 @@ void fw_core_remove_descriptor(struct fw_descriptor *desc) - mutex_lock(&card_mutex); - - list_del(&desc->link); -+ config_rom_length -= required_space(desc); - descriptor_count--; - if (desc->immediate > 0) - descriptor_count--; -@@ -436,7 +453,6 @@ int fw_card_add(struct fw_card *card, - u32 max_receive, u32 link_speed, u64 guid) - { - u32 *config_rom; -- size_t length; - int ret; - - card->max_receive = max_receive; -@@ -445,8 +461,8 @@ int fw_card_add(struct fw_card *card, - - mutex_lock(&card_mutex); - -- config_rom = generate_config_rom(card, &length); -- ret = card->driver->enable(card, config_rom, length); -+ config_rom = generate_config_rom(card); -+ ret = card->driver->enable(card, config_rom, config_rom_length); - if (ret == 0) - list_add_tail(&card->link, &card_list); - -diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c -index 1e504de..720b39b 100644 ---- a/drivers/firewire/ohci.c -+++ b/drivers/firewire/ohci.c -@@ -2412,6 +2412,7 @@ static void ohci_pmac_off(struct pci_dev *dev) - - #define PCI_VENDOR_ID_AGERE PCI_VENDOR_ID_ATT - #define PCI_DEVICE_ID_AGERE_FW643 0x5901 -+#define PCI_DEVICE_ID_TI_TSB43AB23 0x8024 - - static int __devinit pci_probe(struct pci_dev *dev, - const struct pci_device_id *ent) -@@ -2477,7 +2478,8 @@ static int __devinit pci_probe(struct pci_dev *dev, - #if !defined(CONFIG_X86_32) - /* dual-buffer mode is broken with descriptor addresses above 2G */ - if (dev->vendor == PCI_VENDOR_ID_TI && -- dev->device == PCI_DEVICE_ID_TI_TSB43AB22) -+ (dev->device == PCI_DEVICE_ID_TI_TSB43AB22 || -+ dev->device == PCI_DEVICE_ID_TI_TSB43AB23)) - ohci->use_dualbuffer = false; - #endif - -diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c -index e9dbb48..8bf3770 100644 ---- a/drivers/gpu/drm/drm_gem.c -+++ b/drivers/gpu/drm/drm_gem.c -@@ -142,19 +142,6 @@ drm_gem_object_alloc(struct drm_device *dev, size_t size) - if (IS_ERR(obj->filp)) - goto free; - -- /* Basically we want to disable the OOM killer and handle ENOMEM -- * ourselves by sacrificing pages from cached buffers. -- * XXX shmem_file_[gs]et_gfp_mask() -- */ -- mapping_set_gfp_mask(obj->filp->f_path.dentry->d_inode->i_mapping, -- GFP_HIGHUSER | -- __GFP_COLD | -- __GFP_FS | -- __GFP_RECLAIMABLE | -- __GFP_NORETRY | -- __GFP_NOWARN | -- __GFP_NOMEMALLOC); -- - kref_init(&obj->refcount); - kref_init(&obj->handlecount); - obj->size = size; -diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c -index 26bf055..af655e8 100644 ---- a/drivers/gpu/drm/i915/i915_debugfs.c -+++ b/drivers/gpu/drm/i915/i915_debugfs.c -@@ -288,7 +288,7 @@ static int i915_batchbuffer_info(struct seq_file *m, void *data) - list_for_each_entry(obj_priv, &dev_priv->mm.active_list, list) { - obj = obj_priv->obj; - if (obj->read_domains & I915_GEM_DOMAIN_COMMAND) { -- ret = i915_gem_object_get_pages(obj); -+ ret = i915_gem_object_get_pages(obj, 0); - if (ret) { - DRM_ERROR("Failed to get pages: %d\n", ret); - spin_unlock(&dev_priv->mm.active_list_lock); -diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c -index bc2db7d..eaa1893 100644 ---- a/drivers/gpu/drm/i915/i915_dma.c -+++ b/drivers/gpu/drm/i915/i915_dma.c -@@ -1252,6 +1252,8 @@ static int i915_load_modeset_init(struct drm_device *dev, - if (ret) - goto destroy_ringbuffer; - -+ intel_modeset_init(dev); -+ - ret = drm_irq_install(dev); - if (ret) - goto destroy_ringbuffer; -@@ -1266,8 +1268,6 @@ static int i915_load_modeset_init(struct drm_device *dev, - - I915_WRITE(INSTPM, (1 << 5) | (1 << 21)); - -- intel_modeset_init(dev); -- - drm_helper_initial_config(dev); - - return 0; -diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h -index 791fded..7277246 100644 ---- a/drivers/gpu/drm/i915/i915_drv.h -+++ b/drivers/gpu/drm/i915/i915_drv.h -@@ -822,7 +822,7 @@ int i915_gem_attach_phys_object(struct drm_device *dev, - void i915_gem_detach_phys_object(struct drm_device *dev, - struct drm_gem_object *obj); - void i915_gem_free_all_phys_object(struct drm_device *dev); --int i915_gem_object_get_pages(struct drm_gem_object *obj); -+int i915_gem_object_get_pages(struct drm_gem_object *obj, gfp_t gfpmask); - void i915_gem_object_put_pages(struct drm_gem_object *obj); - void i915_gem_release(struct drm_device * dev, struct drm_file *file_priv); - -diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c -index df2c625..8ad244a 100644 ---- a/drivers/gpu/drm/i915/i915_gem.c -+++ b/drivers/gpu/drm/i915/i915_gem.c -@@ -277,7 +277,7 @@ i915_gem_shmem_pread_fast(struct drm_device *dev, struct drm_gem_object *obj, - - mutex_lock(&dev->struct_mutex); - -- ret = i915_gem_object_get_pages(obj); -+ ret = i915_gem_object_get_pages(obj, 0); - if (ret != 0) - goto fail_unlock; - -@@ -321,40 +321,24 @@ fail_unlock: - return ret; - } - --static inline gfp_t --i915_gem_object_get_page_gfp_mask (struct drm_gem_object *obj) --{ -- return mapping_gfp_mask(obj->filp->f_path.dentry->d_inode->i_mapping); --} -- --static inline void --i915_gem_object_set_page_gfp_mask (struct drm_gem_object *obj, gfp_t gfp) --{ -- mapping_set_gfp_mask(obj->filp->f_path.dentry->d_inode->i_mapping, gfp); --} -- - static int - i915_gem_object_get_pages_or_evict(struct drm_gem_object *obj) - { - int ret; - -- ret = i915_gem_object_get_pages(obj); -+ ret = i915_gem_object_get_pages(obj, __GFP_NORETRY | __GFP_NOWARN); - - /* If we've insufficient memory to map in the pages, attempt - * to make some space by throwing out some old buffers. - */ - if (ret == -ENOMEM) { - struct drm_device *dev = obj->dev; -- gfp_t gfp; - - ret = i915_gem_evict_something(dev, obj->size); - if (ret) - return ret; - -- gfp = i915_gem_object_get_page_gfp_mask(obj); -- i915_gem_object_set_page_gfp_mask(obj, gfp & ~__GFP_NORETRY); -- ret = i915_gem_object_get_pages(obj); -- i915_gem_object_set_page_gfp_mask (obj, gfp); -+ ret = i915_gem_object_get_pages(obj, 0); - } - - return ret; -@@ -790,7 +774,7 @@ i915_gem_shmem_pwrite_fast(struct drm_device *dev, struct drm_gem_object *obj, - - mutex_lock(&dev->struct_mutex); - -- ret = i915_gem_object_get_pages(obj); -+ ret = i915_gem_object_get_pages(obj, 0); - if (ret != 0) - goto fail_unlock; - -@@ -2219,7 +2203,8 @@ i915_gem_evict_something(struct drm_device *dev, int min_size) - } - - int --i915_gem_object_get_pages(struct drm_gem_object *obj) -+i915_gem_object_get_pages(struct drm_gem_object *obj, -+ gfp_t gfpmask) - { - struct drm_i915_gem_object *obj_priv = obj->driver_private; - int page_count, i; -@@ -2245,7 +2230,10 @@ i915_gem_object_get_pages(struct drm_gem_object *obj) - inode = obj->filp->f_path.dentry->d_inode; - mapping = inode->i_mapping; - for (i = 0; i < page_count; i++) { -- page = read_mapping_page(mapping, i, NULL); -+ page = read_cache_page_gfp(mapping, i, -+ mapping_gfp_mask (mapping) | -+ __GFP_COLD | -+ gfpmask); - if (IS_ERR(page)) { - ret = PTR_ERR(page); - i915_gem_object_put_pages(obj); -@@ -2568,7 +2556,7 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment) - drm_i915_private_t *dev_priv = dev->dev_private; - struct drm_i915_gem_object *obj_priv = obj->driver_private; - struct drm_mm_node *free_space; -- bool retry_alloc = false; -+ gfp_t gfpmask = __GFP_NORETRY | __GFP_NOWARN; - int ret; - - if (obj_priv->madv != I915_MADV_WILLNEED) { -@@ -2612,15 +2600,7 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment) - DRM_INFO("Binding object of size %zd at 0x%08x\n", - obj->size, obj_priv->gtt_offset); - #endif -- if (retry_alloc) { -- i915_gem_object_set_page_gfp_mask (obj, -- i915_gem_object_get_page_gfp_mask (obj) & ~__GFP_NORETRY); -- } -- ret = i915_gem_object_get_pages(obj); -- if (retry_alloc) { -- i915_gem_object_set_page_gfp_mask (obj, -- i915_gem_object_get_page_gfp_mask (obj) | __GFP_NORETRY); -- } -+ ret = i915_gem_object_get_pages(obj, gfpmask); - if (ret) { - drm_mm_put_block(obj_priv->gtt_space); - obj_priv->gtt_space = NULL; -@@ -2630,9 +2610,9 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment) - ret = i915_gem_evict_something(dev, obj->size); - if (ret) { - /* now try to shrink everyone else */ -- if (! retry_alloc) { -- retry_alloc = true; -- goto search_free; -+ if (gfpmask) { -+ gfpmask = 0; -+ goto search_free; - } - - return ret; -@@ -4695,7 +4675,7 @@ void i915_gem_detach_phys_object(struct drm_device *dev, - if (!obj_priv->phys_obj) - return; - -- ret = i915_gem_object_get_pages(obj); -+ ret = i915_gem_object_get_pages(obj, 0); - if (ret) - goto out; - -@@ -4753,7 +4733,7 @@ i915_gem_attach_phys_object(struct drm_device *dev, - obj_priv->phys_obj = dev_priv->mm.phys_objs[id - 1]; - obj_priv->phys_obj->cur_obj = obj; - -- ret = i915_gem_object_get_pages(obj); -+ ret = i915_gem_object_get_pages(obj, 0); - if (ret) { - DRM_ERROR("failed to get page list\n"); - goto out; -diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c -index 7d1357e..63f28ad 100644 ---- a/drivers/gpu/drm/i915/i915_irq.c -+++ b/drivers/gpu/drm/i915/i915_irq.c -@@ -282,6 +282,8 @@ irqreturn_t igdng_irq_handler(struct drm_device *dev) - dev_priv->mm.irq_gem_seqno = seqno; - trace_i915_gem_request_complete(dev, seqno); - DRM_WAKEUP(&dev_priv->irq_queue); -+ dev_priv->hangcheck_count = 0; -+ mod_timer(&dev_priv->hangcheck_timer, jiffies + DRM_I915_HANGCHECK_PERIOD); - } - - I915_WRITE(GTIIR, gt_iir); -@@ -1042,6 +1044,10 @@ void i915_driver_irq_preinstall(struct drm_device * dev) - (void) I915_READ(IER); - } - -+/* -+ * Must be called after intel_modeset_init or hotplug interrupts won't be -+ * enabled correctly. -+ */ - int i915_driver_irq_postinstall(struct drm_device *dev) - { - drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; -@@ -1064,19 +1070,23 @@ int i915_driver_irq_postinstall(struct drm_device *dev) - if (I915_HAS_HOTPLUG(dev)) { - u32 hotplug_en = I915_READ(PORT_HOTPLUG_EN); - -- /* Leave other bits alone */ -- hotplug_en |= HOTPLUG_EN_MASK; -+ /* Note HDMI and DP share bits */ -+ if (dev_priv->hotplug_supported_mask & HDMIB_HOTPLUG_INT_STATUS) -+ hotplug_en |= HDMIB_HOTPLUG_INT_EN; -+ if (dev_priv->hotplug_supported_mask & HDMIC_HOTPLUG_INT_STATUS) -+ hotplug_en |= HDMIC_HOTPLUG_INT_EN; -+ if (dev_priv->hotplug_supported_mask & HDMID_HOTPLUG_INT_STATUS) -+ hotplug_en |= HDMID_HOTPLUG_INT_EN; -+ if (dev_priv->hotplug_supported_mask & SDVOC_HOTPLUG_INT_STATUS) -+ hotplug_en |= SDVOC_HOTPLUG_INT_EN; -+ if (dev_priv->hotplug_supported_mask & SDVOB_HOTPLUG_INT_STATUS) -+ hotplug_en |= SDVOB_HOTPLUG_INT_EN; -+ if (dev_priv->hotplug_supported_mask & CRT_HOTPLUG_INT_STATUS) -+ hotplug_en |= CRT_HOTPLUG_INT_EN; -+ /* Ignore TV since it's buggy */ -+ - I915_WRITE(PORT_HOTPLUG_EN, hotplug_en); - -- dev_priv->hotplug_supported_mask = CRT_HOTPLUG_INT_STATUS | -- TV_HOTPLUG_INT_STATUS | SDVOC_HOTPLUG_INT_STATUS | -- SDVOB_HOTPLUG_INT_STATUS; -- if (IS_G4X(dev)) { -- dev_priv->hotplug_supported_mask |= -- HDMIB_HOTPLUG_INT_STATUS | -- HDMIC_HOTPLUG_INT_STATUS | -- HDMID_HOTPLUG_INT_STATUS; -- } - /* Enable in IER... */ - enable_mask |= I915_DISPLAY_PORT_INTERRUPT; - /* and unmask in IMR */ -diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h -index 54e5907..fd537f4 100644 ---- a/drivers/gpu/drm/i915/i915_reg.h -+++ b/drivers/gpu/drm/i915/i915_reg.h -@@ -863,14 +863,6 @@ - #define CRT_HOTPLUG_DETECT_VOLTAGE_475MV (1 << 2) - #define CRT_HOTPLUG_MASK (0x3fc) /* Bits 9-2 */ - #define CRT_FORCE_HOTPLUG_MASK 0xfffffe1f --#define HOTPLUG_EN_MASK (HDMIB_HOTPLUG_INT_EN | \ -- HDMIC_HOTPLUG_INT_EN | \ -- HDMID_HOTPLUG_INT_EN | \ -- SDVOB_HOTPLUG_INT_EN | \ -- SDVOC_HOTPLUG_INT_EN | \ -- TV_HOTPLUG_INT_EN | \ -- CRT_HOTPLUG_INT_EN) -- - - #define PORT_HOTPLUG_STAT 0x61114 - #define HDMIB_HOTPLUG_INT_STATUS (1 << 29) -diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c -index e505144..6d3730f 100644 ---- a/drivers/gpu/drm/i915/intel_crt.c -+++ b/drivers/gpu/drm/i915/intel_crt.c -@@ -576,4 +576,6 @@ void intel_crt_init(struct drm_device *dev) - drm_connector_helper_add(connector, &intel_crt_connector_helper_funcs); - - drm_sysfs_connector_add(connector); -+ -+ dev_priv->hotplug_supported_mask |= CRT_HOTPLUG_INT_STATUS; - } -diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c -index 121b92e..601415d 100644 ---- a/drivers/gpu/drm/i915/intel_display.c -+++ b/drivers/gpu/drm/i915/intel_display.c -@@ -4068,29 +4068,43 @@ static void intel_setup_outputs(struct drm_device *dev) - bool found = false; - - if (I915_READ(SDVOB) & SDVO_DETECTED) { -+ DRM_DEBUG_KMS("probing SDVOB\n"); - found = intel_sdvo_init(dev, SDVOB); -- if (!found && SUPPORTS_INTEGRATED_HDMI(dev)) -+ if (!found && SUPPORTS_INTEGRATED_HDMI(dev)) { -+ DRM_DEBUG_KMS("probing HDMI on SDVOB\n"); - intel_hdmi_init(dev, SDVOB); -+ } - -- if (!found && SUPPORTS_INTEGRATED_DP(dev)) -+ if (!found && SUPPORTS_INTEGRATED_DP(dev)) { -+ DRM_DEBUG_KMS("probing DP_B\n"); - intel_dp_init(dev, DP_B); -+ } - } - - /* Before G4X SDVOC doesn't have its own detect register */ - -- if (I915_READ(SDVOB) & SDVO_DETECTED) -+ if (I915_READ(SDVOB) & SDVO_DETECTED) { -+ DRM_DEBUG_KMS("probing SDVOC\n"); - found = intel_sdvo_init(dev, SDVOC); -+ } - - if (!found && (I915_READ(SDVOC) & SDVO_DETECTED)) { - -- if (SUPPORTS_INTEGRATED_HDMI(dev)) -+ if (SUPPORTS_INTEGRATED_HDMI(dev)) { -+ DRM_DEBUG_KMS("probing HDMI on SDVOC\n"); - intel_hdmi_init(dev, SDVOC); -- if (SUPPORTS_INTEGRATED_DP(dev)) -+ } -+ if (SUPPORTS_INTEGRATED_DP(dev)) { -+ DRM_DEBUG_KMS("probing DP_C\n"); - intel_dp_init(dev, DP_C); -+ } - } - -- if (SUPPORTS_INTEGRATED_DP(dev) && (I915_READ(DP_D) & DP_DETECTED)) -+ if (SUPPORTS_INTEGRATED_DP(dev) && -+ (I915_READ(DP_D) & DP_DETECTED)) { -+ DRM_DEBUG_KMS("probing DP_D\n"); - intel_dp_init(dev, DP_D); -+ } - } else if (IS_I8XX(dev)) - intel_dvo_init(dev); - -diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c -index 92a3d7b..d487771 100644 ---- a/drivers/gpu/drm/i915/intel_dp.c -+++ b/drivers/gpu/drm/i915/intel_dp.c -@@ -1290,14 +1290,20 @@ intel_dp_init(struct drm_device *dev, int output_reg) - break; - case DP_B: - case PCH_DP_B: -+ dev_priv->hotplug_supported_mask |= -+ HDMIB_HOTPLUG_INT_STATUS; - name = "DPDDC-B"; - break; - case DP_C: - case PCH_DP_C: -+ dev_priv->hotplug_supported_mask |= -+ HDMIC_HOTPLUG_INT_STATUS; - name = "DPDDC-C"; - break; - case DP_D: - case PCH_DP_D: -+ dev_priv->hotplug_supported_mask |= -+ HDMID_HOTPLUG_INT_STATUS; - name = "DPDDC-D"; - break; - } -diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c -index c33451a..85760bf 100644 ---- a/drivers/gpu/drm/i915/intel_hdmi.c -+++ b/drivers/gpu/drm/i915/intel_hdmi.c -@@ -254,21 +254,26 @@ void intel_hdmi_init(struct drm_device *dev, int sdvox_reg) - if (sdvox_reg == SDVOB) { - intel_output->clone_mask = (1 << INTEL_HDMIB_CLONE_BIT); - intel_output->ddc_bus = intel_i2c_create(dev, GPIOE, "HDMIB"); -+ dev_priv->hotplug_supported_mask |= HDMIB_HOTPLUG_INT_STATUS; - } else if (sdvox_reg == SDVOC) { - intel_output->clone_mask = (1 << INTEL_HDMIC_CLONE_BIT); - intel_output->ddc_bus = intel_i2c_create(dev, GPIOD, "HDMIC"); -+ dev_priv->hotplug_supported_mask |= HDMIC_HOTPLUG_INT_STATUS; - } else if (sdvox_reg == HDMIB) { - intel_output->clone_mask = (1 << INTEL_HDMID_CLONE_BIT); - intel_output->ddc_bus = intel_i2c_create(dev, PCH_GPIOE, - "HDMIB"); -+ dev_priv->hotplug_supported_mask |= HDMIB_HOTPLUG_INT_STATUS; - } else if (sdvox_reg == HDMIC) { - intel_output->clone_mask = (1 << INTEL_HDMIE_CLONE_BIT); - intel_output->ddc_bus = intel_i2c_create(dev, PCH_GPIOD, - "HDMIC"); -+ dev_priv->hotplug_supported_mask |= HDMIC_HOTPLUG_INT_STATUS; - } else if (sdvox_reg == HDMID) { - intel_output->clone_mask = (1 << INTEL_HDMIF_CLONE_BIT); - intel_output->ddc_bus = intel_i2c_create(dev, PCH_GPIOF, - "HDMID"); -+ dev_priv->hotplug_supported_mask |= HDMID_HOTPLUG_INT_STATUS; - } - if (!intel_output->ddc_bus) - goto err_connector; -diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c -index 29e21d3..3f5aaf1 100644 ---- a/drivers/gpu/drm/i915/intel_sdvo.c -+++ b/drivers/gpu/drm/i915/intel_sdvo.c -@@ -2743,6 +2743,7 @@ static void intel_sdvo_create_enhance_property(struct drm_connector *connector) - - bool intel_sdvo_init(struct drm_device *dev, int output_device) - { -+ struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_connector *connector; - struct intel_output *intel_output; - struct intel_sdvo_priv *sdvo_priv; -@@ -2789,10 +2790,12 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device) - intel_output->ddc_bus = intel_i2c_create(dev, GPIOE, "SDVOB DDC BUS"); - sdvo_priv->analog_ddc_bus = intel_i2c_create(dev, GPIOA, - "SDVOB/VGA DDC BUS"); -+ dev_priv->hotplug_supported_mask |= SDVOB_HOTPLUG_INT_STATUS; - } else { - intel_output->ddc_bus = intel_i2c_create(dev, GPIOE, "SDVOC DDC BUS"); - sdvo_priv->analog_ddc_bus = intel_i2c_create(dev, GPIOA, - "SDVOC/VGA DDC BUS"); -+ dev_priv->hotplug_supported_mask |= SDVOC_HOTPLUG_INT_STATUS; - } - - if (intel_output->ddc_bus == NULL) -diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c -index 5b28b4e..ce026f0 100644 ---- a/drivers/gpu/drm/i915/intel_tv.c -+++ b/drivers/gpu/drm/i915/intel_tv.c -@@ -1801,6 +1801,8 @@ intel_tv_init(struct drm_device *dev) - drm_connector_attach_property(connector, - dev->mode_config.tv_bottom_margin_property, - tv_priv->margin[TV_MARGIN_BOTTOM]); -+ -+ dev_priv->hotplug_supported_mask |= TV_HOTPLUG_INT_STATUS; - out: - drm_sysfs_connector_add(connector); - } -diff --git a/drivers/infiniband/hw/ipath/ipath_fs.c b/drivers/infiniband/hw/ipath/ipath_fs.c -index b368406..100da85 100644 ---- a/drivers/infiniband/hw/ipath/ipath_fs.c -+++ b/drivers/infiniband/hw/ipath/ipath_fs.c -@@ -346,10 +346,8 @@ static int ipathfs_fill_super(struct super_block *sb, void *data, - list_for_each_entry_safe(dd, tmp, &ipath_dev_list, ipath_list) { - spin_unlock_irqrestore(&ipath_devs_lock, flags); - ret = create_device_files(sb, dd); -- if (ret) { -- deactivate_locked_super(sb); -+ if (ret) - goto bail; -- } - spin_lock_irqsave(&ipath_devs_lock, flags); - } - -diff --git a/drivers/input/misc/winbond-cir.c b/drivers/input/misc/winbond-cir.c -index 33309fe..c8f5a9a 100644 ---- a/drivers/input/misc/winbond-cir.c -+++ b/drivers/input/misc/winbond-cir.c -@@ -768,7 +768,7 @@ wbcir_parse_rc6(struct device *dev, struct wbcir_data *data) - return; - } - -- dev_info(dev, "IR-RC6 ad 0x%02X cm 0x%02X cu 0x%04X " -+ dev_dbg(dev, "IR-RC6 ad 0x%02X cm 0x%02X cu 0x%04X " - "toggle %u mode %u scan 0x%08X\n", - address, - command, -diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c -index 610e914..b6992b7 100644 ---- a/drivers/message/fusion/mptbase.c -+++ b/drivers/message/fusion/mptbase.c -@@ -4330,6 +4330,8 @@ initChainBuffers(MPT_ADAPTER *ioc) - - if (ioc->bus_type == SPI) - num_chain *= MPT_SCSI_CAN_QUEUE; -+ else if (ioc->bus_type == SAS) -+ num_chain *= MPT_SAS_CAN_QUEUE; - else - num_chain *= MPT_FC_CAN_QUEUE; - -diff --git a/drivers/mtd/ubi/cdev.c b/drivers/mtd/ubi/cdev.c -index f237ddb..111ea41 100644 ---- a/drivers/mtd/ubi/cdev.c -+++ b/drivers/mtd/ubi/cdev.c -@@ -853,7 +853,6 @@ static long ubi_cdev_ioctl(struct file *file, unsigned int cmd, - break; - } - -- req.name[req.name_len] = '\0'; - err = verify_mkvol_req(ubi, &req); - if (err) - break; -diff --git a/drivers/net/benet/be.h b/drivers/net/benet/be.h -index a84f1c5..511b922 100644 ---- a/drivers/net/benet/be.h -+++ b/drivers/net/benet/be.h -@@ -272,8 +272,13 @@ struct be_adapter { - u32 cap; - u32 rx_fc; /* Rx flow control */ - u32 tx_fc; /* Tx flow control */ -+ u8 generation; /* BladeEngine ASIC generation */ - }; - -+/* BladeEngine Generation numbers */ -+#define BE_GEN2 2 -+#define BE_GEN3 3 -+ - extern const struct ethtool_ops be_ethtool_ops; - - #define drvr_stats(adapter) (&adapter->stats.drvr_stats) -diff --git a/drivers/net/benet/be_cmds.h b/drivers/net/benet/be_cmds.h -index e5f9676..ad33d55 100644 ---- a/drivers/net/benet/be_cmds.h -+++ b/drivers/net/benet/be_cmds.h -@@ -154,7 +154,8 @@ struct be_cmd_req_hdr { - u8 domain; /* dword 0 */ - u32 timeout; /* dword 1 */ - u32 request_length; /* dword 2 */ -- u32 rsvd; /* dword 3 */ -+ u8 version; /* dword 3 */ -+ u8 rsvd[3]; /* dword 3 */ - }; - - #define RESP_HDR_INFO_OPCODE_SHIFT 0 /* bits 0 - 7 */ -diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c -index 3749bb1..ec983cb 100644 ---- a/drivers/net/benet/be_main.c -+++ b/drivers/net/benet/be_main.c -@@ -1944,6 +1944,7 @@ static void be_unmap_pci_bars(struct be_adapter *adapter) - static int be_map_pci_bars(struct be_adapter *adapter) - { - u8 __iomem *addr; -+ int pcicfg_reg; - - addr = ioremap_nocache(pci_resource_start(adapter->pdev, 2), - pci_resource_len(adapter->pdev, 2)); -@@ -1957,8 +1958,13 @@ static int be_map_pci_bars(struct be_adapter *adapter) - goto pci_map_err; - adapter->db = addr; - -- addr = ioremap_nocache(pci_resource_start(adapter->pdev, 1), -- pci_resource_len(adapter->pdev, 1)); -+ if (adapter->generation == BE_GEN2) -+ pcicfg_reg = 1; -+ else -+ pcicfg_reg = 0; -+ -+ addr = ioremap_nocache(pci_resource_start(adapter->pdev, pcicfg_reg), -+ pci_resource_len(adapter->pdev, pcicfg_reg)); - if (addr == NULL) - goto pci_map_err; - adapter->pcicfg = addr; -@@ -2028,6 +2034,7 @@ static int be_stats_init(struct be_adapter *adapter) - cmd->va = pci_alloc_consistent(adapter->pdev, cmd->size, &cmd->dma); - if (cmd->va == NULL) - return -1; -+ memset(cmd->va, 0, cmd->size); - return 0; - } - -@@ -2101,6 +2108,20 @@ static int __devinit be_probe(struct pci_dev *pdev, - goto rel_reg; - } - adapter = netdev_priv(netdev); -+ -+ switch (pdev->device) { -+ case BE_DEVICE_ID1: -+ case OC_DEVICE_ID1: -+ adapter->generation = BE_GEN2; -+ break; -+ case BE_DEVICE_ID2: -+ case OC_DEVICE_ID2: -+ adapter->generation = BE_GEN3; -+ break; -+ default: -+ adapter->generation = 0; -+ } -+ - adapter->pdev = pdev; - pci_set_drvdata(pdev, adapter); - adapter->netdev = netdev; -diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h -index 42e2b7e..4a2ee85 100644 ---- a/drivers/net/e1000/e1000.h -+++ b/drivers/net/e1000/e1000.h -@@ -326,6 +326,8 @@ struct e1000_adapter { - /* for ioport free */ - int bars; - int need_ioport; -+ -+ bool discarding; - }; - - enum e1000_state_t { -diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c -index bcd192c..1a23f16 100644 ---- a/drivers/net/e1000/e1000_main.c -+++ b/drivers/net/e1000/e1000_main.c -@@ -1698,18 +1698,6 @@ static void e1000_setup_rctl(struct e1000_adapter *adapter) - rctl &= ~E1000_RCTL_SZ_4096; - rctl |= E1000_RCTL_BSEX; - switch (adapter->rx_buffer_len) { -- case E1000_RXBUFFER_256: -- rctl |= E1000_RCTL_SZ_256; -- rctl &= ~E1000_RCTL_BSEX; -- break; -- case E1000_RXBUFFER_512: -- rctl |= E1000_RCTL_SZ_512; -- rctl &= ~E1000_RCTL_BSEX; -- break; -- case E1000_RXBUFFER_1024: -- rctl |= E1000_RCTL_SZ_1024; -- rctl &= ~E1000_RCTL_BSEX; -- break; - case E1000_RXBUFFER_2048: - default: - rctl |= E1000_RCTL_SZ_2048; -@@ -3154,13 +3142,7 @@ static int e1000_change_mtu(struct net_device *netdev, int new_mtu) - * however with the new *_jumbo_rx* routines, jumbo receives will use - * fragmented skbs */ - -- if (max_frame <= E1000_RXBUFFER_256) -- adapter->rx_buffer_len = E1000_RXBUFFER_256; -- else if (max_frame <= E1000_RXBUFFER_512) -- adapter->rx_buffer_len = E1000_RXBUFFER_512; -- else if (max_frame <= E1000_RXBUFFER_1024) -- adapter->rx_buffer_len = E1000_RXBUFFER_1024; -- else if (max_frame <= E1000_RXBUFFER_2048) -+ if (max_frame <= E1000_RXBUFFER_2048) - adapter->rx_buffer_len = E1000_RXBUFFER_2048; - else - #if (PAGE_SIZE >= E1000_RXBUFFER_16384) -@@ -3827,13 +3809,22 @@ static bool e1000_clean_rx_irq(struct e1000_adapter *adapter, - - length = le16_to_cpu(rx_desc->length); - /* !EOP means multiple descriptors were used to store a single -- * packet, also make sure the frame isn't just CRC only */ -- if (unlikely(!(status & E1000_RXD_STAT_EOP) || (length <= 4))) { -+ * packet, if thats the case we need to toss it. In fact, we -+ * to toss every packet with the EOP bit clear and the next -+ * frame that _does_ have the EOP bit set, as it is by -+ * definition only a frame fragment -+ */ -+ if (unlikely(!(status & E1000_RXD_STAT_EOP))) -+ adapter->discarding = true; -+ -+ if (adapter->discarding) { - /* All receives must fit into a single buffer */ - E1000_DBG("%s: Receive packet consumed multiple" - " buffers\n", netdev->name); - /* recycle */ - buffer_info->skb = skb; -+ if (status & E1000_RXD_STAT_EOP) -+ adapter->discarding = false; - goto next_desc; - } - -diff --git a/drivers/net/e1000e/e1000.h b/drivers/net/e1000e/e1000.h -index 3e187b0..47db9bd 100644 ---- a/drivers/net/e1000e/e1000.h -+++ b/drivers/net/e1000e/e1000.h -@@ -417,6 +417,7 @@ struct e1000_info { - /* CRC Stripping defines */ - #define FLAG2_CRC_STRIPPING (1 << 0) - #define FLAG2_HAS_PHY_WAKEUP (1 << 1) -+#define FLAG2_IS_DISCARDING (1 << 2) - - #define E1000_RX_DESC_PS(R, i) \ - (&(((union e1000_rx_desc_packet_split *)((R).desc))[i])) -diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c -index fad8f9e..2154530 100644 ---- a/drivers/net/e1000e/netdev.c -+++ b/drivers/net/e1000e/netdev.c -@@ -482,14 +482,24 @@ static bool e1000_clean_rx_irq(struct e1000_adapter *adapter, - - length = le16_to_cpu(rx_desc->length); - -- /* !EOP means multiple descriptors were used to store a single -- * packet, also make sure the frame isn't just CRC only */ -- if (!(status & E1000_RXD_STAT_EOP) || (length <= 4)) { -+ /* -+ * !EOP means multiple descriptors were used to store a single -+ * packet, if that's the case we need to toss it. In fact, we -+ * need to toss every packet with the EOP bit clear and the -+ * next frame that _does_ have the EOP bit set, as it is by -+ * definition only a frame fragment -+ */ -+ if (unlikely(!(status & E1000_RXD_STAT_EOP))) -+ adapter->flags2 |= FLAG2_IS_DISCARDING; -+ -+ if (adapter->flags2 & FLAG2_IS_DISCARDING) { - /* All receives must fit into a single buffer */ - e_dbg("%s: Receive packet consumed multiple buffers\n", - netdev->name); - /* recycle */ - buffer_info->skb = skb; -+ if (status & E1000_RXD_STAT_EOP) -+ adapter->flags2 &= ~FLAG2_IS_DISCARDING; - goto next_desc; - } - -@@ -747,10 +757,16 @@ static bool e1000_clean_rx_irq_ps(struct e1000_adapter *adapter, - PCI_DMA_FROMDEVICE); - buffer_info->dma = 0; - -- if (!(staterr & E1000_RXD_STAT_EOP)) { -+ /* see !EOP comment in other rx routine */ -+ if (!(staterr & E1000_RXD_STAT_EOP)) -+ adapter->flags2 |= FLAG2_IS_DISCARDING; -+ -+ if (adapter->flags2 & FLAG2_IS_DISCARDING) { - e_dbg("%s: Packet Split buffers didn't pick up the " - "full packet\n", netdev->name); - dev_kfree_skb_irq(skb); -+ if (staterr & E1000_RXD_STAT_EOP) -+ adapter->flags2 &= ~FLAG2_IS_DISCARDING; - goto next_desc; - } - -@@ -1120,6 +1136,7 @@ static void e1000_clean_rx_ring(struct e1000_adapter *adapter) - - rx_ring->next_to_clean = 0; - rx_ring->next_to_use = 0; -+ adapter->flags2 &= ~FLAG2_IS_DISCARDING; - - writel(0, adapter->hw.hw_addr + rx_ring->head); - writel(0, adapter->hw.hw_addr + rx_ring->tail); -@@ -2330,18 +2347,6 @@ static void e1000_setup_rctl(struct e1000_adapter *adapter) - rctl &= ~E1000_RCTL_SZ_4096; - rctl |= E1000_RCTL_BSEX; - switch (adapter->rx_buffer_len) { -- case 256: -- rctl |= E1000_RCTL_SZ_256; -- rctl &= ~E1000_RCTL_BSEX; -- break; -- case 512: -- rctl |= E1000_RCTL_SZ_512; -- rctl &= ~E1000_RCTL_BSEX; -- break; -- case 1024: -- rctl |= E1000_RCTL_SZ_1024; -- rctl &= ~E1000_RCTL_BSEX; -- break; - case 2048: - default: - rctl |= E1000_RCTL_SZ_2048; -@@ -4321,13 +4326,7 @@ static int e1000_change_mtu(struct net_device *netdev, int new_mtu) - * fragmented skbs - */ - -- if (max_frame <= 256) -- adapter->rx_buffer_len = 256; -- else if (max_frame <= 512) -- adapter->rx_buffer_len = 512; -- else if (max_frame <= 1024) -- adapter->rx_buffer_len = 1024; -- else if (max_frame <= 2048) -+ if (max_frame <= 2048) - adapter->rx_buffer_len = 2048; - else - adapter->rx_buffer_len = 4096; -diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c -index 6a10d7b..f3600b3 100644 ---- a/drivers/net/sky2.c -+++ b/drivers/net/sky2.c -@@ -1806,7 +1806,8 @@ static void sky2_tx_complete(struct sky2_port *sky2, u16 done) - sky2->tx_cons = idx; - smp_mb(); - -- if (tx_avail(sky2) > MAX_SKB_TX_LE + 4) -+ /* Wake unless it's detached, and called e.g. from sky2_down() */ -+ if (tx_avail(sky2) > MAX_SKB_TX_LE + 4 && netif_device_present(dev)) - netif_wake_queue(dev); - } - -diff --git a/drivers/net/starfire.c b/drivers/net/starfire.c -index a36e2b5..e65ee4d 100644 ---- a/drivers/net/starfire.c -+++ b/drivers/net/starfire.c -@@ -1063,7 +1063,7 @@ static int netdev_open(struct net_device *dev) - if (retval) { - printk(KERN_ERR "starfire: Failed to load firmware \"%s\"\n", - FIRMWARE_RX); -- return retval; -+ goto out_init; - } - if (fw_rx->size % 4) { - printk(KERN_ERR "starfire: bogus length %zu in \"%s\"\n", -@@ -1108,6 +1108,9 @@ out_tx: - release_firmware(fw_tx); - out_rx: - release_firmware(fw_rx); -+out_init: -+ if (retval) -+ netdev_close(dev); - return retval; - } - -diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c -index c7aa05a..0905b38 100644 ---- a/drivers/net/wireless/ath/ath9k/hw.c -+++ b/drivers/net/wireless/ath/ath9k/hw.c -@@ -880,12 +880,11 @@ static void ath9k_hw_init_mode_gain_regs(struct ath_hw *ah) - } - } - --static void ath9k_hw_init_11a_eeprom_fix(struct ath_hw *ah) -+static void ath9k_hw_init_eeprom_fix(struct ath_hw *ah) - { - u32 i, j; - -- if ((ah->hw_version.devid == AR9280_DEVID_PCI) && -- test_bit(ATH9K_MODE_11A, ah->caps.wireless_modes)) { -+ if (ah->hw_version.devid == AR9280_DEVID_PCI) { - - /* EEPROM Fixup */ - for (i = 0; i < ah->iniModes.ia_rows; i++) { -@@ -980,7 +979,7 @@ int ath9k_hw_init(struct ath_hw *ah) - - ath9k_hw_init_mode_gain_regs(ah); - ath9k_hw_fill_cap_info(ah); -- ath9k_hw_init_11a_eeprom_fix(ah); -+ ath9k_hw_init_eeprom_fix(ah); - - r = ath9k_hw_init_macaddr(ah); - if (r) { -diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c -index 80df8f3..5864eaa 100644 ---- a/drivers/net/wireless/ath/ath9k/main.c -+++ b/drivers/net/wireless/ath/ath9k/main.c -@@ -2285,10 +2285,10 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw, - (sc->sc_ah->opmode == NL80211_IFTYPE_MESH_POINT)) { - ath9k_ps_wakeup(sc); - ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq); -- ath_beacon_return(sc, avp); - ath9k_ps_restore(sc); - } - -+ ath_beacon_return(sc, avp); - sc->sc_flags &= ~SC_OP_BEACONS; - - for (i = 0; i < ARRAY_SIZE(sc->beacon.bslot); i++) { -diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c -index 81726ee..0eb2591 100644 ---- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c -+++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c -@@ -2808,7 +2808,7 @@ static void rs_fill_link_cmd(struct iwl_priv *priv, - repeat_rate--; - } - -- lq_cmd->agg_params.agg_frame_cnt_limit = LINK_QUAL_AGG_FRAME_LIMIT_MAX; -+ lq_cmd->agg_params.agg_frame_cnt_limit = LINK_QUAL_AGG_FRAME_LIMIT_DEF; - lq_cmd->agg_params.agg_dis_start_th = LINK_QUAL_AGG_DISABLE_START_DEF; - lq_cmd->agg_params.agg_time_limit = - cpu_to_le16(LINK_QUAL_AGG_TIME_LIMIT_DEF); -diff --git a/drivers/regulator/wm8350-regulator.c b/drivers/regulator/wm8350-regulator.c -index 768bd0e..43ed81e 100644 ---- a/drivers/regulator/wm8350-regulator.c -+++ b/drivers/regulator/wm8350-regulator.c -@@ -1504,7 +1504,8 @@ int wm8350_register_led(struct wm8350 *wm8350, int lednum, int dcdc, int isink, - led->isink_init.consumer_supplies = &led->isink_consumer; - led->isink_init.constraints.min_uA = 0; - led->isink_init.constraints.max_uA = pdata->max_uA; -- led->isink_init.constraints.valid_ops_mask = REGULATOR_CHANGE_CURRENT; -+ led->isink_init.constraints.valid_ops_mask -+ = REGULATOR_CHANGE_CURRENT | REGULATOR_CHANGE_STATUS; - led->isink_init.constraints.valid_modes_mask = REGULATOR_MODE_NORMAL; - ret = wm8350_register_regulator(wm8350, isink, &led->isink_init); - if (ret != 0) { -@@ -1517,6 +1518,7 @@ int wm8350_register_led(struct wm8350 *wm8350, int lednum, int dcdc, int isink, - led->dcdc_init.num_consumer_supplies = 1; - led->dcdc_init.consumer_supplies = &led->dcdc_consumer; - led->dcdc_init.constraints.valid_modes_mask = REGULATOR_MODE_NORMAL; -+ led->dcdc_init.constraints.valid_ops_mask = REGULATOR_CHANGE_STATUS; - ret = wm8350_register_regulator(wm8350, dcdc, &led->dcdc_init); - if (ret != 0) { - platform_device_put(pdev); -diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c -index aaccc8e..513dec9 100644 ---- a/drivers/s390/block/dasd.c -+++ b/drivers/s390/block/dasd.c -@@ -1005,8 +1005,8 @@ static void dasd_handle_killed_request(struct ccw_device *cdev, - if (device == NULL || - device != dasd_device_from_cdev_locked(cdev) || - strncmp(device->discipline->ebcname, (char *) &cqr->magic, 4)) { -- DBF_DEV_EVENT(DBF_DEBUG, device, "invalid device in request: " -- "bus_id %s", dev_name(&cdev->dev)); -+ DBF_EVENT_DEVID(DBF_DEBUG, cdev, "%s", -+ "invalid device in request"); - return; - } - -@@ -1078,8 +1078,8 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm, - device = (struct dasd_device *) cqr->startdev; - if (!device || - strncmp(device->discipline->ebcname, (char *) &cqr->magic, 4)) { -- DBF_DEV_EVENT(DBF_DEBUG, device, "invalid device in request: " -- "bus_id %s", dev_name(&cdev->dev)); -+ DBF_EVENT_DEVID(DBF_DEBUG, cdev, "%s", -+ "invalid device in request"); - return; - } - -diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c -index 417b97c..80c205b 100644 ---- a/drivers/s390/block/dasd_eckd.c -+++ b/drivers/s390/block/dasd_eckd.c -@@ -2980,7 +2980,7 @@ static void dasd_eckd_dump_sense_ccw(struct dasd_device *device, - len += sprintf(page + len, KERN_ERR PRINTK_HEADER - " in req: %p CS: 0x%02X DS: 0x%02X CC: 0x%02X RC: %d\n", - req, scsw_cstat(&irb->scsw), scsw_dstat(&irb->scsw), -- scsw_cc(&irb->scsw), req->intrc); -+ scsw_cc(&irb->scsw), req ? req->intrc : 0); - len += sprintf(page + len, KERN_ERR PRINTK_HEADER - " device %s: Failing CCW: %p\n", - dev_name(&device->cdev->dev), -diff --git a/drivers/s390/block/dasd_ioctl.c b/drivers/s390/block/dasd_ioctl.c -index f756a1b..a5354b8 100644 ---- a/drivers/s390/block/dasd_ioctl.c -+++ b/drivers/s390/block/dasd_ioctl.c -@@ -260,7 +260,7 @@ static int dasd_ioctl_information(struct dasd_block *block, - struct ccw_dev_id dev_id; - - base = block->base; -- if (!base->discipline->fill_info) -+ if (!base->discipline || !base->discipline->fill_info) - return -EINVAL; - - dasd_info = kzalloc(sizeof(struct dasd_information2_t), GFP_KERNEL); -@@ -303,10 +303,7 @@ static int dasd_ioctl_information(struct dasd_block *block, - dasd_info->features |= - ((base->features & DASD_FEATURE_READONLY) != 0); - -- if (base->discipline) -- memcpy(dasd_info->type, base->discipline->name, 4); -- else -- memcpy(dasd_info->type, "none", 4); -+ memcpy(dasd_info->type, base->discipline->name, 4); - - if (block->request_queue->request_fn) { - struct list_head *l; -diff --git a/drivers/s390/block/dasd_proc.c b/drivers/s390/block/dasd_proc.c -index 654daa3..f9d7d38 100644 ---- a/drivers/s390/block/dasd_proc.c -+++ b/drivers/s390/block/dasd_proc.c -@@ -71,7 +71,7 @@ dasd_devices_show(struct seq_file *m, void *v) - /* Print device number. */ - seq_printf(m, "%s", dev_name(&device->cdev->dev)); - /* Print discipline string. */ -- if (device != NULL && device->discipline != NULL) -+ if (device->discipline != NULL) - seq_printf(m, "(%s)", device->discipline->name); - else - seq_printf(m, "(none)"); -@@ -91,10 +91,7 @@ dasd_devices_show(struct seq_file *m, void *v) - substr = (device->features & DASD_FEATURE_READONLY) ? "(ro)" : " "; - seq_printf(m, "%4s: ", substr); - /* Print device status information. */ -- switch ((device != NULL) ? device->state : -1) { -- case -1: -- seq_printf(m, "unknown"); -- break; -+ switch (device->state) { - case DASD_STATE_NEW: - seq_printf(m, "new"); - break; -diff --git a/drivers/s390/crypto/zcrypt_pcicc.c b/drivers/s390/crypto/zcrypt_pcicc.c -index f4b0c47..7f1e3ba 100644 ---- a/drivers/s390/crypto/zcrypt_pcicc.c -+++ b/drivers/s390/crypto/zcrypt_pcicc.c -@@ -373,6 +373,8 @@ static int convert_type86(struct zcrypt_device *zdev, - zdev->max_mod_size = PCICC_MAX_MOD_SIZE_OLD; - return -EAGAIN; - } -+ if (service_rc == 8 && service_rs == 72) -+ return -EINVAL; - zdev->online = 0; - return -EAGAIN; /* repeat the request on a different device. */ - } -diff --git a/drivers/s390/crypto/zcrypt_pcixcc.c b/drivers/s390/crypto/zcrypt_pcixcc.c -index 5677b40..1f9e923 100644 ---- a/drivers/s390/crypto/zcrypt_pcixcc.c -+++ b/drivers/s390/crypto/zcrypt_pcixcc.c -@@ -462,6 +462,8 @@ static int convert_type86_ica(struct zcrypt_device *zdev, - } - if (service_rc == 12 && service_rs == 769) - return -EINVAL; -+ if (service_rc == 8 && service_rs == 72) -+ return -EINVAL; - zdev->online = 0; - return -EAGAIN; /* repeat the request on a different device. */ - } -diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c -index 5987da8..bc9a881 100644 ---- a/drivers/scsi/scsi_lib.c -+++ b/drivers/scsi/scsi_lib.c -@@ -749,9 +749,9 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes) - */ - req->next_rq->resid_len = scsi_in(cmd)->resid; - -+ scsi_release_buffers(cmd); - blk_end_request_all(req, 0); - -- scsi_release_buffers(cmd); - scsi_next_command(cmd); - return; - } -diff --git a/drivers/serial/uartlite.c b/drivers/serial/uartlite.c -index 377f271..ab2ab3c 100644 ---- a/drivers/serial/uartlite.c -+++ b/drivers/serial/uartlite.c -@@ -394,7 +394,7 @@ static void ulite_console_write(struct console *co, const char *s, - spin_unlock_irqrestore(&port->lock, flags); - } - --static int __init ulite_console_setup(struct console *co, char *options) -+static int __devinit ulite_console_setup(struct console *co, char *options) - { - struct uart_port *port; - int baud = 9600; -diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c -index e33d362..5b56f53 100644 ---- a/drivers/usb/host/r8a66597-hcd.c -+++ b/drivers/usb/host/r8a66597-hcd.c -@@ -216,8 +216,17 @@ static void disable_controller(struct r8a66597 *r8a66597) - { - int port; - -+ /* disable interrupts */ - r8a66597_write(r8a66597, 0, INTENB0); -- r8a66597_write(r8a66597, 0, INTSTS0); -+ r8a66597_write(r8a66597, 0, INTENB1); -+ r8a66597_write(r8a66597, 0, BRDYENB); -+ r8a66597_write(r8a66597, 0, BEMPENB); -+ r8a66597_write(r8a66597, 0, NRDYENB); -+ -+ /* clear status */ -+ r8a66597_write(r8a66597, 0, BRDYSTS); -+ r8a66597_write(r8a66597, 0, NRDYSTS); -+ r8a66597_write(r8a66597, 0, BEMPSTS); - - for (port = 0; port < r8a66597->max_root_hub; port++) - r8a66597_disable_port(r8a66597, port); -@@ -2470,6 +2479,12 @@ static int __devinit r8a66597_probe(struct platform_device *pdev) - r8a66597->rh_timer.data = (unsigned long)r8a66597; - r8a66597->reg = (unsigned long)reg; - -+ /* make sure no interrupts are pending */ -+ ret = r8a66597_clock_enable(r8a66597); -+ if (ret < 0) -+ goto clean_up3; -+ disable_controller(r8a66597); -+ - for (i = 0; i < R8A66597_MAX_NUM_PIPE; i++) { - INIT_LIST_HEAD(&r8a66597->pipe_queue[i]); - init_timer(&r8a66597->td_timer[i]); -diff --git a/drivers/video/imxfb.c b/drivers/video/imxfb.c -index 66358fa..b4b6dec 100644 ---- a/drivers/video/imxfb.c -+++ b/drivers/video/imxfb.c -@@ -593,7 +593,8 @@ static int imxfb_activate_var(struct fb_var_screeninfo *var, struct fb_info *inf - */ - static int imxfb_suspend(struct platform_device *dev, pm_message_t state) - { -- struct imxfb_info *fbi = platform_get_drvdata(dev); -+ struct fb_info *info = platform_get_drvdata(dev); -+ struct imxfb_info *fbi = info->par; - - pr_debug("%s\n", __func__); - -@@ -603,7 +604,8 @@ static int imxfb_suspend(struct platform_device *dev, pm_message_t state) - - static int imxfb_resume(struct platform_device *dev) - { -- struct imxfb_info *fbi = platform_get_drvdata(dev); -+ struct fb_info *info = platform_get_drvdata(dev); -+ struct imxfb_info *fbi = info->par; - - pr_debug("%s\n", __func__); - -diff --git a/drivers/video/mx3fb.c b/drivers/video/mx3fb.c -index 054ef29..772ba3f 100644 ---- a/drivers/video/mx3fb.c -+++ b/drivers/video/mx3fb.c -@@ -324,8 +324,11 @@ static void sdc_enable_channel(struct mx3fb_info *mx3_fbi) - unsigned long flags; - dma_cookie_t cookie; - -- dev_dbg(mx3fb->dev, "mx3fbi %p, desc %p, sg %p\n", mx3_fbi, -- to_tx_desc(mx3_fbi->txd), to_tx_desc(mx3_fbi->txd)->sg); -+ if (mx3_fbi->txd) -+ dev_dbg(mx3fb->dev, "mx3fbi %p, desc %p, sg %p\n", mx3_fbi, -+ to_tx_desc(mx3_fbi->txd), to_tx_desc(mx3_fbi->txd)->sg); -+ else -+ dev_dbg(mx3fb->dev, "mx3fbi %p, txd = NULL\n", mx3_fbi); - - /* This enables the channel */ - if (mx3_fbi->cookie < 0) { -@@ -646,6 +649,7 @@ static int sdc_set_global_alpha(struct mx3fb_data *mx3fb, bool enable, uint8_t a - - static void sdc_set_brightness(struct mx3fb_data *mx3fb, uint8_t value) - { -+ dev_dbg(mx3fb->dev, "%s: value = %d\n", __func__, value); - /* This might be board-specific */ - mx3fb_write_reg(mx3fb, 0x03000000UL | value << 16, SDC_PWM_CTRL); - return; -@@ -1486,12 +1490,12 @@ static int mx3fb_probe(struct platform_device *pdev) - goto ersdc0; - } - -+ mx3fb->backlight_level = 255; -+ - ret = init_fb_chan(mx3fb, to_idmac_chan(chan)); - if (ret < 0) - goto eisdc0; - -- mx3fb->backlight_level = 255; -- - return 0; - - eisdc0: -diff --git a/fs/9p/vfs_super.c b/fs/9p/vfs_super.c -index 14a8644..69357c0 100644 ---- a/fs/9p/vfs_super.c -+++ b/fs/9p/vfs_super.c -@@ -188,7 +188,8 @@ static void v9fs_kill_super(struct super_block *s) - - P9_DPRINTK(P9_DEBUG_VFS, " %p\n", s); - -- v9fs_dentry_release(s->s_root); /* clunk root */ -+ if (s->s_root) -+ v9fs_dentry_release(s->s_root); /* clunk root */ - - kill_anon_super(s); - -diff --git a/fs/affs/affs.h b/fs/affs/affs.h -index e511dc6..0e40caa 100644 ---- a/fs/affs/affs.h -+++ b/fs/affs/affs.h -@@ -106,8 +106,8 @@ struct affs_sb_info { - u32 s_last_bmap; - struct buffer_head *s_bmap_bh; - char *s_prefix; /* Prefix for volumes and assigns. */ -- int s_prefix_len; /* Length of prefix. */ - char s_volume[32]; /* Volume prefix for absolute symlinks. */ -+ spinlock_t symlink_lock; /* protects the previous two */ - }; - - #define SF_INTL 0x0001 /* International filesystem. */ -diff --git a/fs/affs/namei.c b/fs/affs/namei.c -index 960d336..d70bbba 100644 ---- a/fs/affs/namei.c -+++ b/fs/affs/namei.c -@@ -341,10 +341,13 @@ affs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) - p = (char *)AFFS_HEAD(bh)->table; - lc = '/'; - if (*symname == '/') { -+ struct affs_sb_info *sbi = AFFS_SB(sb); - while (*symname == '/') - symname++; -- while (AFFS_SB(sb)->s_volume[i]) /* Cannot overflow */ -- *p++ = AFFS_SB(sb)->s_volume[i++]; -+ spin_lock(&sbi->symlink_lock); -+ while (sbi->s_volume[i]) /* Cannot overflow */ -+ *p++ = sbi->s_volume[i++]; -+ spin_unlock(&sbi->symlink_lock); - } - while (i < maxlen && (c = *symname++)) { - if (c == '.' && lc == '/' && *symname == '.' && symname[1] == '/') { -diff --git a/fs/affs/super.c b/fs/affs/super.c -index 104fdcb..d41e967 100644 ---- a/fs/affs/super.c -+++ b/fs/affs/super.c -@@ -203,7 +203,7 @@ parse_options(char *options, uid_t *uid, gid_t *gid, int *mode, int *reserved, s - switch (token) { - case Opt_bs: - if (match_int(&args[0], &n)) -- return -EINVAL; -+ return 0; - if (n != 512 && n != 1024 && n != 2048 - && n != 4096) { - printk ("AFFS: Invalid blocksize (512, 1024, 2048, 4096 allowed)\n"); -@@ -213,7 +213,7 @@ parse_options(char *options, uid_t *uid, gid_t *gid, int *mode, int *reserved, s - break; - case Opt_mode: - if (match_octal(&args[0], &option)) -- return 1; -+ return 0; - *mode = option & 0777; - *mount_opts |= SF_SETMODE; - break; -@@ -221,8 +221,6 @@ parse_options(char *options, uid_t *uid, gid_t *gid, int *mode, int *reserved, s - *mount_opts |= SF_MUFS; - break; - case Opt_prefix: -- /* Free any previous prefix */ -- kfree(*prefix); - *prefix = match_strdup(&args[0]); - if (!*prefix) - return 0; -@@ -233,21 +231,21 @@ parse_options(char *options, uid_t *uid, gid_t *gid, int *mode, int *reserved, s - break; - case Opt_reserved: - if (match_int(&args[0], reserved)) -- return 1; -+ return 0; - break; - case Opt_root: - if (match_int(&args[0], root)) -- return 1; -+ return 0; - break; - case Opt_setgid: - if (match_int(&args[0], &option)) -- return 1; -+ return 0; - *gid = option; - *mount_opts |= SF_SETGID; - break; - case Opt_setuid: - if (match_int(&args[0], &option)) -- return -EINVAL; -+ return 0; - *uid = option; - *mount_opts |= SF_SETUID; - break; -@@ -311,11 +309,14 @@ static int affs_fill_super(struct super_block *sb, void *data, int silent) - return -ENOMEM; - sb->s_fs_info = sbi; - mutex_init(&sbi->s_bmlock); -+ spin_lock_init(&sbi->symlink_lock); - - if (!parse_options(data,&uid,&gid,&i,&reserved,&root_block, - &blocksize,&sbi->s_prefix, - sbi->s_volume, &mount_flags)) { - printk(KERN_ERR "AFFS: Error parsing options\n"); -+ kfree(sbi->s_prefix); -+ kfree(sbi); - return -EINVAL; - } - /* N.B. after this point s_prefix must be released */ -@@ -516,14 +517,18 @@ affs_remount(struct super_block *sb, int *flags, char *data) - unsigned long mount_flags; - int res = 0; - char *new_opts = kstrdup(data, GFP_KERNEL); -+ char volume[32]; -+ char *prefix = NULL; - - pr_debug("AFFS: remount(flags=0x%x,opts=\"%s\")\n",*flags,data); - - *flags |= MS_NODIRATIME; - -+ memcpy(volume, sbi->s_volume, 32); - if (!parse_options(data, &uid, &gid, &mode, &reserved, &root_block, -- &blocksize, &sbi->s_prefix, sbi->s_volume, -+ &blocksize, &prefix, volume, - &mount_flags)) { -+ kfree(prefix); - kfree(new_opts); - return -EINVAL; - } -@@ -534,6 +539,14 @@ affs_remount(struct super_block *sb, int *flags, char *data) - sbi->s_mode = mode; - sbi->s_uid = uid; - sbi->s_gid = gid; -+ /* protect against readers */ -+ spin_lock(&sbi->symlink_lock); -+ if (prefix) { -+ kfree(sbi->s_prefix); -+ sbi->s_prefix = prefix; -+ } -+ memcpy(sbi->s_volume, volume, 32); -+ spin_unlock(&sbi->symlink_lock); - - if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY)) { - unlock_kernel(); -diff --git a/fs/affs/symlink.c b/fs/affs/symlink.c -index 4178253..ee00f08 100644 ---- a/fs/affs/symlink.c -+++ b/fs/affs/symlink.c -@@ -20,7 +20,6 @@ static int affs_symlink_readpage(struct file *file, struct page *page) - int i, j; - char c; - char lc; -- char *pf; - - pr_debug("AFFS: follow_link(ino=%lu)\n",inode->i_ino); - -@@ -32,11 +31,15 @@ static int affs_symlink_readpage(struct file *file, struct page *page) - j = 0; - lf = (struct slink_front *)bh->b_data; - lc = 0; -- pf = AFFS_SB(inode->i_sb)->s_prefix ? AFFS_SB(inode->i_sb)->s_prefix : "/"; - - if (strchr(lf->symname,':')) { /* Handle assign or volume name */ -+ struct affs_sb_info *sbi = AFFS_SB(inode->i_sb); -+ char *pf; -+ spin_lock(&sbi->symlink_lock); -+ pf = sbi->s_prefix ? sbi->s_prefix : "/"; - while (i < 1023 && (c = pf[i])) - link[i++] = c; -+ spin_unlock(&sbi->symlink_lock); - while (i < 1023 && lf->symname[j] != ':') - link[i++] = lf->symname[j++]; - if (i < 1023) -diff --git a/fs/bfs/inode.c b/fs/bfs/inode.c -index 6f60336..8f3d9fd 100644 ---- a/fs/bfs/inode.c -+++ b/fs/bfs/inode.c -@@ -353,35 +353,35 @@ static int bfs_fill_super(struct super_block *s, void *data, int silent) - struct inode *inode; - unsigned i, imap_len; - struct bfs_sb_info *info; -- long ret = -EINVAL; -+ int ret = -EINVAL; - unsigned long i_sblock, i_eblock, i_eoff, s_size; - - info = kzalloc(sizeof(*info), GFP_KERNEL); - if (!info) - return -ENOMEM; -+ mutex_init(&info->bfs_lock); - s->s_fs_info = info; - - sb_set_blocksize(s, BFS_BSIZE); - -- bh = sb_bread(s, 0); -- if(!bh) -+ info->si_sbh = sb_bread(s, 0); -+ if (!info->si_sbh) - goto out; -- bfs_sb = (struct bfs_super_block *)bh->b_data; -+ bfs_sb = (struct bfs_super_block *)info->si_sbh->b_data; - if (le32_to_cpu(bfs_sb->s_magic) != BFS_MAGIC) { - if (!silent) - printf("No BFS filesystem on %s (magic=%08x)\n", - s->s_id, le32_to_cpu(bfs_sb->s_magic)); -- goto out; -+ goto out1; - } - if (BFS_UNCLEAN(bfs_sb, s) && !silent) - printf("%s is unclean, continuing\n", s->s_id); - - s->s_magic = BFS_MAGIC; -- info->si_sbh = bh; - - if (le32_to_cpu(bfs_sb->s_start) > le32_to_cpu(bfs_sb->s_end)) { - printf("Superblock is corrupted\n"); -- goto out; -+ goto out1; - } - - info->si_lasti = (le32_to_cpu(bfs_sb->s_start) - BFS_BSIZE) / -@@ -390,7 +390,7 @@ static int bfs_fill_super(struct super_block *s, void *data, int silent) - imap_len = (info->si_lasti / 8) + 1; - info->si_imap = kzalloc(imap_len, GFP_KERNEL); - if (!info->si_imap) -- goto out; -+ goto out1; - for (i = 0; i < BFS_ROOT_INO; i++) - set_bit(i, info->si_imap); - -@@ -398,15 +398,13 @@ static int bfs_fill_super(struct super_block *s, void *data, int silent) - inode = bfs_iget(s, BFS_ROOT_INO); - if (IS_ERR(inode)) { - ret = PTR_ERR(inode); -- kfree(info->si_imap); -- goto out; -+ goto out2; - } - s->s_root = d_alloc_root(inode); - if (!s->s_root) { - iput(inode); - ret = -ENOMEM; -- kfree(info->si_imap); -- goto out; -+ goto out2; - } - - info->si_blocks = (le32_to_cpu(bfs_sb->s_end) + 1) >> BFS_BSIZE_BITS; -@@ -419,10 +417,8 @@ static int bfs_fill_super(struct super_block *s, void *data, int silent) - bh = sb_bread(s, info->si_blocks - 1); - if (!bh) { - printf("Last block not available: %lu\n", info->si_blocks - 1); -- iput(inode); - ret = -EIO; -- kfree(info->si_imap); -- goto out; -+ goto out3; - } - brelse(bh); - -@@ -459,11 +455,8 @@ static int bfs_fill_super(struct super_block *s, void *data, int silent) - printf("Inode 0x%08x corrupted\n", i); - - brelse(bh); -- s->s_root = NULL; -- kfree(info->si_imap); -- kfree(info); -- s->s_fs_info = NULL; -- return -EIO; -+ ret = -EIO; -+ goto out3; - } - - if (!di->i_ino) { -@@ -483,11 +476,17 @@ static int bfs_fill_super(struct super_block *s, void *data, int silent) - s->s_dirt = 1; - } - dump_imap("read_super", s); -- mutex_init(&info->bfs_lock); - return 0; - -+out3: -+ dput(s->s_root); -+ s->s_root = NULL; -+out2: -+ kfree(info->si_imap); -+out1: -+ brelse(info->si_sbh); - out: -- brelse(bh); -+ mutex_destroy(&info->bfs_lock); - kfree(info); - s->s_fs_info = NULL; - return ret; -diff --git a/fs/binfmt_aout.c b/fs/binfmt_aout.c -index b639dcf..0133b5a 100644 ---- a/fs/binfmt_aout.c -+++ b/fs/binfmt_aout.c -@@ -263,6 +263,7 @@ static int load_aout_binary(struct linux_binprm * bprm, struct pt_regs * regs) - #else - set_personality(PER_LINUX); - #endif -+ setup_new_exec(bprm); - - current->mm->end_code = ex.a_text + - (current->mm->start_code = N_TXTADDR(ex)); -diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c -index b9b3bb5..1ed37ba 100644 ---- a/fs/binfmt_elf.c -+++ b/fs/binfmt_elf.c -@@ -662,27 +662,6 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs) - if (elf_interpreter[elf_ppnt->p_filesz - 1] != '\0') - goto out_free_interp; - -- /* -- * The early SET_PERSONALITY here is so that the lookup -- * for the interpreter happens in the namespace of the -- * to-be-execed image. SET_PERSONALITY can select an -- * alternate root. -- * -- * However, SET_PERSONALITY is NOT allowed to switch -- * this task into the new images's memory mapping -- * policy - that is, TASK_SIZE must still evaluate to -- * that which is appropriate to the execing application. -- * This is because exit_mmap() needs to have TASK_SIZE -- * evaluate to the size of the old image. -- * -- * So if (say) a 64-bit application is execing a 32-bit -- * application it is the architecture's responsibility -- * to defer changing the value of TASK_SIZE until the -- * switch really is going to happen - do this in -- * flush_thread(). - akpm -- */ -- SET_PERSONALITY(loc->elf_ex); -- - interpreter = open_exec(elf_interpreter); - retval = PTR_ERR(interpreter); - if (IS_ERR(interpreter)) -@@ -730,9 +709,6 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs) - /* Verify the interpreter has a valid arch */ - if (!elf_check_arch(&loc->interp_elf_ex)) - goto out_free_dentry; -- } else { -- /* Executables without an interpreter also need a personality */ -- SET_PERSONALITY(loc->elf_ex); - } - - /* Flush all traces of the currently running executable */ -@@ -752,7 +728,8 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs) - - if (!(current->personality & ADDR_NO_RANDOMIZE) && randomize_va_space) - current->flags |= PF_RANDOMIZE; -- arch_pick_mmap_layout(current->mm); -+ -+ setup_new_exec(bprm); - - /* Do this so that we can load the interpreter, if need be. We will - change some of these later */ -diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c -index 38502c6..e7a0bb4 100644 ---- a/fs/binfmt_elf_fdpic.c -+++ b/fs/binfmt_elf_fdpic.c -@@ -171,6 +171,9 @@ static int load_elf_fdpic_binary(struct linux_binprm *bprm, - #ifdef ELF_FDPIC_PLAT_INIT - unsigned long dynaddr; - #endif -+#ifndef CONFIG_MMU -+ unsigned long stack_prot; -+#endif - struct file *interpreter = NULL; /* to shut gcc up */ - char *interpreter_name = NULL; - int executable_stack; -@@ -316,6 +319,11 @@ static int load_elf_fdpic_binary(struct linux_binprm *bprm, - * defunct, deceased, etc. after this point we have to exit via - * error_kill */ - set_personality(PER_LINUX_FDPIC); -+ if (elf_read_implies_exec(&exec_params.hdr, executable_stack)) -+ current->personality |= READ_IMPLIES_EXEC; -+ -+ setup_new_exec(bprm); -+ - set_binfmt(&elf_fdpic_format); - - current->mm->start_code = 0; -@@ -377,9 +385,13 @@ static int load_elf_fdpic_binary(struct linux_binprm *bprm, - if (stack_size < PAGE_SIZE * 2) - stack_size = PAGE_SIZE * 2; - -+ stack_prot = PROT_READ | PROT_WRITE; -+ if (executable_stack == EXSTACK_ENABLE_X || -+ (executable_stack == EXSTACK_DEFAULT && VM_STACK_FLAGS & VM_EXEC)) -+ stack_prot |= PROT_EXEC; -+ - down_write(¤t->mm->mmap_sem); -- current->mm->start_brk = do_mmap(NULL, 0, stack_size, -- PROT_READ | PROT_WRITE | PROT_EXEC, -+ current->mm->start_brk = do_mmap(NULL, 0, stack_size, stack_prot, - MAP_PRIVATE | MAP_ANONYMOUS | MAP_GROWSDOWN, - 0); - -diff --git a/fs/binfmt_flat.c b/fs/binfmt_flat.c -index a279665..ca88c46 100644 ---- a/fs/binfmt_flat.c -+++ b/fs/binfmt_flat.c -@@ -519,6 +519,7 @@ static int load_flat_file(struct linux_binprm * bprm, - - /* OK, This is the point of no return */ - set_personality(PER_LINUX_32BIT); -+ setup_new_exec(bprm); - } - - /* -diff --git a/fs/binfmt_som.c b/fs/binfmt_som.c -index eff74b9..35cf002 100644 ---- a/fs/binfmt_som.c -+++ b/fs/binfmt_som.c -@@ -227,6 +227,7 @@ load_som_binary(struct linux_binprm * bprm, struct pt_regs * regs) - /* OK, This is the point of no return */ - current->flags &= ~PF_FORKNOEXEC; - current->personality = PER_HPUX; -+ setup_new_exec(bprm); - - /* Set the task size for HP-UX processes such that - * the gateway page is outside the address space. -diff --git a/fs/bio-integrity.c b/fs/bio-integrity.c -index 49a34e7..a16f29e 100644 ---- a/fs/bio-integrity.c -+++ b/fs/bio-integrity.c -@@ -61,7 +61,7 @@ static inline unsigned int vecs_to_idx(unsigned int nr) - - static inline int use_bip_pool(unsigned int idx) - { -- if (idx == BIOVEC_NR_POOLS) -+ if (idx == BIOVEC_MAX_IDX) - return 1; - - return 0; -@@ -95,6 +95,7 @@ struct bio_integrity_payload *bio_integrity_alloc_bioset(struct bio *bio, - - /* Use mempool if lower order alloc failed or max vecs were requested */ - if (bip == NULL) { -+ idx = BIOVEC_MAX_IDX; /* so we free the payload properly later */ - bip = mempool_alloc(bs->bio_integrity_pool, gfp_mask); - - if (unlikely(bip == NULL)) { -diff --git a/fs/bio.c b/fs/bio.c -index 12da5db..e0c9e71 100644 ---- a/fs/bio.c -+++ b/fs/bio.c -@@ -542,13 +542,18 @@ static int __bio_add_page(struct request_queue *q, struct bio *bio, struct page - - if (page == prev->bv_page && - offset == prev->bv_offset + prev->bv_len) { -+ unsigned int prev_bv_len = prev->bv_len; - prev->bv_len += len; - - if (q->merge_bvec_fn) { - struct bvec_merge_data bvm = { -+ /* prev_bvec is already charged in -+ bi_size, discharge it in order to -+ simulate merging updated prev_bvec -+ as new bvec. */ - .bi_bdev = bio->bi_bdev, - .bi_sector = bio->bi_sector, -- .bi_size = bio->bi_size, -+ .bi_size = bio->bi_size - prev_bv_len, - .bi_rw = bio->bi_rw, - }; - -diff --git a/fs/exec.c b/fs/exec.c -index ba112bd..7fa4efd 100644 ---- a/fs/exec.c -+++ b/fs/exec.c -@@ -931,9 +931,7 @@ void set_task_comm(struct task_struct *tsk, char *buf) - - int flush_old_exec(struct linux_binprm * bprm) - { -- char * name; -- int i, ch, retval; -- char tcomm[sizeof(current->comm)]; -+ int retval; - - /* - * Make sure we have a private signal table and that -@@ -954,6 +952,25 @@ int flush_old_exec(struct linux_binprm * bprm) - - bprm->mm = NULL; /* We're using it now */ - -+ current->flags &= ~PF_RANDOMIZE; -+ flush_thread(); -+ current->personality &= ~bprm->per_clear; -+ -+ return 0; -+ -+out: -+ return retval; -+} -+EXPORT_SYMBOL(flush_old_exec); -+ -+void setup_new_exec(struct linux_binprm * bprm) -+{ -+ int i, ch; -+ char * name; -+ char tcomm[sizeof(current->comm)]; -+ -+ arch_pick_mmap_layout(current->mm); -+ - /* This is the point of no return */ - current->sas_ss_sp = current->sas_ss_size = 0; - -@@ -975,9 +992,6 @@ int flush_old_exec(struct linux_binprm * bprm) - tcomm[i] = '\0'; - set_task_comm(current, tcomm); - -- current->flags &= ~PF_RANDOMIZE; -- flush_thread(); -- - /* Set the new mm task size. We have to do that late because it may - * depend on TIF_32BIT which is only updated in flush_thread() on - * some architectures like powerpc -@@ -993,8 +1007,6 @@ int flush_old_exec(struct linux_binprm * bprm) - set_dumpable(current->mm, suid_dumpable); - } - -- current->personality &= ~bprm->per_clear; -- - /* - * Flush performance counters when crossing a - * security domain: -@@ -1009,14 +1021,8 @@ int flush_old_exec(struct linux_binprm * bprm) - - flush_signal_handlers(current, 0); - flush_old_files(current->files); -- -- return 0; -- --out: -- return retval; - } -- --EXPORT_SYMBOL(flush_old_exec); -+EXPORT_SYMBOL(setup_new_exec); - - /* - * Prepare credentials and lock ->cred_guard_mutex. -diff --git a/fs/fuse/file.c b/fs/fuse/file.c -index c18913a..a9f5e13 100644 ---- a/fs/fuse/file.c -+++ b/fs/fuse/file.c -@@ -828,6 +828,9 @@ static ssize_t fuse_fill_write_pages(struct fuse_req *req, - if (!page) - break; - -+ if (mapping_writably_mapped(mapping)) -+ flush_dcache_page(page); -+ - pagefault_disable(); - tmp = iov_iter_copy_from_user_atomic(page, ii, offset, bytes); - pagefault_enable(); -diff --git a/fs/romfs/super.c b/fs/romfs/super.c -index c117fa8..42d2135 100644 ---- a/fs/romfs/super.c -+++ b/fs/romfs/super.c -@@ -544,6 +544,7 @@ error: - error_rsb_inval: - ret = -EINVAL; - error_rsb: -+ kfree(rsb); - return ret; - } - -diff --git a/include/linux/acpi.h b/include/linux/acpi.h -index dfcd920..c010b94 100644 ---- a/include/linux/acpi.h -+++ b/include/linux/acpi.h -@@ -253,6 +253,13 @@ void __init acpi_old_suspend_ordering(void); - void __init acpi_s4_no_nvs(void); - #endif /* CONFIG_PM_SLEEP */ - -+struct acpi_osc_context { -+ char *uuid_str; /* uuid string */ -+ int rev; -+ struct acpi_buffer cap; /* arg2/arg3 */ -+ struct acpi_buffer ret; /* free by caller if success */ -+}; -+ - #define OSC_QUERY_TYPE 0 - #define OSC_SUPPORT_TYPE 1 - #define OSC_CONTROL_TYPE 2 -@@ -265,6 +272,15 @@ void __init acpi_s4_no_nvs(void); - #define OSC_INVALID_REVISION_ERROR 8 - #define OSC_CAPABILITIES_MASK_ERROR 16 - -+acpi_status acpi_run_osc(acpi_handle handle, struct acpi_osc_context *context); -+ -+/* platform-wide _OSC bits */ -+#define OSC_SB_PAD_SUPPORT 1 -+#define OSC_SB_PPC_OST_SUPPORT 2 -+#define OSC_SB_PR3_SUPPORT 4 -+#define OSC_SB_CPUHP_OST_SUPPORT 8 -+#define OSC_SB_APEI_SUPPORT 16 -+ - /* _OSC DW1 Definition (OS Support Fields) */ - #define OSC_EXT_PCI_CONFIG_SUPPORT 1 - #define OSC_ACTIVE_STATE_PWR_SUPPORT 2 -diff --git a/include/linux/binfmts.h b/include/linux/binfmts.h -index aece486..340f441 100644 ---- a/include/linux/binfmts.h -+++ b/include/linux/binfmts.h -@@ -101,6 +101,7 @@ extern int prepare_binprm(struct linux_binprm *); - extern int __must_check remove_arg_zero(struct linux_binprm *); - extern int search_binary_handler(struct linux_binprm *,struct pt_regs *); - extern int flush_old_exec(struct linux_binprm * bprm); -+extern void setup_new_exec(struct linux_binprm * bprm); - - extern int suid_dumpable; - #define SUID_DUMP_DISABLE 0 /* No setuid dumping */ -diff --git a/include/linux/connector.h b/include/linux/connector.h -index 3a14615..ecb61c4 100644 ---- a/include/linux/connector.h -+++ b/include/linux/connector.h -@@ -24,9 +24,6 @@ - - #include - --#define CN_IDX_CONNECTOR 0xffffffff --#define CN_VAL_CONNECTOR 0xffffffff -- - /* - * Process Events connector unique ids -- used for message routing - */ -@@ -73,30 +70,6 @@ struct cn_msg { - __u8 data[0]; - }; - --/* -- * Notify structure - requests notification about -- * registering/unregistering idx/val in range [first, first+range]. -- */ --struct cn_notify_req { -- __u32 first; -- __u32 range; --}; -- --/* -- * Main notification control message -- * *_notify_num - number of appropriate cn_notify_req structures after -- * this struct. -- * group - notification receiver's idx. -- * len - total length of the attached data. -- */ --struct cn_ctl_msg { -- __u32 idx_notify_num; -- __u32 val_notify_num; -- __u32 group; -- __u32 len; -- __u8 data[0]; --}; -- - #ifdef __KERNEL__ - - #include -@@ -149,11 +122,6 @@ struct cn_callback_entry { - u32 seq, group; - }; - --struct cn_ctl_entry { -- struct list_head notify_entry; -- struct cn_ctl_msg *msg; --}; -- - struct cn_dev { - struct cb_id id; - -diff --git a/include/linux/inetdevice.h b/include/linux/inetdevice.h -index ad27c7d..9cd0bcf 100644 ---- a/include/linux/inetdevice.h -+++ b/include/linux/inetdevice.h -@@ -83,6 +83,7 @@ static inline void ipv4_devconf_setall(struct in_device *in_dev) - #define IN_DEV_FORWARD(in_dev) IN_DEV_CONF_GET((in_dev), FORWARDING) - #define IN_DEV_MFORWARD(in_dev) IN_DEV_ANDCONF((in_dev), MC_FORWARDING) - #define IN_DEV_RPFILTER(in_dev) IN_DEV_MAXCONF((in_dev), RP_FILTER) -+#define IN_DEV_SRC_VMARK(in_dev) IN_DEV_ORCONF((in_dev), SRC_VMARK) - #define IN_DEV_SOURCE_ROUTE(in_dev) IN_DEV_ANDCONF((in_dev), \ - ACCEPT_SOURCE_ROUTE) - #define IN_DEV_BOOTP_RELAY(in_dev) IN_DEV_ANDCONF((in_dev), BOOTP_RELAY) -diff --git a/include/linux/kvm.h b/include/linux/kvm.h -index 8908dd6..0eadd71 100644 ---- a/include/linux/kvm.h -+++ b/include/linux/kvm.h -@@ -439,6 +439,7 @@ struct kvm_ioeventfd { - #endif - #define KVM_CAP_IOEVENTFD 36 - #define KVM_CAP_SET_IDENTITY_MAP_ADDR 37 -+#define KVM_CAP_ADJUST_CLOCK 39 - - #ifdef KVM_CAP_IRQ_ROUTING - -@@ -501,6 +502,12 @@ struct kvm_irqfd { - __u8 pad[20]; - }; - -+struct kvm_clock_data { -+ __u64 clock; -+ __u32 flags; -+ __u32 pad[9]; -+}; -+ - /* - * ioctls for VM fds - */ -@@ -550,6 +557,8 @@ struct kvm_irqfd { - #define KVM_CREATE_PIT2 _IOW(KVMIO, 0x77, struct kvm_pit_config) - #define KVM_SET_BOOT_CPU_ID _IO(KVMIO, 0x78) - #define KVM_IOEVENTFD _IOW(KVMIO, 0x79, struct kvm_ioeventfd) -+#define KVM_SET_CLOCK _IOW(KVMIO, 0x7b, struct kvm_clock_data) -+#define KVM_GET_CLOCK _IOR(KVMIO, 0x7c, struct kvm_clock_data) - - /* - * ioctls for vcpu fds -diff --git a/include/linux/libata.h b/include/linux/libata.h -index 8769864..b0f6d97 100644 ---- a/include/linux/libata.h -+++ b/include/linux/libata.h -@@ -354,6 +354,9 @@ enum { - /* max tries if error condition is still set after ->error_handler */ - ATA_EH_MAX_TRIES = 5, - -+ /* sometimes resuming a link requires several retries */ -+ ATA_LINK_RESUME_TRIES = 5, -+ - /* how hard are we gonna try to probe/recover devices */ - ATA_PROBE_MAX_TRIES = 3, - ATA_EH_DEV_TRIES = 3, -diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h -index ed5d750..3c62ed4 100644 ---- a/include/linux/pagemap.h -+++ b/include/linux/pagemap.h -@@ -253,6 +253,8 @@ extern struct page * read_cache_page_async(struct address_space *mapping, - extern struct page * read_cache_page(struct address_space *mapping, - pgoff_t index, filler_t *filler, - void *data); -+extern struct page * read_cache_page_gfp(struct address_space *mapping, -+ pgoff_t index, gfp_t gfp_mask); - extern int read_cache_pages(struct address_space *mapping, - struct list_head *pages, filler_t *filler, void *data); - -diff --git a/include/linux/sched.h b/include/linux/sched.h -index 0f67914..d3dce7d 100644 ---- a/include/linux/sched.h -+++ b/include/linux/sched.h -@@ -1354,7 +1354,7 @@ struct task_struct { - char comm[TASK_COMM_LEN]; /* executable name excluding path - - access with [gs]et_task_comm (which lock - it with task_lock()) -- - initialized normally by flush_old_exec */ -+ - initialized normally by setup_new_exec */ - /* file system info */ - int link_count, total_link_count; - #ifdef CONFIG_SYSVIPC -diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h -index 1e4743e..0eb6942 100644 ---- a/include/linux/sysctl.h -+++ b/include/linux/sysctl.h -@@ -490,6 +490,7 @@ enum - NET_IPV4_CONF_PROMOTE_SECONDARIES=20, - NET_IPV4_CONF_ARP_ACCEPT=21, - NET_IPV4_CONF_ARP_NOTIFY=22, -+ NET_IPV4_CONF_SRC_VMARK=24, - __NET_IPV4_CONF_MAX - }; - -diff --git a/include/net/netrom.h b/include/net/netrom.h -index 15696b1..ab170a6 100644 ---- a/include/net/netrom.h -+++ b/include/net/netrom.h -@@ -132,6 +132,8 @@ static __inline__ void nr_node_put(struct nr_node *nr_node) - static __inline__ void nr_neigh_put(struct nr_neigh *nr_neigh) - { - if (atomic_dec_and_test(&nr_neigh->refcount)) { -+ if (nr_neigh->ax25) -+ ax25_cb_put(nr_neigh->ax25); - kfree(nr_neigh->digipeat); - kfree(nr_neigh); - } -diff --git a/kernel/cred.c b/kernel/cred.c -index dd76cfe..1ed8ca1 100644 ---- a/kernel/cred.c -+++ b/kernel/cred.c -@@ -224,7 +224,7 @@ struct cred *cred_alloc_blank(void) - #ifdef CONFIG_KEYS - new->tgcred = kzalloc(sizeof(*new->tgcred), GFP_KERNEL); - if (!new->tgcred) { -- kfree(new); -+ kmem_cache_free(cred_jar, new); - return NULL; - } - atomic_set(&new->tgcred->usage, 1); -diff --git a/kernel/sysctl_check.c b/kernel/sysctl_check.c -index b6e7aae..469193c 100644 ---- a/kernel/sysctl_check.c -+++ b/kernel/sysctl_check.c -@@ -220,6 +220,7 @@ static const struct trans_ctl_table trans_net_ipv4_conf_vars_table[] = { - { NET_IPV4_CONF_PROMOTE_SECONDARIES, "promote_secondaries" }, - { NET_IPV4_CONF_ARP_ACCEPT, "arp_accept" }, - { NET_IPV4_CONF_ARP_NOTIFY, "arp_notify" }, -+ { NET_IPV4_CONF_SRC_VMARK, "src_valid_mark" }, - {} - }; - -diff --git a/kernel/time/clocksource.c b/kernel/time/clocksource.c -index 5155dc3..ecc7adb 100644 ---- a/kernel/time/clocksource.c -+++ b/kernel/time/clocksource.c -@@ -413,8 +413,6 @@ void clocksource_touch_watchdog(void) - clocksource_resume_watchdog(); - } - --#ifdef CONFIG_GENERIC_TIME -- - /** - * clocksource_max_deferment - Returns max time the clocksource can be deferred - * @cs: Pointer to clocksource -@@ -456,6 +454,8 @@ static u64 clocksource_max_deferment(struct clocksource *cs) - return max_nsecs - (max_nsecs >> 5); - } - -+#ifdef CONFIG_GENERIC_TIME -+ - /** - * clocksource_select - Select the best clocksource available - * -diff --git a/mm/filemap.c b/mm/filemap.c -index ef169f3..8e96c90 100644 ---- a/mm/filemap.c -+++ b/mm/filemap.c -@@ -1655,14 +1655,15 @@ EXPORT_SYMBOL(generic_file_readonly_mmap); - static struct page *__read_cache_page(struct address_space *mapping, - pgoff_t index, - int (*filler)(void *,struct page*), -- void *data) -+ void *data, -+ gfp_t gfp) - { - struct page *page; - int err; - repeat: - page = find_get_page(mapping, index); - if (!page) { -- page = page_cache_alloc_cold(mapping); -+ page = __page_cache_alloc(gfp | __GFP_COLD); - if (!page) - return ERR_PTR(-ENOMEM); - err = add_to_page_cache_lru(page, mapping, index, GFP_KERNEL); -@@ -1682,31 +1683,18 @@ repeat: - return page; - } - --/** -- * read_cache_page_async - read into page cache, fill it if needed -- * @mapping: the page's address_space -- * @index: the page index -- * @filler: function to perform the read -- * @data: destination for read data -- * -- * Same as read_cache_page, but don't wait for page to become unlocked -- * after submitting it to the filler. -- * -- * Read into the page cache. If a page already exists, and PageUptodate() is -- * not set, try to fill the page but don't wait for it to become unlocked. -- * -- * If the page does not get brought uptodate, return -EIO. -- */ --struct page *read_cache_page_async(struct address_space *mapping, -+static struct page *do_read_cache_page(struct address_space *mapping, - pgoff_t index, - int (*filler)(void *,struct page*), -- void *data) -+ void *data, -+ gfp_t gfp) -+ - { - struct page *page; - int err; - - retry: -- page = __read_cache_page(mapping, index, filler, data); -+ page = __read_cache_page(mapping, index, filler, data, gfp); - if (IS_ERR(page)) - return page; - if (PageUptodate(page)) -@@ -1731,8 +1719,67 @@ out: - mark_page_accessed(page); - return page; - } -+ -+/** -+ * read_cache_page_async - read into page cache, fill it if needed -+ * @mapping: the page's address_space -+ * @index: the page index -+ * @filler: function to perform the read -+ * @data: destination for read data -+ * -+ * Same as read_cache_page, but don't wait for page to become unlocked -+ * after submitting it to the filler. -+ * -+ * Read into the page cache. If a page already exists, and PageUptodate() is -+ * not set, try to fill the page but don't wait for it to become unlocked. -+ * -+ * If the page does not get brought uptodate, return -EIO. -+ */ -+struct page *read_cache_page_async(struct address_space *mapping, -+ pgoff_t index, -+ int (*filler)(void *,struct page*), -+ void *data) -+{ -+ return do_read_cache_page(mapping, index, filler, data, mapping_gfp_mask(mapping)); -+} - EXPORT_SYMBOL(read_cache_page_async); - -+static struct page *wait_on_page_read(struct page *page) -+{ -+ if (!IS_ERR(page)) { -+ wait_on_page_locked(page); -+ if (!PageUptodate(page)) { -+ page_cache_release(page); -+ page = ERR_PTR(-EIO); -+ } -+ } -+ return page; -+} -+ -+/** -+ * read_cache_page_gfp - read into page cache, using specified page allocation flags. -+ * @mapping: the page's address_space -+ * @index: the page index -+ * @gfp: the page allocator flags to use if allocating -+ * -+ * This is the same as "read_mapping_page(mapping, index, NULL)", but with -+ * any new page allocations done using the specified allocation flags. Note -+ * that the Radix tree operations will still use GFP_KERNEL, so you can't -+ * expect to do this atomically or anything like that - but you can pass in -+ * other page requirements. -+ * -+ * If the page does not get brought uptodate, return -EIO. -+ */ -+struct page *read_cache_page_gfp(struct address_space *mapping, -+ pgoff_t index, -+ gfp_t gfp) -+{ -+ filler_t *filler = (filler_t *)mapping->a_ops->readpage; -+ -+ return wait_on_page_read(do_read_cache_page(mapping, index, filler, NULL, gfp)); -+} -+EXPORT_SYMBOL(read_cache_page_gfp); -+ - /** - * read_cache_page - read into page cache, fill it if needed - * @mapping: the page's address_space -@@ -1750,18 +1797,7 @@ struct page *read_cache_page(struct address_space *mapping, - int (*filler)(void *,struct page*), - void *data) - { -- struct page *page; -- -- page = read_cache_page_async(mapping, index, filler, data); -- if (IS_ERR(page)) -- goto out; -- wait_on_page_locked(page); -- if (!PageUptodate(page)) { -- page_cache_release(page); -- page = ERR_PTR(-EIO); -- } -- out: -- return page; -+ return wait_on_page_read(read_cache_page_async(mapping, index, filler, data)); - } - EXPORT_SYMBOL(read_cache_page); - -@@ -2217,6 +2253,9 @@ again: - if (unlikely(status)) - break; - -+ if (mapping_writably_mapped(mapping)) -+ flush_dcache_page(page); -+ - pagefault_disable(); - copied = iov_iter_copy_from_user_atomic(page, i, offset, bytes); - pagefault_enable(); -diff --git a/mm/page_alloc.c b/mm/page_alloc.c -index 3a78e2e..36992b6 100644 ---- a/mm/page_alloc.c -+++ b/mm/page_alloc.c -@@ -559,8 +559,9 @@ static void free_pcppages_bulk(struct zone *zone, int count, - page = list_entry(list->prev, struct page, lru); - /* must delete as __free_one_page list manipulates */ - list_del(&page->lru); -- __free_one_page(page, zone, 0, migratetype); -- trace_mm_page_pcpu_drain(page, 0, migratetype); -+ /* MIGRATE_MOVABLE list may include MIGRATE_RESERVEs */ -+ __free_one_page(page, zone, 0, page_private(page)); -+ trace_mm_page_pcpu_drain(page, 0, page_private(page)); - } while (--count && --batch_free && !list_empty(list)); - } - spin_unlock(&zone->lock); -diff --git a/mm/vmalloc.c b/mm/vmalloc.c -index a3a99d3..c228731 100644 ---- a/mm/vmalloc.c -+++ b/mm/vmalloc.c -@@ -509,6 +509,9 @@ static unsigned long lazy_max_pages(void) - - static atomic_t vmap_lazy_nr = ATOMIC_INIT(0); - -+/* for per-CPU blocks */ -+static void purge_fragmented_blocks_allcpus(void); -+ - /* - * Purges all lazily-freed vmap areas. - * -@@ -539,6 +542,9 @@ static void __purge_vmap_area_lazy(unsigned long *start, unsigned long *end, - } else - spin_lock(&purge_lock); - -+ if (sync) -+ purge_fragmented_blocks_allcpus(); -+ - rcu_read_lock(); - list_for_each_entry_rcu(va, &vmap_area_list, list) { - if (va->flags & VM_LAZY_FREE) { -@@ -667,8 +673,6 @@ static bool vmap_initialized __read_mostly = false; - struct vmap_block_queue { - spinlock_t lock; - struct list_head free; -- struct list_head dirty; -- unsigned int nr_dirty; - }; - - struct vmap_block { -@@ -678,10 +682,9 @@ struct vmap_block { - unsigned long free, dirty; - DECLARE_BITMAP(alloc_map, VMAP_BBMAP_BITS); - DECLARE_BITMAP(dirty_map, VMAP_BBMAP_BITS); -- union { -- struct list_head free_list; -- struct rcu_head rcu_head; -- }; -+ struct list_head free_list; -+ struct rcu_head rcu_head; -+ struct list_head purge; - }; - - /* Queue of free and dirty vmap blocks, for allocation and flushing purposes */ -@@ -757,7 +760,7 @@ static struct vmap_block *new_vmap_block(gfp_t gfp_mask) - vbq = &get_cpu_var(vmap_block_queue); - vb->vbq = vbq; - spin_lock(&vbq->lock); -- list_add(&vb->free_list, &vbq->free); -+ list_add_rcu(&vb->free_list, &vbq->free); - spin_unlock(&vbq->lock); - put_cpu_var(vmap_cpu_blocks); - -@@ -776,8 +779,6 @@ static void free_vmap_block(struct vmap_block *vb) - struct vmap_block *tmp; - unsigned long vb_idx; - -- BUG_ON(!list_empty(&vb->free_list)); -- - vb_idx = addr_to_vb_idx(vb->va->va_start); - spin_lock(&vmap_block_tree_lock); - tmp = radix_tree_delete(&vmap_block_tree, vb_idx); -@@ -788,12 +789,61 @@ static void free_vmap_block(struct vmap_block *vb) - call_rcu(&vb->rcu_head, rcu_free_vb); - } - -+static void purge_fragmented_blocks(int cpu) -+{ -+ LIST_HEAD(purge); -+ struct vmap_block *vb; -+ struct vmap_block *n_vb; -+ struct vmap_block_queue *vbq = &per_cpu(vmap_block_queue, cpu); -+ -+ rcu_read_lock(); -+ list_for_each_entry_rcu(vb, &vbq->free, free_list) { -+ -+ if (!(vb->free + vb->dirty == VMAP_BBMAP_BITS && vb->dirty != VMAP_BBMAP_BITS)) -+ continue; -+ -+ spin_lock(&vb->lock); -+ if (vb->free + vb->dirty == VMAP_BBMAP_BITS && vb->dirty != VMAP_BBMAP_BITS) { -+ vb->free = 0; /* prevent further allocs after releasing lock */ -+ vb->dirty = VMAP_BBMAP_BITS; /* prevent purging it again */ -+ bitmap_fill(vb->alloc_map, VMAP_BBMAP_BITS); -+ bitmap_fill(vb->dirty_map, VMAP_BBMAP_BITS); -+ spin_lock(&vbq->lock); -+ list_del_rcu(&vb->free_list); -+ spin_unlock(&vbq->lock); -+ spin_unlock(&vb->lock); -+ list_add_tail(&vb->purge, &purge); -+ } else -+ spin_unlock(&vb->lock); -+ } -+ rcu_read_unlock(); -+ -+ list_for_each_entry_safe(vb, n_vb, &purge, purge) { -+ list_del(&vb->purge); -+ free_vmap_block(vb); -+ } -+} -+ -+static void purge_fragmented_blocks_thiscpu(void) -+{ -+ purge_fragmented_blocks(smp_processor_id()); -+} -+ -+static void purge_fragmented_blocks_allcpus(void) -+{ -+ int cpu; -+ -+ for_each_possible_cpu(cpu) -+ purge_fragmented_blocks(cpu); -+} -+ - static void *vb_alloc(unsigned long size, gfp_t gfp_mask) - { - struct vmap_block_queue *vbq; - struct vmap_block *vb; - unsigned long addr = 0; - unsigned int order; -+ int purge = 0; - - BUG_ON(size & ~PAGE_MASK); - BUG_ON(size > PAGE_SIZE*VMAP_MAX_ALLOC); -@@ -806,24 +856,37 @@ again: - int i; - - spin_lock(&vb->lock); -+ if (vb->free < 1UL << order) -+ goto next; - i = bitmap_find_free_region(vb->alloc_map, - VMAP_BBMAP_BITS, order); - -- if (i >= 0) { -- addr = vb->va->va_start + (i << PAGE_SHIFT); -- BUG_ON(addr_to_vb_idx(addr) != -- addr_to_vb_idx(vb->va->va_start)); -- vb->free -= 1UL << order; -- if (vb->free == 0) { -- spin_lock(&vbq->lock); -- list_del_init(&vb->free_list); -- spin_unlock(&vbq->lock); -+ if (i < 0) { -+ if (vb->free + vb->dirty == VMAP_BBMAP_BITS) { -+ /* fragmented and no outstanding allocations */ -+ BUG_ON(vb->dirty != VMAP_BBMAP_BITS); -+ purge = 1; - } -- spin_unlock(&vb->lock); -- break; -+ goto next; - } -+ addr = vb->va->va_start + (i << PAGE_SHIFT); -+ BUG_ON(addr_to_vb_idx(addr) != -+ addr_to_vb_idx(vb->va->va_start)); -+ vb->free -= 1UL << order; -+ if (vb->free == 0) { -+ spin_lock(&vbq->lock); -+ list_del_rcu(&vb->free_list); -+ spin_unlock(&vbq->lock); -+ } -+ spin_unlock(&vb->lock); -+ break; -+next: - spin_unlock(&vb->lock); - } -+ -+ if (purge) -+ purge_fragmented_blocks_thiscpu(); -+ - put_cpu_var(vmap_cpu_blocks); - rcu_read_unlock(); - -@@ -860,11 +923,11 @@ static void vb_free(const void *addr, unsigned long size) - BUG_ON(!vb); - - spin_lock(&vb->lock); -- bitmap_allocate_region(vb->dirty_map, offset >> PAGE_SHIFT, order); -+ BUG_ON(bitmap_allocate_region(vb->dirty_map, offset >> PAGE_SHIFT, order)); - - vb->dirty += 1UL << order; - if (vb->dirty == VMAP_BBMAP_BITS) { -- BUG_ON(vb->free || !list_empty(&vb->free_list)); -+ BUG_ON(vb->free); - spin_unlock(&vb->lock); - free_vmap_block(vb); - } else -@@ -1033,8 +1096,6 @@ void __init vmalloc_init(void) - vbq = &per_cpu(vmap_block_queue, i); - spin_lock_init(&vbq->lock); - INIT_LIST_HEAD(&vbq->free); -- INIT_LIST_HEAD(&vbq->dirty); -- vbq->nr_dirty = 0; - } - - /* Import existing vmlist entries. */ -diff --git a/net/ax25/ax25_out.c b/net/ax25/ax25_out.c -index bf706f8..1491260 100644 ---- a/net/ax25/ax25_out.c -+++ b/net/ax25/ax25_out.c -@@ -92,6 +92,12 @@ ax25_cb *ax25_send_frame(struct sk_buff *skb, int paclen, ax25_address *src, ax2 - #endif - } - -+ /* -+ * There is one ref for the state machine; a caller needs -+ * one more to put it back, just like with the existing one. -+ */ -+ ax25_cb_hold(ax25); -+ - ax25_cb_add(ax25); - - ax25->state = AX25_STATE_1; -diff --git a/net/core/sock.c b/net/core/sock.c -index 7626b6a..6605e75 100644 ---- a/net/core/sock.c -+++ b/net/core/sock.c -@@ -1181,6 +1181,10 @@ struct sock *sk_clone(const struct sock *sk, const gfp_t priority) - - if (newsk->sk_prot->sockets_allocated) - percpu_counter_inc(newsk->sk_prot->sockets_allocated); -+ -+ if (sock_flag(newsk, SOCK_TIMESTAMP) || -+ sock_flag(newsk, SOCK_TIMESTAMPING_RX_SOFTWARE)) -+ net_enable_timestamp(); - } - out: - return newsk; -diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c -index 5df2f6a..0030e73 100644 ---- a/net/ipv4/devinet.c -+++ b/net/ipv4/devinet.c -@@ -1450,6 +1450,7 @@ static struct devinet_sysctl_table { - DEVINET_SYSCTL_RW_ENTRY(SEND_REDIRECTS, "send_redirects"), - DEVINET_SYSCTL_RW_ENTRY(ACCEPT_SOURCE_ROUTE, - "accept_source_route"), -+ DEVINET_SYSCTL_RW_ENTRY(SRC_VMARK, "src_valid_mark"), - DEVINET_SYSCTL_RW_ENTRY(PROXY_ARP, "proxy_arp"), - DEVINET_SYSCTL_RW_ENTRY(MEDIUM_ID, "medium_id"), - DEVINET_SYSCTL_RW_ENTRY(BOOTP_RELAY, "bootp_relay"), -diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c -index aa00398..29391ee 100644 ---- a/net/ipv4/fib_frontend.c -+++ b/net/ipv4/fib_frontend.c -@@ -251,6 +251,8 @@ int fib_validate_source(__be32 src, __be32 dst, u8 tos, int oif, - if (in_dev) { - no_addr = in_dev->ifa_list == NULL; - rpf = IN_DEV_RPFILTER(in_dev); -+ if (mark && !IN_DEV_SRC_VMARK(in_dev)) -+ fl.mark = 0; - } - rcu_read_unlock(); - -diff --git a/net/mac80211/driver-trace.h b/net/mac80211/driver-trace.h -index 37b9051..d87645e 100644 ---- a/net/mac80211/driver-trace.h -+++ b/net/mac80211/driver-trace.h -@@ -655,7 +655,7 @@ TRACE_EVENT(drv_ampdu_action, - __entry->ret = ret; - __entry->action = action; - __entry->tid = tid; -- __entry->ssn = *ssn; -+ __entry->ssn = ssn ? *ssn : 0; - ), - - TP_printk( -diff --git a/net/netrom/nr_route.c b/net/netrom/nr_route.c -index 4eb1ac9..850ffc0 100644 ---- a/net/netrom/nr_route.c -+++ b/net/netrom/nr_route.c -@@ -842,12 +842,13 @@ int nr_route_frame(struct sk_buff *skb, ax25_cb *ax25) - dptr = skb_push(skb, 1); - *dptr = AX25_P_NETROM; - -- ax25s = ax25_send_frame(skb, 256, (ax25_address *)dev->dev_addr, &nr_neigh->callsign, nr_neigh->digipeat, nr_neigh->dev); -- if (nr_neigh->ax25 && ax25s) { -- /* We were already holding this ax25_cb */ -+ ax25s = nr_neigh->ax25; -+ nr_neigh->ax25 = ax25_send_frame(skb, 256, -+ (ax25_address *)dev->dev_addr, -+ &nr_neigh->callsign, -+ nr_neigh->digipeat, nr_neigh->dev); -+ if (ax25s) - ax25_cb_put(ax25s); -- } -- nr_neigh->ax25 = ax25s; - - dev_put(dev); - ret = (nr_neigh->ax25 != NULL); -diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c -index f2d116a..41866eb 100644 ---- a/net/packet/af_packet.c -+++ b/net/packet/af_packet.c -@@ -1028,8 +1028,20 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg) - - status = TP_STATUS_SEND_REQUEST; - err = dev_queue_xmit(skb); -- if (unlikely(err > 0 && (err = net_xmit_errno(err)) != 0)) -- goto out_xmit; -+ if (unlikely(err > 0)) { -+ err = net_xmit_errno(err); -+ if (err && __packet_get_status(po, ph) == -+ TP_STATUS_AVAILABLE) { -+ /* skb was destructed already */ -+ skb = NULL; -+ goto out_status; -+ } -+ /* -+ * skb was dropped but not destructed yet; -+ * let's treat it like congestion or err < 0 -+ */ -+ err = 0; -+ } - packet_increment_head(&po->tx_ring); - len_sum += tp_len; - } while (likely((ph != NULL) || ((!(msg->msg_flags & MSG_DONTWAIT)) -@@ -1039,9 +1051,6 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg) - err = len_sum; - goto out_put; - --out_xmit: -- skb->destructor = sock_wfree; -- atomic_dec(&po->tx_ring.pending); - out_status: - __packet_set_status(po, ph, status); - kfree_skb(skb); -diff --git a/net/rose/rose_link.c b/net/rose/rose_link.c -index bd86a63..5ef5f69 100644 ---- a/net/rose/rose_link.c -+++ b/net/rose/rose_link.c -@@ -101,13 +101,17 @@ static void rose_t0timer_expiry(unsigned long param) - static int rose_send_frame(struct sk_buff *skb, struct rose_neigh *neigh) - { - ax25_address *rose_call; -+ ax25_cb *ax25s; - - if (ax25cmp(&rose_callsign, &null_ax25_address) == 0) - rose_call = (ax25_address *)neigh->dev->dev_addr; - else - rose_call = &rose_callsign; - -+ ax25s = neigh->ax25; - neigh->ax25 = ax25_send_frame(skb, 260, rose_call, &neigh->callsign, neigh->digipeat, neigh->dev); -+ if (ax25s) -+ ax25_cb_put(ax25s); - - return (neigh->ax25 != NULL); - } -@@ -120,13 +124,17 @@ static int rose_send_frame(struct sk_buff *skb, struct rose_neigh *neigh) - static int rose_link_up(struct rose_neigh *neigh) - { - ax25_address *rose_call; -+ ax25_cb *ax25s; - - if (ax25cmp(&rose_callsign, &null_ax25_address) == 0) - rose_call = (ax25_address *)neigh->dev->dev_addr; - else - rose_call = &rose_callsign; - -+ ax25s = neigh->ax25; - neigh->ax25 = ax25_find_cb(rose_call, &neigh->callsign, neigh->digipeat, neigh->dev); -+ if (ax25s) -+ ax25_cb_put(ax25s); - - return (neigh->ax25 != NULL); - } -diff --git a/net/rose/rose_route.c b/net/rose/rose_route.c -index f3e2198..08230fa 100644 ---- a/net/rose/rose_route.c -+++ b/net/rose/rose_route.c -@@ -234,6 +234,8 @@ static void rose_remove_neigh(struct rose_neigh *rose_neigh) - - if ((s = rose_neigh_list) == rose_neigh) { - rose_neigh_list = rose_neigh->next; -+ if (rose_neigh->ax25) -+ ax25_cb_put(rose_neigh->ax25); - kfree(rose_neigh->digipeat); - kfree(rose_neigh); - return; -@@ -242,6 +244,8 @@ static void rose_remove_neigh(struct rose_neigh *rose_neigh) - while (s != NULL && s->next != NULL) { - if (s->next == rose_neigh) { - s->next = rose_neigh->next; -+ if (rose_neigh->ax25) -+ ax25_cb_put(rose_neigh->ax25); - kfree(rose_neigh->digipeat); - kfree(rose_neigh); - return; -@@ -810,6 +814,7 @@ void rose_link_failed(ax25_cb *ax25, int reason) - - if (rose_neigh != NULL) { - rose_neigh->ax25 = NULL; -+ ax25_cb_put(ax25); - - rose_del_route_by_neigh(rose_neigh); - rose_kill_by_neigh(rose_neigh); -diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c -index bb230d5..36d9e25 100644 ---- a/security/selinux/hooks.c -+++ b/security/selinux/hooks.c -@@ -2366,7 +2366,7 @@ static void selinux_bprm_committing_creds(struct linux_binprm *bprm) - initrlim = init_task.signal->rlim + i; - rlim->rlim_cur = min(rlim->rlim_max, initrlim->rlim_cur); - } -- update_rlimit_cpu(rlim->rlim_cur); -+ update_rlimit_cpu(current->signal->rlim[RLIMIT_CPU].rlim_cur); - } - } - diff --git a/debian/patches/bugfix/all/via-velocity-give-rx-descriptors-later.patch b/debian/patches/bugfix/all/via-velocity-give-rx-descriptors-later.patch deleted file mode 100644 index 2900b14c4..000000000 --- a/debian/patches/bugfix/all/via-velocity-give-rx-descriptors-later.patch +++ /dev/null @@ -1,35 +0,0 @@ -From: Ben Hutchings -Subject: [PATCH] via-velocity: Give RX descriptors to the NIC later on open or MTU change - -velocity_open() calls velocity_give_many_rx_descs(), which gives RX -descriptors to the NIC, before installing an interrupt handler or -calling velocity_init_registers(). I think this is very unsafe and it -appears to explain the bug report . - -On MTU change, velocity_give_many_rx_descs() is again called before -velocity_init_registers(). I'm not sure whether this is unsafe but -it does look wrong. - -Therefore, move the calls to velocity_give_many_rx_descs() after -request_irq() and velocity_init_registers(). - ---- a/drivers/net/via-velocity.c -+++ b/drivers/net/via-velocity.c -@@ -2237,8 +2237,6 @@ static int velocity_open(struct net_device *dev) - /* Ensure chip is running */ - pci_set_power_state(vptr->pdev, PCI_D0); - -- velocity_give_many_rx_descs(vptr); -- - velocity_init_registers(vptr, VELOCITY_INIT_COLD); - - ret = request_irq(vptr->pdev->irq, velocity_intr, IRQF_SHARED, -@@ -2250,6 +2248,8 @@ static int velocity_open(struct net_device *dev) - goto out; - } - -+ velocity_give_many_rx_descs(vptr); -+ - mac_enable_int(vptr->mac_regs); - netif_start_queue(dev); - napi_enable(&vptr->napi); diff --git a/debian/patches/bugfix/arm/scsi-osd-build-fix.patch b/debian/patches/bugfix/arm/scsi-osd-build-fix.patch deleted file mode 100644 index 9809a8ab7..000000000 --- a/debian/patches/bugfix/arm/scsi-osd-build-fix.patch +++ /dev/null @@ -1,26 +0,0 @@ -From: Martin Michlmayr - -include/scsi/osd_protocol.h uses ALIGN() without an #include -, leading to: -| include/scsi/osd_protocol.h:362: error: implicit declaration of function 'ALIGN' - -Signed-off-by: Martin Michlmayr -Signed-off-by: Boaz Harrosh ---- - include/scsi/osd_protocol.h | 1 + - 1 files changed, 1 insertions(+), 0 deletions(-) - -diff --git a/include/scsi/osd_protocol.h b/include/scsi/osd_protocol.h -index 2cc8e8b..6856612 100644 ---- a/include/scsi/osd_protocol.h -+++ b/include/scsi/osd_protocol.h -@@ -17,6 +17,7 @@ - #define __OSD_PROTOCOL_H__ - - #include -+#include - #include - #include - --- -1.6.5.2 diff --git a/debian/patches/bugfix/mips/drm-ttm-build-fix.patch b/debian/patches/bugfix/mips/drm-ttm-build-fix.patch deleted file mode 100644 index 2e75117c1..000000000 --- a/debian/patches/bugfix/mips/drm-ttm-build-fix.patch +++ /dev/null @@ -1,25 +0,0 @@ -drm/ttm: Fix build failure due to missing struct page - -drm/ttm fails to build on MIPS because "struct page" is not known: -| In file included from drivers/gpu/drm/ttm/ttm_memory.c:28: -| include/drm/ttm/ttm_memory.h:154: warning: 'struct page' declared inside parameter list -| include/drm/ttm/ttm_memory.h:154: warning: its scope is only this definition or declaration, which is probably not what you want -| include/drm/ttm/ttm_memory.h:156: warning: 'struct page' declared inside parameter list -| drivers/gpu/drm/ttm/ttm_memory.c:540: error: conflicting types for 'ttm_mem_global_alloc_page' -| include/drm/ttm/ttm_memory.h:154: error: previous declaration of 'ttm_mem_global_alloc_page' was here -| drivers/gpu/drm/ttm/ttm_memory.c:561: error: conflicting types for 'ttm_mem_global_free_page' -| include/drm/ttm/ttm_memory.h:156: error: previous declaration of 'ttm_mem_global_free_page' was here - -Signed-off-by: Martin Michlmayr - ---- a/include/drm/ttm/ttm_memory.h -+++ b/include/drm/ttm/ttm_memory.h -@@ -33,6 +33,7 @@ - #include - #include - #include -+#include - - /** - * struct ttm_mem_shrink - callback to shrink TTM memory usage. - diff --git a/debian/patches/debian/arch-mips-not-embedded.patch b/debian/patches/debian/arch-mips-not-embedded.patch deleted file mode 100644 index 3d515b36f..000000000 --- a/debian/patches/debian/arch-mips-not-embedded.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig -index 705a7a9..290d999 100644 ---- a/arch/mips/Kconfig -+++ b/arch/mips/Kconfig -@@ -4,8 +4,6 @@ config MIPS - select HAVE_IDE - select HAVE_OPROFILE - select HAVE_ARCH_KGDB -- # Horrible source of confusion. Die, die, die ... -- select EMBEDDED - select RTC_LIB if !LEMOTE_FULOONG2E - - mainmenu "Linux/MIPS Kernel Configuration" diff --git a/debian/patches/debian/dfsg/drivers-staging-rt2860-disable.patch b/debian/patches/debian/dfsg/drivers-staging-rt2860-disable.patch index 8885c480e..3eecd6e87 100644 --- a/debian/patches/debian/dfsg/drivers-staging-rt2860-disable.patch +++ b/debian/patches/debian/dfsg/drivers-staging-rt2860-disable.patch @@ -1,9 +1,12 @@ +diff --git a/drivers/staging/rt2860/Kconfig b/drivers/staging/rt2860/Kconfig +index f9962b6..8d2da65 100644 --- a/drivers/staging/rt2860/Kconfig +++ b/drivers/staging/rt2860/Kconfig -@@ -1,5 +1,6 @@ +@@ -1,6 +1,7 @@ config RT2860 - tristate "Ralink 2860 wireless support" -+ depends on BROKEN + tristate "Ralink 2860/3090 wireless support" depends on PCI && X86 && WLAN ++ depends on BROKEN + select WIRELESS_EXT + select WEXT_PRIV ---help--- - This is an experimental driver for the Ralink 2860 wireless chip. diff --git a/debian/patches/debian/dfsg/drivers-staging-rt2870-disable.patch b/debian/patches/debian/dfsg/drivers-staging-rt2870-disable.patch index 6e9759d10..aa4f68524 100644 --- a/debian/patches/debian/dfsg/drivers-staging-rt2870-disable.patch +++ b/debian/patches/debian/dfsg/drivers-staging-rt2870-disable.patch @@ -1,9 +1,12 @@ +diff --git a/drivers/staging/rt2870/Kconfig b/drivers/staging/rt2870/Kconfig +index fd3ba3a..ce46b49 100644 --- a/drivers/staging/rt2870/Kconfig +++ b/drivers/staging/rt2870/Kconfig -@@ -1,5 +1,6 @@ +@@ -1,6 +1,7 @@ config RT2870 tristate "Ralink 2870/3070 wireless support" -+ depends on BROKEN depends on USB && X86 && WLAN ++ depends on BROKEN + select WIRELESS_EXT + select WEXT_PRIV ---help--- - This is an experimental driver for the Ralink xx70 wireless chips. diff --git a/debian/patches/debian/dfsg/drivers-staging-rt3090-disable.patch b/debian/patches/debian/dfsg/drivers-staging-rt3090-disable.patch deleted file mode 100644 index e4a4bc261..000000000 --- a/debian/patches/debian/dfsg/drivers-staging-rt3090-disable.patch +++ /dev/null @@ -1,9 +0,0 @@ ---- a/drivers/staging/rt3090/Kconfig -+++ b/drivers/staging/rt3090/Kconfig -@@ -1,5 +1,6 @@ - config RT3090 - tristate "Ralink 3090 wireless support" -+ depends on BROKEN - depends on PCI && X86 && WLAN - ---help--- - This is an experimental driver for the Ralink 3090 wireless chip. diff --git a/debian/patches/debian/dfsg/drivers-staging-rtl8192su-disable.patch b/debian/patches/debian/dfsg/drivers-staging-rtl8192su-disable.patch index beacebb8b..e4fd5b065 100644 --- a/debian/patches/debian/dfsg/drivers-staging-rtl8192su-disable.patch +++ b/debian/patches/debian/dfsg/drivers-staging-rtl8192su-disable.patch @@ -1,9 +1,11 @@ +diff --git a/drivers/staging/rtl8192su/Kconfig b/drivers/staging/rtl8192su/Kconfig +index 123fa6d..5e081b1 100644 --- a/drivers/staging/rtl8192su/Kconfig +++ b/drivers/staging/rtl8192su/Kconfig -@@ -1,5 +1,6 @@ - config RTL8192SU +@@ -2,5 +2,6 @@ config RTL8192SU tristate "RealTek RTL8192SU Wireless LAN NIC driver" -+ depends on BROKEN - depends on PCI && WLAN + depends on PCI && WLAN && USB depends on WIRELESS_EXT ++ depends on BROKEN default N + ---help--- diff --git a/debian/patches/debian/dfsg/firmware-cleanup.patch b/debian/patches/debian/dfsg/firmware-cleanup.patch index a9c912b94..8a44a99b6 100644 --- a/debian/patches/debian/dfsg/firmware-cleanup.patch +++ b/debian/patches/debian/dfsg/firmware-cleanup.patch @@ -1,6 +1,8 @@ +diff --git a/firmware/Makefile b/firmware/Makefile +index 1c00d05..3bf888d 100644 --- a/firmware/Makefile +++ b/firmware/Makefile -@@ -20,122 +20,19 @@ fw-external-y := $(subst ",,$(CONFIG_EXTRA_FIRMWARE)) +@@ -20,53 +20,8 @@ fw-external-y := $(subst ",,$(CONFIG_EXTRA_FIRMWARE)) # accurate. In the latter case it doesn't matter -- it'll use $(fw-shipped-all). # But be aware that the config file might not be included at all. @@ -16,7 +18,7 @@ - adaptec/starfire_tx.bin fw-shipped-$(CONFIG_ATARI_DSP56K) += dsp56k/bootstrap.bin -fw-shipped-$(CONFIG_ATM_AMBASSADOR) += atmsar11.fw --fw-shipped-$(CONFIG_BNX2X) += bnx2x-e1-5.0.21.0.fw bnx2x-e1h-5.0.21.0.fw +-fw-shipped-$(CONFIG_BNX2X) += bnx2x-e1-5.2.7.0.fw bnx2x-e1h-5.2.7.0.fw -fw-shipped-$(CONFIG_BNX2) += bnx2/bnx2-mips-09-5.0.0.j3.fw \ - bnx2/bnx2-rv2p-09-5.0.0.j3.fw \ - bnx2/bnx2-rv2p-09ax-5.0.0.j3.fw \ @@ -53,10 +55,8 @@ -fw-shipped-$(CONFIG_MYRI_SBUS) += myricom/lanai.bin fw-shipped-$(CONFIG_PCMCIA_PCNET) += cis/LA-PCM.cis cis/PCMLM28.cis \ cis/DP83903.cis cis/NE2K.cis \ - cis/tamarack.cis cis/PE-200.cis - fw-shipped-$(CONFIG_PCMCIA_3C589) += cis/3CXEM556.cis - fw-shipped-$(CONFIG_PCMCIA_3C574) += cis/3CCFEM556.cis - fw-shipped-$(CONFIG_SERIAL_8250_CS) += cis/MT5634ZLX.cis cis/RS-COM-2P.cis \ + cis/tamarack.cis cis/PE-200.cis \ +@@ -77,66 +32,8 @@ fw-shipped-$(CONFIG_SERIAL_8250_CS) += cis/MT5634ZLX.cis cis/RS-COM-2P.cis \ cis/COMpad2.cis cis/COMpad4.cis \ cis/SW_555_SER.cis cis/SW_7xx_SER.cis \ cis/SW_8xx_SER.cis diff --git a/debian/patches/debian/dfsg/r8169-rtl8168d-1-2-disable.patch b/debian/patches/debian/dfsg/r8169-rtl8168d-1-2-disable.patch index 5adc0cd6c..db3856328 100644 --- a/debian/patches/debian/dfsg/r8169-rtl8168d-1-2-disable.patch +++ b/debian/patches/debian/dfsg/r8169-rtl8168d-1-2-disable.patch @@ -16,7 +16,7 @@ index fa49356..3495ff6 100644 { 0x06, 0x5561 } }; +#ifdef REMOVE_DFSG - static struct phy_reg phy_reg_init_2[] = { + static const struct phy_reg phy_reg_init_2[] = { { 0x1f, 0x0005 }, { 0x05, 0xffc2 }, @@ -2074,6 +2075,7 @@ static void rtl8168d_1_hw_phy_config(void __iomem *ioaddr) @@ -42,7 +42,7 @@ index fa49356..3495ff6 100644 { 0x06, 0x5561 } }; +#ifdef REMOVE_DFSG - static struct phy_reg phy_reg_init_1[] = { + static const struct phy_reg phy_reg_init_1[] = { { 0x1f, 0x0005 }, { 0x05, 0xffc2 }, @@ -2473,6 +2478,7 @@ static void rtl8168d_2_hw_phy_config(void __iomem *ioaddr) diff --git a/debian/patches/debian/sched-fix-conflict-between-2.6.32.7-and-vserver.patch b/debian/patches/debian/sched-fix-conflict-between-2.6.32.7-and-vserver.patch deleted file mode 100644 index 107c3865e..000000000 --- a/debian/patches/debian/sched-fix-conflict-between-2.6.32.7-and-vserver.patch +++ /dev/null @@ -1,19 +0,0 @@ -From: Ben Hutchings -Subject: [PATCH] sched: Fix conflict between 2.6.32.7 and vserver - -Make some cosmetic changes to sched.c on top of 2.6.32.7 so that -the vserver patch will still apply. - ---- a/kernel/sched.c -+++ b/kernel/sched.c -@@ -1812,8 +1813,9 @@ - } - #endif - -+static void update_sysctl(void); -+ - static void calc_load_account_active(struct rq *this_rq); --static void update_sysctl(void); - - #include "sched_stats.h" - #include "sched_idletask.c" diff --git a/debian/patches/debian/scripts-kconfig-reportoldconfig.patch b/debian/patches/debian/scripts-kconfig-reportoldconfig.patch index 6f823cd91..89185f836 100644 --- a/debian/patches/debian/scripts-kconfig-reportoldconfig.patch +++ b/debian/patches/debian/scripts-kconfig-reportoldconfig.patch @@ -1,5 +1,5 @@ diff --git a/scripts/kconfig/Makefile b/scripts/kconfig/Makefile -index fa8c2dd..7936c57 100644 +index 999e8a7..3b5d4ba 100644 --- a/scripts/kconfig/Makefile +++ b/scripts/kconfig/Makefile @@ -3,7 +3,7 @@ @@ -11,7 +11,7 @@ index fa8c2dd..7936c57 100644 ifdef KBUILD_KCONFIG Kconfig := $(KBUILD_KCONFIG) -@@ -25,9 +25,15 @@ config: $(obj)/conf +@@ -26,10 +26,16 @@ config: $(obj)/conf oldconfig: $(obj)/conf $< -o $(Kconfig) @@ -19,6 +19,7 @@ index fa8c2dd..7936c57 100644 + $< -R $(Kconfig) + silentoldconfig: $(obj)/conf + $(Q)mkdir -p include/generated $< -s $(Kconfig) +updateoldconfig: $(obj)/conf diff --git a/debian/patches/features/all/SCSI-3w-sas-Add-new-driver-for-LSI-3ware-9750.patch b/debian/patches/features/all/SCSI-3w-sas-Add-new-driver-for-LSI-3ware-9750.patch deleted file mode 100644 index 7071a301b..000000000 --- a/debian/patches/features/all/SCSI-3w-sas-Add-new-driver-for-LSI-3ware-9750.patch +++ /dev/null @@ -1,2385 +0,0 @@ -From 90f851a3806e331d295d20fd2c9cec5186077416 Mon Sep 17 00:00:00 2001 -From: adam radford -Date: Fri, 23 Oct 2009 14:52:33 -0700 -Subject: [PATCH] [SCSI] 3w-sas: Add new driver for LSI 3ware 9750 - -commit f619106bdd9d197c947f07108af57946f19a7f7e upstream - -[jejb: fix up for new queue depth code] -[bwh: undo the above] -Signed-off-by: Adam Radford -Signed-off-by: James Bottomley ---- - drivers/scsi/3w-sas.c | 1920 +++++++++++++++++++++++++++++++++++++++++++++++++ - drivers/scsi/3w-sas.h | 396 ++++++++++ - drivers/scsi/Kconfig | 11 + - drivers/scsi/Makefile | 1 + - 4 files changed, 2328 insertions(+), 0 deletions(-) - create mode 100644 drivers/scsi/3w-sas.c - create mode 100644 drivers/scsi/3w-sas.h - -diff --git a/drivers/scsi/3w-sas.c b/drivers/scsi/3w-sas.c -new file mode 100644 -index 0000000..aa5a304 ---- /dev/null -+++ b/drivers/scsi/3w-sas.c -@@ -0,0 +1,1920 @@ -+/* -+ 3w-sas.c -- LSI 3ware SAS/SATA-RAID Controller device driver for Linux. -+ -+ Written By: Adam Radford -+ -+ Copyright (C) 2009 LSI Corporation. -+ -+ This program is free software; you can redistribute it and/or modify -+ it under the terms of the GNU General Public License as published by -+ the Free Software Foundation; version 2 of the License. -+ -+ This program is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ GNU General Public License for more details. -+ -+ NO WARRANTY -+ THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR -+ CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT -+ LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, -+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is -+ solely responsible for determining the appropriateness of using and -+ distributing the Program and assumes all risks associated with its -+ exercise of rights under this Agreement, including but not limited to -+ the risks and costs of program errors, damage to or loss of data, -+ programs or equipment, and unavailability or interruption of operations. -+ -+ DISCLAIMER OF LIABILITY -+ NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY -+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -+ DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND -+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR -+ TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE -+ USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED -+ HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES -+ -+ You should have received a copy of the GNU General Public License -+ along with this program; if not, write to the Free Software -+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ -+ Controllers supported by this driver: -+ -+ LSI 3ware 9750 6Gb/s SAS/SATA-RAID -+ -+ Bugs/Comments/Suggestions should be mailed to: -+ linuxraid@lsi.com -+ -+ For more information, goto: -+ http://www.lsi.com -+ -+ History -+ ------- -+ 3.26.02.000 - Initial driver release. -+*/ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "3w-sas.h" -+ -+/* Globals */ -+#define TW_DRIVER_VERSION "3.26.02.000" -+static TW_Device_Extension *twl_device_extension_list[TW_MAX_SLOT]; -+static unsigned int twl_device_extension_count; -+static int twl_major = -1; -+extern struct timezone sys_tz; -+ -+/* Module parameters */ -+MODULE_AUTHOR ("LSI"); -+MODULE_DESCRIPTION ("LSI 3ware SAS/SATA-RAID Linux Driver"); -+MODULE_LICENSE("GPL"); -+MODULE_VERSION(TW_DRIVER_VERSION); -+ -+static int use_msi; -+module_param(use_msi, int, S_IRUGO); -+MODULE_PARM_DESC(use_msi, "Use Message Signaled Interrupts. Default: 0"); -+ -+/* Function prototypes */ -+static int twl_reset_device_extension(TW_Device_Extension *tw_dev, int ioctl_reset); -+ -+/* Functions */ -+ -+/* This function returns AENs through sysfs */ -+static ssize_t twl_sysfs_aen_read(struct kobject *kobj, -+ struct bin_attribute *bin_attr, -+ char *outbuf, loff_t offset, size_t count) -+{ -+ struct device *dev = container_of(kobj, struct device, kobj); -+ struct Scsi_Host *shost = class_to_shost(dev); -+ TW_Device_Extension *tw_dev = (TW_Device_Extension *)shost->hostdata; -+ unsigned long flags = 0; -+ ssize_t ret; -+ -+ if (!capable(CAP_SYS_ADMIN)) -+ return -EACCES; -+ -+ spin_lock_irqsave(tw_dev->host->host_lock, flags); -+ ret = memory_read_from_buffer(outbuf, count, &offset, tw_dev->event_queue[0], sizeof(TW_Event) * TW_Q_LENGTH); -+ spin_unlock_irqrestore(tw_dev->host->host_lock, flags); -+ -+ return ret; -+} /* End twl_sysfs_aen_read() */ -+ -+/* aen_read sysfs attribute initializer */ -+static struct bin_attribute twl_sysfs_aen_read_attr = { -+ .attr = { -+ .name = "3ware_aen_read", -+ .mode = S_IRUSR, -+ }, -+ .size = 0, -+ .read = twl_sysfs_aen_read -+}; -+ -+/* This function returns driver compatibility info through sysfs */ -+static ssize_t twl_sysfs_compat_info(struct kobject *kobj, -+ struct bin_attribute *bin_attr, -+ char *outbuf, loff_t offset, size_t count) -+{ -+ struct device *dev = container_of(kobj, struct device, kobj); -+ struct Scsi_Host *shost = class_to_shost(dev); -+ TW_Device_Extension *tw_dev = (TW_Device_Extension *)shost->hostdata; -+ unsigned long flags = 0; -+ ssize_t ret; -+ -+ if (!capable(CAP_SYS_ADMIN)) -+ return -EACCES; -+ -+ spin_lock_irqsave(tw_dev->host->host_lock, flags); -+ ret = memory_read_from_buffer(outbuf, count, &offset, &tw_dev->tw_compat_info, sizeof(TW_Compatibility_Info)); -+ spin_unlock_irqrestore(tw_dev->host->host_lock, flags); -+ -+ return ret; -+} /* End twl_sysfs_compat_info() */ -+ -+/* compat_info sysfs attribute initializer */ -+static struct bin_attribute twl_sysfs_compat_info_attr = { -+ .attr = { -+ .name = "3ware_compat_info", -+ .mode = S_IRUSR, -+ }, -+ .size = 0, -+ .read = twl_sysfs_compat_info -+}; -+ -+/* Show some statistics about the card */ -+static ssize_t twl_show_stats(struct device *dev, -+ struct device_attribute *attr, char *buf) -+{ -+ struct Scsi_Host *host = class_to_shost(dev); -+ TW_Device_Extension *tw_dev = (TW_Device_Extension *)host->hostdata; -+ unsigned long flags = 0; -+ ssize_t len; -+ -+ spin_lock_irqsave(tw_dev->host->host_lock, flags); -+ len = snprintf(buf, PAGE_SIZE, "3w-sas Driver version: %s\n" -+ "Current commands posted: %4d\n" -+ "Max commands posted: %4d\n" -+ "Last sgl length: %4d\n" -+ "Max sgl length: %4d\n" -+ "Last sector count: %4d\n" -+ "Max sector count: %4d\n" -+ "SCSI Host Resets: %4d\n" -+ "AEN's: %4d\n", -+ TW_DRIVER_VERSION, -+ tw_dev->posted_request_count, -+ tw_dev->max_posted_request_count, -+ tw_dev->sgl_entries, -+ tw_dev->max_sgl_entries, -+ tw_dev->sector_count, -+ tw_dev->max_sector_count, -+ tw_dev->num_resets, -+ tw_dev->aen_count); -+ spin_unlock_irqrestore(tw_dev->host->host_lock, flags); -+ return len; -+} /* End twl_show_stats() */ -+ -+/* This function will set a devices queue depth */ -+static int twl_change_queue_depth(struct scsi_device *sdev, int queue_depth) -+{ -+ if (queue_depth > TW_Q_LENGTH-2) -+ queue_depth = TW_Q_LENGTH-2; -+ scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, queue_depth); -+ return queue_depth; -+} /* End twl_change_queue_depth() */ -+ -+/* stats sysfs attribute initializer */ -+static struct device_attribute twl_host_stats_attr = { -+ .attr = { -+ .name = "3ware_stats", -+ .mode = S_IRUGO, -+ }, -+ .show = twl_show_stats -+}; -+ -+/* Host attributes initializer */ -+static struct device_attribute *twl_host_attrs[] = { -+ &twl_host_stats_attr, -+ NULL, -+}; -+ -+/* This function will look up an AEN severity string */ -+static char *twl_aen_severity_lookup(unsigned char severity_code) -+{ -+ char *retval = NULL; -+ -+ if ((severity_code < (unsigned char) TW_AEN_SEVERITY_ERROR) || -+ (severity_code > (unsigned char) TW_AEN_SEVERITY_DEBUG)) -+ goto out; -+ -+ retval = twl_aen_severity_table[severity_code]; -+out: -+ return retval; -+} /* End twl_aen_severity_lookup() */ -+ -+/* This function will queue an event */ -+static void twl_aen_queue_event(TW_Device_Extension *tw_dev, TW_Command_Apache_Header *header) -+{ -+ u32 local_time; -+ struct timeval time; -+ TW_Event *event; -+ unsigned short aen; -+ char host[16]; -+ char *error_str; -+ -+ tw_dev->aen_count++; -+ -+ /* Fill out event info */ -+ event = tw_dev->event_queue[tw_dev->error_index]; -+ -+ host[0] = '\0'; -+ if (tw_dev->host) -+ sprintf(host, " scsi%d:", tw_dev->host->host_no); -+ -+ aen = le16_to_cpu(header->status_block.error); -+ memset(event, 0, sizeof(TW_Event)); -+ -+ event->severity = TW_SEV_OUT(header->status_block.severity__reserved); -+ do_gettimeofday(&time); -+ local_time = (u32)(time.tv_sec - (sys_tz.tz_minuteswest * 60)); -+ event->time_stamp_sec = local_time; -+ event->aen_code = aen; -+ event->retrieved = TW_AEN_NOT_RETRIEVED; -+ event->sequence_id = tw_dev->error_sequence_id; -+ tw_dev->error_sequence_id++; -+ -+ /* Check for embedded error string */ -+ error_str = &(header->err_specific_desc[strlen(header->err_specific_desc)+1]); -+ -+ header->err_specific_desc[sizeof(header->err_specific_desc) - 1] = '\0'; -+ event->parameter_len = strlen(header->err_specific_desc); -+ memcpy(event->parameter_data, header->err_specific_desc, event->parameter_len + 1 + strlen(error_str)); -+ if (event->severity != TW_AEN_SEVERITY_DEBUG) -+ printk(KERN_WARNING "3w-sas:%s AEN: %s (0x%02X:0x%04X): %s:%s.\n", -+ host, -+ twl_aen_severity_lookup(TW_SEV_OUT(header->status_block.severity__reserved)), -+ TW_MESSAGE_SOURCE_CONTROLLER_EVENT, aen, error_str, -+ header->err_specific_desc); -+ else -+ tw_dev->aen_count--; -+ -+ tw_dev->error_index = (tw_dev->error_index + 1 ) % TW_Q_LENGTH; -+} /* End twl_aen_queue_event() */ -+ -+/* This function will attempt to post a command packet to the board */ -+static int twl_post_command_packet(TW_Device_Extension *tw_dev, int request_id) -+{ -+ dma_addr_t command_que_value; -+ -+ command_que_value = tw_dev->command_packet_phys[request_id]; -+ command_que_value += TW_COMMAND_OFFSET; -+ -+ /* First write upper 4 bytes */ -+ writel((u32)((u64)command_que_value >> 32), TWL_HIBQPH_REG_ADDR(tw_dev)); -+ /* Then the lower 4 bytes */ -+ writel((u32)(command_que_value | TWL_PULL_MODE), TWL_HIBQPL_REG_ADDR(tw_dev)); -+ -+ tw_dev->state[request_id] = TW_S_POSTED; -+ tw_dev->posted_request_count++; -+ if (tw_dev->posted_request_count > tw_dev->max_posted_request_count) -+ tw_dev->max_posted_request_count = tw_dev->posted_request_count; -+ -+ return 0; -+} /* End twl_post_command_packet() */ -+ -+/* This function will perform a pci-dma mapping for a scatter gather list */ -+static int twl_map_scsi_sg_data(TW_Device_Extension *tw_dev, int request_id) -+{ -+ int use_sg; -+ struct scsi_cmnd *cmd = tw_dev->srb[request_id]; -+ -+ use_sg = scsi_dma_map(cmd); -+ if (!use_sg) -+ return 0; -+ else if (use_sg < 0) { -+ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1, "Failed to map scatter gather list"); -+ return 0; -+ } -+ -+ cmd->SCp.phase = TW_PHASE_SGLIST; -+ cmd->SCp.have_data_in = use_sg; -+ -+ return use_sg; -+} /* End twl_map_scsi_sg_data() */ -+ -+/* This function hands scsi cdb's to the firmware */ -+static int twl_scsiop_execute_scsi(TW_Device_Extension *tw_dev, int request_id, char *cdb, int use_sg, TW_SG_Entry_ISO *sglistarg) -+{ -+ TW_Command_Full *full_command_packet; -+ TW_Command_Apache *command_packet; -+ int i, sg_count; -+ struct scsi_cmnd *srb = NULL; -+ struct scatterlist *sglist = NULL, *sg; -+ int retval = 1; -+ -+ if (tw_dev->srb[request_id]) { -+ srb = tw_dev->srb[request_id]; -+ if (scsi_sglist(srb)) -+ sglist = scsi_sglist(srb); -+ } -+ -+ /* Initialize command packet */ -+ full_command_packet = tw_dev->command_packet_virt[request_id]; -+ full_command_packet->header.header_desc.size_header = 128; -+ full_command_packet->header.status_block.error = 0; -+ full_command_packet->header.status_block.severity__reserved = 0; -+ -+ command_packet = &full_command_packet->command.newcommand; -+ command_packet->status = 0; -+ command_packet->opcode__reserved = TW_OPRES_IN(0, TW_OP_EXECUTE_SCSI); -+ -+ /* We forced 16 byte cdb use earlier */ -+ if (!cdb) -+ memcpy(command_packet->cdb, srb->cmnd, TW_MAX_CDB_LEN); -+ else -+ memcpy(command_packet->cdb, cdb, TW_MAX_CDB_LEN); -+ -+ if (srb) { -+ command_packet->unit = srb->device->id; -+ command_packet->request_id__lunl = -+ cpu_to_le16(TW_REQ_LUN_IN(srb->device->lun, request_id)); -+ } else { -+ command_packet->request_id__lunl = -+ cpu_to_le16(TW_REQ_LUN_IN(0, request_id)); -+ command_packet->unit = 0; -+ } -+ -+ command_packet->sgl_offset = 16; -+ -+ if (!sglistarg) { -+ /* Map sglist from scsi layer to cmd packet */ -+ if (scsi_sg_count(srb)) { -+ sg_count = twl_map_scsi_sg_data(tw_dev, request_id); -+ if (sg_count == 0) -+ goto out; -+ -+ scsi_for_each_sg(srb, sg, sg_count, i) { -+ command_packet->sg_list[i].address = TW_CPU_TO_SGL(sg_dma_address(sg)); -+ command_packet->sg_list[i].length = TW_CPU_TO_SGL(sg_dma_len(sg)); -+ } -+ command_packet->sgl_entries__lunh = cpu_to_le16(TW_REQ_LUN_IN((srb->device->lun >> 4), scsi_sg_count(tw_dev->srb[request_id]))); -+ } -+ } else { -+ /* Internal cdb post */ -+ for (i = 0; i < use_sg; i++) { -+ command_packet->sg_list[i].address = TW_CPU_TO_SGL(sglistarg[i].address); -+ command_packet->sg_list[i].length = TW_CPU_TO_SGL(sglistarg[i].length); -+ } -+ command_packet->sgl_entries__lunh = cpu_to_le16(TW_REQ_LUN_IN(0, use_sg)); -+ } -+ -+ /* Update some stats */ -+ if (srb) { -+ tw_dev->sector_count = scsi_bufflen(srb) / 512; -+ if (tw_dev->sector_count > tw_dev->max_sector_count) -+ tw_dev->max_sector_count = tw_dev->sector_count; -+ tw_dev->sgl_entries = scsi_sg_count(srb); -+ if (tw_dev->sgl_entries > tw_dev->max_sgl_entries) -+ tw_dev->max_sgl_entries = tw_dev->sgl_entries; -+ } -+ -+ /* Now post the command to the board */ -+ retval = twl_post_command_packet(tw_dev, request_id); -+ -+out: -+ return retval; -+} /* End twl_scsiop_execute_scsi() */ -+ -+/* This function will read the aen queue from the isr */ -+static int twl_aen_read_queue(TW_Device_Extension *tw_dev, int request_id) -+{ -+ char cdb[TW_MAX_CDB_LEN]; -+ TW_SG_Entry_ISO sglist[1]; -+ TW_Command_Full *full_command_packet; -+ int retval = 1; -+ -+ full_command_packet = tw_dev->command_packet_virt[request_id]; -+ memset(full_command_packet, 0, sizeof(TW_Command_Full)); -+ -+ /* Initialize cdb */ -+ memset(&cdb, 0, TW_MAX_CDB_LEN); -+ cdb[0] = REQUEST_SENSE; /* opcode */ -+ cdb[4] = TW_ALLOCATION_LENGTH; /* allocation length */ -+ -+ /* Initialize sglist */ -+ memset(&sglist, 0, sizeof(TW_SG_Entry_ISO)); -+ sglist[0].length = TW_SECTOR_SIZE; -+ sglist[0].address = tw_dev->generic_buffer_phys[request_id]; -+ -+ /* Mark internal command */ -+ tw_dev->srb[request_id] = NULL; -+ -+ /* Now post the command packet */ -+ if (twl_scsiop_execute_scsi(tw_dev, request_id, cdb, 1, sglist)) { -+ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x2, "Post failed while reading AEN queue"); -+ goto out; -+ } -+ retval = 0; -+out: -+ return retval; -+} /* End twl_aen_read_queue() */ -+ -+/* This function will sync firmware time with the host time */ -+static void twl_aen_sync_time(TW_Device_Extension *tw_dev, int request_id) -+{ -+ u32 schedulertime; -+ struct timeval utc; -+ TW_Command_Full *full_command_packet; -+ TW_Command *command_packet; -+ TW_Param_Apache *param; -+ u32 local_time; -+ -+ /* Fill out the command packet */ -+ full_command_packet = tw_dev->command_packet_virt[request_id]; -+ memset(full_command_packet, 0, sizeof(TW_Command_Full)); -+ command_packet = &full_command_packet->command.oldcommand; -+ command_packet->opcode__sgloffset = TW_OPSGL_IN(2, TW_OP_SET_PARAM); -+ command_packet->request_id = request_id; -+ command_packet->byte8_offset.param.sgl[0].address = TW_CPU_TO_SGL(tw_dev->generic_buffer_phys[request_id]); -+ command_packet->byte8_offset.param.sgl[0].length = TW_CPU_TO_SGL(TW_SECTOR_SIZE); -+ command_packet->size = TW_COMMAND_SIZE; -+ command_packet->byte6_offset.parameter_count = cpu_to_le16(1); -+ -+ /* Setup the param */ -+ param = (TW_Param_Apache *)tw_dev->generic_buffer_virt[request_id]; -+ memset(param, 0, TW_SECTOR_SIZE); -+ param->table_id = cpu_to_le16(TW_TIMEKEEP_TABLE | 0x8000); /* Controller time keep table */ -+ param->parameter_id = cpu_to_le16(0x3); /* SchedulerTime */ -+ param->parameter_size_bytes = cpu_to_le16(4); -+ -+ /* Convert system time in UTC to local time seconds since last -+ Sunday 12:00AM */ -+ do_gettimeofday(&utc); -+ local_time = (u32)(utc.tv_sec - (sys_tz.tz_minuteswest * 60)); -+ schedulertime = local_time - (3 * 86400); -+ schedulertime = cpu_to_le32(schedulertime % 604800); -+ -+ memcpy(param->data, &schedulertime, sizeof(u32)); -+ -+ /* Mark internal command */ -+ tw_dev->srb[request_id] = NULL; -+ -+ /* Now post the command */ -+ twl_post_command_packet(tw_dev, request_id); -+} /* End twl_aen_sync_time() */ -+ -+/* This function will assign an available request id */ -+static void twl_get_request_id(TW_Device_Extension *tw_dev, int *request_id) -+{ -+ *request_id = tw_dev->free_queue[tw_dev->free_head]; -+ tw_dev->free_head = (tw_dev->free_head + 1) % TW_Q_LENGTH; -+ tw_dev->state[*request_id] = TW_S_STARTED; -+} /* End twl_get_request_id() */ -+ -+/* This function will free a request id */ -+static void twl_free_request_id(TW_Device_Extension *tw_dev, int request_id) -+{ -+ tw_dev->free_queue[tw_dev->free_tail] = request_id; -+ tw_dev->state[request_id] = TW_S_FINISHED; -+ tw_dev->free_tail = (tw_dev->free_tail + 1) % TW_Q_LENGTH; -+} /* End twl_free_request_id() */ -+ -+/* This function will complete an aen request from the isr */ -+static int twl_aen_complete(TW_Device_Extension *tw_dev, int request_id) -+{ -+ TW_Command_Full *full_command_packet; -+ TW_Command *command_packet; -+ TW_Command_Apache_Header *header; -+ unsigned short aen; -+ int retval = 1; -+ -+ header = (TW_Command_Apache_Header *)tw_dev->generic_buffer_virt[request_id]; -+ tw_dev->posted_request_count--; -+ aen = le16_to_cpu(header->status_block.error); -+ full_command_packet = tw_dev->command_packet_virt[request_id]; -+ command_packet = &full_command_packet->command.oldcommand; -+ -+ /* First check for internal completion of set param for time sync */ -+ if (TW_OP_OUT(command_packet->opcode__sgloffset) == TW_OP_SET_PARAM) { -+ /* Keep reading the queue in case there are more aen's */ -+ if (twl_aen_read_queue(tw_dev, request_id)) -+ goto out2; -+ else { -+ retval = 0; -+ goto out; -+ } -+ } -+ -+ switch (aen) { -+ case TW_AEN_QUEUE_EMPTY: -+ /* Quit reading the queue if this is the last one */ -+ break; -+ case TW_AEN_SYNC_TIME_WITH_HOST: -+ twl_aen_sync_time(tw_dev, request_id); -+ retval = 0; -+ goto out; -+ default: -+ twl_aen_queue_event(tw_dev, header); -+ -+ /* If there are more aen's, keep reading the queue */ -+ if (twl_aen_read_queue(tw_dev, request_id)) -+ goto out2; -+ else { -+ retval = 0; -+ goto out; -+ } -+ } -+ retval = 0; -+out2: -+ tw_dev->state[request_id] = TW_S_COMPLETED; -+ twl_free_request_id(tw_dev, request_id); -+ clear_bit(TW_IN_ATTENTION_LOOP, &tw_dev->flags); -+out: -+ return retval; -+} /* End twl_aen_complete() */ -+ -+/* This function will poll for a response */ -+static int twl_poll_response(TW_Device_Extension *tw_dev, int request_id, int seconds) -+{ -+ unsigned long before; -+ dma_addr_t mfa; -+ u32 regh, regl; -+ u32 response; -+ int retval = 1; -+ int found = 0; -+ -+ before = jiffies; -+ -+ while (!found) { -+ if (sizeof(dma_addr_t) > 4) { -+ regh = readl(TWL_HOBQPH_REG_ADDR(tw_dev)); -+ regl = readl(TWL_HOBQPL_REG_ADDR(tw_dev)); -+ mfa = ((u64)regh << 32) | regl; -+ } else -+ mfa = readl(TWL_HOBQPL_REG_ADDR(tw_dev)); -+ -+ response = (u32)mfa; -+ -+ if (TW_RESID_OUT(response) == request_id) -+ found = 1; -+ -+ if (time_after(jiffies, before + HZ * seconds)) -+ goto out; -+ -+ msleep(50); -+ } -+ retval = 0; -+out: -+ return retval; -+} /* End twl_poll_response() */ -+ -+/* This function will drain the aen queue */ -+static int twl_aen_drain_queue(TW_Device_Extension *tw_dev, int no_check_reset) -+{ -+ int request_id = 0; -+ char cdb[TW_MAX_CDB_LEN]; -+ TW_SG_Entry_ISO sglist[1]; -+ int finished = 0, count = 0; -+ TW_Command_Full *full_command_packet; -+ TW_Command_Apache_Header *header; -+ unsigned short aen; -+ int first_reset = 0, queue = 0, retval = 1; -+ -+ if (no_check_reset) -+ first_reset = 0; -+ else -+ first_reset = 1; -+ -+ full_command_packet = tw_dev->command_packet_virt[request_id]; -+ memset(full_command_packet, 0, sizeof(TW_Command_Full)); -+ -+ /* Initialize cdb */ -+ memset(&cdb, 0, TW_MAX_CDB_LEN); -+ cdb[0] = REQUEST_SENSE; /* opcode */ -+ cdb[4] = TW_ALLOCATION_LENGTH; /* allocation length */ -+ -+ /* Initialize sglist */ -+ memset(&sglist, 0, sizeof(TW_SG_Entry_ISO)); -+ sglist[0].length = TW_SECTOR_SIZE; -+ sglist[0].address = tw_dev->generic_buffer_phys[request_id]; -+ -+ /* Mark internal command */ -+ tw_dev->srb[request_id] = NULL; -+ -+ do { -+ /* Send command to the board */ -+ if (twl_scsiop_execute_scsi(tw_dev, request_id, cdb, 1, sglist)) { -+ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x3, "Error posting request sense"); -+ goto out; -+ } -+ -+ /* Now poll for completion */ -+ if (twl_poll_response(tw_dev, request_id, 30)) { -+ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x4, "No valid response while draining AEN queue"); -+ tw_dev->posted_request_count--; -+ goto out; -+ } -+ -+ tw_dev->posted_request_count--; -+ header = (TW_Command_Apache_Header *)tw_dev->generic_buffer_virt[request_id]; -+ aen = le16_to_cpu(header->status_block.error); -+ queue = 0; -+ count++; -+ -+ switch (aen) { -+ case TW_AEN_QUEUE_EMPTY: -+ if (first_reset != 1) -+ goto out; -+ else -+ finished = 1; -+ break; -+ case TW_AEN_SOFT_RESET: -+ if (first_reset == 0) -+ first_reset = 1; -+ else -+ queue = 1; -+ break; -+ case TW_AEN_SYNC_TIME_WITH_HOST: -+ break; -+ default: -+ queue = 1; -+ } -+ -+ /* Now queue an event info */ -+ if (queue) -+ twl_aen_queue_event(tw_dev, header); -+ } while ((finished == 0) && (count < TW_MAX_AEN_DRAIN)); -+ -+ if (count == TW_MAX_AEN_DRAIN) -+ goto out; -+ -+ retval = 0; -+out: -+ tw_dev->state[request_id] = TW_S_INITIAL; -+ return retval; -+} /* End twl_aen_drain_queue() */ -+ -+/* This function will allocate memory and check if it is correctly aligned */ -+static int twl_allocate_memory(TW_Device_Extension *tw_dev, int size, int which) -+{ -+ int i; -+ dma_addr_t dma_handle; -+ unsigned long *cpu_addr; -+ int retval = 1; -+ -+ cpu_addr = pci_alloc_consistent(tw_dev->tw_pci_dev, size*TW_Q_LENGTH, &dma_handle); -+ if (!cpu_addr) { -+ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x5, "Memory allocation failed"); -+ goto out; -+ } -+ -+ memset(cpu_addr, 0, size*TW_Q_LENGTH); -+ -+ for (i = 0; i < TW_Q_LENGTH; i++) { -+ switch(which) { -+ case 0: -+ tw_dev->command_packet_phys[i] = dma_handle+(i*size); -+ tw_dev->command_packet_virt[i] = (TW_Command_Full *)((unsigned char *)cpu_addr + (i*size)); -+ break; -+ case 1: -+ tw_dev->generic_buffer_phys[i] = dma_handle+(i*size); -+ tw_dev->generic_buffer_virt[i] = (unsigned long *)((unsigned char *)cpu_addr + (i*size)); -+ break; -+ case 2: -+ tw_dev->sense_buffer_phys[i] = dma_handle+(i*size); -+ tw_dev->sense_buffer_virt[i] = (TW_Command_Apache_Header *)((unsigned char *)cpu_addr + (i*size)); -+ break; -+ } -+ } -+ retval = 0; -+out: -+ return retval; -+} /* End twl_allocate_memory() */ -+ -+/* This function will load the request id and various sgls for ioctls */ -+static void twl_load_sgl(TW_Device_Extension *tw_dev, TW_Command_Full *full_command_packet, int request_id, dma_addr_t dma_handle, int length) -+{ -+ TW_Command *oldcommand; -+ TW_Command_Apache *newcommand; -+ TW_SG_Entry_ISO *sgl; -+ unsigned int pae = 0; -+ -+ if ((sizeof(long) < 8) && (sizeof(dma_addr_t) > 4)) -+ pae = 1; -+ -+ if (TW_OP_OUT(full_command_packet->command.newcommand.opcode__reserved) == TW_OP_EXECUTE_SCSI) { -+ newcommand = &full_command_packet->command.newcommand; -+ newcommand->request_id__lunl = -+ cpu_to_le16(TW_REQ_LUN_IN(TW_LUN_OUT(newcommand->request_id__lunl), request_id)); -+ if (length) { -+ newcommand->sg_list[0].address = TW_CPU_TO_SGL(dma_handle + sizeof(TW_Ioctl_Buf_Apache) - 1); -+ newcommand->sg_list[0].length = TW_CPU_TO_SGL(length); -+ } -+ newcommand->sgl_entries__lunh = -+ cpu_to_le16(TW_REQ_LUN_IN(TW_LUN_OUT(newcommand->sgl_entries__lunh), length ? 1 : 0)); -+ } else { -+ oldcommand = &full_command_packet->command.oldcommand; -+ oldcommand->request_id = request_id; -+ -+ if (TW_SGL_OUT(oldcommand->opcode__sgloffset)) { -+ /* Load the sg list */ -+ sgl = (TW_SG_Entry_ISO *)((u32 *)oldcommand+oldcommand->size - (sizeof(TW_SG_Entry_ISO)/4) + pae + (sizeof(dma_addr_t) > 4 ? 1 : 0)); -+ sgl->address = TW_CPU_TO_SGL(dma_handle + sizeof(TW_Ioctl_Buf_Apache) - 1); -+ sgl->length = TW_CPU_TO_SGL(length); -+ oldcommand->size += pae; -+ oldcommand->size += sizeof(dma_addr_t) > 4 ? 1 : 0; -+ } -+ } -+} /* End twl_load_sgl() */ -+ -+/* This function handles ioctl for the character device -+ This interface is used by smartmontools open source software */ -+static int twl_chrdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) -+{ -+ long timeout; -+ unsigned long *cpu_addr, data_buffer_length_adjusted = 0, flags = 0; -+ dma_addr_t dma_handle; -+ int request_id = 0; -+ TW_Ioctl_Driver_Command driver_command; -+ TW_Ioctl_Buf_Apache *tw_ioctl; -+ TW_Command_Full *full_command_packet; -+ TW_Device_Extension *tw_dev = twl_device_extension_list[iminor(inode)]; -+ int retval = -EFAULT; -+ void __user *argp = (void __user *)arg; -+ -+ /* Only let one of these through at a time */ -+ if (mutex_lock_interruptible(&tw_dev->ioctl_lock)) { -+ retval = -EINTR; -+ goto out; -+ } -+ -+ /* First copy down the driver command */ -+ if (copy_from_user(&driver_command, argp, sizeof(TW_Ioctl_Driver_Command))) -+ goto out2; -+ -+ /* Check data buffer size */ -+ if (driver_command.buffer_length > TW_MAX_SECTORS * 2048) { -+ retval = -EINVAL; -+ goto out2; -+ } -+ -+ /* Hardware can only do multiple of 512 byte transfers */ -+ data_buffer_length_adjusted = (driver_command.buffer_length + 511) & ~511; -+ -+ /* Now allocate ioctl buf memory */ -+ cpu_addr = dma_alloc_coherent(&tw_dev->tw_pci_dev->dev, data_buffer_length_adjusted+sizeof(TW_Ioctl_Buf_Apache) - 1, &dma_handle, GFP_KERNEL); -+ if (!cpu_addr) { -+ retval = -ENOMEM; -+ goto out2; -+ } -+ -+ tw_ioctl = (TW_Ioctl_Buf_Apache *)cpu_addr; -+ -+ /* Now copy down the entire ioctl */ -+ if (copy_from_user(tw_ioctl, argp, driver_command.buffer_length + sizeof(TW_Ioctl_Buf_Apache) - 1)) -+ goto out3; -+ -+ /* See which ioctl we are doing */ -+ switch (cmd) { -+ case TW_IOCTL_FIRMWARE_PASS_THROUGH: -+ spin_lock_irqsave(tw_dev->host->host_lock, flags); -+ twl_get_request_id(tw_dev, &request_id); -+ -+ /* Flag internal command */ -+ tw_dev->srb[request_id] = NULL; -+ -+ /* Flag chrdev ioctl */ -+ tw_dev->chrdev_request_id = request_id; -+ -+ full_command_packet = (TW_Command_Full *)&tw_ioctl->firmware_command; -+ -+ /* Load request id and sglist for both command types */ -+ twl_load_sgl(tw_dev, full_command_packet, request_id, dma_handle, data_buffer_length_adjusted); -+ -+ memcpy(tw_dev->command_packet_virt[request_id], &(tw_ioctl->firmware_command), sizeof(TW_Command_Full)); -+ -+ /* Now post the command packet to the controller */ -+ twl_post_command_packet(tw_dev, request_id); -+ spin_unlock_irqrestore(tw_dev->host->host_lock, flags); -+ -+ timeout = TW_IOCTL_CHRDEV_TIMEOUT*HZ; -+ -+ /* Now wait for command to complete */ -+ timeout = wait_event_timeout(tw_dev->ioctl_wqueue, tw_dev->chrdev_request_id == TW_IOCTL_CHRDEV_FREE, timeout); -+ -+ /* We timed out, and didn't get an interrupt */ -+ if (tw_dev->chrdev_request_id != TW_IOCTL_CHRDEV_FREE) { -+ /* Now we need to reset the board */ -+ printk(KERN_WARNING "3w-sas: scsi%d: WARNING: (0x%02X:0x%04X): Character ioctl (0x%x) timed out, resetting card.\n", -+ tw_dev->host->host_no, TW_DRIVER, 0x6, -+ cmd); -+ retval = -EIO; -+ twl_reset_device_extension(tw_dev, 1); -+ goto out3; -+ } -+ -+ /* Now copy in the command packet response */ -+ memcpy(&(tw_ioctl->firmware_command), tw_dev->command_packet_virt[request_id], sizeof(TW_Command_Full)); -+ -+ /* Now complete the io */ -+ spin_lock_irqsave(tw_dev->host->host_lock, flags); -+ tw_dev->posted_request_count--; -+ tw_dev->state[request_id] = TW_S_COMPLETED; -+ twl_free_request_id(tw_dev, request_id); -+ spin_unlock_irqrestore(tw_dev->host->host_lock, flags); -+ break; -+ default: -+ retval = -ENOTTY; -+ goto out3; -+ } -+ -+ /* Now copy the entire response to userspace */ -+ if (copy_to_user(argp, tw_ioctl, sizeof(TW_Ioctl_Buf_Apache) + driver_command.buffer_length - 1) == 0) -+ retval = 0; -+out3: -+ /* Now free ioctl buf memory */ -+ dma_free_coherent(&tw_dev->tw_pci_dev->dev, data_buffer_length_adjusted+sizeof(TW_Ioctl_Buf_Apache) - 1, cpu_addr, dma_handle); -+out2: -+ mutex_unlock(&tw_dev->ioctl_lock); -+out: -+ return retval; -+} /* End twl_chrdev_ioctl() */ -+ -+/* This function handles open for the character device */ -+static int twl_chrdev_open(struct inode *inode, struct file *file) -+{ -+ unsigned int minor_number; -+ int retval = -ENODEV; -+ -+ if (!capable(CAP_SYS_ADMIN)) { -+ retval = -EACCES; -+ goto out; -+ } -+ -+ cycle_kernel_lock(); -+ minor_number = iminor(inode); -+ if (minor_number >= twl_device_extension_count) -+ goto out; -+ retval = 0; -+out: -+ return retval; -+} /* End twl_chrdev_open() */ -+ -+/* File operations struct for character device */ -+static const struct file_operations twl_fops = { -+ .owner = THIS_MODULE, -+ .ioctl = twl_chrdev_ioctl, -+ .open = twl_chrdev_open, -+ .release = NULL -+}; -+ -+/* This function passes sense data from firmware to scsi layer */ -+static int twl_fill_sense(TW_Device_Extension *tw_dev, int i, int request_id, int copy_sense, int print_host) -+{ -+ TW_Command_Apache_Header *header; -+ TW_Command_Full *full_command_packet; -+ unsigned short error; -+ char *error_str; -+ int retval = 1; -+ -+ header = tw_dev->sense_buffer_virt[i]; -+ full_command_packet = tw_dev->command_packet_virt[request_id]; -+ -+ /* Get embedded firmware error string */ -+ error_str = &(header->err_specific_desc[strlen(header->err_specific_desc) + 1]); -+ -+ /* Don't print error for Logical unit not supported during rollcall */ -+ error = le16_to_cpu(header->status_block.error); -+ if ((error != TW_ERROR_LOGICAL_UNIT_NOT_SUPPORTED) && (error != TW_ERROR_UNIT_OFFLINE) && (error != TW_ERROR_INVALID_FIELD_IN_CDB)) { -+ if (print_host) -+ printk(KERN_WARNING "3w-sas: scsi%d: ERROR: (0x%02X:0x%04X): %s:%s.\n", -+ tw_dev->host->host_no, -+ TW_MESSAGE_SOURCE_CONTROLLER_ERROR, -+ header->status_block.error, -+ error_str, -+ header->err_specific_desc); -+ else -+ printk(KERN_WARNING "3w-sas: ERROR: (0x%02X:0x%04X): %s:%s.\n", -+ TW_MESSAGE_SOURCE_CONTROLLER_ERROR, -+ header->status_block.error, -+ error_str, -+ header->err_specific_desc); -+ } -+ -+ if (copy_sense) { -+ memcpy(tw_dev->srb[request_id]->sense_buffer, header->sense_data, TW_SENSE_DATA_LENGTH); -+ tw_dev->srb[request_id]->result = (full_command_packet->command.newcommand.status << 1); -+ goto out; -+ } -+out: -+ return retval; -+} /* End twl_fill_sense() */ -+ -+/* This function will free up device extension resources */ -+static void twl_free_device_extension(TW_Device_Extension *tw_dev) -+{ -+ if (tw_dev->command_packet_virt[0]) -+ pci_free_consistent(tw_dev->tw_pci_dev, -+ sizeof(TW_Command_Full)*TW_Q_LENGTH, -+ tw_dev->command_packet_virt[0], -+ tw_dev->command_packet_phys[0]); -+ -+ if (tw_dev->generic_buffer_virt[0]) -+ pci_free_consistent(tw_dev->tw_pci_dev, -+ TW_SECTOR_SIZE*TW_Q_LENGTH, -+ tw_dev->generic_buffer_virt[0], -+ tw_dev->generic_buffer_phys[0]); -+ -+ if (tw_dev->sense_buffer_virt[0]) -+ pci_free_consistent(tw_dev->tw_pci_dev, -+ sizeof(TW_Command_Apache_Header)* -+ TW_Q_LENGTH, -+ tw_dev->sense_buffer_virt[0], -+ tw_dev->sense_buffer_phys[0]); -+ -+ kfree(tw_dev->event_queue[0]); -+} /* End twl_free_device_extension() */ -+ -+/* This function will get parameter table entries from the firmware */ -+static void *twl_get_param(TW_Device_Extension *tw_dev, int request_id, int table_id, int parameter_id, int parameter_size_bytes) -+{ -+ TW_Command_Full *full_command_packet; -+ TW_Command *command_packet; -+ TW_Param_Apache *param; -+ void *retval = NULL; -+ -+ /* Setup the command packet */ -+ full_command_packet = tw_dev->command_packet_virt[request_id]; -+ memset(full_command_packet, 0, sizeof(TW_Command_Full)); -+ command_packet = &full_command_packet->command.oldcommand; -+ -+ command_packet->opcode__sgloffset = TW_OPSGL_IN(2, TW_OP_GET_PARAM); -+ command_packet->size = TW_COMMAND_SIZE; -+ command_packet->request_id = request_id; -+ command_packet->byte6_offset.block_count = cpu_to_le16(1); -+ -+ /* Now setup the param */ -+ param = (TW_Param_Apache *)tw_dev->generic_buffer_virt[request_id]; -+ memset(param, 0, TW_SECTOR_SIZE); -+ param->table_id = cpu_to_le16(table_id | 0x8000); -+ param->parameter_id = cpu_to_le16(parameter_id); -+ param->parameter_size_bytes = cpu_to_le16(parameter_size_bytes); -+ -+ command_packet->byte8_offset.param.sgl[0].address = TW_CPU_TO_SGL(tw_dev->generic_buffer_phys[request_id]); -+ command_packet->byte8_offset.param.sgl[0].length = TW_CPU_TO_SGL(TW_SECTOR_SIZE); -+ -+ /* Post the command packet to the board */ -+ twl_post_command_packet(tw_dev, request_id); -+ -+ /* Poll for completion */ -+ if (twl_poll_response(tw_dev, request_id, 30)) -+ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x7, "No valid response during get param") -+ else -+ retval = (void *)&(param->data[0]); -+ -+ tw_dev->posted_request_count--; -+ tw_dev->state[request_id] = TW_S_INITIAL; -+ -+ return retval; -+} /* End twl_get_param() */ -+ -+/* This function will send an initconnection command to controller */ -+static int twl_initconnection(TW_Device_Extension *tw_dev, int message_credits, -+ u32 set_features, unsigned short current_fw_srl, -+ unsigned short current_fw_arch_id, -+ unsigned short current_fw_branch, -+ unsigned short current_fw_build, -+ unsigned short *fw_on_ctlr_srl, -+ unsigned short *fw_on_ctlr_arch_id, -+ unsigned short *fw_on_ctlr_branch, -+ unsigned short *fw_on_ctlr_build, -+ u32 *init_connect_result) -+{ -+ TW_Command_Full *full_command_packet; -+ TW_Initconnect *tw_initconnect; -+ int request_id = 0, retval = 1; -+ -+ /* Initialize InitConnection command packet */ -+ full_command_packet = tw_dev->command_packet_virt[request_id]; -+ memset(full_command_packet, 0, sizeof(TW_Command_Full)); -+ full_command_packet->header.header_desc.size_header = 128; -+ -+ tw_initconnect = (TW_Initconnect *)&full_command_packet->command.oldcommand; -+ tw_initconnect->opcode__reserved = TW_OPRES_IN(0, TW_OP_INIT_CONNECTION); -+ tw_initconnect->request_id = request_id; -+ tw_initconnect->message_credits = cpu_to_le16(message_credits); -+ tw_initconnect->features = set_features; -+ -+ /* Turn on 64-bit sgl support if we need to */ -+ tw_initconnect->features |= sizeof(dma_addr_t) > 4 ? 1 : 0; -+ -+ tw_initconnect->features = cpu_to_le32(tw_initconnect->features); -+ -+ if (set_features & TW_EXTENDED_INIT_CONNECT) { -+ tw_initconnect->size = TW_INIT_COMMAND_PACKET_SIZE_EXTENDED; -+ tw_initconnect->fw_srl = cpu_to_le16(current_fw_srl); -+ tw_initconnect->fw_arch_id = cpu_to_le16(current_fw_arch_id); -+ tw_initconnect->fw_branch = cpu_to_le16(current_fw_branch); -+ tw_initconnect->fw_build = cpu_to_le16(current_fw_build); -+ } else -+ tw_initconnect->size = TW_INIT_COMMAND_PACKET_SIZE; -+ -+ /* Send command packet to the board */ -+ twl_post_command_packet(tw_dev, request_id); -+ -+ /* Poll for completion */ -+ if (twl_poll_response(tw_dev, request_id, 30)) { -+ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x8, "No valid response during init connection"); -+ } else { -+ if (set_features & TW_EXTENDED_INIT_CONNECT) { -+ *fw_on_ctlr_srl = le16_to_cpu(tw_initconnect->fw_srl); -+ *fw_on_ctlr_arch_id = le16_to_cpu(tw_initconnect->fw_arch_id); -+ *fw_on_ctlr_branch = le16_to_cpu(tw_initconnect->fw_branch); -+ *fw_on_ctlr_build = le16_to_cpu(tw_initconnect->fw_build); -+ *init_connect_result = le32_to_cpu(tw_initconnect->result); -+ } -+ retval = 0; -+ } -+ -+ tw_dev->posted_request_count--; -+ tw_dev->state[request_id] = TW_S_INITIAL; -+ -+ return retval; -+} /* End twl_initconnection() */ -+ -+/* This function will initialize the fields of a device extension */ -+static int twl_initialize_device_extension(TW_Device_Extension *tw_dev) -+{ -+ int i, retval = 1; -+ -+ /* Initialize command packet buffers */ -+ if (twl_allocate_memory(tw_dev, sizeof(TW_Command_Full), 0)) { -+ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x9, "Command packet memory allocation failed"); -+ goto out; -+ } -+ -+ /* Initialize generic buffer */ -+ if (twl_allocate_memory(tw_dev, TW_SECTOR_SIZE, 1)) { -+ TW_PRINTK(tw_dev->host, TW_DRIVER, 0xa, "Generic memory allocation failed"); -+ goto out; -+ } -+ -+ /* Allocate sense buffers */ -+ if (twl_allocate_memory(tw_dev, sizeof(TW_Command_Apache_Header), 2)) { -+ TW_PRINTK(tw_dev->host, TW_DRIVER, 0xb, "Sense buffer allocation failed"); -+ goto out; -+ } -+ -+ /* Allocate event info space */ -+ tw_dev->event_queue[0] = kcalloc(TW_Q_LENGTH, sizeof(TW_Event), GFP_KERNEL); -+ if (!tw_dev->event_queue[0]) { -+ TW_PRINTK(tw_dev->host, TW_DRIVER, 0xc, "Event info memory allocation failed"); -+ goto out; -+ } -+ -+ for (i = 0; i < TW_Q_LENGTH; i++) { -+ tw_dev->event_queue[i] = (TW_Event *)((unsigned char *)tw_dev->event_queue[0] + (i * sizeof(TW_Event))); -+ tw_dev->free_queue[i] = i; -+ tw_dev->state[i] = TW_S_INITIAL; -+ } -+ -+ tw_dev->free_head = TW_Q_START; -+ tw_dev->free_tail = TW_Q_START; -+ tw_dev->error_sequence_id = 1; -+ tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE; -+ -+ mutex_init(&tw_dev->ioctl_lock); -+ init_waitqueue_head(&tw_dev->ioctl_wqueue); -+ -+ retval = 0; -+out: -+ return retval; -+} /* End twl_initialize_device_extension() */ -+ -+/* This function will perform a pci-dma unmap */ -+static void twl_unmap_scsi_data(TW_Device_Extension *tw_dev, int request_id) -+{ -+ struct scsi_cmnd *cmd = tw_dev->srb[request_id]; -+ -+ if (cmd->SCp.phase == TW_PHASE_SGLIST) -+ scsi_dma_unmap(cmd); -+} /* End twl_unmap_scsi_data() */ -+ -+/* This function will handle attention interrupts */ -+static int twl_handle_attention_interrupt(TW_Device_Extension *tw_dev) -+{ -+ int retval = 1; -+ u32 request_id, doorbell; -+ -+ /* Read doorbell status */ -+ doorbell = readl(TWL_HOBDB_REG_ADDR(tw_dev)); -+ -+ /* Check for controller errors */ -+ if (doorbell & TWL_DOORBELL_CONTROLLER_ERROR) { -+ TW_PRINTK(tw_dev->host, TW_DRIVER, 0xd, "Microcontroller Error: clearing"); -+ goto out; -+ } -+ -+ /* Check if we need to perform an AEN drain */ -+ if (doorbell & TWL_DOORBELL_ATTENTION_INTERRUPT) { -+ if (!(test_and_set_bit(TW_IN_ATTENTION_LOOP, &tw_dev->flags))) { -+ twl_get_request_id(tw_dev, &request_id); -+ if (twl_aen_read_queue(tw_dev, request_id)) { -+ tw_dev->state[request_id] = TW_S_COMPLETED; -+ twl_free_request_id(tw_dev, request_id); -+ clear_bit(TW_IN_ATTENTION_LOOP, &tw_dev->flags); -+ } -+ } -+ } -+ -+ retval = 0; -+out: -+ /* Clear doorbell interrupt */ -+ TWL_CLEAR_DB_INTERRUPT(tw_dev); -+ -+ /* Make sure the clear was flushed by reading it back */ -+ readl(TWL_HOBDBC_REG_ADDR(tw_dev)); -+ -+ return retval; -+} /* End twl_handle_attention_interrupt() */ -+ -+/* Interrupt service routine */ -+static irqreturn_t twl_interrupt(int irq, void *dev_instance) -+{ -+ TW_Device_Extension *tw_dev = (TW_Device_Extension *)dev_instance; -+ int i, handled = 0, error = 0; -+ dma_addr_t mfa = 0; -+ u32 reg, regl, regh, response, request_id = 0; -+ struct scsi_cmnd *cmd; -+ TW_Command_Full *full_command_packet; -+ -+ spin_lock(tw_dev->host->host_lock); -+ -+ /* Read host interrupt status */ -+ reg = readl(TWL_HISTAT_REG_ADDR(tw_dev)); -+ -+ /* Check if this is our interrupt, otherwise bail */ -+ if (!(reg & TWL_HISTATUS_VALID_INTERRUPT)) -+ goto twl_interrupt_bail; -+ -+ handled = 1; -+ -+ /* If we are resetting, bail */ -+ if (test_bit(TW_IN_RESET, &tw_dev->flags)) -+ goto twl_interrupt_bail; -+ -+ /* Attention interrupt */ -+ if (reg & TWL_HISTATUS_ATTENTION_INTERRUPT) { -+ if (twl_handle_attention_interrupt(tw_dev)) { -+ TWL_MASK_INTERRUPTS(tw_dev); -+ goto twl_interrupt_bail; -+ } -+ } -+ -+ /* Response interrupt */ -+ while (reg & TWL_HISTATUS_RESPONSE_INTERRUPT) { -+ if (sizeof(dma_addr_t) > 4) { -+ regh = readl(TWL_HOBQPH_REG_ADDR(tw_dev)); -+ regl = readl(TWL_HOBQPL_REG_ADDR(tw_dev)); -+ mfa = ((u64)regh << 32) | regl; -+ } else -+ mfa = readl(TWL_HOBQPL_REG_ADDR(tw_dev)); -+ -+ error = 0; -+ response = (u32)mfa; -+ -+ /* Check for command packet error */ -+ if (!TW_NOTMFA_OUT(response)) { -+ for (i=0;isense_buffer_phys[i] == mfa) { -+ request_id = le16_to_cpu(tw_dev->sense_buffer_virt[i]->header_desc.request_id); -+ if (tw_dev->srb[request_id] != NULL) -+ error = twl_fill_sense(tw_dev, i, request_id, 1, 1); -+ else { -+ /* Skip ioctl error prints */ -+ if (request_id != tw_dev->chrdev_request_id) -+ error = twl_fill_sense(tw_dev, i, request_id, 0, 1); -+ else -+ memcpy(tw_dev->command_packet_virt[request_id], tw_dev->sense_buffer_virt[i], sizeof(TW_Command_Apache_Header)); -+ } -+ -+ /* Now re-post the sense buffer */ -+ writel((u32)((u64)tw_dev->sense_buffer_phys[i] >> 32), TWL_HOBQPH_REG_ADDR(tw_dev)); -+ writel((u32)tw_dev->sense_buffer_phys[i], TWL_HOBQPL_REG_ADDR(tw_dev)); -+ break; -+ } -+ } -+ } else -+ request_id = TW_RESID_OUT(response); -+ -+ full_command_packet = tw_dev->command_packet_virt[request_id]; -+ -+ /* Check for correct state */ -+ if (tw_dev->state[request_id] != TW_S_POSTED) { -+ if (tw_dev->srb[request_id] != NULL) { -+ TW_PRINTK(tw_dev->host, TW_DRIVER, 0xe, "Received a request id that wasn't posted"); -+ TWL_MASK_INTERRUPTS(tw_dev); -+ goto twl_interrupt_bail; -+ } -+ } -+ -+ /* Check for internal command completion */ -+ if (tw_dev->srb[request_id] == NULL) { -+ if (request_id != tw_dev->chrdev_request_id) { -+ if (twl_aen_complete(tw_dev, request_id)) -+ TW_PRINTK(tw_dev->host, TW_DRIVER, 0xf, "Error completing AEN during attention interrupt"); -+ } else { -+ tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE; -+ wake_up(&tw_dev->ioctl_wqueue); -+ } -+ } else { -+ cmd = tw_dev->srb[request_id]; -+ -+ if (!error) -+ cmd->result = (DID_OK << 16); -+ -+ /* Report residual bytes for single sgl */ -+ if ((scsi_sg_count(cmd) <= 1) && (full_command_packet->command.newcommand.status == 0)) { -+ if (full_command_packet->command.newcommand.sg_list[0].length < scsi_bufflen(tw_dev->srb[request_id])) -+ scsi_set_resid(cmd, scsi_bufflen(cmd) - full_command_packet->command.newcommand.sg_list[0].length); -+ } -+ -+ /* Now complete the io */ -+ tw_dev->state[request_id] = TW_S_COMPLETED; -+ twl_free_request_id(tw_dev, request_id); -+ tw_dev->posted_request_count--; -+ tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]); -+ twl_unmap_scsi_data(tw_dev, request_id); -+ } -+ -+ /* Check for another response interrupt */ -+ reg = readl(TWL_HISTAT_REG_ADDR(tw_dev)); -+ } -+ -+twl_interrupt_bail: -+ spin_unlock(tw_dev->host->host_lock); -+ return IRQ_RETVAL(handled); -+} /* End twl_interrupt() */ -+ -+/* This function will poll for a register change */ -+static int twl_poll_register(TW_Device_Extension *tw_dev, void *reg, u32 value, u32 result, int seconds) -+{ -+ unsigned long before; -+ int retval = 1; -+ u32 reg_value; -+ -+ reg_value = readl(reg); -+ before = jiffies; -+ -+ while ((reg_value & value) != result) { -+ reg_value = readl(reg); -+ if (time_after(jiffies, before + HZ * seconds)) -+ goto out; -+ msleep(50); -+ } -+ retval = 0; -+out: -+ return retval; -+} /* End twl_poll_register() */ -+ -+/* This function will reset a controller */ -+static int twl_reset_sequence(TW_Device_Extension *tw_dev, int soft_reset) -+{ -+ int retval = 1; -+ int i = 0; -+ u32 status = 0; -+ unsigned short fw_on_ctlr_srl = 0, fw_on_ctlr_arch_id = 0; -+ unsigned short fw_on_ctlr_branch = 0, fw_on_ctlr_build = 0; -+ u32 init_connect_result = 0; -+ int tries = 0; -+ int do_soft_reset = soft_reset; -+ -+ while (tries < TW_MAX_RESET_TRIES) { -+ /* Do a soft reset if one is needed */ -+ if (do_soft_reset) { -+ TWL_SOFT_RESET(tw_dev); -+ -+ /* Make sure controller is in a good state */ -+ if (twl_poll_register(tw_dev, TWL_SCRPD3_REG_ADDR(tw_dev), TWL_CONTROLLER_READY, 0x0, 30)) { -+ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x10, "Controller never went non-ready during reset sequence"); -+ tries++; -+ continue; -+ } -+ if (twl_poll_register(tw_dev, TWL_SCRPD3_REG_ADDR(tw_dev), TWL_CONTROLLER_READY, TWL_CONTROLLER_READY, 60)) { -+ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x11, "Controller not ready during reset sequence"); -+ tries++; -+ continue; -+ } -+ } -+ -+ /* Initconnect */ -+ if (twl_initconnection(tw_dev, TW_INIT_MESSAGE_CREDITS, -+ TW_EXTENDED_INIT_CONNECT, TW_CURRENT_DRIVER_SRL, -+ TW_9750_ARCH_ID, TW_CURRENT_DRIVER_BRANCH, -+ TW_CURRENT_DRIVER_BUILD, &fw_on_ctlr_srl, -+ &fw_on_ctlr_arch_id, &fw_on_ctlr_branch, -+ &fw_on_ctlr_build, &init_connect_result)) { -+ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x12, "Initconnection failed while checking SRL"); -+ do_soft_reset = 1; -+ tries++; -+ continue; -+ } -+ -+ /* Load sense buffers */ -+ while (i < TW_Q_LENGTH) { -+ writel((u32)((u64)tw_dev->sense_buffer_phys[i] >> 32), TWL_HOBQPH_REG_ADDR(tw_dev)); -+ writel((u32)tw_dev->sense_buffer_phys[i], TWL_HOBQPL_REG_ADDR(tw_dev)); -+ -+ /* Check status for over-run after each write */ -+ status = readl(TWL_STATUS_REG_ADDR(tw_dev)); -+ if (!(status & TWL_STATUS_OVERRUN_SUBMIT)) -+ i++; -+ } -+ -+ /* Now check status */ -+ status = readl(TWL_STATUS_REG_ADDR(tw_dev)); -+ if (status) { -+ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x13, "Bad controller status after loading sense buffers"); -+ do_soft_reset = 1; -+ tries++; -+ continue; -+ } -+ -+ /* Drain the AEN queue */ -+ if (twl_aen_drain_queue(tw_dev, soft_reset)) { -+ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x14, "AEN drain failed during reset sequence"); -+ do_soft_reset = 1; -+ tries++; -+ continue; -+ } -+ -+ /* Load rest of compatibility struct */ -+ strncpy(tw_dev->tw_compat_info.driver_version, TW_DRIVER_VERSION, strlen(TW_DRIVER_VERSION)); -+ tw_dev->tw_compat_info.driver_srl_high = TW_CURRENT_DRIVER_SRL; -+ tw_dev->tw_compat_info.driver_branch_high = TW_CURRENT_DRIVER_BRANCH; -+ tw_dev->tw_compat_info.driver_build_high = TW_CURRENT_DRIVER_BUILD; -+ tw_dev->tw_compat_info.driver_srl_low = TW_BASE_FW_SRL; -+ tw_dev->tw_compat_info.driver_branch_low = TW_BASE_FW_BRANCH; -+ tw_dev->tw_compat_info.driver_build_low = TW_BASE_FW_BUILD; -+ tw_dev->tw_compat_info.fw_on_ctlr_srl = fw_on_ctlr_srl; -+ tw_dev->tw_compat_info.fw_on_ctlr_branch = fw_on_ctlr_branch; -+ tw_dev->tw_compat_info.fw_on_ctlr_build = fw_on_ctlr_build; -+ -+ /* If we got here, controller is in a good state */ -+ retval = 0; -+ goto out; -+ } -+out: -+ return retval; -+} /* End twl_reset_sequence() */ -+ -+/* This function will reset a device extension */ -+static int twl_reset_device_extension(TW_Device_Extension *tw_dev, int ioctl_reset) -+{ -+ int i = 0, retval = 1; -+ unsigned long flags = 0; -+ -+ /* Block SCSI requests while we are resetting */ -+ if (ioctl_reset) -+ scsi_block_requests(tw_dev->host); -+ -+ set_bit(TW_IN_RESET, &tw_dev->flags); -+ TWL_MASK_INTERRUPTS(tw_dev); -+ TWL_CLEAR_DB_INTERRUPT(tw_dev); -+ -+ spin_lock_irqsave(tw_dev->host->host_lock, flags); -+ -+ /* Abort all requests that are in progress */ -+ for (i = 0; i < TW_Q_LENGTH; i++) { -+ if ((tw_dev->state[i] != TW_S_FINISHED) && -+ (tw_dev->state[i] != TW_S_INITIAL) && -+ (tw_dev->state[i] != TW_S_COMPLETED)) { -+ if (tw_dev->srb[i]) { -+ tw_dev->srb[i]->result = (DID_RESET << 16); -+ tw_dev->srb[i]->scsi_done(tw_dev->srb[i]); -+ twl_unmap_scsi_data(tw_dev, i); -+ } -+ } -+ } -+ -+ /* Reset queues and counts */ -+ for (i = 0; i < TW_Q_LENGTH; i++) { -+ tw_dev->free_queue[i] = i; -+ tw_dev->state[i] = TW_S_INITIAL; -+ } -+ tw_dev->free_head = TW_Q_START; -+ tw_dev->free_tail = TW_Q_START; -+ tw_dev->posted_request_count = 0; -+ -+ spin_unlock_irqrestore(tw_dev->host->host_lock, flags); -+ -+ if (twl_reset_sequence(tw_dev, 1)) -+ goto out; -+ -+ TWL_UNMASK_INTERRUPTS(tw_dev); -+ -+ clear_bit(TW_IN_RESET, &tw_dev->flags); -+ tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE; -+ -+ retval = 0; -+out: -+ if (ioctl_reset) -+ scsi_unblock_requests(tw_dev->host); -+ return retval; -+} /* End twl_reset_device_extension() */ -+ -+/* This funciton returns unit geometry in cylinders/heads/sectors */ -+static int twl_scsi_biosparam(struct scsi_device *sdev, struct block_device *bdev, sector_t capacity, int geom[]) -+{ -+ int heads, sectors; -+ TW_Device_Extension *tw_dev; -+ -+ tw_dev = (TW_Device_Extension *)sdev->host->hostdata; -+ -+ if (capacity >= 0x200000) { -+ heads = 255; -+ sectors = 63; -+ } else { -+ heads = 64; -+ sectors = 32; -+ } -+ -+ geom[0] = heads; -+ geom[1] = sectors; -+ geom[2] = sector_div(capacity, heads * sectors); /* cylinders */ -+ -+ return 0; -+} /* End twl_scsi_biosparam() */ -+ -+/* This is the new scsi eh reset function */ -+static int twl_scsi_eh_reset(struct scsi_cmnd *SCpnt) -+{ -+ TW_Device_Extension *tw_dev = NULL; -+ int retval = FAILED; -+ -+ tw_dev = (TW_Device_Extension *)SCpnt->device->host->hostdata; -+ -+ tw_dev->num_resets++; -+ -+ sdev_printk(KERN_WARNING, SCpnt->device, -+ "WARNING: (0x%02X:0x%04X): Command (0x%x) timed out, resetting card.\n", -+ TW_DRIVER, 0x2c, SCpnt->cmnd[0]); -+ -+ /* Make sure we are not issuing an ioctl or resetting from ioctl */ -+ mutex_lock(&tw_dev->ioctl_lock); -+ -+ /* Now reset the card and some of the device extension data */ -+ if (twl_reset_device_extension(tw_dev, 0)) { -+ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x15, "Controller reset failed during scsi host reset"); -+ goto out; -+ } -+ -+ retval = SUCCESS; -+out: -+ mutex_unlock(&tw_dev->ioctl_lock); -+ return retval; -+} /* End twl_scsi_eh_reset() */ -+ -+/* This is the main scsi queue function to handle scsi opcodes */ -+static int twl_scsi_queue(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) -+{ -+ int request_id, retval; -+ TW_Device_Extension *tw_dev = (TW_Device_Extension *)SCpnt->device->host->hostdata; -+ -+ /* If we are resetting due to timed out ioctl, report as busy */ -+ if (test_bit(TW_IN_RESET, &tw_dev->flags)) { -+ retval = SCSI_MLQUEUE_HOST_BUSY; -+ goto out; -+ } -+ -+ /* Save done function into scsi_cmnd struct */ -+ SCpnt->scsi_done = done; -+ -+ /* Get a free request id */ -+ twl_get_request_id(tw_dev, &request_id); -+ -+ /* Save the scsi command for use by the ISR */ -+ tw_dev->srb[request_id] = SCpnt; -+ -+ /* Initialize phase to zero */ -+ SCpnt->SCp.phase = TW_PHASE_INITIAL; -+ -+ retval = twl_scsiop_execute_scsi(tw_dev, request_id, NULL, 0, NULL); -+ if (retval) { -+ tw_dev->state[request_id] = TW_S_COMPLETED; -+ twl_free_request_id(tw_dev, request_id); -+ SCpnt->result = (DID_ERROR << 16); -+ done(SCpnt); -+ retval = 0; -+ } -+out: -+ return retval; -+} /* End twl_scsi_queue() */ -+ -+/* This function tells the controller to shut down */ -+static void __twl_shutdown(TW_Device_Extension *tw_dev) -+{ -+ /* Disable interrupts */ -+ TWL_MASK_INTERRUPTS(tw_dev); -+ -+ /* Free up the IRQ */ -+ free_irq(tw_dev->tw_pci_dev->irq, tw_dev); -+ -+ printk(KERN_WARNING "3w-sas: Shutting down host %d.\n", tw_dev->host->host_no); -+ -+ /* Tell the card we are shutting down */ -+ if (twl_initconnection(tw_dev, 1, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL)) { -+ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x16, "Connection shutdown failed"); -+ } else { -+ printk(KERN_WARNING "3w-sas: Shutdown complete.\n"); -+ } -+ -+ /* Clear doorbell interrupt just before exit */ -+ TWL_CLEAR_DB_INTERRUPT(tw_dev); -+} /* End __twl_shutdown() */ -+ -+/* Wrapper for __twl_shutdown */ -+static void twl_shutdown(struct pci_dev *pdev) -+{ -+ struct Scsi_Host *host = pci_get_drvdata(pdev); -+ TW_Device_Extension *tw_dev; -+ -+ if (!host) -+ return; -+ -+ tw_dev = (TW_Device_Extension *)host->hostdata; -+ -+ if (tw_dev->online) -+ __twl_shutdown(tw_dev); -+} /* End twl_shutdown() */ -+ -+/* This function configures unit settings when a unit is coming on-line */ -+static int twl_slave_configure(struct scsi_device *sdev) -+{ -+ /* Force 60 second timeout */ -+ blk_queue_rq_timeout(sdev->request_queue, 60 * HZ); -+ -+ return 0; -+} /* End twl_slave_configure() */ -+ -+/* scsi_host_template initializer */ -+static struct scsi_host_template driver_template = { -+ .module = THIS_MODULE, -+ .name = "3w-sas", -+ .queuecommand = twl_scsi_queue, -+ .eh_host_reset_handler = twl_scsi_eh_reset, -+ .bios_param = twl_scsi_biosparam, -+ .change_queue_depth = twl_change_queue_depth, -+ .can_queue = TW_Q_LENGTH-2, -+ .slave_configure = twl_slave_configure, -+ .this_id = -1, -+ .sg_tablesize = TW_LIBERATOR_MAX_SGL_LENGTH, -+ .max_sectors = TW_MAX_SECTORS, -+ .cmd_per_lun = TW_MAX_CMDS_PER_LUN, -+ .use_clustering = ENABLE_CLUSTERING, -+ .shost_attrs = twl_host_attrs, -+ .emulated = 1 -+}; -+ -+/* This function will probe and initialize a card */ -+static int __devinit twl_probe(struct pci_dev *pdev, const struct pci_device_id *dev_id) -+{ -+ struct Scsi_Host *host = NULL; -+ TW_Device_Extension *tw_dev; -+ int retval = -ENODEV; -+ int *ptr_phycount, phycount=0; -+ -+ retval = pci_enable_device(pdev); -+ if (retval) { -+ TW_PRINTK(host, TW_DRIVER, 0x17, "Failed to enable pci device"); -+ goto out_disable_device; -+ } -+ -+ pci_set_master(pdev); -+ pci_try_set_mwi(pdev); -+ -+ if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) -+ || pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64))) -+ if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) -+ || pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32))) { -+ TW_PRINTK(host, TW_DRIVER, 0x18, "Failed to set dma mask"); -+ retval = -ENODEV; -+ goto out_disable_device; -+ } -+ -+ host = scsi_host_alloc(&driver_template, sizeof(TW_Device_Extension)); -+ if (!host) { -+ TW_PRINTK(host, TW_DRIVER, 0x19, "Failed to allocate memory for device extension"); -+ retval = -ENOMEM; -+ goto out_disable_device; -+ } -+ tw_dev = shost_priv(host); -+ -+ /* Save values to device extension */ -+ tw_dev->host = host; -+ tw_dev->tw_pci_dev = pdev; -+ -+ if (twl_initialize_device_extension(tw_dev)) { -+ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1a, "Failed to initialize device extension"); -+ goto out_free_device_extension; -+ } -+ -+ /* Request IO regions */ -+ retval = pci_request_regions(pdev, "3w-sas"); -+ if (retval) { -+ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1b, "Failed to get mem region"); -+ goto out_free_device_extension; -+ } -+ -+ /* Save base address, use region 1 */ -+ tw_dev->base_addr = pci_iomap(pdev, 1, 0); -+ if (!tw_dev->base_addr) { -+ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1c, "Failed to ioremap"); -+ goto out_release_mem_region; -+ } -+ -+ /* Disable interrupts on the card */ -+ TWL_MASK_INTERRUPTS(tw_dev); -+ -+ /* Initialize the card */ -+ if (twl_reset_sequence(tw_dev, 0)) { -+ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1d, "Controller reset failed during probe"); -+ goto out_iounmap; -+ } -+ -+ /* Set host specific parameters */ -+ host->max_id = TW_MAX_UNITS; -+ host->max_cmd_len = TW_MAX_CDB_LEN; -+ host->max_lun = TW_MAX_LUNS; -+ host->max_channel = 0; -+ -+ /* Register the card with the kernel SCSI layer */ -+ retval = scsi_add_host(host, &pdev->dev); -+ if (retval) { -+ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1e, "scsi add host failed"); -+ goto out_iounmap; -+ } -+ -+ pci_set_drvdata(pdev, host); -+ -+ printk(KERN_WARNING "3w-sas: scsi%d: Found an LSI 3ware %s Controller at 0x%llx, IRQ: %d.\n", -+ host->host_no, -+ (char *)twl_get_param(tw_dev, 1, TW_VERSION_TABLE, -+ TW_PARAM_MODEL, TW_PARAM_MODEL_LENGTH), -+ (u64)pci_resource_start(pdev, 1), pdev->irq); -+ -+ ptr_phycount = twl_get_param(tw_dev, 2, TW_PARAM_PHY_SUMMARY_TABLE, -+ TW_PARAM_PHYCOUNT, TW_PARAM_PHYCOUNT_LENGTH); -+ if (ptr_phycount) -+ phycount = le32_to_cpu(*(int *)ptr_phycount); -+ -+ printk(KERN_WARNING "3w-sas: scsi%d: Firmware %s, BIOS %s, Phys: %d.\n", -+ host->host_no, -+ (char *)twl_get_param(tw_dev, 1, TW_VERSION_TABLE, -+ TW_PARAM_FWVER, TW_PARAM_FWVER_LENGTH), -+ (char *)twl_get_param(tw_dev, 2, TW_VERSION_TABLE, -+ TW_PARAM_BIOSVER, TW_PARAM_BIOSVER_LENGTH), -+ phycount); -+ -+ /* Try to enable MSI */ -+ if (use_msi && !pci_enable_msi(pdev)) -+ set_bit(TW_USING_MSI, &tw_dev->flags); -+ -+ /* Now setup the interrupt handler */ -+ retval = request_irq(pdev->irq, twl_interrupt, IRQF_SHARED, "3w-sas", tw_dev); -+ if (retval) { -+ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1f, "Error requesting IRQ"); -+ goto out_remove_host; -+ } -+ -+ twl_device_extension_list[twl_device_extension_count] = tw_dev; -+ twl_device_extension_count++; -+ -+ /* Re-enable interrupts on the card */ -+ TWL_UNMASK_INTERRUPTS(tw_dev); -+ -+ /* Finally, scan the host */ -+ scsi_scan_host(host); -+ -+ /* Add sysfs binary files */ -+ if (sysfs_create_bin_file(&host->shost_dev.kobj, &twl_sysfs_aen_read_attr)) -+ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x20, "Failed to create sysfs binary file: 3ware_aen_read"); -+ if (sysfs_create_bin_file(&host->shost_dev.kobj, &twl_sysfs_compat_info_attr)) -+ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x21, "Failed to create sysfs binary file: 3ware_compat_info"); -+ -+ if (twl_major == -1) { -+ if ((twl_major = register_chrdev (0, "twl", &twl_fops)) < 0) -+ TW_PRINTK(host, TW_DRIVER, 0x22, "Failed to register character device"); -+ } -+ tw_dev->online = 1; -+ return 0; -+ -+out_remove_host: -+ if (test_bit(TW_USING_MSI, &tw_dev->flags)) -+ pci_disable_msi(pdev); -+ scsi_remove_host(host); -+out_iounmap: -+ iounmap(tw_dev->base_addr); -+out_release_mem_region: -+ pci_release_regions(pdev); -+out_free_device_extension: -+ twl_free_device_extension(tw_dev); -+ scsi_host_put(host); -+out_disable_device: -+ pci_disable_device(pdev); -+ -+ return retval; -+} /* End twl_probe() */ -+ -+/* This function is called to remove a device */ -+static void twl_remove(struct pci_dev *pdev) -+{ -+ struct Scsi_Host *host = pci_get_drvdata(pdev); -+ TW_Device_Extension *tw_dev; -+ -+ if (!host) -+ return; -+ -+ tw_dev = (TW_Device_Extension *)host->hostdata; -+ -+ if (!tw_dev->online) -+ return; -+ -+ /* Remove sysfs binary files */ -+ sysfs_remove_bin_file(&host->shost_dev.kobj, &twl_sysfs_aen_read_attr); -+ sysfs_remove_bin_file(&host->shost_dev.kobj, &twl_sysfs_compat_info_attr); -+ -+ scsi_remove_host(tw_dev->host); -+ -+ /* Unregister character device */ -+ if (twl_major >= 0) { -+ unregister_chrdev(twl_major, "twl"); -+ twl_major = -1; -+ } -+ -+ /* Shutdown the card */ -+ __twl_shutdown(tw_dev); -+ -+ /* Disable MSI if enabled */ -+ if (test_bit(TW_USING_MSI, &tw_dev->flags)) -+ pci_disable_msi(pdev); -+ -+ /* Free IO remapping */ -+ iounmap(tw_dev->base_addr); -+ -+ /* Free up the mem region */ -+ pci_release_regions(pdev); -+ -+ /* Free up device extension resources */ -+ twl_free_device_extension(tw_dev); -+ -+ scsi_host_put(tw_dev->host); -+ pci_disable_device(pdev); -+ twl_device_extension_count--; -+} /* End twl_remove() */ -+ -+#ifdef CONFIG_PM -+/* This function is called on PCI suspend */ -+static int twl_suspend(struct pci_dev *pdev, pm_message_t state) -+{ -+ struct Scsi_Host *host = pci_get_drvdata(pdev); -+ TW_Device_Extension *tw_dev = (TW_Device_Extension *)host->hostdata; -+ -+ printk(KERN_WARNING "3w-sas: Suspending host %d.\n", tw_dev->host->host_no); -+ /* Disable interrupts */ -+ TWL_MASK_INTERRUPTS(tw_dev); -+ -+ free_irq(tw_dev->tw_pci_dev->irq, tw_dev); -+ -+ /* Tell the card we are shutting down */ -+ if (twl_initconnection(tw_dev, 1, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL)) { -+ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x23, "Connection shutdown failed during suspend"); -+ } else { -+ printk(KERN_WARNING "3w-sas: Suspend complete.\n"); -+ } -+ -+ /* Clear doorbell interrupt */ -+ TWL_CLEAR_DB_INTERRUPT(tw_dev); -+ -+ pci_save_state(pdev); -+ pci_disable_device(pdev); -+ pci_set_power_state(pdev, pci_choose_state(pdev, state)); -+ -+ return 0; -+} /* End twl_suspend() */ -+ -+/* This function is called on PCI resume */ -+static int twl_resume(struct pci_dev *pdev) -+{ -+ int retval = 0; -+ struct Scsi_Host *host = pci_get_drvdata(pdev); -+ TW_Device_Extension *tw_dev = (TW_Device_Extension *)host->hostdata; -+ -+ printk(KERN_WARNING "3w-sas: Resuming host %d.\n", tw_dev->host->host_no); -+ pci_set_power_state(pdev, PCI_D0); -+ pci_enable_wake(pdev, PCI_D0, 0); -+ pci_restore_state(pdev); -+ -+ retval = pci_enable_device(pdev); -+ if (retval) { -+ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x24, "Enable device failed during resume"); -+ return retval; -+ } -+ -+ pci_set_master(pdev); -+ pci_try_set_mwi(pdev); -+ -+ if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) -+ || pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64))) -+ if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) -+ || pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32))) { -+ TW_PRINTK(host, TW_DRIVER, 0x25, "Failed to set dma mask during resume"); -+ retval = -ENODEV; -+ goto out_disable_device; -+ } -+ -+ /* Initialize the card */ -+ if (twl_reset_sequence(tw_dev, 0)) { -+ retval = -ENODEV; -+ goto out_disable_device; -+ } -+ -+ /* Now setup the interrupt handler */ -+ retval = request_irq(pdev->irq, twl_interrupt, IRQF_SHARED, "3w-sas", tw_dev); -+ if (retval) { -+ TW_PRINTK(tw_dev->host, TW_DRIVER, 0x26, "Error requesting IRQ during resume"); -+ retval = -ENODEV; -+ goto out_disable_device; -+ } -+ -+ /* Now enable MSI if enabled */ -+ if (test_bit(TW_USING_MSI, &tw_dev->flags)) -+ pci_enable_msi(pdev); -+ -+ /* Re-enable interrupts on the card */ -+ TWL_UNMASK_INTERRUPTS(tw_dev); -+ -+ printk(KERN_WARNING "3w-sas: Resume complete.\n"); -+ return 0; -+ -+out_disable_device: -+ scsi_remove_host(host); -+ pci_disable_device(pdev); -+ -+ return retval; -+} /* End twl_resume() */ -+#endif -+ -+/* PCI Devices supported by this driver */ -+static struct pci_device_id twl_pci_tbl[] __devinitdata = { -+ { PCI_VDEVICE(3WARE, PCI_DEVICE_ID_3WARE_9750) }, -+ { } -+}; -+MODULE_DEVICE_TABLE(pci, twl_pci_tbl); -+ -+/* pci_driver initializer */ -+static struct pci_driver twl_driver = { -+ .name = "3w-sas", -+ .id_table = twl_pci_tbl, -+ .probe = twl_probe, -+ .remove = twl_remove, -+#ifdef CONFIG_PM -+ .suspend = twl_suspend, -+ .resume = twl_resume, -+#endif -+ .shutdown = twl_shutdown -+}; -+ -+/* This function is called on driver initialization */ -+static int __init twl_init(void) -+{ -+ printk(KERN_INFO "LSI 3ware SAS/SATA-RAID Controller device driver for Linux v%s.\n", TW_DRIVER_VERSION); -+ -+ return pci_register_driver(&twl_driver); -+} /* End twl_init() */ -+ -+/* This function is called on driver exit */ -+static void __exit twl_exit(void) -+{ -+ pci_unregister_driver(&twl_driver); -+} /* End twl_exit() */ -+ -+module_init(twl_init); -+module_exit(twl_exit); -+ -diff --git a/drivers/scsi/3w-sas.h b/drivers/scsi/3w-sas.h -new file mode 100644 -index 0000000..d474892 ---- /dev/null -+++ b/drivers/scsi/3w-sas.h -@@ -0,0 +1,396 @@ -+/* -+ 3w-sas.h -- LSI 3ware SAS/SATA-RAID Controller device driver for Linux. -+ -+ Written By: Adam Radford -+ -+ Copyright (C) 2009 LSI Corporation. -+ -+ This program is free software; you can redistribute it and/or modify -+ it under the terms of the GNU General Public License as published by -+ the Free Software Foundation; version 2 of the License. -+ -+ This program is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ GNU General Public License for more details. -+ -+ NO WARRANTY -+ THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR -+ CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT -+ LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, -+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is -+ solely responsible for determining the appropriateness of using and -+ distributing the Program and assumes all risks associated with its -+ exercise of rights under this Agreement, including but not limited to -+ the risks and costs of program errors, damage to or loss of data, -+ programs or equipment, and unavailability or interruption of operations. -+ -+ DISCLAIMER OF LIABILITY -+ NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY -+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -+ DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND -+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR -+ TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE -+ USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED -+ HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES -+ -+ You should have received a copy of the GNU General Public License -+ along with this program; if not, write to the Free Software -+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ -+ Bugs/Comments/Suggestions should be mailed to: -+ linuxraid@lsi.com -+ -+ For more information, goto: -+ http://www.lsi.com -+*/ -+ -+#ifndef _3W_SAS_H -+#define _3W_SAS_H -+ -+/* AEN severity table */ -+static char *twl_aen_severity_table[] = -+{ -+ "None", "ERROR", "WARNING", "INFO", "DEBUG", NULL -+}; -+ -+/* Liberator register offsets */ -+#define TWL_STATUS 0x0 /* Status */ -+#define TWL_HIBDB 0x20 /* Inbound doorbell */ -+#define TWL_HISTAT 0x30 /* Host interrupt status */ -+#define TWL_HIMASK 0x34 /* Host interrupt mask */ -+#define TWL_HOBDB 0x9C /* Outbound doorbell */ -+#define TWL_HOBDBC 0xA0 /* Outbound doorbell clear */ -+#define TWL_SCRPD3 0xBC /* Scratchpad */ -+#define TWL_HIBQPL 0xC0 /* Host inbound Q low */ -+#define TWL_HIBQPH 0xC4 /* Host inbound Q high */ -+#define TWL_HOBQPL 0xC8 /* Host outbound Q low */ -+#define TWL_HOBQPH 0xCC /* Host outbound Q high */ -+#define TWL_HISTATUS_VALID_INTERRUPT 0xC -+#define TWL_HISTATUS_ATTENTION_INTERRUPT 0x4 -+#define TWL_HISTATUS_RESPONSE_INTERRUPT 0x8 -+#define TWL_STATUS_OVERRUN_SUBMIT 0x2000 -+#define TWL_ISSUE_SOFT_RESET 0x100 -+#define TWL_CONTROLLER_READY 0x2000 -+#define TWL_DOORBELL_CONTROLLER_ERROR 0x200000 -+#define TWL_DOORBELL_ATTENTION_INTERRUPT 0x40000 -+#define TWL_PULL_MODE 0x1 -+ -+/* Command packet opcodes used by the driver */ -+#define TW_OP_INIT_CONNECTION 0x1 -+#define TW_OP_GET_PARAM 0x12 -+#define TW_OP_SET_PARAM 0x13 -+#define TW_OP_EXECUTE_SCSI 0x10 -+ -+/* Asynchronous Event Notification (AEN) codes used by the driver */ -+#define TW_AEN_QUEUE_EMPTY 0x0000 -+#define TW_AEN_SOFT_RESET 0x0001 -+#define TW_AEN_SYNC_TIME_WITH_HOST 0x031 -+#define TW_AEN_SEVERITY_ERROR 0x1 -+#define TW_AEN_SEVERITY_DEBUG 0x4 -+#define TW_AEN_NOT_RETRIEVED 0x1 -+ -+/* Command state defines */ -+#define TW_S_INITIAL 0x1 /* Initial state */ -+#define TW_S_STARTED 0x2 /* Id in use */ -+#define TW_S_POSTED 0x4 /* Posted to the controller */ -+#define TW_S_COMPLETED 0x8 /* Completed by isr */ -+#define TW_S_FINISHED 0x10 /* I/O completely done */ -+ -+/* Compatibility defines */ -+#define TW_9750_ARCH_ID 10 -+#define TW_CURRENT_DRIVER_SRL 40 -+#define TW_CURRENT_DRIVER_BUILD 0 -+#define TW_CURRENT_DRIVER_BRANCH 0 -+ -+/* Phase defines */ -+#define TW_PHASE_INITIAL 0 -+#define TW_PHASE_SGLIST 2 -+ -+/* Misc defines */ -+#define TW_SECTOR_SIZE 512 -+#define TW_MAX_UNITS 32 -+#define TW_INIT_MESSAGE_CREDITS 0x100 -+#define TW_INIT_COMMAND_PACKET_SIZE 0x3 -+#define TW_INIT_COMMAND_PACKET_SIZE_EXTENDED 0x6 -+#define TW_EXTENDED_INIT_CONNECT 0x2 -+#define TW_BASE_FW_SRL 24 -+#define TW_BASE_FW_BRANCH 0 -+#define TW_BASE_FW_BUILD 1 -+#define TW_Q_LENGTH 256 -+#define TW_Q_START 0 -+#define TW_MAX_SLOT 32 -+#define TW_MAX_RESET_TRIES 2 -+#define TW_MAX_CMDS_PER_LUN 254 -+#define TW_MAX_AEN_DRAIN 255 -+#define TW_IN_RESET 2 -+#define TW_USING_MSI 3 -+#define TW_IN_ATTENTION_LOOP 4 -+#define TW_MAX_SECTORS 256 -+#define TW_MAX_CDB_LEN 16 -+#define TW_IOCTL_CHRDEV_TIMEOUT 60 /* 60 seconds */ -+#define TW_IOCTL_CHRDEV_FREE -1 -+#define TW_COMMAND_OFFSET 128 /* 128 bytes */ -+#define TW_VERSION_TABLE 0x0402 -+#define TW_TIMEKEEP_TABLE 0x040A -+#define TW_INFORMATION_TABLE 0x0403 -+#define TW_PARAM_FWVER 3 -+#define TW_PARAM_FWVER_LENGTH 16 -+#define TW_PARAM_BIOSVER 4 -+#define TW_PARAM_BIOSVER_LENGTH 16 -+#define TW_PARAM_MODEL 8 -+#define TW_PARAM_MODEL_LENGTH 16 -+#define TW_PARAM_PHY_SUMMARY_TABLE 1 -+#define TW_PARAM_PHYCOUNT 2 -+#define TW_PARAM_PHYCOUNT_LENGTH 1 -+#define TW_IOCTL_FIRMWARE_PASS_THROUGH 0x108 // Used by smartmontools -+#define TW_ALLOCATION_LENGTH 128 -+#define TW_SENSE_DATA_LENGTH 18 -+#define TW_ERROR_LOGICAL_UNIT_NOT_SUPPORTED 0x10a -+#define TW_ERROR_INVALID_FIELD_IN_CDB 0x10d -+#define TW_ERROR_UNIT_OFFLINE 0x128 -+#define TW_MESSAGE_SOURCE_CONTROLLER_ERROR 3 -+#define TW_MESSAGE_SOURCE_CONTROLLER_EVENT 4 -+#define TW_DRIVER 6 -+#ifndef PCI_DEVICE_ID_3WARE_9750 -+#define PCI_DEVICE_ID_3WARE_9750 0x1010 -+#endif -+ -+/* Bitmask macros to eliminate bitfields */ -+ -+/* opcode: 5, reserved: 3 */ -+#define TW_OPRES_IN(x,y) ((x << 5) | (y & 0x1f)) -+#define TW_OP_OUT(x) (x & 0x1f) -+ -+/* opcode: 5, sgloffset: 3 */ -+#define TW_OPSGL_IN(x,y) ((x << 5) | (y & 0x1f)) -+#define TW_SGL_OUT(x) ((x >> 5) & 0x7) -+ -+/* severity: 3, reserved: 5 */ -+#define TW_SEV_OUT(x) (x & 0x7) -+ -+/* not_mfa: 1, reserved: 7, status: 8, request_id: 16 */ -+#define TW_RESID_OUT(x) ((x >> 16) & 0xffff) -+#define TW_NOTMFA_OUT(x) (x & 0x1) -+ -+/* request_id: 12, lun: 4 */ -+#define TW_REQ_LUN_IN(lun, request_id) (((lun << 12) & 0xf000) | (request_id & 0xfff)) -+#define TW_LUN_OUT(lun) ((lun >> 12) & 0xf) -+ -+/* Register access macros */ -+#define TWL_STATUS_REG_ADDR(x) ((unsigned char __iomem *)x->base_addr + TWL_STATUS) -+#define TWL_HOBQPL_REG_ADDR(x) ((unsigned char __iomem *)x->base_addr + TWL_HOBQPL) -+#define TWL_HOBQPH_REG_ADDR(x) ((unsigned char __iomem *)x->base_addr + TWL_HOBQPH) -+#define TWL_HOBDB_REG_ADDR(x) ((unsigned char __iomem *)x->base_addr + TWL_HOBDB) -+#define TWL_HOBDBC_REG_ADDR(x) ((unsigned char __iomem *)x->base_addr + TWL_HOBDBC) -+#define TWL_HIMASK_REG_ADDR(x) ((unsigned char __iomem *)x->base_addr + TWL_HIMASK) -+#define TWL_HISTAT_REG_ADDR(x) ((unsigned char __iomem *)x->base_addr + TWL_HISTAT) -+#define TWL_HIBQPH_REG_ADDR(x) ((unsigned char __iomem *)x->base_addr + TWL_HIBQPH) -+#define TWL_HIBQPL_REG_ADDR(x) ((unsigned char __iomem *)x->base_addr + TWL_HIBQPL) -+#define TWL_HIBDB_REG_ADDR(x) ((unsigned char __iomem *)x->base_addr + TWL_HIBDB) -+#define TWL_SCRPD3_REG_ADDR(x) ((unsigned char __iomem *)x->base_addr + TWL_SCRPD3) -+#define TWL_MASK_INTERRUPTS(x) (writel(~0, TWL_HIMASK_REG_ADDR(tw_dev))) -+#define TWL_UNMASK_INTERRUPTS(x) (writel(~TWL_HISTATUS_VALID_INTERRUPT, TWL_HIMASK_REG_ADDR(tw_dev))) -+#define TWL_CLEAR_DB_INTERRUPT(x) (writel(~0, TWL_HOBDBC_REG_ADDR(tw_dev))) -+#define TWL_SOFT_RESET(x) (writel(TWL_ISSUE_SOFT_RESET, TWL_HIBDB_REG_ADDR(tw_dev))) -+ -+/* Macros */ -+#define TW_PRINTK(h,a,b,c) { \ -+if (h) \ -+printk(KERN_WARNING "3w-sas: scsi%d: ERROR: (0x%02X:0x%04X): %s.\n",h->host_no,a,b,c); \ -+else \ -+printk(KERN_WARNING "3w-sas: ERROR: (0x%02X:0x%04X): %s.\n",a,b,c); \ -+} -+#define TW_MAX_LUNS 16 -+#define TW_COMMAND_SIZE (sizeof(dma_addr_t) > 4 ? 6 : 4) -+#define TW_LIBERATOR_MAX_SGL_LENGTH (sizeof(dma_addr_t) > 4 ? 46 : 92) -+#define TW_LIBERATOR_MAX_SGL_LENGTH_OLD (sizeof(dma_addr_t) > 4 ? 47 : 94) -+#define TW_PADDING_LENGTH_LIBERATOR 136 -+#define TW_PADDING_LENGTH_LIBERATOR_OLD 132 -+#define TW_CPU_TO_SGL(x) (sizeof(dma_addr_t) > 4 ? cpu_to_le64(x) : cpu_to_le32(x)) -+ -+#pragma pack(1) -+ -+/* SGL entry */ -+typedef struct TAG_TW_SG_Entry_ISO { -+ dma_addr_t address; -+ dma_addr_t length; -+} TW_SG_Entry_ISO; -+ -+/* Old Command Packet with ISO SGL */ -+typedef struct TW_Command { -+ unsigned char opcode__sgloffset; -+ unsigned char size; -+ unsigned char request_id; -+ unsigned char unit__hostid; -+ /* Second DWORD */ -+ unsigned char status; -+ unsigned char flags; -+ union { -+ unsigned short block_count; -+ unsigned short parameter_count; -+ } byte6_offset; -+ union { -+ struct { -+ u32 lba; -+ TW_SG_Entry_ISO sgl[TW_LIBERATOR_MAX_SGL_LENGTH_OLD]; -+ unsigned char padding[TW_PADDING_LENGTH_LIBERATOR_OLD]; -+ } io; -+ struct { -+ TW_SG_Entry_ISO sgl[TW_LIBERATOR_MAX_SGL_LENGTH_OLD]; -+ u32 padding; -+ unsigned char padding2[TW_PADDING_LENGTH_LIBERATOR_OLD]; -+ } param; -+ } byte8_offset; -+} TW_Command; -+ -+/* New Command Packet with ISO SGL */ -+typedef struct TAG_TW_Command_Apache { -+ unsigned char opcode__reserved; -+ unsigned char unit; -+ unsigned short request_id__lunl; -+ unsigned char status; -+ unsigned char sgl_offset; -+ unsigned short sgl_entries__lunh; -+ unsigned char cdb[16]; -+ TW_SG_Entry_ISO sg_list[TW_LIBERATOR_MAX_SGL_LENGTH]; -+ unsigned char padding[TW_PADDING_LENGTH_LIBERATOR]; -+} TW_Command_Apache; -+ -+/* New command packet header */ -+typedef struct TAG_TW_Command_Apache_Header { -+ unsigned char sense_data[TW_SENSE_DATA_LENGTH]; -+ struct { -+ char reserved[4]; -+ unsigned short error; -+ unsigned char padding; -+ unsigned char severity__reserved; -+ } status_block; -+ unsigned char err_specific_desc[98]; -+ struct { -+ unsigned char size_header; -+ unsigned short request_id; -+ unsigned char size_sense; -+ } header_desc; -+} TW_Command_Apache_Header; -+ -+/* This struct is a union of the 2 command packets */ -+typedef struct TAG_TW_Command_Full { -+ TW_Command_Apache_Header header; -+ union { -+ TW_Command oldcommand; -+ TW_Command_Apache newcommand; -+ } command; -+} TW_Command_Full; -+ -+/* Initconnection structure */ -+typedef struct TAG_TW_Initconnect { -+ unsigned char opcode__reserved; -+ unsigned char size; -+ unsigned char request_id; -+ unsigned char res2; -+ unsigned char status; -+ unsigned char flags; -+ unsigned short message_credits; -+ u32 features; -+ unsigned short fw_srl; -+ unsigned short fw_arch_id; -+ unsigned short fw_branch; -+ unsigned short fw_build; -+ u32 result; -+} TW_Initconnect; -+ -+/* Event info structure */ -+typedef struct TAG_TW_Event -+{ -+ unsigned int sequence_id; -+ unsigned int time_stamp_sec; -+ unsigned short aen_code; -+ unsigned char severity; -+ unsigned char retrieved; -+ unsigned char repeat_count; -+ unsigned char parameter_len; -+ unsigned char parameter_data[98]; -+} TW_Event; -+ -+typedef struct TAG_TW_Ioctl_Driver_Command { -+ unsigned int control_code; -+ unsigned int status; -+ unsigned int unique_id; -+ unsigned int sequence_id; -+ unsigned int os_specific; -+ unsigned int buffer_length; -+} TW_Ioctl_Driver_Command; -+ -+typedef struct TAG_TW_Ioctl_Apache { -+ TW_Ioctl_Driver_Command driver_command; -+ char padding[488]; -+ TW_Command_Full firmware_command; -+ char data_buffer[1]; -+} TW_Ioctl_Buf_Apache; -+ -+/* GetParam descriptor */ -+typedef struct { -+ unsigned short table_id; -+ unsigned short parameter_id; -+ unsigned short parameter_size_bytes; -+ unsigned short actual_parameter_size_bytes; -+ unsigned char data[1]; -+} TW_Param_Apache; -+ -+/* Compatibility information structure */ -+typedef struct TAG_TW_Compatibility_Info -+{ -+ char driver_version[32]; -+ unsigned short working_srl; -+ unsigned short working_branch; -+ unsigned short working_build; -+ unsigned short driver_srl_high; -+ unsigned short driver_branch_high; -+ unsigned short driver_build_high; -+ unsigned short driver_srl_low; -+ unsigned short driver_branch_low; -+ unsigned short driver_build_low; -+ unsigned short fw_on_ctlr_srl; -+ unsigned short fw_on_ctlr_branch; -+ unsigned short fw_on_ctlr_build; -+} TW_Compatibility_Info; -+ -+#pragma pack() -+ -+typedef struct TAG_TW_Device_Extension { -+ void __iomem *base_addr; -+ unsigned long *generic_buffer_virt[TW_Q_LENGTH]; -+ dma_addr_t generic_buffer_phys[TW_Q_LENGTH]; -+ TW_Command_Full *command_packet_virt[TW_Q_LENGTH]; -+ dma_addr_t command_packet_phys[TW_Q_LENGTH]; -+ TW_Command_Apache_Header *sense_buffer_virt[TW_Q_LENGTH]; -+ dma_addr_t sense_buffer_phys[TW_Q_LENGTH]; -+ struct pci_dev *tw_pci_dev; -+ struct scsi_cmnd *srb[TW_Q_LENGTH]; -+ unsigned char free_queue[TW_Q_LENGTH]; -+ unsigned char free_head; -+ unsigned char free_tail; -+ int state[TW_Q_LENGTH]; -+ unsigned int posted_request_count; -+ unsigned int max_posted_request_count; -+ unsigned int max_sgl_entries; -+ unsigned int sgl_entries; -+ unsigned int num_resets; -+ unsigned int sector_count; -+ unsigned int max_sector_count; -+ unsigned int aen_count; -+ struct Scsi_Host *host; -+ long flags; -+ TW_Event *event_queue[TW_Q_LENGTH]; -+ unsigned char error_index; -+ unsigned int error_sequence_id; -+ int chrdev_request_id; -+ wait_queue_head_t ioctl_wqueue; -+ struct mutex ioctl_lock; -+ TW_Compatibility_Info tw_compat_info; -+ char online; -+} TW_Device_Extension; -+ -+#endif /* _3W_SAS_H */ -+ -diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig -index 3fd99c8..991fa1f 100644 ---- a/drivers/scsi/Kconfig -+++ b/drivers/scsi/Kconfig -@@ -399,6 +399,17 @@ config SCSI_3W_9XXX - Please read the comments at the top of - . - -+config SCSI_3W_SAS -+ tristate "3ware 97xx SAS/SATA-RAID support" -+ depends on PCI && SCSI -+ help -+ This driver supports the LSI 3ware 9750 6Gb/s SAS/SATA-RAID cards. -+ -+ -+ -+ Please read the comments at the top of -+ . -+ - config SCSI_7000FASST - tristate "7000FASST SCSI support" - depends on ISA && SCSI && ISA_DMA_API -diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile -index 3ad61db..4f0cca9 100644 ---- a/drivers/scsi/Makefile -+++ b/drivers/scsi/Makefile -@@ -113,6 +113,7 @@ obj-$(CONFIG_SCSI_MESH) += mesh.o - obj-$(CONFIG_SCSI_MAC53C94) += mac53c94.o - obj-$(CONFIG_BLK_DEV_3W_XXXX_RAID) += 3w-xxxx.o - obj-$(CONFIG_SCSI_3W_9XXX) += 3w-9xxx.o -+obj-$(CONFIG_SCSI_3W_SAS) += 3w-sas.o - obj-$(CONFIG_SCSI_PPA) += ppa.o - obj-$(CONFIG_SCSI_IMM) += imm.o - obj-$(CONFIG_JAZZ_ESP) += esp_scsi.o jazz_esp.o --- -1.6.6 - diff --git a/debian/patches/features/all/aufs2/aufs2-20091205.patch b/debian/patches/features/all/aufs2/aufs2-20091205.patch deleted file mode 100644 index d5e978a22..000000000 --- a/debian/patches/features/all/aufs2/aufs2-20091205.patch +++ /dev/null @@ -1,234 +0,0 @@ -diff --git a/fs/aufs/f_op.c b/fs/aufs/f_op.c -index 7601012..65c50bc 100644 ---- a/fs/aufs/f_op.c -+++ b/fs/aufs/f_op.c -@@ -810,6 +810,7 @@ const struct file_operations aufs_file_fop = { - #ifdef CONFIG_AUFS_POLL - .poll = aufs_poll, - #endif -+ .unlocked_ioctl = aufs_ioctl_nondir, - .mmap = aufs_mmap, - .open = aufs_open_nondir, - .flush = aufs_flush, -diff --git a/fs/aufs/file.h b/fs/aufs/file.h -index 79a63fb..d665cc7 100644 ---- a/fs/aufs/file.h -+++ b/fs/aufs/file.h -@@ -94,6 +94,9 @@ void au_finfo_fin(struct file *file); - int au_finfo_init(struct file *file); - int au_fi_realloc(struct au_finfo *finfo, int nbr); - -+/* ioctl.c */ -+long aufs_ioctl_nondir(struct file *file, unsigned int cmd, unsigned long arg); -+ - /* ---------------------------------------------------------------------- */ - - static inline struct au_finfo *au_fi(struct file *file) -diff --git a/fs/aufs/i_op.c b/fs/aufs/i_op.c -index a7f3bc7..8151896 100644 ---- a/fs/aufs/i_op.c -+++ b/fs/aufs/i_op.c -@@ -159,6 +159,9 @@ static struct dentry *aufs_lookup(struct inode *dir, struct dentry *dentry, - - sb = dir->i_sb; - si_read_lock(sb, AuLock_FLUSH); -+ ret = ERR_PTR(-ENAMETOOLONG); -+ if (unlikely(dentry->d_name.len > AUFS_MAX_NAMELEN)) -+ goto out; - err = au_alloc_dinfo(dentry); - ret = ERR_PTR(err); - if (unlikely(err)) -diff --git a/fs/aufs/ioctl.c b/fs/aufs/ioctl.c -index 012361a..6f8bad8 100644 ---- a/fs/aufs/ioctl.c -+++ b/fs/aufs/ioctl.c -@@ -19,10 +19,67 @@ - /* - * ioctl - * plink-management and readdir in userspace. -+ * assist the pathconf(3) wrapper library. - */ - -+#include - #include "aufs.h" - -+static int au_wbr_fd(struct path *path) -+{ -+ int err, fd, flags; -+ aufs_bindex_t wbi, bindex, bend; -+ struct file *h_file; -+ struct super_block *sb; -+ struct dentry *root; -+ struct au_branch *wbr; -+ -+ err = get_unused_fd(); -+ if (unlikely(err < 0)) -+ goto out; -+ fd = err; -+ -+ flags = O_RDONLY | O_DIRECTORY; -+ if (force_o_largefile()) -+ flags |= O_LARGEFILE; -+ -+ wbi = 0; -+ sb = path->dentry->d_sb; -+ root = sb->s_root; -+ aufs_read_lock(root, AuLock_IR); -+ wbr = au_sbr(sb, wbi); -+ if (!(path->mnt->mnt_flags & MNT_READONLY) -+ && !au_br_writable(wbr->br_perm)) { -+ bend = au_sbend(sb); -+ for (bindex = 1; bindex <= bend; bindex++) { -+ wbr = au_sbr(sb, bindex); -+ if (au_br_writable(wbr->br_perm)) { -+ wbi = bindex; -+ break; -+ } -+ } -+ wbr = au_sbr(sb, wbi); -+ } -+ AuDbg("wbi %d\n", wbi); -+ h_file = au_h_open(root, wbi, flags, NULL); -+ aufs_read_unlock(root, AuLock_IR); -+ err = PTR_ERR(h_file); -+ if (IS_ERR(h_file)) -+ goto out_fd; -+ -+ atomic_dec(&wbr->br_count); /* cf. au_h_open() */ -+ fd_install(fd, h_file); -+ err = fd; -+ goto out; /* success */ -+ -+ out_fd: -+ put_unused_fd(fd); -+ out: -+ return err; -+} -+ -+/* ---------------------------------------------------------------------- */ -+ - long aufs_ioctl_dir(struct file *file, unsigned int cmd, unsigned long arg) - { - long err; -@@ -38,6 +95,27 @@ long aufs_ioctl_dir(struct file *file, unsigned int cmd, unsigned long arg) - err = au_rdu_ioctl(file, cmd, arg); - break; - -+ case AUFS_CTL_WBR_FD: -+ err = au_wbr_fd(&file->f_path); -+ break; -+ -+ default: -+ err = -EINVAL; -+ } -+ -+ AuTraceErr(err); -+ return err; -+} -+ -+long aufs_ioctl_nondir(struct file *file, unsigned int cmd, unsigned long arg) -+{ -+ long err; -+ -+ switch (cmd) { -+ case AUFS_CTL_WBR_FD: -+ err = au_wbr_fd(&file->f_path); -+ break; -+ - default: - err = -EINVAL; - } -diff --git a/fs/aufs/rdu.c b/fs/aufs/rdu.c -index 0a224f4..c38f280 100644 ---- a/fs/aufs/rdu.c -+++ b/fs/aufs/rdu.c -@@ -59,6 +59,8 @@ static int au_rdu_fill(void *__arg, const char *name, int nlen, - ent.bindex = rdu->cookie.bindex; - ent.type = d_type; - ent.nlen = nlen; -+ if (unlikely(nlen > AUFS_MAX_NAMELEN)) -+ ent.type = DT_UNKNOWN; - - err = -EFAULT; - if (copy_to_user(arg->ent.e, &ent, sizeof(ent))) -diff --git a/fs/aufs/vdir.c b/fs/aufs/vdir.c -index 50a3caf..361de5e 100644 ---- a/fs/aufs/vdir.c -+++ b/fs/aufs/vdir.c -@@ -474,9 +474,12 @@ static int fillvdir(void *__arg, const char *__name, int nlen, - - sb = arg->file->f_dentry->d_sb; - arg->err = au_ino(sb, arg->bindex, h_ino, d_type, &ino); -- if (!arg->err) -+ if (!arg->err) { -+ if (unlikely(nlen > AUFS_MAX_NAMELEN)) -+ d_type = DT_UNKNOWN; - arg->err = append_de(arg->vdir, name, nlen, ino, - d_type, &arg->delist); -+ } - } else if (au_ftest_fillvdir(arg->flags, WHABLE)) { - name += AUFS_WH_PFX_LEN; - nlen -= AUFS_WH_PFX_LEN; -@@ -486,10 +489,13 @@ static int fillvdir(void *__arg, const char *__name, int nlen, - if (shwh) - arg->err = au_wh_ino(sb, arg->bindex, h_ino, d_type, - &ino); -- if (!arg->err) -+ if (!arg->err) { -+ if (nlen <= AUFS_MAX_NAMELEN + AUFS_WH_PFX_LEN) -+ d_type = DT_UNKNOWN; - arg->err = au_nhash_append_wh - (&arg->whlist, name, nlen, ino, d_type, - arg->bindex, shwh); -+ } - } - - out: -diff --git a/fs/aufs/whout.c b/fs/aufs/whout.c -index b0ee925..674ab35 100644 ---- a/fs/aufs/whout.c -+++ b/fs/aufs/whout.c -@@ -123,9 +123,8 @@ struct dentry *au_whtmp_lkup(struct dentry *h_parent, struct au_branch *br, - { - struct dentry *dentry; - int i; -- /* cf. AUFS_MAX_NAMELEN in include/linux/aufs_type.h */ -- char defname[AUFS_WH_PFX_LEN * 2 + DNAME_INLINE_LEN_MIN + 1 -- + AUFS_WH_TMP_LEN + 1], *name, *p; -+ char defname[NAME_MAX - AUFS_MAX_NAMELEN + DNAME_INLINE_LEN_MIN + 1], -+ *name, *p; - static unsigned short cnt; - struct qstr qs; - -diff --git a/include/linux/aufs_type.h b/include/linux/aufs_type.h -index b4fee85..cc0263d 100644 ---- a/include/linux/aufs_type.h -+++ b/include/linux/aufs_type.h -@@ -23,7 +23,7 @@ - #include - #include - --#define AUFS_VERSION "2-standalone.tree-20091130" -+#define AUFS_VERSION "2-standalone.tree-20091207" - - /* todo? move this to linux-2.6.19/include/magic.h */ - #define AUFS_SUPER_MAGIC ('a' << 24 | 'u' << 16 | 'f' << 8 | 's') -@@ -110,7 +110,10 @@ enum { - - /* readdir in userspace */ - AuCtl_RDU, -- AuCtl_RDU_INO -+ AuCtl_RDU_INO, -+ -+ /* pathconf wrapper */ -+ AuCtl_WBR_FD - }; - - /* borrowed from linux/include/linux/kernel.h */ -@@ -187,5 +190,6 @@ struct aufs_rdu { - #define AUFS_CTL_PLINK_CLEAN _IO(AuCtlType, AuCtl_PLINK_CLEAN) - #define AUFS_CTL_RDU _IOWR(AuCtlType, AuCtl_RDU, struct aufs_rdu) - #define AUFS_CTL_RDU_INO _IOWR(AuCtlType, AuCtl_RDU_INO, struct aufs_rdu) -+#define AUFS_CTL_WBR_FD _IO(AuCtlType, AuCtl_WBR_FD) - - #endif /* __AUFS_TYPE_H__ */ diff --git a/debian/patches/features/all/aufs2/aufs2-20100125.patch b/debian/patches/features/all/aufs2/aufs2-20100125.patch deleted file mode 100644 index d7cd0772f..000000000 --- a/debian/patches/features/all/aufs2/aufs2-20100125.patch +++ /dev/null @@ -1,2865 +0,0 @@ -diff --git a/fs/aufs/Kconfig b/fs/aufs/Kconfig -index 3258e33..107f4fa 100644 ---- a/fs/aufs/Kconfig -+++ b/fs/aufs/Kconfig -@@ -80,6 +80,17 @@ config AUFS_RDU - environment variables for your readdir(3). - See detail in aufs.5. - -+config AUFS_SP_IATTR -+ bool "Respect the attributes (mtime/ctime mainly) of special files" -+ help -+ When you write something to a special file, some attributes of it -+ (mtime/ctime mainly) may be updated. Generally such updates are -+ less important (actually some device drivers and NFS ignore -+ it). But some applications (such like test program) requires -+ such updates. If you need these updates, then enable this -+ configuration which introduces some overhead. -+ Currently this configuration handles FIFO only. -+ - config AUFS_SHWH - bool "Show whiteouts" - help -diff --git a/fs/aufs/Makefile b/fs/aufs/Makefile -index 2b26cd1..9b075f1 100644 ---- a/fs/aufs/Makefile -+++ b/fs/aufs/Makefile -@@ -29,5 +29,6 @@ aufs-$(CONFIG_AUFS_HINOTIFY) += hinotify.o - aufs-$(CONFIG_AUFS_EXPORT) += export.o - aufs-$(CONFIG_AUFS_POLL) += poll.o - aufs-$(CONFIG_AUFS_RDU) += rdu.o -+aufs-$(CONFIG_AUFS_SP_IATTR) += f_op_sp.o - aufs-$(CONFIG_AUFS_DEBUG) += debug.o - aufs-$(CONFIG_AUFS_MAGIC_SYSRQ) += sysrq.o -diff --git a/fs/aufs/aufs.h b/fs/aufs/aufs.h -index 96307bb..0dfb6fb 100644 ---- a/fs/aufs/aufs.h -+++ b/fs/aufs/aufs.h -@@ -1,5 +1,5 @@ - /* -- * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * Copyright (C) 2005-2010 Junjiro R. Okajima - * - * This program, aufs is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by -@@ -25,6 +25,14 @@ - - #ifdef __KERNEL__ - -+#define AuStub(type, name, body, ...) \ -+ static inline type name(__VA_ARGS__) { body; } -+ -+#define AuStubVoid(name, ...) \ -+ AuStub(void, name, , __VA_ARGS__) -+#define AuStubInt0(name, ...) \ -+ AuStub(int, name, return 0, __VA_ARGS__) -+ - #include "debug.h" - - #include "branch.h" -diff --git a/fs/aufs/branch.c b/fs/aufs/branch.c -index bb7ad86..2ec2a63 100644 ---- a/fs/aufs/branch.c -+++ b/fs/aufs/branch.c -@@ -1,5 +1,5 @@ - /* -- * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * Copyright (C) 2005-2010 Junjiro R. Okajima - * - * This program, aufs is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by -@@ -111,7 +111,9 @@ static struct au_branch *au_br_alloc(struct super_block *sb, int new_nbranch, - { - struct au_branch *add_branch; - struct dentry *root; -+ int err; - -+ err = -ENOMEM; - root = sb->s_root; - add_branch = kmalloc(sizeof(*add_branch), GFP_NOFS); - if (unlikely(!add_branch)) -@@ -126,18 +128,20 @@ static struct au_branch *au_br_alloc(struct super_block *sb, int new_nbranch, - goto out_br; - } - -- if (unlikely(au_sbr_realloc(au_sbi(sb), new_nbranch) -- || au_di_realloc(au_di(root), new_nbranch) -- || au_ii_realloc(au_ii(root->d_inode), new_nbranch))) -- goto out_wbr; -- return add_branch; /* success */ -+ err = au_sbr_realloc(au_sbi(sb), new_nbranch); -+ if (!err) -+ err = au_di_realloc(au_di(root), new_nbranch); -+ if (!err) -+ err = au_ii_realloc(au_ii(root->d_inode), new_nbranch); -+ if (!err) -+ return add_branch; /* success */ - -- out_wbr: - kfree(add_branch->br_wbr); -+ - out_br: - kfree(add_branch); - out: -- return ERR_PTR(-ENOMEM); -+ return ERR_PTR(err); - } - - /* -@@ -147,13 +151,14 @@ static int test_br(struct inode *inode, int brperm, char *path) - { - int err; - -- err = 0; -- if (unlikely(au_br_writable(brperm) && IS_RDONLY(inode))) { -- pr_err("write permission for readonly mount or inode, %s\n", -- path); -- err = -EINVAL; -- } -+ err = (au_br_writable(brperm) && IS_RDONLY(inode)); -+ if (!err) -+ goto out; - -+ err = -EINVAL; -+ pr_err("write permission for readonly mount or inode, %s\n", path); -+ -+ out: - return err; - } - -@@ -421,7 +426,7 @@ static void au_br_do_add(struct super_block *sb, struct dentry *h_dentry, - - root = sb->s_root; - root_inode = root->d_inode; -- au_plink_block_maintain(sb); -+ au_plink_maint_block(sb); - bend = au_sbend(sb); - amount = bend + 1 - bindex; - au_br_do_add_brp(au_sbi(sb), bindex, br, bend, amount); -@@ -647,6 +652,7 @@ static void au_br_do_del_brp(struct au_sbinfo *sbinfo, - p = krealloc(sbinfo->si_branch, sizeof(*p) * bend, GFP_NOFS); - if (p) - sbinfo->si_branch = p; -+ /* harmless error */ - } - - static void au_br_do_del_hdp(struct au_dinfo *dinfo, const aufs_bindex_t bindex, -@@ -665,6 +671,7 @@ static void au_br_do_del_hdp(struct au_dinfo *dinfo, const aufs_bindex_t bindex, - p = krealloc(dinfo->di_hdentry, sizeof(*p) * bend, GFP_NOFS); - if (p) - dinfo->di_hdentry = p; -+ /* harmless error */ - } - - static void au_br_do_del_hip(struct au_iinfo *iinfo, const aufs_bindex_t bindex, -@@ -684,6 +691,7 @@ static void au_br_do_del_hip(struct au_iinfo *iinfo, const aufs_bindex_t bindex, - p = krealloc(iinfo->ii_hinode, sizeof(*p) * bend, GFP_NOFS); - if (p) - iinfo->ii_hinode = p; -+ /* harmless error */ - } - - static void au_br_do_del(struct super_block *sb, aufs_bindex_t bindex, -@@ -698,7 +706,7 @@ static void au_br_do_del(struct super_block *sb, aufs_bindex_t bindex, - - root = sb->s_root; - inode = root->d_inode; -- au_plink_block_maintain(sb); -+ au_plink_maint_block(sb); - sbinfo = au_sbi(sb); - bend = sbinfo->si_bend; - -@@ -912,7 +920,7 @@ int au_br_mod(struct super_block *sb, struct au_opt_mod *mod, int remount, - struct au_branch *br; - - root = sb->s_root; -- au_plink_block_maintain(sb); -+ au_plink_maint_block(sb); - bindex = au_find_dbindex(root, mod->h_root); - if (bindex < 0) { - if (remount) -diff --git a/fs/aufs/branch.h b/fs/aufs/branch.h -index 1a7219c..5e0e030 100644 ---- a/fs/aufs/branch.h -+++ b/fs/aufs/branch.h -@@ -1,5 +1,5 @@ - /* -- * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * Copyright (C) 2005-2010 Junjiro R. Okajima - * - * This program, aufs is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by -diff --git a/fs/aufs/conf.mk b/fs/aufs/conf.mk -index 9939c03..02b43a1 100644 ---- a/fs/aufs/conf.mk -+++ b/fs/aufs/conf.mk -@@ -11,6 +11,7 @@ $(foreach i, BRANCH_MAX_127 BRANCH_MAX_511 BRANCH_MAX_1023 BRANCH_MAX_32767 \ - HINOTIFY \ - EXPORT INO_T_64 \ - RDU \ -+ SP_IATTR \ - SHWH \ - BR_RAMFS \ - BR_FUSE POLL \ -diff --git a/fs/aufs/cpup.c b/fs/aufs/cpup.c -index 1219aad..0408da8 100644 ---- a/fs/aufs/cpup.c -+++ b/fs/aufs/cpup.c -@@ -1,5 +1,5 @@ - /* -- * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * Copyright (C) 2005-2010 Junjiro R. Okajima - * - * This program, aufs is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by -diff --git a/fs/aufs/cpup.h b/fs/aufs/cpup.h -index 29e2508..506350d 100644 ---- a/fs/aufs/cpup.h -+++ b/fs/aufs/cpup.h -@@ -1,5 +1,5 @@ - /* -- * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * Copyright (C) 2005-2010 Junjiro R. Okajima - * - * This program, aufs is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by -diff --git a/fs/aufs/dbgaufs.c b/fs/aufs/dbgaufs.c -index 9573b70..e69cbd3 100644 ---- a/fs/aufs/dbgaufs.c -+++ b/fs/aufs/dbgaufs.c -@@ -1,5 +1,5 @@ - /* -- * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * Copyright (C) 2005-2010 Junjiro R. Okajima - * - * This program, aufs is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by -diff --git a/fs/aufs/dbgaufs.h b/fs/aufs/dbgaufs.h -index 67a7964..ae41480 100644 ---- a/fs/aufs/dbgaufs.h -+++ b/fs/aufs/dbgaufs.h -@@ -1,5 +1,5 @@ - /* -- * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * Copyright (C) 2005-2010 Junjiro R. Okajima - * - * This program, aufs is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by -@@ -39,40 +39,13 @@ void dbgaufs_si_fin(struct au_sbinfo *sbinfo); - int dbgaufs_si_init(struct au_sbinfo *sbinfo); - void dbgaufs_fin(void); - int __init dbgaufs_init(void); -- - #else -- --static inline --void dbgaufs_brs_del(struct super_block *sb, aufs_bindex_t bindex) --{ -- /* empty */ --} -- --static inline --void dbgaufs_brs_add(struct super_block *sb, aufs_bindex_t bindex) --{ -- /* empty */ --} -- --static inline --void dbgaufs_si_fin(struct au_sbinfo *sbinfo) --{ -- /* empty */ --} -- --static inline --int dbgaufs_si_init(struct au_sbinfo *sbinfo) --{ -- return 0; --} -- --#define dbgaufs_fin() do {} while (0) -- --static inline --int __init dbgaufs_init(void) --{ -- return 0; --} -+AuStubVoid(dbgaufs_brs_del, struct super_block *sb, aufs_bindex_t bindex) -+AuStubVoid(dbgaufs_brs_add, struct super_block *sb, aufs_bindex_t bindex) -+AuStubVoid(dbgaufs_si_fin, struct au_sbinfo *sbinfo) -+AuStubInt0(dbgaufs_si_init, struct au_sbinfo *sbinfo) -+AuStubVoid(dbgaufs_fin, void) -+AuStubInt0(__init dbgaufs_init, void) - #endif /* CONFIG_DEBUG_FS */ - - #endif /* __KERNEL__ */ -diff --git a/fs/aufs/dcsub.c b/fs/aufs/dcsub.c -index 43a8cb4..e7ad06c 100644 ---- a/fs/aufs/dcsub.c -+++ b/fs/aufs/dcsub.c -@@ -1,5 +1,5 @@ - /* -- * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * Copyright (C) 2005-2010 Junjiro R. Okajima - * - * This program, aufs is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by -diff --git a/fs/aufs/dcsub.h b/fs/aufs/dcsub.h -index bb934b4..469d3b4 100644 ---- a/fs/aufs/dcsub.h -+++ b/fs/aufs/dcsub.h -@@ -1,5 +1,5 @@ - /* -- * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * Copyright (C) 2005-2010 Junjiro R. Okajima - * - * This program, aufs is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by -diff --git a/fs/aufs/debug.c b/fs/aufs/debug.c -index e34d1c2..87935e9 100644 ---- a/fs/aufs/debug.c -+++ b/fs/aufs/debug.c -@@ -1,5 +1,5 @@ - /* -- * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * Copyright (C) 2005-2010 Junjiro R. Okajima - * - * This program, aufs is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by -@@ -188,7 +188,8 @@ static int do_pri_file(aufs_bindex_t bindex, struct file *file) - && file->f_dentry - && au_test_aufs(file->f_dentry->d_sb) - && au_fi(file)) -- snprintf(a, sizeof(a), ", mmapped %d", au_test_mmapped(file)); -+ snprintf(a, sizeof(a), ", mmapped %d", -+ !!au_fi(file)->fi_h_vm_ops); - dpri("f%d: mode 0x%x, flags 0%o, cnt %ld, pos %llu%s\n", - bindex, file->f_mode, file->f_flags, (long)file_count(file), - file->f_pos, a); -diff --git a/fs/aufs/debug.h b/fs/aufs/debug.h -index 312e1af..dea0ea6 100644 ---- a/fs/aufs/debug.h -+++ b/fs/aufs/debug.h -@@ -1,5 +1,5 @@ - /* -- * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * Copyright (C) 2005-2010 Junjiro R. Okajima - * - * This program, aufs is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by -@@ -55,11 +55,8 @@ static inline int au_debug_test(void) - } - #else - #define AuDebugOn(a) do {} while (0) --#define au_debug() do {} while (0) --static inline int au_debug_test(void) --{ -- return 0; --} -+AuStubVoid(au_debug, int n) -+AuStubInt0(au_debug_test, void) - #endif /* CONFIG_AUFS_DEBUG */ - - /* ---------------------------------------------------------------------- */ -@@ -187,37 +184,15 @@ void au_debug_sbinfo_init(struct au_sbinfo *sbinfo); - au_dbg_iattr(ia); \ - } while (0) - #else --static inline void au_dbg_verify_dir_parent(struct dentry *dentry, -- unsigned int sigen) --{ -- /* empty */ --} --static inline void au_dbg_verify_nondir_parent(struct dentry *dentry, -- unsigned int sigen) --{ -- /* empty */ --} --static inline void au_dbg_verify_gen(struct dentry *parent, unsigned int sigen) --{ -- /* empty */ --} --static inline void au_dbg_verify_hf(struct au_finfo *finfo) --{ -- /* empty */ --} --static inline void au_dbg_verify_kthread(void) --{ -- /* empty */ --} -+AuStubVoid(au_dbg_verify_dir_parent, struct dentry *dentry, unsigned int sigen) -+AuStubVoid(au_dbg_verify_nondir_parent, struct dentry *dentry, -+ unsigned int sigen) -+AuStubVoid(au_dbg_verify_gen, struct dentry *parent, unsigned int sigen) -+AuStubVoid(au_dbg_verify_hf, struct au_finfo *finfo) -+AuStubVoid(au_dbg_verify_kthread, void) -+AuStubInt0(__init au_debug_init, void) -+AuStubVoid(au_debug_sbinfo_init, struct au_sbinfo *sbinfo) - --static inline int au_debug_init(void) --{ -- return 0; --} --static inline void au_debug_sbinfo_init(struct au_sbinfo *sbinfo) --{ -- /* empty */ --} - #define AuDbgWhlist(w) do {} while (0) - #define AuDbgVdir(v) do {} while (0) - #define AuDbgInode(i) do {} while (0) -@@ -241,16 +216,13 @@ void au_sysrq_fin(void); - handle_sysrq('w', vc_cons[fg_console].d->vc_tty); \ - } while (0) - #else --#define au_dbg_blocked() do {} while (0) -+AuStubVoid(au_dbg_blocked, void) - #endif - - #else --static inline int au_sysrq_init(void) --{ -- return 0; --} --#define au_sysrq_fin() do {} while (0) --#define au_dbg_blocked() do {} while (0) -+AuStubInt0(__init au_sysrq_init, void) -+AuStubVoid(au_sysrq_fin, void) -+AuStubVoid(au_dbg_blocked, void) - #endif /* CONFIG_AUFS_MAGIC_SYSRQ */ - - #endif /* __KERNEL__ */ -diff --git a/fs/aufs/dentry.c b/fs/aufs/dentry.c -index 28525d4..718df2e 100644 ---- a/fs/aufs/dentry.c -+++ b/fs/aufs/dentry.c -@@ -1,5 +1,5 @@ - /* -- * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * Copyright (C) 2005-2010 Junjiro R. Okajima - * - * This program, aufs is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by -@@ -102,13 +102,11 @@ au_do_lookup(struct dentry *h_parent, struct dentry *dentry, - { - struct dentry *h_dentry; - struct inode *h_inode, *inode; -- struct qstr *name; - struct au_branch *br; - int wh_found, opq; - unsigned char wh_able; - const unsigned char allow_neg = !!au_ftest_lkup(args->flags, ALLOW_NEG); - -- name = &dentry->d_name; - wh_found = 0; - br = au_sbr(dentry->d_sb, bindex); - wh_able = !!au_br_whable(br->br_perm); -@@ -127,7 +125,7 @@ au_do_lookup(struct dentry *h_parent, struct dentry *dentry, - return NULL; /* success */ - - real_lookup: -- h_dentry = au_lkup_one(name, h_parent, br, args->nd); -+ h_dentry = au_lkup_one(&dentry->d_name, h_parent, br, args->nd); - if (IS_ERR(h_dentry)) - goto out; - -@@ -197,7 +195,6 @@ int au_lkup_dentry(struct dentry *dentry, aufs_bindex_t bstart, mode_t type, - struct dentry *parent; - struct inode *inode; - -- parent = dget_parent(dentry); - err = au_test_shwh(dentry->d_sb, name); - if (unlikely(err)) - goto out; -@@ -212,6 +209,7 @@ int au_lkup_dentry(struct dentry *dentry, aufs_bindex_t bstart, mode_t type, - au_fset_lkup(args.flags, ALLOW_NEG); - - npositive = 0; -+ parent = dget_parent(dentry); - btail = au_dbtaildir(parent); - for (bindex = bstart; bindex <= btail; bindex++) { - struct dentry *h_parent, *h_dentry; -@@ -238,7 +236,7 @@ int au_lkup_dentry(struct dentry *dentry, aufs_bindex_t bstart, mode_t type, - mutex_unlock(&h_dir->i_mutex); - err = PTR_ERR(h_dentry); - if (IS_ERR(h_dentry)) -- goto out_wh; -+ goto out_parent; - au_fclr_lkup(args.flags, ALLOW_NEG); - - if (au_dbwh(dentry) >= 0) -@@ -271,10 +269,10 @@ int au_lkup_dentry(struct dentry *dentry, aufs_bindex_t bstart, mode_t type, - /* both of real entry and whiteout found */ - err = -EIO; - -- out_wh: -+ out_parent: -+ dput(parent); - kfree(whname.name); - out: -- dput(parent); - return err; - } - -@@ -310,12 +308,10 @@ int au_lkup_neg(struct dentry *dentry, aufs_bindex_t bindex) - { - int err; - struct dentry *parent, *h_parent, *h_dentry; -- struct qstr *name; - -- name = &dentry->d_name; - parent = dget_parent(dentry); - h_parent = au_h_dptr(parent, bindex); -- h_dentry = au_sio_lkup_one(name, h_parent, -+ h_dentry = au_sio_lkup_one(&dentry->d_name, h_parent, - au_sbr(dentry->d_sb, bindex)); - err = PTR_ERR(h_dentry); - if (IS_ERR(h_dentry)) -@@ -328,12 +324,12 @@ int au_lkup_neg(struct dentry *dentry, aufs_bindex_t bindex) - goto out; - } - -+ err = 0; - if (bindex < au_dbstart(dentry)) - au_set_dbstart(dentry, bindex); - if (au_dbend(dentry) < bindex) - au_set_dbend(dentry, bindex); - au_set_h_dptr(dentry, bindex, h_dentry); -- err = 0; - - out: - dput(parent); -diff --git a/fs/aufs/dentry.h b/fs/aufs/dentry.h -index b1f9a6e..42cd70c 100644 ---- a/fs/aufs/dentry.h -+++ b/fs/aufs/dentry.h -@@ -1,5 +1,5 @@ - /* -- * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * Copyright (C) 2005-2010 Junjiro R. Okajima - * - * This program, aufs is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by -@@ -221,10 +221,7 @@ static inline void au_hin_di_reinit(struct dentry *dentry) - dentry->d_fsdata = NULL; - } - #else --static inline void au_hin_di_reinit(struct dentry *dentry __maybe_unused) --{ -- /* empty */ --} -+AuStubVoid(au_hin_di_reinit, struct dentry *dentry __maybe_unused) - #endif /* CONFIG_AUFS_HINOTIFY */ - - #endif /* __KERNEL__ */ -diff --git a/fs/aufs/dinfo.c b/fs/aufs/dinfo.c -index 0010c99..dfe4eb8 100644 ---- a/fs/aufs/dinfo.c -+++ b/fs/aufs/dinfo.c -@@ -1,5 +1,5 @@ - /* -- * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * Copyright (C) 2005-2010 Junjiro R. Okajima - * - * This program, aufs is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by -diff --git a/fs/aufs/dir.c b/fs/aufs/dir.c -index bb0eb64..aec9452 100644 ---- a/fs/aufs/dir.c -+++ b/fs/aufs/dir.c -@@ -1,5 +1,5 @@ - /* -- * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * Copyright (C) 2005-2010 Junjiro R. Okajima - * - * This program, aufs is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by -@@ -112,9 +112,7 @@ static int reopen_dir(struct file *file) - au_set_h_fptr(file, bindex, NULL); - au_set_fbend(file, btail); - -- spin_lock(&file->f_lock); -- flags = file->f_flags; -- spin_unlock(&file->f_lock); -+ flags = vfsub_file_flags(file); - for (bindex = bstart; bindex <= btail; bindex++) { - h_dentry = au_h_dptr(dentry, bindex); - if (!h_dentry) -@@ -150,7 +148,6 @@ static int do_open_dir(struct file *file, int flags) - err = 0; - dentry = file->f_dentry; - au_set_fvdir_cache(file, NULL); -- au_fi(file)->fi_maintain_plink = 0; - file->f_version = dentry->d_inode->i_version; - bindex = au_dbstart(dentry); - au_set_fbstart(file, bindex); -@@ -193,24 +190,13 @@ static int aufs_release_dir(struct inode *inode __maybe_unused, - { - struct au_vdir *vdir_cache; - struct super_block *sb; -- struct au_sbinfo *sbinfo; - - sb = file->f_dentry->d_sb; -- si_noflush_read_lock(sb); -- fi_write_lock(file); -- vdir_cache = au_fvdir_cache(file); -+ vdir_cache = au_fi(file)->fi_vdir_cache; /* lock-free */ - if (vdir_cache) - au_vdir_free(vdir_cache); -- if (au_fi(file)->fi_maintain_plink) { -- sbinfo = au_sbi(sb); -- /* clear the flag without write-lock */ -- sbinfo->au_si_status &= ~AuSi_MAINTAIN_PLINK; -- smp_mb(); -- wake_up_all(&sbinfo->si_plink_wq); -- } -- fi_write_unlock(file); -+ au_plink_maint_leave(file); - au_finfo_fin(file); -- si_read_unlock(sb); - return 0; - } - -diff --git a/fs/aufs/dir.h b/fs/aufs/dir.h -index d90c63f..8ba9c88 100644 ---- a/fs/aufs/dir.h -+++ b/fs/aufs/dir.h -@@ -1,5 +1,5 @@ - /* -- * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * Copyright (C) 2005-2010 Junjiro R. Okajima - * - * This program, aufs is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by -diff --git a/fs/aufs/export.c b/fs/aufs/export.c -index 5b5c2c4..1b3a9d9 100644 ---- a/fs/aufs/export.c -+++ b/fs/aufs/export.c -@@ -1,5 +1,5 @@ - /* -- * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * Copyright (C) 2005-2010 Junjiro R. Okajima - * - * This program, aufs is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by -@@ -347,8 +347,7 @@ static struct dentry *au_lkup_by_ino(struct path *path, ino_t ino, - parent = path->dentry; - if (nsi_lock) - si_read_unlock(parent->d_sb); -- path_get(path); -- file = vfsub_dentry_open(path, au_dir_roflags, current_cred()); -+ file = vfsub_dentry_open(path, au_dir_roflags); - dentry = (void *)file; - if (IS_ERR(file)) - goto out; -diff --git a/fs/aufs/f_op.c b/fs/aufs/f_op.c -index 65c50bc..529fca6 100644 ---- a/fs/aufs/f_op.c -+++ b/fs/aufs/f_op.c -@@ -1,5 +1,5 @@ - /* -- * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * Copyright (C) 2005-2010 Junjiro R. Okajima - * - * This program, aufs is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by -@@ -26,6 +26,7 @@ - #include - #include - #include -+#include - #include "aufs.h" - - /* common function to regular file and dir */ -@@ -63,7 +64,7 @@ int aufs_flush(struct file *file, fl_owner_t id) - - /* ---------------------------------------------------------------------- */ - --static int do_open_nondir(struct file *file, int flags) -+int au_do_open_nondir(struct file *file, int flags) - { - int err; - aufs_bindex_t bindex; -@@ -100,18 +101,13 @@ static int do_open_nondir(struct file *file, int flags) - static int aufs_open_nondir(struct inode *inode __maybe_unused, - struct file *file) - { -- return au_do_open(file, do_open_nondir); -+ return au_do_open(file, au_do_open_nondir); - } - --static int aufs_release_nondir(struct inode *inode __maybe_unused, -- struct file *file) -+int aufs_release_nondir(struct inode *inode __maybe_unused, struct file *file) - { -- struct super_block *sb = file->f_dentry->d_sb; -- -- si_noflush_read_lock(sb); - kfree(au_fi(file)->fi_vm_ops); - au_finfo_fin(file); -- si_read_unlock(sb); - return 0; - } - -@@ -188,6 +184,34 @@ static ssize_t aufs_write(struct file *file, const char __user *ubuf, - return err; - } - -+static ssize_t au_do_aio(struct file *h_file, int rw, struct kiocb *kio, -+ const struct iovec *iov, unsigned long nv, loff_t pos) -+{ -+ ssize_t err; -+ struct file *file; -+ -+ err = security_file_permission(h_file, rw); -+ if (unlikely(err)) -+ goto out; -+ -+ file = kio->ki_filp; -+ if (!is_sync_kiocb(kio)) { -+ get_file(h_file); -+ fput(file); -+ } -+ kio->ki_filp = h_file; -+ if (rw == MAY_READ) -+ err = h_file->f_op->aio_read(kio, iov, nv, pos); -+ else if (rw == MAY_WRITE) -+ err = h_file->f_op->aio_write(kio, iov, nv, pos); -+ else -+ BUG(); -+ /* do not restore kio->ki_filp */ -+ -+ out: -+ return err; -+} -+ - static ssize_t aufs_aio_read(struct kiocb *kio, const struct iovec *iov, - unsigned long nv, loff_t pos) - { -@@ -207,15 +231,7 @@ static ssize_t aufs_aio_read(struct kiocb *kio, const struct iovec *iov, - err = -ENOSYS; - h_file = au_h_fptr(file, au_fbstart(file)); - if (h_file->f_op && h_file->f_op->aio_read) { -- err = security_file_permission(h_file, MAY_READ); -- if (unlikely(err)) -- goto out_unlock; -- if (!is_sync_kiocb(kio)) { -- get_file(h_file); -- fput(file); -- } -- kio->ki_filp = h_file; -- err = h_file->f_op->aio_read(kio, iov, nv, pos); -+ err = au_do_aio(h_file, MAY_READ, kio, iov, nv, pos); - /* todo: necessary? */ - /* file->f_ra = h_file->f_ra; */ - fsstack_copy_attr_atime(dentry->d_inode, -@@ -224,9 +240,9 @@ static ssize_t aufs_aio_read(struct kiocb *kio, const struct iovec *iov, - /* currently there is no such fs */ - WARN_ON_ONCE(h_file->f_op && h_file->f_op->read); - -- out_unlock: - di_read_unlock(dentry, AuLock_IR); - fi_read_unlock(file); -+ - out: - si_read_unlock(sb); - return err; -@@ -236,7 +252,6 @@ static ssize_t aufs_aio_write(struct kiocb *kio, const struct iovec *iov, - unsigned long nv, loff_t pos) - { - ssize_t err; -- aufs_bindex_t bstart; - struct au_pin pin; - struct dentry *dentry; - struct inode *inode; -@@ -260,19 +275,10 @@ static ssize_t aufs_aio_write(struct kiocb *kio, const struct iovec *iov, - goto out_unlock; - - err = -ENOSYS; -- bstart = au_fbstart(file); -- h_file = au_h_fptr(file, bstart); -+ h_file = au_h_fptr(file, au_fbstart(file)); - au_unpin(&pin); - if (h_file->f_op && h_file->f_op->aio_write) { -- err = security_file_permission(h_file, MAY_WRITE); -- if (unlikely(err)) -- goto out_unlock; -- if (!is_sync_kiocb(kio)) { -- get_file(h_file); -- fput(file); -- } -- kio->ki_filp = h_file; -- err = h_file->f_op->aio_write(kio, iov, nv, pos); -+ err = au_do_aio(h_file, MAY_WRITE, kio, iov, nv, pos); - au_cpup_attr_timesizes(inode); - inode->i_mode = h_file->f_dentry->d_inode->i_mode; - } else -@@ -464,33 +470,62 @@ static struct vm_operations_struct aufs_vm_ops = { - - /* ---------------------------------------------------------------------- */ - -+/* cf. linux/include/linux/mman.h: calc_vm_prot_bits() */ -+#define AuConv_VM_PROT(f, b) _calc_vm_trans(f, VM_##b, PROT_##b) -+ -+static unsigned long au_arch_prot_conv(unsigned long flags) -+{ -+ /* currently ppc64 only */ -+#ifdef CONFIG_PPC64 -+ /* cf. linux/arch/powerpc/include/asm/mman.h */ -+ AuDebugOn(arch_calc_vm_prot_bits(-1) != VM_SAO); -+ return AuConv_VM_PROT(flags, SAO); -+#else -+ AuDebugOn(arch_calc_vm_prot_bits(-1)); -+ return 0; -+#endif -+} -+ - static unsigned long au_prot_conv(unsigned long flags) - { -- unsigned long prot; -+ return AuConv_VM_PROT(flags, READ) -+ | AuConv_VM_PROT(flags, WRITE) -+ | AuConv_VM_PROT(flags, EXEC) -+ | au_arch_prot_conv(flags); -+} -+ -+/* cf. linux/include/linux/mman.h: calc_vm_flag_bits() */ -+#define AuConv_VM_MAP(f, b) _calc_vm_trans(f, VM_##b, MAP_##b) - -- prot = 0; -- if (flags & VM_READ) -- prot |= PROT_READ; -- if (flags & VM_WRITE) -- prot |= PROT_WRITE; -- if (flags & VM_EXEC) -- prot |= PROT_EXEC; -- return prot; -+static unsigned long au_flag_conv(unsigned long flags) -+{ -+ return AuConv_VM_MAP(flags, GROWSDOWN) -+ | AuConv_VM_MAP(flags, DENYWRITE) -+ | AuConv_VM_MAP(flags, EXECUTABLE) -+ | AuConv_VM_MAP(flags, LOCKED); - } - - static struct vm_operations_struct *au_vm_ops(struct file *h_file, - struct vm_area_struct *vma) - { - struct vm_operations_struct *vm_ops; -+ unsigned long prot; - int err; - - vm_ops = ERR_PTR(-ENODEV); - if (!h_file->f_op || !h_file->f_op->mmap) - goto out; - -- err = ima_file_mmap(h_file, au_prot_conv(vma->vm_flags)); -+ prot = au_prot_conv(vma->vm_flags); -+ err = security_file_mmap(h_file, /*reqprot*/prot, prot, -+ au_flag_conv(vma->vm_flags), vma->vm_start, 0); - vm_ops = ERR_PTR(err); -- if (err) -+ if (unlikely(err)) -+ goto out; -+ -+ err = ima_file_mmap(h_file, prot); -+ vm_ops = ERR_PTR(err); -+ if (unlikely(err)) - goto out; - - err = h_file->f_op->mmap(h_file, vma); -@@ -555,10 +590,25 @@ static int aufs_mmap(struct file *file, struct vm_area_struct *vma) - dentry = file->f_dentry; - wlock = !!(file->f_mode & FMODE_WRITE) && (vma->vm_flags & VM_SHARED); - sb = dentry->d_sb; -+ /* -+ * Very ugly BKL approach to keep the order of locks. -+ * Here mm->mmap_sem is acquired by our caller. -+ * -+ * native readdir, i_mutex, copy_to_user, mmap_sem -+ * aufs readdir, i_mutex, rwsem, nested-i_mutex, copy_to_user, mmap_sem -+ * aufs mmap, mmap_sem, rwsem -+ * -+ * Unlock it temporary. -+ */ -+ lock_kernel(); -+ up_write(¤t->mm->mmap_sem); - si_read_lock(sb, AuLock_FLUSH); - err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/1); -- if (unlikely(err)) -+ if (unlikely(err)) { -+ down_write(¤t->mm->mmap_sem); -+ unlock_kernel(); - goto out; -+ } - - mmapped = !!au_test_mmapped(file); - if (wlock) { -@@ -566,11 +616,16 @@ static int aufs_mmap(struct file *file, struct vm_area_struct *vma) - - err = au_ready_to_write(file, -1, &pin); - di_downgrade_lock(dentry, AuLock_IR); -- if (unlikely(err)) -+ if (unlikely(err)) { -+ down_write(¤t->mm->mmap_sem); -+ unlock_kernel(); - goto out_unlock; -+ } - au_unpin(&pin); - } else - di_downgrade_lock(dentry, AuLock_IR); -+ down_write(¤t->mm->mmap_sem); -+ unlock_kernel(); - - h_file = au_h_fptr(file, au_fbstart(file)); - if (!mmapped && au_test_fs_bad_mapping(h_file->f_dentry->d_sb)) { -diff --git a/fs/aufs/f_op_sp.c b/fs/aufs/f_op_sp.c -new file mode 100644 -index 0000000..f4a4124 ---- /dev/null -+++ b/fs/aufs/f_op_sp.c -@@ -0,0 +1,290 @@ -+/* -+ * Copyright (C) 2005-2010 Junjiro R. Okajima -+ * -+ * This program, aufs is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ */ -+ -+/* -+ * file operations for special files. -+ * while they exist in aufs virtually, -+ * their file I/O is handled out of aufs. -+ */ -+ -+#include -+#include "aufs.h" -+ -+static ssize_t aufs_aio_read_sp(struct kiocb *kio, const struct iovec *iov, -+ unsigned long nv, loff_t pos) -+{ -+ ssize_t err; -+ aufs_bindex_t bstart; -+ unsigned char wbr; -+ struct file *file, *h_file; -+ struct super_block *sb; -+ -+ file = kio->ki_filp; -+ sb = file->f_dentry->d_sb; -+ si_read_lock(sb, AuLock_FLUSH); -+ fi_read_lock(file); -+ bstart = au_fbstart(file); -+ h_file = au_h_fptr(file, bstart); -+ fi_read_unlock(file); -+ wbr = !!au_br_writable(au_sbr(sb, bstart)->br_perm); -+ si_read_unlock(sb); -+ -+ /* do not change the file in kio */ -+ AuDebugOn(!h_file->f_op || !h_file->f_op->aio_read); -+ err = h_file->f_op->aio_read(kio, iov, nv, pos); -+ if (err > 0 && wbr) -+ file_accessed(h_file); -+ -+ return err; -+} -+ -+static ssize_t aufs_aio_write_sp(struct kiocb *kio, const struct iovec *iov, -+ unsigned long nv, loff_t pos) -+{ -+ ssize_t err; -+ aufs_bindex_t bstart; -+ unsigned char wbr; -+ struct super_block *sb; -+ struct file *file, *h_file; -+ -+ file = kio->ki_filp; -+ sb = file->f_dentry->d_sb; -+ si_read_lock(sb, AuLock_FLUSH); -+ fi_read_lock(file); -+ bstart = au_fbstart(file); -+ h_file = au_h_fptr(file, bstart); -+ fi_read_unlock(file); -+ wbr = !!au_br_writable(au_sbr(sb, bstart)->br_perm); -+ si_read_unlock(sb); -+ -+ /* do not change the file in kio */ -+ AuDebugOn(!h_file->f_op || !h_file->f_op->aio_write); -+ err = h_file->f_op->aio_write(kio, iov, nv, pos); -+ if (err > 0 && wbr) -+ file_update_time(h_file); -+ -+ return err; -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+static int aufs_release_sp(struct inode *inode, struct file *file) -+{ -+ int err; -+ struct file *h_file; -+ -+ fi_read_lock(file); -+ h_file = au_h_fptr(file, au_fbstart(file)); -+ fi_read_unlock(file); -+ /* close this fifo in aufs */ -+ err = h_file->f_op->release(inode, file); /* ignore */ -+ aufs_release_nondir(inode, file); /* ignore */ -+ return err; -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+/* currently, support only FIFO */ -+enum {AuSp_FIFO, AuSp_FIFO_R, AuSp_FIFO_W, AuSp_FIFO_RW, -+ /* AuSp_SOCK, AuSp_CHR, AuSp_BLK, */ -+ AuSp_Last}; -+static int aufs_open_sp(struct inode *inode, struct file *file); -+static struct au_sp_fop { -+ int done; -+ struct file_operations fop; /* not 'const' */ -+ spinlock_t spin; -+} au_sp_fop[AuSp_Last] = { -+ [AuSp_FIFO] = { -+ .fop = { -+ .open = aufs_open_sp -+ } -+ } -+}; -+ -+static void au_init_fop_sp(struct file *file) -+{ -+ struct au_sp_fop *p; -+ int i; -+ struct file *h_file; -+ -+ p = au_sp_fop; -+ if (unlikely(!p->done)) { -+ /* initialize first time only */ -+ static DEFINE_SPINLOCK(spin); -+ -+ spin_lock(&spin); -+ if (!p->done) { -+ BUILD_BUG_ON(sizeof(au_sp_fop)/sizeof(*au_sp_fop) -+ != AuSp_Last); -+ for (i = 0; i < AuSp_Last; i++) -+ spin_lock_init(&p[i].spin); -+ p->done = 1; -+ } -+ spin_unlock(&spin); -+ } -+ -+ switch (file->f_mode & (FMODE_READ | FMODE_WRITE)) { -+ case FMODE_READ: -+ i = AuSp_FIFO_R; -+ break; -+ case FMODE_WRITE: -+ i = AuSp_FIFO_W; -+ break; -+ case FMODE_READ | FMODE_WRITE: -+ i = AuSp_FIFO_RW; -+ break; -+ default: -+ BUG(); -+ } -+ -+ p += i; -+ if (unlikely(!p->done)) { -+ /* initialize first time only */ -+ h_file = au_h_fptr(file, au_fbstart(file)); -+ spin_lock(&p->spin); -+ if (!p->done) { -+ p->fop = *h_file->f_op; -+ if (p->fop.aio_read) -+ p->fop.aio_read = aufs_aio_read_sp; -+ if (p->fop.aio_write) -+ p->fop.aio_write = aufs_aio_write_sp; -+ p->fop.release = aufs_release_sp; -+ p->done = 1; -+ } -+ spin_unlock(&p->spin); -+ } -+ file->f_op = &p->fop; -+} -+ -+static int au_cpup_sp(struct dentry *dentry) -+{ -+ int err; -+ aufs_bindex_t bcpup; -+ struct au_pin pin; -+ struct au_wr_dir_args wr_dir_args = { -+ .force_btgt = -1, -+ .flags = 0 -+ }; -+ -+ AuDbg("%.*s\n", AuDLNPair(dentry)); -+ -+ di_read_unlock(dentry, AuLock_IR); -+ di_write_lock_child(dentry); -+ err = au_wr_dir(dentry, /*src_dentry*/NULL, &wr_dir_args); -+ if (unlikely(err < 0)) -+ goto out; -+ bcpup = err; -+ err = 0; -+ if (bcpup == au_dbstart(dentry)) -+ goto out; /* success */ -+ -+ err = au_pin(&pin, dentry, bcpup, au_opt_udba(dentry->d_sb), -+ AuPin_MNT_WRITE); -+ if (!err) { -+ err = au_sio_cpup_simple(dentry, bcpup, -1, AuCpup_DTIME); -+ au_unpin(&pin); -+ } -+ -+ out: -+ di_downgrade_lock(dentry, AuLock_IR); -+ return err; -+} -+ -+static int au_do_open_sp(struct file *file, int flags) -+{ -+ int err; -+ struct dentry *dentry; -+ struct super_block *sb; -+ struct file *h_file; -+ struct inode *h_inode; -+ -+ dentry = file->f_dentry; -+ AuDbg("%.*s\n", AuDLNPair(dentry)); -+ -+ /* -+ * try copying-up. -+ * operate on the ro branch is not an error. -+ */ -+ au_cpup_sp(dentry); /* ignore */ -+ -+ /* prepare h_file */ -+ err = au_do_open_nondir(file, vfsub_file_flags(file)); -+ if (unlikely(err)) -+ goto out; -+ -+ sb = dentry->d_sb; -+ h_file = au_h_fptr(file, au_fbstart(file)); -+ h_inode = h_file->f_dentry->d_inode; -+ di_read_unlock(dentry, AuLock_IR); -+ fi_write_unlock(file); -+ si_read_unlock(sb); -+ /* open this fifo in aufs */ -+ err = h_inode->i_fop->open(file->f_dentry->d_inode, file); -+ si_noflush_read_lock(sb); -+ fi_write_lock(file); -+ di_read_lock_child(dentry, AuLock_IR); -+ if (!err) -+ au_init_fop_sp(file); -+ else -+ au_finfo_fin(file); -+ -+ out: -+ return err; -+} -+ -+static int aufs_open_sp(struct inode *inode, struct file *file) -+{ -+ return au_do_open(file, au_do_open_sp); -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+void au_init_special_fop(struct inode *inode, umode_t mode, dev_t rdev) -+{ -+ init_special_inode(inode, mode, rdev); -+ -+ switch (mode & S_IFMT) { -+ case S_IFIFO: -+ inode->i_fop = &au_sp_fop[AuSp_FIFO].fop; -+ /*FALLTHROUGH*/ -+ case S_IFCHR: -+ case S_IFBLK: -+ case S_IFSOCK: -+ break; -+ default: -+ AuDebugOn(1); -+ } -+} -+ -+int au_special_file(umode_t mode) -+{ -+ int ret; -+ -+ ret = 0; -+ switch (mode & S_IFMT) { -+ case S_IFIFO: -+#if 0 -+ case S_IFCHR: -+ case S_IFBLK: -+ case S_IFSOCK: -+#endif -+ ret = 1; -+ } -+ -+ return ret; -+} -diff --git a/fs/aufs/file.c b/fs/aufs/file.c -index a4f33aa..1985b32 100644 ---- a/fs/aufs/file.c -+++ b/fs/aufs/file.c -@@ -1,5 +1,5 @@ - /* -- * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * Copyright (C) 2005-2010 Junjiro R. Okajima - * - * This program, aufs is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by -@@ -43,8 +43,8 @@ struct file *au_h_open(struct dentry *dentry, aufs_bindex_t bindex, int flags, - struct inode *h_inode; - struct super_block *sb; - struct au_branch *br; -- int err, exec_flag; - struct path h_path; -+ int err, exec_flag; - - /* a race condition can happen between open and unlink/rmdir */ - h_file = ERR_PTR(-ENOENT); -@@ -72,8 +72,18 @@ struct file *au_h_open(struct dentry *dentry, aufs_bindex_t bindex, int flags, - atomic_inc(&br->br_count); - h_path.dentry = h_dentry; - h_path.mnt = br->br_mnt; -- path_get(&h_path); -- h_file = vfsub_dentry_open(&h_path, flags, current_cred()); -+ if (!au_special_file(h_inode->i_mode)) -+ h_file = vfsub_dentry_open(&h_path, flags); -+ else { -+ /* this block depends upon the configuration */ -+ di_read_unlock(dentry, AuLock_IR); -+ fi_write_unlock(file); -+ si_read_unlock(sb); -+ h_file = vfsub_dentry_open(&h_path, flags); -+ si_noflush_read_lock(sb); -+ fi_write_lock(file); -+ di_read_lock_child(dentry, AuLock_IR); -+ } - if (IS_ERR(h_file)) - goto out_br; - -@@ -97,7 +107,6 @@ struct file *au_h_open(struct dentry *dentry, aufs_bindex_t bindex, int flags, - int au_do_open(struct file *file, int (*open)(struct file *file, int flags)) - { - int err; -- unsigned int flags; - struct dentry *dentry; - struct super_block *sb; - -@@ -109,10 +118,7 @@ int au_do_open(struct file *file, int (*open)(struct file *file, int flags)) - goto out; - - di_read_lock_child(dentry, AuLock_IR); -- spin_lock(&file->f_lock); -- flags = file->f_flags; -- spin_unlock(&file->f_lock); -- err = open(file, flags); -+ err = open(file, vfsub_file_flags(file)); - di_read_unlock(dentry, AuLock_IR); - - fi_write_unlock(file); -@@ -126,12 +132,12 @@ int au_do_open(struct file *file, int (*open)(struct file *file, int flags)) - int au_reopen_nondir(struct file *file) - { - int err; -- unsigned int flags; - aufs_bindex_t bstart, bindex, bend; - struct dentry *dentry; - struct file *h_file, *h_file_tmp; - - dentry = file->f_dentry; -+ AuDebugOn(au_special_file(dentry->d_inode->i_mode)); - bstart = au_dbstart(dentry); - h_file_tmp = NULL; - if (au_fbstart(file) == bstart) { -@@ -145,10 +151,8 @@ int au_reopen_nondir(struct file *file) - AuDebugOn(au_fbstart(file) < bstart - || au_fi(file)->fi_hfile[0 + bstart].hf_file); - -- spin_lock(&file->f_lock); -- flags = file->f_flags & ~O_TRUNC; -- spin_unlock(&file->f_lock); -- h_file = au_h_open(dentry, bstart, flags, file); -+ h_file = au_h_open(dentry, bstart, vfsub_file_flags(file) & ~O_TRUNC, -+ file); - err = PTR_ERR(h_file); - if (IS_ERR(h_file)) - goto out; /* todo: close all? */ -@@ -202,9 +206,9 @@ static int au_ready_to_write_wh(struct file *file, loff_t len, - int err; - struct inode *inode; - struct dentry *dentry, *hi_wh; -- struct super_block *sb; - - dentry = file->f_dentry; -+ au_update_dbstart(dentry); - inode = dentry->d_inode; - hi_wh = au_hi_wh(inode, bcpup); - if (!hi_wh) -@@ -213,8 +217,9 @@ static int au_ready_to_write_wh(struct file *file, loff_t len, - /* already copied-up after unlink */ - err = au_reopen_wh(file, bcpup, hi_wh); - -- sb = dentry->d_sb; -- if (!err && inode->i_nlink > 1 && au_opt_test(au_mntflags(sb), PLINK)) -+ if (!err -+ && inode->i_nlink > 1 -+ && au_opt_test(au_mntflags(dentry->d_sb), PLINK)) - au_plink_append(inode, bcpup, au_h_dptr(dentry, bcpup)); - - return err; -@@ -233,8 +238,9 @@ int au_ready_to_write(struct file *file, loff_t len, struct au_pin *pin) - - dentry = file->f_dentry; - sb = dentry->d_sb; -- bstart = au_fbstart(file); - inode = dentry->d_inode; -+ AuDebugOn(au_special_file(inode->i_mode)); -+ bstart = au_fbstart(file); - err = au_test_ro(sb, bstart, inode); - if (!err && (au_h_fptr(file, bstart)->f_mode & FMODE_WRITE)) { - err = au_pin(pin, dentry, bstart, AuOpt_UDBA_NONE, /*flags*/0); -@@ -474,15 +480,18 @@ int au_reval_and_lock_fdi(struct file *file, int (*reopen)(struct file *file), - aufs_bindex_t bstart; - unsigned char pseudo_link; - struct dentry *dentry; -+ struct inode *inode; - - err = 0; - dentry = file->f_dentry; -+ inode = dentry->d_inode; -+ AuDebugOn(au_special_file(inode->i_mode)); - sigen = au_sigen(dentry->d_sb); - fi_write_lock(file); - figen = au_figen(file); - di_write_lock_child(dentry); - bstart = au_dbstart(dentry); -- pseudo_link = (bstart != au_ibstart(dentry->d_inode)); -+ pseudo_link = (bstart != au_ibstart(inode)); - if (sigen == figen && !pseudo_link && au_fbstart(file) == bstart) { - if (!wlock) { - di_downgrade_lock(dentry, AuLock_IR); -@@ -493,12 +502,12 @@ int au_reval_and_lock_fdi(struct file *file, int (*reopen)(struct file *file), - - AuDbg("sigen %d, figen %d\n", sigen, figen); - if (sigen != au_digen(dentry) -- || sigen != au_iigen(dentry->d_inode)) { -+ || sigen != au_iigen(inode)) { - err = au_reval_dpath(dentry, sigen); - if (unlikely(err < 0)) - goto out; - AuDebugOn(au_digen(dentry) != sigen -- || au_iigen(dentry->d_inode) != sigen); -+ || au_iigen(inode) != sigen); - } - - err = refresh_file(file, reopen); -diff --git a/fs/aufs/file.h b/fs/aufs/file.h -index d665cc7..14b6655 100644 ---- a/fs/aufs/file.h -+++ b/fs/aufs/file.h -@@ -1,5 +1,5 @@ - /* -- * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * Copyright (C) 2005-2010 Junjiro R. Okajima - * - * This program, aufs is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by -@@ -55,7 +55,6 @@ struct au_finfo { - /* dir only */ - struct { - struct au_vdir *fi_vdir_cache; -- int fi_maintain_plink; - }; - }; - }; -@@ -82,6 +81,21 @@ unsigned int aufs_poll(struct file *file, poll_table *wait); - /* f_op.c */ - extern const struct file_operations aufs_file_fop; - int aufs_flush(struct file *file, fl_owner_t id); -+int au_do_open_nondir(struct file *file, int flags); -+int aufs_release_nondir(struct inode *inode __maybe_unused, struct file *file); -+ -+#ifdef CONFIG_AUFS_SP_IATTR -+/* f_op_sp.c */ -+int au_special_file(umode_t mode); -+void au_init_special_fop(struct inode *inode, umode_t mode, dev_t rdev); -+#else -+AuStubInt0(au_special_file, umode_t mode) -+static inline void au_init_special_fop(struct inode *inode, umode_t mode, -+ dev_t rdev) -+{ -+ init_special_inode(inode, mode, rdev); -+} -+#endif - - /* finfo.c */ - void au_hfput(struct au_hfile *hf, struct file *file); -@@ -170,7 +184,7 @@ static inline unsigned int au_figen(struct file *f) - - static inline int au_test_mmapped(struct file *f) - { -- /* FiMustAnyLock(f); */ -+ FiMustAnyLock(f); - return !!(au_fi(f)->fi_h_vm_ops); - } - -diff --git a/fs/aufs/finfo.c b/fs/aufs/finfo.c -index c52d669..b15b32b 100644 ---- a/fs/aufs/finfo.c -+++ b/fs/aufs/finfo.c -@@ -1,5 +1,5 @@ - /* -- * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * Copyright (C) 2005-2010 Junjiro R. Okajima - * - * This program, aufs is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by -@@ -25,7 +25,8 @@ - - void au_hfput(struct au_hfile *hf, struct file *file) - { -- if (file->f_flags & vfsub_fmode_to_uint(FMODE_EXEC)) -+ /* todo: direct access f_flags */ -+ if (vfsub_file_flags(file) & vfsub_fmode_to_uint(FMODE_EXEC)) - allow_write_access(hf->hf_file); - fput(hf->hf_file); - hf->hf_file = NULL; -@@ -42,6 +43,7 @@ void au_set_h_fptr(struct file *file, aufs_bindex_t bindex, struct file *val) - if (hf->hf_file) - au_hfput(hf, file); - if (val) { -+ FiMustWriteLock(file); - hf->hf_file = val; - hf->hf_br = au_sbr(file->f_dentry->d_sb, bindex); - } -@@ -60,21 +62,20 @@ void au_finfo_fin(struct file *file) - struct au_finfo *finfo; - aufs_bindex_t bindex, bend; - -- fi_write_lock(file); -- bend = au_fbend(file); -- bindex = au_fbstart(file); -- if (bindex >= 0) -+ finfo = au_fi(file); -+ bindex = finfo->fi_bstart; -+ if (bindex >= 0) { - /* - * calls fput() instead of filp_close(), - * since no dnotify or lock for the lower file. - */ -+ bend = finfo->fi_bend; - for (; bindex <= bend; bindex++) - au_set_h_fptr(file, bindex, NULL); -+ } - -- finfo = au_fi(file); - au_dbg_verify_hf(finfo); - kfree(finfo->fi_hfile); -- fi_write_unlock(file); - AuRwDestroy(&finfo->fi_rwsem); - au_cache_free_finfo(finfo); - } -diff --git a/fs/aufs/fstype.h b/fs/aufs/fstype.h -index db859fa..febf77e 100644 ---- a/fs/aufs/fstype.h -+++ b/fs/aufs/fstype.h -@@ -1,5 +1,5 @@ - /* -- * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * Copyright (C) 2005-2010 Junjiro R. Okajima - * - * This program, aufs is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by -diff --git a/fs/aufs/hinotify.c b/fs/aufs/hinotify.c -index 43890bc..37e92ce 100644 ---- a/fs/aufs/hinotify.c -+++ b/fs/aufs/hinotify.c -@@ -1,5 +1,5 @@ - /* -- * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * Copyright (C) 2005-2010 Junjiro R. Okajima - * - * This program, aufs is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by -@@ -750,6 +750,7 @@ int __init au_hinotify_init(void) - void au_hinotify_fin(void) - { - inotify_destroy(au_hin_handle); -+ /* cf. au_cache_fin() */ - if (au_cachep[AuCache_HINOTIFY]) - au_hin_destroy_cache(); - } -diff --git a/fs/aufs/i_op.c b/fs/aufs/i_op.c -index 8151896..1b98274 100644 ---- a/fs/aufs/i_op.c -+++ b/fs/aufs/i_op.c -@@ -1,5 +1,5 @@ - /* -- * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * Copyright (C) 2005-2010 Junjiro R. Okajima - * - * This program, aufs is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by -@@ -109,7 +109,7 @@ static int aufs_permission(struct inode *inode, int mask) - bindex = au_ibstart(inode); - br = au_sbr(sb, bindex); - err = h_permission(h_inode, mask, br->br_mnt, br->br_perm); -- if (write_mask && !err) { -+ if (write_mask && !err && !special_file(h_inode->i_mode)) { - /* test whether the upper writable branch exists */ - err = -EROFS; - for (; bindex >= 0; bindex--) -diff --git a/fs/aufs/i_op_add.c b/fs/aufs/i_op_add.c -index 813890f..c407b7a 100644 ---- a/fs/aufs/i_op_add.c -+++ b/fs/aufs/i_op_add.c -@@ -1,5 +1,5 @@ - /* -- * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * Copyright (C) 2005-2010 Junjiro R. Okajima - * - * This program, aufs is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by -diff --git a/fs/aufs/i_op_del.c b/fs/aufs/i_op_del.c -index d47ddfb..c03610b 100644 ---- a/fs/aufs/i_op_del.c -+++ b/fs/aufs/i_op_del.c -@@ -1,5 +1,5 @@ - /* -- * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * Copyright (C) 2005-2010 Junjiro R. Okajima - * - * This program, aufs is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by -diff --git a/fs/aufs/i_op_ren.c b/fs/aufs/i_op_ren.c -index b107f93..88759b3 100644 ---- a/fs/aufs/i_op_ren.c -+++ b/fs/aufs/i_op_ren.c -@@ -1,5 +1,5 @@ - /* -- * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * Copyright (C) 2005-2010 Junjiro R. Okajima - * - * This program, aufs is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by -@@ -238,11 +238,15 @@ static int au_ren_or_cpup(struct au_ren_args *a) - au_set_h_dptr(d, a->btgt, dget(a->dst_h_dentry)); - err = au_sio_cpup_single(d, a->btgt, a->src_bstart, -1, - !AuCpup_DTIME, a->dst_parent); -- if (unlikely(err)) { -+ mutex_unlock(h_mtx); -+ if (!err) { -+ d = a->dst_dentry; -+ au_set_h_dptr(d, a->btgt, NULL); -+ au_update_dbstart(d); -+ } else { - au_set_h_dptr(d, a->btgt, NULL); - au_set_dbstart(d, a->src_bstart); - } -- mutex_unlock(h_mtx); - } - - return err; -diff --git a/fs/aufs/iinfo.c b/fs/aufs/iinfo.c -index 072ddfc..5a61d8c 100644 ---- a/fs/aufs/iinfo.c -+++ b/fs/aufs/iinfo.c -@@ -1,5 +1,5 @@ - /* -- * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * Copyright (C) 2005-2010 Junjiro R. Okajima - * - * This program, aufs is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by -diff --git a/fs/aufs/inode.c b/fs/aufs/inode.c -index 3f146a6..99ba16d 100644 ---- a/fs/aufs/inode.c -+++ b/fs/aufs/inode.c -@@ -1,5 +1,5 @@ - /* -- * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * Copyright (C) 2005-2010 Junjiro R. Okajima - * - * This program, aufs is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by -@@ -197,7 +197,7 @@ static int set_inode(struct inode *inode, struct dentry *dentry) - case S_IFSOCK: - btail = au_dbtail(dentry); - inode->i_op = &aufs_iop; -- init_special_inode(inode, mode, h_inode->i_rdev); -+ au_init_special_fop(inode, mode, h_inode->i_rdev); - break; - default: - AuIOErr("Unknown file type 0%o\n", mode); -@@ -337,13 +337,14 @@ struct inode *au_new_inode(struct dentry *dentry, int must_new) - if (inode->i_state & I_NEW) { - ii_write_lock_new_child(inode); - err = set_inode(inode, dentry); -- unlock_new_inode(inode); -- if (!err) -+ if (!err) { -+ unlock_new_inode(inode); - goto out; /* success */ -+ } - -- iget_failed(inode); - ii_write_unlock(inode); -- goto out_iput; -+ iget_failed(inode); -+ goto out_err; - } else if (!must_new) { - err = reval_inode(inode, dentry, &match); - if (!err) -@@ -366,6 +367,7 @@ struct inode *au_new_inode(struct dentry *dentry, int must_new) - - out_iput: - iput(inode); -+ out_err: - inode = ERR_PTR(err); - out: - return inode; -diff --git a/fs/aufs/inode.h b/fs/aufs/inode.h -index 1c5559b..086791c 100644 ---- a/fs/aufs/inode.h -+++ b/fs/aufs/inode.h -@@ -1,5 +1,5 @@ - /* -- * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * Copyright (C) 2005-2010 Junjiro R. Okajima - * - * This program, aufs is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by -@@ -203,14 +203,12 @@ void au_iinfo_fin(struct inode *inode); - int au_ii_realloc(struct au_iinfo *iinfo, int nbr); - - /* plink.c */ --void au_plink_block_maintain(struct super_block *sb); -+void au_plink_maint_block(struct super_block *sb); -+void au_plink_maint_leave(struct file *file); - #ifdef CONFIG_AUFS_DEBUG - void au_plink_list(struct super_block *sb); - #else --static inline void au_plink_list(struct super_block *sb) --{ -- /* nothing */ --} -+AuStubVoid(au_plink_list, struct super_block *sb) - #endif - int au_plink_test(struct inode *inode); - struct dentry *au_plink_lkup(struct inode *inode, aufs_bindex_t bindex); -@@ -432,36 +430,15 @@ int au_hin_alloc(struct au_hinode *hinode __maybe_unused, - return -EOPNOTSUPP; - } - --static inline void au_hin_free(struct au_hinode *hinode __maybe_unused) --{ -- /* nothing */ --} -- --static inline void au_hin_ctl(struct au_hinode *hinode __maybe_unused, -- int do_set __maybe_unused) --{ -- /* nothing */ --} -- --static inline void au_reset_hinotify(struct inode *inode __maybe_unused, -- unsigned int flags __maybe_unused) --{ -- /* nothing */ --} -- --static inline int au_hinotify_init(void) --{ -- return 0; --} -- --#define au_hinotify_fin() do {} while (0) -- --static inline --void au_hin_init(struct au_hinode *hinode __maybe_unused, -- struct au_hinotify *val __maybe_unused) --{ -- /* empty */ --} -+AuStubVoid(au_hin_free, struct au_hinode *hinode __maybe_unused) -+AuStubVoid(au_hin_ctl, struct au_hinode *hinode __maybe_unused, -+ int do_set __maybe_unused) -+AuStubVoid(au_reset_hinotify, struct inode *inode __maybe_unused, -+ unsigned int flags __maybe_unused) -+AuStubInt0(__init au_hinotify_init, void) -+AuStubVoid(au_hinotify_fin, void) -+AuStubVoid(au_hin_init, struct au_hinode *hinode __maybe_unused, -+ struct au_hinotify *val __maybe_unused) - #endif /* CONFIG_AUFS_HINOTIFY */ - - static inline void au_hin_suspend(struct au_hinode *hdir) -diff --git a/fs/aufs/ioctl.c b/fs/aufs/ioctl.c -index 6f8bad8..bfff168 100644 ---- a/fs/aufs/ioctl.c -+++ b/fs/aufs/ioctl.c -@@ -1,5 +1,5 @@ - /* -- * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * Copyright (C) 2005-2010 Junjiro R. Okajima - * - * This program, aufs is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by -@@ -100,6 +100,7 @@ long aufs_ioctl_dir(struct file *file, unsigned int cmd, unsigned long arg) - break; - - default: -+ AuDbg("0x%x\n", cmd); - err = -EINVAL; - } - -@@ -117,6 +118,7 @@ long aufs_ioctl_nondir(struct file *file, unsigned int cmd, unsigned long arg) - break; - - default: -+ AuDbg("0x%x\n", cmd); - err = -EINVAL; - } - -diff --git a/fs/aufs/loop.c b/fs/aufs/loop.c -index 277011f..5fceec7 100644 ---- a/fs/aufs/loop.c -+++ b/fs/aufs/loop.c -@@ -1,5 +1,5 @@ - /* -- * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * Copyright (C) 2005-2010 Junjiro R. Okajima - * - * This program, aufs is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by -diff --git a/fs/aufs/loop.h b/fs/aufs/loop.h -index 5a0fd87..e655b4f 100644 ---- a/fs/aufs/loop.h -+++ b/fs/aufs/loop.h -@@ -1,5 +1,5 @@ - /* -- * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * Copyright (C) 2005-2010 Junjiro R. Okajima - * - * This program, aufs is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by -@@ -34,17 +34,9 @@ int au_test_loopback_overlap(struct super_block *sb, struct dentry *h_d1, - struct dentry *h_d2); - int au_test_loopback_kthread(void); - #else --static inline --int au_test_loopback_overlap(struct super_block *sb, struct dentry *h_d1, -- struct dentry *h_d2) --{ -- return 0; --} -- --static inline int au_test_loopback_kthread(void) --{ -- return 0; --} -+AuStubInt0(au_test_loopback_overlap, struct super_block *sb, -+ struct dentry *h_d1, struct dentry *h_d2) -+AuStubInt0(au_test_loopback_kthread, void) - #endif /* BLK_DEV_LOOP */ - - #endif /* __KERNEL__ */ -diff --git a/fs/aufs/module.c b/fs/aufs/module.c -index 5b3531f..bfaa7e6 100644 ---- a/fs/aufs/module.c -+++ b/fs/aufs/module.c -@@ -1,5 +1,5 @@ - /* -- * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * Copyright (C) 2005-2010 Junjiro R. Okajima - * - * This program, aufs is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by -@@ -61,6 +61,8 @@ static int __init au_cache_init(void) - static void au_cache_fin(void) - { - int i; -+ -+ /* including AuCache_HINOTIFY */ - for (i = 0; i < AuCache_Last; i++) - if (au_cachep[i]) { - kmem_cache_destroy(au_cachep[i]); -@@ -82,11 +84,6 @@ MODULE_DESCRIPTION(AUFS_NAME - MODULE_VERSION(AUFS_VERSION); - MODULE_INFO(staging, "Y"); - --/* it should be 'byte', but param_set_byte() prints it by "%c" */ --short aufs_nwkq = AUFS_NWKQ_DEF; --MODULE_PARM_DESC(nwkq, "the number of workqueue thread, " AUFS_WKQ_NAME); --module_param_named(nwkq, aufs_nwkq, short, S_IRUGO); -- - /* this module parameter has no meaning when SYSFS is disabled */ - int sysaufs_brs = 1; - MODULE_PARM_DESC(brs, "use /fs/aufs/si_*/brN"); -@@ -119,11 +116,6 @@ static int __init aufs_init(void) - - sysaufs_brs_init(); - au_debug_init(); -- -- err = -EINVAL; -- if (unlikely(aufs_nwkq <= 0)) -- goto out; -- - err = sysaufs_init(); - if (unlikely(err)) - goto out; -diff --git a/fs/aufs/module.h b/fs/aufs/module.h -index cea7bc7..267ab16 100644 ---- a/fs/aufs/module.h -+++ b/fs/aufs/module.h -@@ -1,5 +1,5 @@ - /* -- * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * Copyright (C) 2005-2010 Junjiro R. Okajima - * - * This program, aufs is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by -@@ -31,7 +31,6 @@ struct path; - struct seq_file; - - /* module parameters */ --extern short aufs_nwkq; - extern int sysaufs_brs; - - /* ---------------------------------------------------------------------- */ -@@ -56,21 +55,21 @@ enum { - AuCache_Last - }; - --#define AuCache(type) KMEM_CACHE(type, SLAB_RECLAIM_ACCOUNT) -+#define AuCache(type) KMEM_CACHE(type, SLAB_RECLAIM_ACCOUNT | SLAB_MEM_SPREAD) - - extern struct kmem_cache *au_cachep[]; - - #define AuCacheFuncs(name, index) \ --static inline void *au_cache_alloc_##name(void) \ -+static inline struct au_##name *au_cache_alloc_##name(void) \ - { return kmem_cache_alloc(au_cachep[AuCache_##index], GFP_NOFS); } \ --static inline void au_cache_free_##name(void *p) \ -+static inline void au_cache_free_##name(struct au_##name *p) \ - { kmem_cache_free(au_cachep[AuCache_##index], p); } - - AuCacheFuncs(dinfo, DINFO); - AuCacheFuncs(icntnr, ICNTNR); - AuCacheFuncs(finfo, FINFO); - AuCacheFuncs(vdir, VDIR); --AuCacheFuncs(dehstr, DEHSTR); -+AuCacheFuncs(vdir_dehstr, DEHSTR); - - /* ---------------------------------------------------------------------- */ - -diff --git a/fs/aufs/opts.c b/fs/aufs/opts.c -index 4d9b60f..a4b330d 100644 ---- a/fs/aufs/opts.c -+++ b/fs/aufs/opts.c -@@ -1,5 +1,5 @@ - /* -- * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * Copyright (C) 2005-2010 Junjiro R. Okajima - * - * This program, aufs is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by -diff --git a/fs/aufs/opts.h b/fs/aufs/opts.h -index 27439b1..83a00ef 100644 ---- a/fs/aufs/opts.h -+++ b/fs/aufs/opts.h -@@ -1,5 +1,5 @@ - /* -- * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * Copyright (C) 2005-2010 Junjiro R. Okajima - * - * This program, aufs is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by -diff --git a/fs/aufs/plink.c b/fs/aufs/plink.c -index 074f143..cd5b258 100644 ---- a/fs/aufs/plink.c -+++ b/fs/aufs/plink.c -@@ -1,5 +1,5 @@ - /* -- * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * Copyright (C) 2005-2010 Junjiro R. Okajima - * - * This program, aufs is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by -@@ -26,14 +26,53 @@ - * during a user process maintains the pseudo-links, - * prohibit adding a new plink and branch manipulation. - */ --void au_plink_block_maintain(struct super_block *sb) -+void au_plink_maint_block(struct super_block *sb) - { - struct au_sbinfo *sbi = au_sbi(sb); - - SiMustAnyLock(sb); - - /* gave up wake_up_bit() */ -- wait_event(sbi->si_plink_wq, !au_ftest_si(sbi, MAINTAIN_PLINK)); -+ wait_event(sbi->si_plink_wq, !sbi->si_plink_maint); -+} -+ -+void au_plink_maint_leave(struct file *file) -+{ -+ struct au_sbinfo *sbinfo; -+ int iam; -+ -+ AuDebugOn(atomic_long_read(&file->f_count)); -+ -+ sbinfo = au_sbi(file->f_dentry->d_sb); -+ spin_lock(&sbinfo->si_plink_maint_lock); -+ iam = (sbinfo->si_plink_maint == file); -+ if (iam) -+ sbinfo->si_plink_maint = NULL; -+ spin_unlock(&sbinfo->si_plink_maint_lock); -+ if (iam) -+ wake_up_all(&sbinfo->si_plink_wq); -+} -+ -+static int au_plink_maint_enter(struct file *file) -+{ -+ int err; -+ struct super_block *sb; -+ struct au_sbinfo *sbinfo; -+ -+ err = 0; -+ sb = file->f_dentry->d_sb; -+ sbinfo = au_sbi(sb); -+ /* make sure i am the only one in this fs */ -+ si_write_lock(sb); -+ /* spin_lock(&sbinfo->si_plink_maint_lock); */ -+ if (!sbinfo->si_plink_maint) -+ sbinfo->si_plink_maint = file; -+ else -+ err = -EBUSY; -+ /* spin_unlock(&sbinfo->si_plink_maint_lock); */ -+ si_write_unlock(sb); -+ -+ return err; - } - - /* ---------------------------------------------------------------------- */ -@@ -272,7 +311,7 @@ void au_plink_append(struct inode *inode, aufs_bindex_t bindex, - spin_unlock(&sbinfo->si_plink.spin); - - if (!err) { -- au_plink_block_maintain(sb); -+ au_plink_maint_block(sb); - err = whplink(h_dentry, inode, bindex, au_sbr(sb, bindex)); - } - -@@ -374,13 +413,7 @@ long au_plink_ioctl(struct file *file, unsigned int cmd) - * pseudo-link maintenance mode, - * cleared by aufs_release_dir() - */ -- si_write_lock(sb); -- if (!au_ftest_si(sbinfo, MAINTAIN_PLINK)) { -- au_fset_si(sbinfo, MAINTAIN_PLINK); -- au_fi(file)->fi_maintain_plink = 1; -- } else -- err = -EBUSY; -- si_write_unlock(sb); -+ err = au_plink_maint_enter(file); - break; - case AUFS_CTL_PLINK_CLEAN: - aufs_write_lock(sb->s_root); -diff --git a/fs/aufs/poll.c b/fs/aufs/poll.c -index 1a1ddae..49dc0aa 100644 ---- a/fs/aufs/poll.c -+++ b/fs/aufs/poll.c -@@ -1,5 +1,5 @@ - /* -- * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * Copyright (C) 2005-2010 Junjiro R. Okajima - * - * This program, aufs is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by -diff --git a/fs/aufs/rdu.c b/fs/aufs/rdu.c -index c38f280..4b8a11b 100644 ---- a/fs/aufs/rdu.c -+++ b/fs/aufs/rdu.c -@@ -1,5 +1,5 @@ - /* -- * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * Copyright (C) 2005-2010 Junjiro R. Okajima - * - * This program, aufs is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by -diff --git a/fs/aufs/rwsem.h b/fs/aufs/rwsem.h -index dfd2c68..d608e24 100644 ---- a/fs/aufs/rwsem.h -+++ b/fs/aufs/rwsem.h -@@ -1,5 +1,5 @@ - /* -- * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * Copyright (C) 2005-2010 Junjiro R. Okajima - * - * This program, aufs is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by -diff --git a/fs/aufs/sbinfo.c b/fs/aufs/sbinfo.c -index f0650e5..89b2b6a 100644 ---- a/fs/aufs/sbinfo.c -+++ b/fs/aufs/sbinfo.c -@@ -1,5 +1,5 @@ - /* -- * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * Copyright (C) 2005-2010 Junjiro R. Okajima - * - * This program, aufs is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by -@@ -32,6 +32,7 @@ void au_si_free(struct kobject *kobj) - - sbinfo = container_of(kobj, struct au_sbinfo, si_kobj); - AuDebugOn(!list_empty(&sbinfo->si_plink.head)); -+ AuDebugOn(sbinfo->si_plink_maint); - - sb = sbinfo->si_sb; - si_write_lock(sb); -@@ -51,7 +52,7 @@ int au_si_alloc(struct super_block *sb) - struct au_sbinfo *sbinfo; - - err = -ENOMEM; -- sbinfo = kmalloc(sizeof(*sbinfo), GFP_NOFS); -+ sbinfo = kzalloc(sizeof(*sbinfo), GFP_NOFS); - if (unlikely(!sbinfo)) - goto out; - -@@ -60,30 +61,22 @@ int au_si_alloc(struct super_block *sb) - if (unlikely(!sbinfo->si_branch)) - goto out_sbinfo; - -- memset(&sbinfo->si_kobj, 0, sizeof(sbinfo->si_kobj)); - err = sysaufs_si_init(sbinfo); - if (unlikely(err)) - goto out_br; - - au_nwt_init(&sbinfo->si_nowait); - au_rw_init_wlock(&sbinfo->si_rwsem); -- sbinfo->si_generation = 0; -- sbinfo->au_si_status = 0; - sbinfo->si_bend = -1; -- sbinfo->si_last_br_id = 0; - - sbinfo->si_wbr_copyup = AuWbrCopyup_Def; - sbinfo->si_wbr_create = AuWbrCreate_Def; -- sbinfo->si_wbr_copyup_ops = au_wbr_copyup_ops + AuWbrCopyup_Def; -- sbinfo->si_wbr_create_ops = au_wbr_create_ops + AuWbrCreate_Def; -+ sbinfo->si_wbr_copyup_ops = au_wbr_copyup_ops + sbinfo->si_wbr_copyup; -+ sbinfo->si_wbr_create_ops = au_wbr_create_ops + sbinfo->si_wbr_create; - - sbinfo->si_mntflags = AuOpt_Def; - -- sbinfo->si_xread = NULL; -- sbinfo->si_xwrite = NULL; -- sbinfo->si_xib = NULL; - mutex_init(&sbinfo->si_xib_mtx); -- sbinfo->si_xib_buf = NULL; - sbinfo->si_xino_brid = -1; - /* leave si_xib_last_pindex and si_xib_next_bit */ - -@@ -94,6 +87,7 @@ int au_si_alloc(struct super_block *sb) - - au_spl_init(&sbinfo->si_plink); - init_waitqueue_head(&sbinfo->si_plink_wq); -+ spin_lock_init(&sbinfo->si_plink_maint_lock); - - /* leave other members for sysaufs and si_mnt. */ - sbinfo->si_sb = sb; -diff --git a/fs/aufs/spl.h b/fs/aufs/spl.h -index bcbbd9a..261edc4 100644 ---- a/fs/aufs/spl.h -+++ b/fs/aufs/spl.h -@@ -1,5 +1,5 @@ - /* -- * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * Copyright (C) 2005-2010 Junjiro R. Okajima - * - * This program, aufs is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by -diff --git a/fs/aufs/super.c b/fs/aufs/super.c -index 10d30f2..f2d1ead 100644 ---- a/fs/aufs/super.c -+++ b/fs/aufs/super.c -@@ -1,5 +1,5 @@ - /* -- * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * Copyright (C) 2005-2010 Junjiro R. Okajima - * - * This program, aufs is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by -@@ -266,9 +266,9 @@ static int aufs_show_options(struct seq_file *m, struct vfsmount *mnt) - si_read_unlock(sb); - return 0; - --#undef Deleted - #undef AuBool - #undef AuStr -+#undef AuUInt - } - - /* ---------------------------------------------------------------------- */ -@@ -814,20 +814,14 @@ static int aufs_fill_super(struct super_block *sb, void *raw_data, - - /* lock vfs_inode first, then aufs. */ - mutex_lock(&inode->i_mutex); -- inode->i_op = &aufs_dir_iop; -- inode->i_fop = &aufs_dir_fop; - aufs_write_lock(root); - err = au_opts_mount(sb, &opts); - au_opts_free(&opts); -- if (unlikely(err)) -- goto out_unlock; - aufs_write_unlock(root); - mutex_unlock(&inode->i_mutex); -- goto out_opts; /* success */ -+ if (!err) -+ goto out_opts; /* success */ - -- out_unlock: -- aufs_write_unlock(root); -- mutex_unlock(&inode->i_mutex); - out_root: - dput(root); - sb->s_root = NULL; -diff --git a/fs/aufs/super.h b/fs/aufs/super.h -index 63d3ad1..cd6fdc4 100644 ---- a/fs/aufs/super.h -+++ b/fs/aufs/super.h -@@ -1,5 +1,5 @@ - /* -- * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * Copyright (C) 2005-2010 Junjiro R. Okajima - * - * This program, aufs is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by -@@ -129,6 +129,8 @@ struct au_sbinfo { - /* pseudo_link list */ - struct au_splhead si_plink; - wait_queue_head_t si_plink_wq; -+ spinlock_t si_plink_maint_lock; -+ struct file *si_plink_maint; - - /* - * sysfs and lifetime management. -@@ -155,7 +157,6 @@ struct au_sbinfo { - * if it is false, refreshing dirs at access time is unnecesary - */ - #define AuSi_FAILED_REFRESH_DIRS 1 --#define AuSi_MAINTAIN_PLINK (1 << 1) /* ioctl */ - static inline unsigned char au_do_ftest_si(struct au_sbinfo *sbi, - unsigned int flag) - { -@@ -245,36 +246,12 @@ static inline int au_busy_or_stale(void) - return -ESTALE; - } - #else --static inline void au_export_init(struct super_block *sb) --{ -- /* nothing */ --} -- --static inline int au_test_nfsd(struct task_struct *tsk) --{ -- return 0; --} -- --static inline int au_xigen_inc(struct inode *inode) --{ -- return 0; --} -- --static inline int au_xigen_new(struct inode *inode) --{ -- return 0; --} -- --static inline int au_xigen_set(struct super_block *sb, struct file *base) --{ -- return 0; --} -- --static inline void au_xigen_clr(struct super_block *sb) --{ -- /* empty */ --} -- -+AuStubVoid(au_export_init, struct super_block *sb) -+AuStubInt0(au_test_nfsd, struct task_struct *tsk) -+AuStubInt0(au_xigen_inc, struct inode *inode) -+AuStubInt0(au_xigen_new, struct inode *inode) -+AuStubInt0(au_xigen_set, struct super_block *sb, struct file *base) -+AuStubVoid(au_xigen_clr, struct super_block *sb) - static inline int au_busy_or_stale(void) - { - return -EBUSY; -diff --git a/fs/aufs/sysaufs.c b/fs/aufs/sysaufs.c -index b796330..919e1b0 100644 ---- a/fs/aufs/sysaufs.c -+++ b/fs/aufs/sysaufs.c -@@ -1,5 +1,5 @@ - /* -- * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * Copyright (C) 2005-2010 Junjiro R. Okajima - * - * This program, aufs is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by -diff --git a/fs/aufs/sysaufs.h b/fs/aufs/sysaufs.h -index 379033a..6796934 100644 ---- a/fs/aufs/sysaufs.h -+++ b/fs/aufs/sysaufs.h -@@ -1,5 +1,5 @@ - /* -- * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * Copyright (C) 2005-2010 Junjiro R. Okajima - * - * This program, aufs is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by -@@ -81,11 +81,7 @@ void sysaufs_brs_del(struct super_block *sb, aufs_bindex_t bindex); - #else - #define sysaufs_attr_group NULL - --static inline --int sysaufs_si_xi_path(struct seq_file *seq, struct super_block *sb) --{ -- return 0; --} -+AuStubInt0(sysaufs_si_xi_path, struct seq_file *seq, struct super_block *sb) - - static inline - ssize_t sysaufs_si_show(struct kobject *kobj, struct attribute *attr, -@@ -94,20 +90,9 @@ ssize_t sysaufs_si_show(struct kobject *kobj, struct attribute *attr, - return 0; - } - --static inline void sysaufs_br_init(struct au_branch *br) --{ -- /* empty */ --} -- --static inline void sysaufs_brs_add(struct super_block *sb, aufs_bindex_t bindex) --{ -- /* nothing */ --} -- --static inline void sysaufs_brs_del(struct super_block *sb, aufs_bindex_t bindex) --{ -- /* nothing */ --} -+AuStubVoid(sysaufs_br_init, struct au_branch *br) -+AuStubVoid(sysaufs_brs_add, struct super_block *sb, aufs_bindex_t bindex) -+AuStubVoid(sysaufs_brs_del, struct super_block *sb, aufs_bindex_t bindex) - - static inline void sysaufs_brs_init(void) - { -diff --git a/fs/aufs/sysfs.c b/fs/aufs/sysfs.c -index 956bbb9..6340cf9 100644 ---- a/fs/aufs/sysfs.c -+++ b/fs/aufs/sysfs.c -@@ -1,5 +1,5 @@ - /* -- * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * Copyright (C) 2005-2010 Junjiro R. Okajima - * - * This program, aufs is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by -diff --git a/fs/aufs/sysrq.c b/fs/aufs/sysrq.c -index 3db9d84..b2f09f7 100644 ---- a/fs/aufs/sysrq.c -+++ b/fs/aufs/sysrq.c -@@ -1,5 +1,5 @@ - /* -- * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * Copyright (C) 2005-2010 Junjiro R. Okajima - * - * This program, aufs is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by -@@ -55,9 +55,12 @@ static void sysrq_sb(struct super_block *sb) - au_dpri_inode(i); - #endif - printk(KERN_WARNING AUFS_NAME ": files\n"); -- list_for_each_entry(file, &sb->s_files, f_u.fu_list) -- if (!special_file(file->f_dentry->d_inode->i_mode)) -+ list_for_each_entry(file, &sb->s_files, f_u.fu_list) { -+ umode_t mode; -+ mode = file->f_dentry->d_inode->i_mode; -+ if (!special_file(mode) || au_special_file(mode)) - au_dpri_file(file); -+ } - - au_plevel = plevel; - au_debug(0); -diff --git a/fs/aufs/vdir.c b/fs/aufs/vdir.c -index 361de5e..36435c9 100644 ---- a/fs/aufs/vdir.c -+++ b/fs/aufs/vdir.c -@@ -1,5 +1,5 @@ - /* -- * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * Copyright (C) 2005-2010 Junjiro R. Okajima - * - * This program, aufs is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by -@@ -122,7 +122,7 @@ static void au_nhash_de_do_free(struct hlist_head *head) - - hlist_for_each_entry_safe(tpos, pos, node, head, hash) { - /* hlist_del(pos); */ -- au_cache_free_dehstr(tpos); -+ au_cache_free_vdir_dehstr(tpos); - } - } - -@@ -332,7 +332,7 @@ static int append_de(struct au_vdir *vdir, char *name, int nlen, ino_t ino, - } - - err = -ENOMEM; -- dehstr = au_cache_alloc_dehstr(); -+ dehstr = au_cache_alloc_vdir_dehstr(); - if (unlikely(!dehstr)) - goto out; - -diff --git a/fs/aufs/vfsub.c b/fs/aufs/vfsub.c -index 34c0d95..921e855 100644 ---- a/fs/aufs/vfsub.c -+++ b/fs/aufs/vfsub.c -@@ -1,5 +1,5 @@ - /* -- * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * Copyright (C) 2005-2010 Junjiro R. Okajima - * - * This program, aufs is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by -@@ -49,12 +49,12 @@ int vfsub_update_h_iattr(struct path *h_path, int *did) - - /* ---------------------------------------------------------------------- */ - --struct file *vfsub_dentry_open(struct path *path, int flags, -- const struct cred *cred) -+struct file *vfsub_dentry_open(struct path *path, int flags) - { - struct file *file; - -- file = dentry_open(path->dentry, path->mnt, flags, cred); -+ path_get(path); -+ file = dentry_open(path->dentry, path->mnt, flags, current_cred()); - if (IS_ERR(file)) - return file; - /* as NFSD does, just call ima_..._get() simply after dentry_open */ -@@ -119,9 +119,12 @@ struct dentry *vfsub_lookup_hash(struct nameidata *nd) - IMustLock(nd->path.dentry->d_inode); - - path.dentry = lookup_hash(nd); -- if (!IS_ERR(path.dentry) && path.dentry->d_inode) -+ if (IS_ERR(path.dentry)) -+ goto out; -+ if (path.dentry->d_inode) - vfsub_update_h_iattr(&path, /*did*/NULL); /*ignore*/ - -+ out: - AuTraceErrPtr(path.dentry); - return path.dentry; - } -diff --git a/fs/aufs/vfsub.h b/fs/aufs/vfsub.h -index 63d21d3..ddd62fc 100644 ---- a/fs/aufs/vfsub.h -+++ b/fs/aufs/vfsub.h -@@ -1,5 +1,5 @@ - /* -- * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * Copyright (C) 2005-2010 Junjiro R. Okajima - * - * This program, aufs is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by -@@ -59,8 +59,7 @@ static inline void vfsub_copy_inode_size(struct inode *inode, - - int vfsub_update_h_iattr(struct path *h_path, int *did); - struct file *vfsub_filp_open(const char *path, int oflags, int mode); --struct file *vfsub_dentry_open(struct path *path, int flags, -- const struct cred *cred); -+struct file *vfsub_dentry_open(struct path *path, int flags); - int vfsub_kern_path(const char *name, unsigned int flags, struct path *path); - struct dentry *vfsub_lookup_one_len(const char *name, struct dentry *parent, - int len); -@@ -85,12 +84,6 @@ int vfsub_rename(struct inode *src_hdir, struct dentry *src_dentry, - int vfsub_mkdir(struct inode *dir, struct path *path, int mode); - int vfsub_rmdir(struct inode *dir, struct path *path); - --int vfsub_sio_mkdir(struct inode *dir, struct path *path, int mode); --int vfsub_sio_rmdir(struct inode *dir, struct path *path); --int vfsub_sio_notify_change(struct path *path, struct iattr *ia); --int vfsub_notify_change(struct path *path, struct iattr *ia); --int vfsub_unlink(struct inode *dir, struct path *path, int force); -- - /* ---------------------------------------------------------------------- */ - - ssize_t vfsub_read_u(struct file *file, char __user *ubuf, size_t count, -@@ -103,13 +96,16 @@ ssize_t vfsub_write_k(struct file *file, void *kbuf, size_t count, - loff_t *ppos); - int vfsub_readdir(struct file *file, filldir_t filldir, void *arg); - --long vfsub_splice_to(struct file *in, loff_t *ppos, -- struct pipe_inode_info *pipe, size_t len, -- unsigned int flags); --long vfsub_splice_from(struct pipe_inode_info *pipe, struct file *out, -- loff_t *ppos, size_t len, unsigned int flags); --int vfsub_trunc(struct path *h_path, loff_t length, unsigned int attr, -- struct file *h_file); -+static inline unsigned int vfsub_file_flags(struct file *file) -+{ -+ unsigned int flags; -+ -+ spin_lock(&file->f_lock); -+ flags = file->f_flags; -+ spin_unlock(&file->f_lock); -+ -+ return flags; -+} - - static inline void vfsub_file_accessed(struct file *h_file) - { -@@ -128,6 +124,14 @@ static inline void vfsub_touch_atime(struct vfsmount *h_mnt, - vfsub_update_h_iattr(&h_path, /*did*/NULL); /*ignore*/ - } - -+long vfsub_splice_to(struct file *in, loff_t *ppos, -+ struct pipe_inode_info *pipe, size_t len, -+ unsigned int flags); -+long vfsub_splice_from(struct pipe_inode_info *pipe, struct file *out, -+ loff_t *ppos, size_t len, unsigned int flags); -+int vfsub_trunc(struct path *h_path, loff_t length, unsigned int attr, -+ struct file *h_file); -+ - /* ---------------------------------------------------------------------- */ - - static inline loff_t vfsub_llseek(struct file *file, loff_t offset, int origin) -@@ -168,5 +172,13 @@ static inline fmode_t vfsub_uint_to_fmode(unsigned int ui) - return u.fm; - } - -+/* ---------------------------------------------------------------------- */ -+ -+int vfsub_sio_mkdir(struct inode *dir, struct path *path, int mode); -+int vfsub_sio_rmdir(struct inode *dir, struct path *path); -+int vfsub_sio_notify_change(struct path *path, struct iattr *ia); -+int vfsub_notify_change(struct path *path, struct iattr *ia); -+int vfsub_unlink(struct inode *dir, struct path *path, int force); -+ - #endif /* __KERNEL__ */ - #endif /* __AUFS_VFSUB_H__ */ -diff --git a/fs/aufs/wbr_policy.c b/fs/aufs/wbr_policy.c -index 05a8c1e..1e888d3 100644 ---- a/fs/aufs/wbr_policy.c -+++ b/fs/aufs/wbr_policy.c -@@ -1,5 +1,5 @@ - /* -- * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * Copyright (C) 2005-2010 Junjiro R. Okajima - * - * This program, aufs is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by -@@ -109,8 +109,7 @@ static int au_cpdown_dir(struct dentry *dentry, aufs_bindex_t bdst, - struct dentry *h_parent, void *arg) - { - int err, rerr; -- aufs_bindex_t bend, bopq, bstart; -- unsigned char parent_opq; -+ aufs_bindex_t bopq, bstart; - struct path h_path; - struct dentry *parent; - struct inode *h_dir, *h_inode, *inode, *dir; -@@ -135,7 +134,6 @@ static int au_cpdown_dir(struct dentry *dentry, aufs_bindex_t bdst, - goto out_put; - au_fset_cpdown(args->flags, MADE_DIR); - -- bend = au_dbend(dentry); - bopq = au_dbdiropq(dentry); - au_fclr_cpdown(args->flags, WHED); - au_fclr_cpdown(args->flags, DIROPQ); -@@ -143,8 +141,6 @@ static int au_cpdown_dir(struct dentry *dentry, aufs_bindex_t bdst, - au_fset_cpdown(args->flags, WHED); - if (!au_ftest_cpdown(args->flags, PARENT_OPQ) && bopq <= bdst) - au_fset_cpdown(args->flags, PARENT_OPQ); -- parent_opq = (au_ftest_cpdown(args->flags, PARENT_OPQ) -- && args->parent == dentry); - h_inode = h_path.dentry->d_inode; - mutex_lock_nested(&h_inode->i_mutex, AuLsc_I_CHILD); - if (au_ftest_cpdown(args->flags, WHED)) { -diff --git a/fs/aufs/whout.c b/fs/aufs/whout.c -index 674ab35..eedec93 100644 ---- a/fs/aufs/whout.c -+++ b/fs/aufs/whout.c -@@ -1,5 +1,5 @@ - /* -- * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * Copyright (C) 2005-2010 Junjiro R. Okajima - * - * This program, aufs is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by -@@ -72,9 +72,7 @@ int au_wh_test(struct dentry *h_parent, struct qstr *wh_name, - { - int err; - struct dentry *wh_dentry; -- struct inode *h_dir; - -- h_dir = h_parent->d_inode; - if (!try_sio) - wh_dentry = au_lkup_one(wh_name, h_parent, br, /*nd*/NULL); - else -@@ -481,7 +479,6 @@ int au_wh_init(struct dentry *h_root, struct au_branch *br, - if (wbr) - WbrWhMustWriteLock(wbr); - -- h_dir = h_root->d_inode; - for (i = 0; i < AuBrWh_Last; i++) { - /* doubly whiteouted */ - struct dentry *d; -@@ -504,12 +501,12 @@ int au_wh_init(struct dentry *h_root, struct au_branch *br, - } - - err = 0; -- - switch (br->br_perm) { - case AuBrPerm_RO: - case AuBrPerm_ROWH: - case AuBrPerm_RR: - case AuBrPerm_RRWH: -+ h_dir = h_root->d_inode; - au_wh_init_ro(h_dir, base, &path); - break; - -diff --git a/fs/aufs/whout.h b/fs/aufs/whout.h -index 40c6926..a59158b 100644 ---- a/fs/aufs/whout.h -+++ b/fs/aufs/whout.h -@@ -1,5 +1,5 @@ - /* -- * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * Copyright (C) 2005-2010 Junjiro R. Okajima - * - * This program, aufs is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by -diff --git a/fs/aufs/wkq.c b/fs/aufs/wkq.c -index 89656e9..307b1c4 100644 ---- a/fs/aufs/wkq.c -+++ b/fs/aufs/wkq.c -@@ -1,5 +1,5 @@ - /* -- * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * Copyright (C) 2005-2010 Junjiro R. Okajima - * - * This program, aufs is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by -@@ -25,12 +25,7 @@ - #include "aufs.h" - - /* internal workqueue named AUFS_WKQ_NAME */ --static struct au_wkq { -- struct workqueue_struct *q; -- -- /* balancing */ -- atomic_t busy; --} *au_wkq; -+static struct workqueue_struct *au_wkq; - - struct au_wkinfo { - struct work_struct wk; -@@ -41,60 +36,16 @@ struct au_wkinfo { - au_wkq_func_t func; - void *args; - -- atomic_t *busyp; - struct completion *comp; - }; - - /* ---------------------------------------------------------------------- */ - --static int enqueue(struct au_wkq *wkq, struct au_wkinfo *wkinfo) --{ -- wkinfo->busyp = &wkq->busy; -- if (au_ftest_wkq(wkinfo->flags, WAIT)) -- return !queue_work(wkq->q, &wkinfo->wk); -- else -- return !schedule_work(&wkinfo->wk); --} -- --static void do_wkq(struct au_wkinfo *wkinfo) --{ -- unsigned int idle, n; -- int i, idle_idx; -- -- while (1) { -- if (au_ftest_wkq(wkinfo->flags, WAIT)) { -- idle_idx = 0; -- idle = UINT_MAX; -- for (i = 0; i < aufs_nwkq; i++) { -- n = atomic_inc_return(&au_wkq[i].busy); -- if (n == 1 && !enqueue(au_wkq + i, wkinfo)) -- return; /* success */ -- -- if (n < idle) { -- idle_idx = i; -- idle = n; -- } -- atomic_dec(&au_wkq[i].busy); -- } -- } else -- idle_idx = aufs_nwkq; -- -- atomic_inc(&au_wkq[idle_idx].busy); -- if (!enqueue(au_wkq + idle_idx, wkinfo)) -- return; /* success */ -- -- /* impossible? */ -- AuWarn1("failed to queue_work()\n"); -- yield(); -- } --} -- - static void wkq_func(struct work_struct *wk) - { - struct au_wkinfo *wkinfo = container_of(wk, struct au_wkinfo, wk); - - wkinfo->func(wkinfo->args); -- atomic_dec_return(wkinfo->busyp); - if (au_ftest_wkq(wkinfo->flags, WAIT)) - complete(wkinfo->comp); - else { -@@ -145,11 +96,14 @@ static void au_wkq_comp_free(struct completion *comp __maybe_unused) - } - #endif /* 4KSTACKS */ - --static void au_wkq_run(struct au_wkinfo *wkinfo) -+static void au_wkq_run(struct au_wkinfo *wkinfo, int do_wait) - { - au_dbg_verify_kthread(); - INIT_WORK(&wkinfo->wk, wkq_func); -- do_wkq(wkinfo); -+ if (do_wait) -+ queue_work(au_wkq, &wkinfo->wk); -+ else -+ schedule_work(&wkinfo->wk); - } - - int au_wkq_wait(au_wkq_func_t func, void *args) -@@ -164,7 +118,7 @@ int au_wkq_wait(au_wkq_func_t func, void *args) - - err = au_wkq_comp_alloc(&wkinfo, &comp); - if (!err) { -- au_wkq_run(&wkinfo); -+ au_wkq_run(&wkinfo, AuWkq_WAIT); - /* no timeout, no interrupt */ - wait_for_completion(wkinfo.comp); - au_wkq_comp_free(comp); -@@ -196,7 +150,7 @@ int au_wkq_nowait(au_wkq_func_t func, void *args, struct super_block *sb) - kobject_get(&au_sbi(sb)->si_kobj); - __module_get(THIS_MODULE); - -- au_wkq_run(wkinfo); -+ au_wkq_run(wkinfo, !AuWkq_WAIT); - } else { - err = -ENOMEM; - atomic_dec(&au_sbi(sb)->si_nowait.nw_len); -@@ -210,50 +164,17 @@ int au_wkq_nowait(au_wkq_func_t func, void *args, struct super_block *sb) - void au_nwt_init(struct au_nowait_tasks *nwt) - { - atomic_set(&nwt->nw_len, 0); -- /* smp_mb();*/ /* atomic_set */ -+ /* smp_mb(); */ /* atomic_set */ - init_waitqueue_head(&nwt->nw_wq); - } - - void au_wkq_fin(void) - { -- int i; -- -- for (i = 0; i < aufs_nwkq; i++) -- if (au_wkq[i].q && !IS_ERR(au_wkq[i].q)) -- destroy_workqueue(au_wkq[i].q); -- kfree(au_wkq); -+ destroy_workqueue(au_wkq); - } - - int __init au_wkq_init(void) - { -- int err, i; -- struct au_wkq *nowaitq; -- -- /* '+1' is for accounting of nowait queue */ -- err = -ENOMEM; -- au_wkq = kcalloc(aufs_nwkq + 1, sizeof(*au_wkq), GFP_NOFS); -- if (unlikely(!au_wkq)) -- goto out; -- -- err = 0; -- for (i = 0; i < aufs_nwkq; i++) { -- au_wkq[i].q = create_singlethread_workqueue(AUFS_WKQ_NAME); -- if (au_wkq[i].q && !IS_ERR(au_wkq[i].q)) { -- atomic_set(&au_wkq[i].busy, 0); -- continue; -- } -- -- err = PTR_ERR(au_wkq[i].q); -- au_wkq_fin(); -- goto out; -- } -- -- /* nowait accounting */ -- nowaitq = au_wkq + aufs_nwkq; -- atomic_set(&nowaitq->busy, 0); -- nowaitq->q = NULL; -- /* smp_mb(); */ /* atomic_set */ -- -- out: -- return err; -+ au_wkq = create_workqueue(AUFS_WKQ_NAME); -+ return 0; - } -diff --git a/fs/aufs/wkq.h b/fs/aufs/wkq.h -index b5b6a61..3fe36b3 100644 ---- a/fs/aufs/wkq.h -+++ b/fs/aufs/wkq.h -@@ -1,5 +1,5 @@ - /* -- * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * Copyright (C) 2005-2010 Junjiro R. Okajima - * - * This program, aufs is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by -@@ -63,7 +63,9 @@ void au_wkq_fin(void); - - static inline int au_test_wkq(struct task_struct *tsk) - { -- return !tsk->mm && !strcmp(tsk->comm, AUFS_WKQ_NAME); -+ return !tsk->mm -+ && !strncmp(tsk->comm, AUFS_WKQ_NAME "/", -+ sizeof(AUFS_WKQ_NAME)); - } - - static inline void au_nwt_done(struct au_nowait_tasks *nwt) -diff --git a/fs/aufs/xino.c b/fs/aufs/xino.c -index b401aa9..a5362dc 100644 ---- a/fs/aufs/xino.c -+++ b/fs/aufs/xino.c -@@ -1,5 +1,5 @@ - /* -- * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * Copyright (C) 2005-2010 Junjiro R. Okajima - * - * This program, aufs is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by -@@ -127,11 +127,11 @@ ssize_t xino_fwrite(au_writef_t func, struct file *file, void *buf, size_t size, - struct file *au_xino_create2(struct file *base_file, struct file *copy_src) - { - struct file *file; -- struct dentry *base, *dentry, *parent; -+ struct dentry *base, *parent; - struct inode *dir; - struct qstr *name; -- int err; - struct path path; -+ int err; - - base = base_file->f_dentry; - parent = base->d_parent; /* dir inode is locked */ -@@ -140,27 +140,25 @@ struct file *au_xino_create2(struct file *base_file, struct file *copy_src) - - file = ERR_PTR(-EINVAL); - name = &base->d_name; -- dentry = vfsub_lookup_one_len(name->name, parent, name->len); -- if (IS_ERR(dentry)) { -- file = (void *)dentry; -+ path.dentry = vfsub_lookup_one_len(name->name, parent, name->len); -+ if (IS_ERR(path.dentry)) { -+ file = (void *)path.dentry; - pr_err("%.*s lookup err %ld\n", -- AuLNPair(name), PTR_ERR(dentry)); -+ AuLNPair(name), PTR_ERR(path.dentry)); - goto out; - } - - /* no need to mnt_want_write() since we call dentry_open() later */ -- err = vfs_create(dir, dentry, S_IRUGO | S_IWUGO, NULL); -+ err = vfs_create(dir, path.dentry, S_IRUGO | S_IWUGO, NULL); - if (unlikely(err)) { - file = ERR_PTR(err); - pr_err("%.*s create err %d\n", AuLNPair(name), err); - goto out_dput; - } - -- path.dentry = dentry; - path.mnt = base_file->f_vfsmnt; -- path_get(&path); -- file = vfsub_dentry_open(&path, O_RDWR | O_CREAT | O_EXCL | O_LARGEFILE, -- current_cred()); -+ file = vfsub_dentry_open(&path, -+ O_RDWR | O_CREAT | O_EXCL | O_LARGEFILE); - if (IS_ERR(file)) { - pr_err("%.*s open err %ld\n", AuLNPair(name), PTR_ERR(file)); - goto out_dput; -@@ -187,7 +185,7 @@ struct file *au_xino_create2(struct file *base_file, struct file *copy_src) - fput(file); - file = ERR_PTR(err); - out_dput: -- dput(dentry); -+ dput(path.dentry); - out: - return file; - } -diff --git a/include/linux/aufs_type.h b/include/linux/aufs_type.h -index cc0263d..3ca3948 100644 ---- a/include/linux/aufs_type.h -+++ b/include/linux/aufs_type.h -@@ -1,5 +1,5 @@ - /* -- * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * Copyright (C) 2005-2010 Junjiro R. Okajima - * - * This program, aufs is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by -@@ -23,7 +23,7 @@ - #include - #include - --#define AUFS_VERSION "2-standalone.tree-20091207" -+#define AUFS_VERSION "2-standalone.tree-32-20100125" - - /* todo? move this to linux-2.6.19/include/magic.h */ - #define AUFS_SUPER_MAGIC ('a' << 24 | 'u' << 16 | 'f' << 8 | 's') -@@ -75,7 +75,6 @@ typedef __s16 aufs_bindex_t; - #define AUFS_RDBLK_DEF 512 /* bytes */ - #define AUFS_RDHASH_DEF 32 - #define AUFS_WKQ_NAME AUFS_NAME "d" --#define AUFS_NWKQ_DEF 4 - #define AUFS_MFS_SECOND_DEF 30 /* seconds */ - #define AUFS_PLINK_WARN 100 /* number of plinks */ - ---- a/security/security.c -+++ b/security/security.c -@@ -651,6 +651,7 @@ - { - return security_ops->file_mmap(file, reqprot, prot, flags, addr, addr_only); - } -+EXPORT_SYMBOL(security_file_mmap); - - int security_file_mprotect(struct vm_area_struct *vma, unsigned long reqprot, - unsigned long prot) ---- a/security/commoncap.c -+++ b/security/commoncap.c -@@ -1014,3 +1014,4 @@ int cap_file_mmap(struct file *file, unsigned long reqprot, - } - return ret; - } -+EXPORT_SYMBOL(cap_file_mmap); diff --git a/debian/patches/features/all/aufs2/aufs2-add.patch b/debian/patches/features/all/aufs2/aufs2-add.patch deleted file mode 100644 index e4abef5e6..000000000 --- a/debian/patches/features/all/aufs2/aufs2-add.patch +++ /dev/null @@ -1,25017 +0,0 @@ -diff --git a/fs/aufs/Kconfig b/fs/aufs/Kconfig -new file mode 100644 -index 0000000..3258e33 ---- /dev/null -+++ b/fs/aufs/Kconfig -@@ -0,0 +1,140 @@ -+config AUFS_FS -+ tristate "Aufs (Advanced multi layered unification filesystem) support" -+ depends on EXPERIMENTAL -+ help -+ Aufs is a stackable unification filesystem such as Unionfs, -+ which unifies several directories and provides a merged single -+ directory. -+ In the early days, aufs was entirely re-designed and -+ re-implemented Unionfs Version 1.x series. Introducing many -+ original ideas, approaches and improvements, it becomes totally -+ different from Unionfs while keeping the basic features. -+ -+if AUFS_FS -+choice -+ prompt "Maximum number of branches" -+ default AUFS_BRANCH_MAX_127 -+ help -+ Specifies the maximum number of branches (or member directories) -+ in a single aufs. The larger value consumes more system -+ resources and has a minor impact to performance. -+config AUFS_BRANCH_MAX_127 -+ bool "127" -+ help -+ Specifies the maximum number of branches (or member directories) -+ in a single aufs. The larger value consumes more system -+ resources and has a minor impact to performance. -+config AUFS_BRANCH_MAX_511 -+ bool "511" -+ help -+ Specifies the maximum number of branches (or member directories) -+ in a single aufs. The larger value consumes more system -+ resources and has a minor impact to performance. -+config AUFS_BRANCH_MAX_1023 -+ bool "1023" -+ help -+ Specifies the maximum number of branches (or member directories) -+ in a single aufs. The larger value consumes more system -+ resources and has a minor impact to performance. -+config AUFS_BRANCH_MAX_32767 -+ bool "32767" -+ help -+ Specifies the maximum number of branches (or member directories) -+ in a single aufs. The larger value consumes more system -+ resources and has a minor impact to performance. -+endchoice -+ -+config AUFS_HINOTIFY -+ bool "Use inotify to detect actions on a branch" -+ depends on INOTIFY -+ help -+ If you want to modify files on branches directly, eg. bypassing aufs, -+ and want aufs to detect the changes of them fully, then enable this -+ option and use 'udba=inotify' mount option. -+ It will have a negative impact to the performance. -+ See detail in aufs.5. -+ -+config AUFS_EXPORT -+ bool "NFS-exportable aufs" -+ depends on (AUFS_FS = y && EXPORTFS = y) || (AUFS_FS = m && EXPORTFS) -+ help -+ If you want to export your mounted aufs via NFS, then enable this -+ option. There are several requirements for this configuration. -+ See detail in aufs.5. -+ -+config AUFS_INO_T_64 -+ bool -+ depends on AUFS_EXPORT -+ depends on 64BIT && !(ALPHA || S390) -+ default y -+ help -+ Automatic configuration for internal use. -+ /* typedef unsigned long/int __kernel_ino_t */ -+ /* alpha and s390x are int */ -+ -+config AUFS_RDU -+ bool "Readdir in userspace" -+ help -+ If you have millions of files under a single aufs directory, and -+ meet the out of memory, then enable this option and set -+ environment variables for your readdir(3). -+ See detail in aufs.5. -+ -+config AUFS_SHWH -+ bool "Show whiteouts" -+ help -+ If you want to make the whiteouts in aufs visible, then enable -+ this option and specify 'shwh' mount option. Although it may -+ sounds like philosophy or something, but in technically it -+ simply shows the name of whiteout with keeping its behaviour. -+ -+config AUFS_BR_RAMFS -+ bool "Ramfs (initramfs/rootfs) as an aufs branch" -+ help -+ If you want to use ramfs as an aufs branch fs, then enable this -+ option. Generally tmpfs is recommended. -+ Aufs prohibited them to be a branch fs by default, because -+ initramfs becomes unusable after switch_root or something -+ generally. If you sets initramfs as an aufs branch and boot your -+ system by switch_root, you will meet a problem easily since the -+ files in initramfs may be inaccessible. -+ Unless you are going to use ramfs as an aufs branch fs without -+ switch_root or something, leave it N. -+ -+config AUFS_BR_FUSE -+ bool "Fuse fs as an aufs branch" -+ depends on FUSE_FS -+ select AUFS_POLL -+ help -+ If you want to use fuse-based userspace filesystem as an aufs -+ branch fs, then enable this option. -+ It implements the internal poll(2) operation which is -+ implemented by fuse only (curretnly). -+ -+config AUFS_POLL -+ bool -+ help -+ Automatic configuration for internal use. -+ -+config AUFS_BDEV_LOOP -+ bool -+ depends on BLK_DEV_LOOP -+ default y -+ help -+ Automatic configuration for internal use. -+ Convert =[ym] into =y. -+ -+config AUFS_DEBUG -+ bool "Debug aufs" -+ help -+ Enable this to compile aufs internal debug code. -+ It will have a negative impact to the performance. -+ -+config AUFS_MAGIC_SYSRQ -+ bool -+ depends on AUFS_DEBUG && MAGIC_SYSRQ -+ default y -+ help -+ Automatic configuration for internal use. -+ When aufs supports Magic SysRq, enabled automatically. -+endif -diff --git a/fs/aufs/Makefile b/fs/aufs/Makefile -new file mode 100644 -index 0000000..2b26cd1 ---- /dev/null -+++ b/fs/aufs/Makefile -@@ -0,0 +1,33 @@ -+ -+include ${src}/magic.mk -+ifeq (${CONFIG_AUFS_FS},m) -+include ${src}/conf.mk -+endif -+-include ${src}/priv_def.mk -+ -+# cf. include/linux/kernel.h -+# enable pr_debug -+ccflags-y += -DDEBUG -+ccflags-y += -D'pr_fmt(fmt)="aufs %s:%d:%s[%d]: " fmt, \ -+ __func__, __LINE__, current->comm, current->pid' -+ -+obj-$(CONFIG_AUFS_FS) += aufs.o -+aufs-y := module.o sbinfo.o super.o branch.o xino.o sysaufs.o opts.o \ -+ wkq.o vfsub.o dcsub.o \ -+ cpup.o whout.o plink.o wbr_policy.o \ -+ dinfo.o dentry.o \ -+ finfo.o file.o f_op.o \ -+ dir.o vdir.o \ -+ iinfo.o inode.o i_op.o i_op_add.o i_op_del.o i_op_ren.o \ -+ ioctl.o -+ -+# all are boolean -+aufs-$(CONFIG_SYSFS) += sysfs.o -+aufs-$(CONFIG_DEBUG_FS) += dbgaufs.o -+aufs-$(CONFIG_AUFS_BDEV_LOOP) += loop.o -+aufs-$(CONFIG_AUFS_HINOTIFY) += hinotify.o -+aufs-$(CONFIG_AUFS_EXPORT) += export.o -+aufs-$(CONFIG_AUFS_POLL) += poll.o -+aufs-$(CONFIG_AUFS_RDU) += rdu.o -+aufs-$(CONFIG_AUFS_DEBUG) += debug.o -+aufs-$(CONFIG_AUFS_MAGIC_SYSRQ) += sysrq.o -diff --git a/fs/aufs/aufs.h b/fs/aufs/aufs.h -new file mode 100644 -index 0000000..96307bb ---- /dev/null -+++ b/fs/aufs/aufs.h -@@ -0,0 +1,51 @@ -+/* -+ * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * -+ * This program, aufs is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ */ -+ -+/* -+ * all header files -+ */ -+ -+#ifndef __AUFS_H__ -+#define __AUFS_H__ -+ -+#ifdef __KERNEL__ -+ -+#include "debug.h" -+ -+#include "branch.h" -+#include "cpup.h" -+#include "dcsub.h" -+#include "dbgaufs.h" -+#include "dentry.h" -+#include "dir.h" -+#include "file.h" -+#include "fstype.h" -+#include "inode.h" -+#include "loop.h" -+#include "module.h" -+#include "opts.h" -+#include "rwsem.h" -+#include "spl.h" -+#include "super.h" -+#include "sysaufs.h" -+#include "vfsub.h" -+#include "whout.h" -+#include "wkq.h" -+ -+#endif /* __KERNEL__ */ -+#endif /* __AUFS_H__ */ -diff --git a/fs/aufs/branch.c b/fs/aufs/branch.c -new file mode 100644 -index 0000000..bb7ad86 ---- /dev/null -+++ b/fs/aufs/branch.c -@@ -0,0 +1,988 @@ -+/* -+ * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * -+ * This program, aufs is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ */ -+ -+/* -+ * branch management -+ */ -+ -+#include -+#include -+#include "aufs.h" -+ -+/* -+ * free a single branch -+ */ -+static void au_br_do_free(struct au_branch *br) -+{ -+ int i; -+ struct au_wbr *wbr; -+ -+ if (br->br_xino.xi_file) -+ fput(br->br_xino.xi_file); -+ mutex_destroy(&br->br_xino.xi_nondir_mtx); -+ -+ AuDebugOn(atomic_read(&br->br_count)); -+ -+ wbr = br->br_wbr; -+ if (wbr) { -+ for (i = 0; i < AuBrWh_Last; i++) -+ dput(wbr->wbr_wh[i]); -+ AuDebugOn(atomic_read(&wbr->wbr_wh_running)); -+ AuRwDestroy(&wbr->wbr_wh_rwsem); -+ } -+ -+ /* some filesystems acquire extra lock */ -+ /* lockdep_off(); */ -+ mntput(br->br_mnt); -+ /* lockdep_on(); */ -+ -+ kfree(wbr); -+ kfree(br); -+} -+ -+/* -+ * frees all branches -+ */ -+void au_br_free(struct au_sbinfo *sbinfo) -+{ -+ aufs_bindex_t bmax; -+ struct au_branch **br; -+ -+ AuRwMustWriteLock(&sbinfo->si_rwsem); -+ -+ bmax = sbinfo->si_bend + 1; -+ br = sbinfo->si_branch; -+ while (bmax--) -+ au_br_do_free(*br++); -+} -+ -+/* -+ * find the index of a branch which is specified by @br_id. -+ */ -+int au_br_index(struct super_block *sb, aufs_bindex_t br_id) -+{ -+ aufs_bindex_t bindex, bend; -+ -+ bend = au_sbend(sb); -+ for (bindex = 0; bindex <= bend; bindex++) -+ if (au_sbr_id(sb, bindex) == br_id) -+ return bindex; -+ return -1; -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+/* -+ * add a branch -+ */ -+ -+static int test_overlap(struct super_block *sb, struct dentry *h_d1, -+ struct dentry *h_d2) -+{ -+ if (unlikely(h_d1 == h_d2)) -+ return 1; -+ return !!au_test_subdir(h_d1, h_d2) -+ || !!au_test_subdir(h_d2, h_d1) -+ || au_test_loopback_overlap(sb, h_d1, h_d2) -+ || au_test_loopback_overlap(sb, h_d2, h_d1); -+} -+ -+/* -+ * returns a newly allocated branch. @new_nbranch is a number of branches -+ * after adding a branch. -+ */ -+static struct au_branch *au_br_alloc(struct super_block *sb, int new_nbranch, -+ int perm) -+{ -+ struct au_branch *add_branch; -+ struct dentry *root; -+ -+ root = sb->s_root; -+ add_branch = kmalloc(sizeof(*add_branch), GFP_NOFS); -+ if (unlikely(!add_branch)) -+ goto out; -+ -+ add_branch->br_wbr = NULL; -+ if (au_br_writable(perm)) { -+ /* may be freed separately at changing the branch permission */ -+ add_branch->br_wbr = kmalloc(sizeof(*add_branch->br_wbr), -+ GFP_NOFS); -+ if (unlikely(!add_branch->br_wbr)) -+ goto out_br; -+ } -+ -+ if (unlikely(au_sbr_realloc(au_sbi(sb), new_nbranch) -+ || au_di_realloc(au_di(root), new_nbranch) -+ || au_ii_realloc(au_ii(root->d_inode), new_nbranch))) -+ goto out_wbr; -+ return add_branch; /* success */ -+ -+ out_wbr: -+ kfree(add_branch->br_wbr); -+ out_br: -+ kfree(add_branch); -+ out: -+ return ERR_PTR(-ENOMEM); -+} -+ -+/* -+ * test if the branch permission is legal or not. -+ */ -+static int test_br(struct inode *inode, int brperm, char *path) -+{ -+ int err; -+ -+ err = 0; -+ if (unlikely(au_br_writable(brperm) && IS_RDONLY(inode))) { -+ pr_err("write permission for readonly mount or inode, %s\n", -+ path); -+ err = -EINVAL; -+ } -+ -+ return err; -+} -+ -+/* -+ * returns: -+ * 0: success, the caller will add it -+ * plus: success, it is already unified, the caller should ignore it -+ * minus: error -+ */ -+static int test_add(struct super_block *sb, struct au_opt_add *add, int remount) -+{ -+ int err; -+ aufs_bindex_t bend, bindex; -+ struct dentry *root; -+ struct inode *inode, *h_inode; -+ -+ root = sb->s_root; -+ bend = au_sbend(sb); -+ if (unlikely(bend >= 0 -+ && au_find_dbindex(root, add->path.dentry) >= 0)) { -+ err = 1; -+ if (!remount) { -+ err = -EINVAL; -+ pr_err("%s duplicated\n", add->pathname); -+ } -+ goto out; -+ } -+ -+ err = -ENOSPC; /* -E2BIG; */ -+ if (unlikely(AUFS_BRANCH_MAX <= add->bindex -+ || AUFS_BRANCH_MAX - 1 <= bend)) { -+ pr_err("number of branches exceeded %s\n", add->pathname); -+ goto out; -+ } -+ -+ err = -EDOM; -+ if (unlikely(add->bindex < 0 || bend + 1 < add->bindex)) { -+ pr_err("bad index %d\n", add->bindex); -+ goto out; -+ } -+ -+ inode = add->path.dentry->d_inode; -+ err = -ENOENT; -+ if (unlikely(!inode->i_nlink)) { -+ pr_err("no existence %s\n", add->pathname); -+ goto out; -+ } -+ -+ err = -EINVAL; -+ if (unlikely(inode->i_sb == sb)) { -+ pr_err("%s must be outside\n", add->pathname); -+ goto out; -+ } -+ -+ if (unlikely(au_test_fs_unsuppoted(inode->i_sb))) { -+ pr_err("unsupported filesystem, %s (%s)\n", -+ add->pathname, au_sbtype(inode->i_sb)); -+ goto out; -+ } -+ -+ err = test_br(add->path.dentry->d_inode, add->perm, add->pathname); -+ if (unlikely(err)) -+ goto out; -+ -+ if (bend < 0) -+ return 0; /* success */ -+ -+ err = -EINVAL; -+ for (bindex = 0; bindex <= bend; bindex++) -+ if (unlikely(test_overlap(sb, add->path.dentry, -+ au_h_dptr(root, bindex)))) { -+ pr_err("%s is overlapped\n", add->pathname); -+ goto out; -+ } -+ -+ err = 0; -+ if (au_opt_test(au_mntflags(sb), WARN_PERM)) { -+ h_inode = au_h_dptr(root, 0)->d_inode; -+ if ((h_inode->i_mode & S_IALLUGO) != (inode->i_mode & S_IALLUGO) -+ || h_inode->i_uid != inode->i_uid -+ || h_inode->i_gid != inode->i_gid) -+ pr_warning("uid/gid/perm %s %u/%u/0%o, %u/%u/0%o\n", -+ add->pathname, -+ inode->i_uid, inode->i_gid, -+ (inode->i_mode & S_IALLUGO), -+ h_inode->i_uid, h_inode->i_gid, -+ (h_inode->i_mode & S_IALLUGO)); -+ } -+ -+ out: -+ return err; -+} -+ -+/* -+ * initialize or clean the whiteouts for an adding branch -+ */ -+static int au_br_init_wh(struct super_block *sb, struct au_branch *br, -+ int new_perm, struct dentry *h_root) -+{ -+ int err, old_perm; -+ aufs_bindex_t bindex; -+ struct mutex *h_mtx; -+ struct au_wbr *wbr; -+ struct au_hinode *hdir; -+ -+ wbr = br->br_wbr; -+ old_perm = br->br_perm; -+ br->br_perm = new_perm; -+ hdir = NULL; -+ h_mtx = NULL; -+ bindex = au_br_index(sb, br->br_id); -+ if (0 <= bindex) { -+ hdir = au_hi(sb->s_root->d_inode, bindex); -+ au_hin_imtx_lock_nested(hdir, AuLsc_I_PARENT); -+ } else { -+ h_mtx = &h_root->d_inode->i_mutex; -+ mutex_lock_nested(h_mtx, AuLsc_I_PARENT); -+ } -+ if (!wbr) -+ err = au_wh_init(h_root, br, sb); -+ else { -+ wbr_wh_write_lock(wbr); -+ err = au_wh_init(h_root, br, sb); -+ wbr_wh_write_unlock(wbr); -+ } -+ if (hdir) -+ au_hin_imtx_unlock(hdir); -+ else -+ mutex_unlock(h_mtx); -+ br->br_perm = old_perm; -+ -+ if (!err && wbr && !au_br_writable(new_perm)) { -+ kfree(wbr); -+ br->br_wbr = NULL; -+ } -+ -+ return err; -+} -+ -+static int au_wbr_init(struct au_branch *br, struct super_block *sb, -+ int perm, struct path *path) -+{ -+ int err; -+ struct kstatfs kst; -+ struct au_wbr *wbr; -+ struct dentry *h_dentry; -+ -+ wbr = br->br_wbr; -+ au_rw_init(&wbr->wbr_wh_rwsem); -+ memset(wbr->wbr_wh, 0, sizeof(wbr->wbr_wh)); -+ atomic_set(&wbr->wbr_wh_running, 0); -+ wbr->wbr_bytes = 0; -+ -+ /* -+ * a limit for rmdir/rename a dir -+ * cf. AUFS_MAX_NAMELEN in include/linux/aufs_type.h -+ */ -+ h_dentry = path->dentry; -+ err = vfs_statfs(h_dentry, &kst); -+ if (unlikely(err)) -+ goto out; -+ err = -EINVAL; -+ if (kst.f_namelen >= NAME_MAX) -+ err = au_br_init_wh(sb, br, perm, h_dentry); -+ else -+ pr_err("%.*s(%s), unsupported namelen %ld\n", -+ AuDLNPair(h_dentry), au_sbtype(h_dentry->d_sb), -+ kst.f_namelen); -+ -+ out: -+ return err; -+} -+ -+/* intialize a new branch */ -+static int au_br_init(struct au_branch *br, struct super_block *sb, -+ struct au_opt_add *add) -+{ -+ int err; -+ -+ err = 0; -+ memset(&br->br_xino, 0, sizeof(br->br_xino)); -+ mutex_init(&br->br_xino.xi_nondir_mtx); -+ br->br_perm = add->perm; -+ br->br_mnt = add->path.mnt; /* set first, mntget() later */ -+ atomic_set(&br->br_count, 0); -+ br->br_xino_upper = AUFS_XINO_TRUNC_INIT; -+ atomic_set(&br->br_xino_running, 0); -+ br->br_id = au_new_br_id(sb); -+ -+ if (au_br_writable(add->perm)) { -+ err = au_wbr_init(br, sb, add->perm, &add->path); -+ if (unlikely(err)) -+ goto out; -+ } -+ -+ if (au_opt_test(au_mntflags(sb), XINO)) { -+ err = au_xino_br(sb, br, add->path.dentry->d_inode->i_ino, -+ au_sbr(sb, 0)->br_xino.xi_file, /*do_test*/1); -+ if (unlikely(err)) { -+ AuDebugOn(br->br_xino.xi_file); -+ goto out; -+ } -+ } -+ -+ sysaufs_br_init(br); -+ mntget(add->path.mnt); -+ -+ out: -+ return err; -+} -+ -+static void au_br_do_add_brp(struct au_sbinfo *sbinfo, aufs_bindex_t bindex, -+ struct au_branch *br, aufs_bindex_t bend, -+ aufs_bindex_t amount) -+{ -+ struct au_branch **brp; -+ -+ AuRwMustWriteLock(&sbinfo->si_rwsem); -+ -+ brp = sbinfo->si_branch + bindex; -+ memmove(brp + 1, brp, sizeof(*brp) * amount); -+ *brp = br; -+ sbinfo->si_bend++; -+ if (unlikely(bend < 0)) -+ sbinfo->si_bend = 0; -+} -+ -+static void au_br_do_add_hdp(struct au_dinfo *dinfo, aufs_bindex_t bindex, -+ aufs_bindex_t bend, aufs_bindex_t amount) -+{ -+ struct au_hdentry *hdp; -+ -+ AuRwMustWriteLock(&dinfo->di_rwsem); -+ -+ hdp = dinfo->di_hdentry + bindex; -+ memmove(hdp + 1, hdp, sizeof(*hdp) * amount); -+ au_h_dentry_init(hdp); -+ dinfo->di_bend++; -+ if (unlikely(bend < 0)) -+ dinfo->di_bstart = 0; -+} -+ -+static void au_br_do_add_hip(struct au_iinfo *iinfo, aufs_bindex_t bindex, -+ aufs_bindex_t bend, aufs_bindex_t amount) -+{ -+ struct au_hinode *hip; -+ -+ AuRwMustWriteLock(&iinfo->ii_rwsem); -+ -+ hip = iinfo->ii_hinode + bindex; -+ memmove(hip + 1, hip, sizeof(*hip) * amount); -+ hip->hi_inode = NULL; -+ au_hin_init(hip, NULL); -+ iinfo->ii_bend++; -+ if (unlikely(bend < 0)) -+ iinfo->ii_bstart = 0; -+} -+ -+static void au_br_do_add(struct super_block *sb, struct dentry *h_dentry, -+ struct au_branch *br, aufs_bindex_t bindex) -+{ -+ struct dentry *root; -+ struct inode *root_inode; -+ aufs_bindex_t bend, amount; -+ -+ root = sb->s_root; -+ root_inode = root->d_inode; -+ au_plink_block_maintain(sb); -+ bend = au_sbend(sb); -+ amount = bend + 1 - bindex; -+ au_br_do_add_brp(au_sbi(sb), bindex, br, bend, amount); -+ au_br_do_add_hdp(au_di(root), bindex, bend, amount); -+ au_br_do_add_hip(au_ii(root_inode), bindex, bend, amount); -+ au_set_h_dptr(root, bindex, dget(h_dentry)); -+ au_set_h_iptr(root_inode, bindex, au_igrab(h_dentry->d_inode), -+ /*flags*/0); -+} -+ -+int au_br_add(struct super_block *sb, struct au_opt_add *add, int remount) -+{ -+ int err; -+ aufs_bindex_t bend, add_bindex; -+ struct dentry *root, *h_dentry; -+ struct inode *root_inode; -+ struct au_branch *add_branch; -+ -+ root = sb->s_root; -+ root_inode = root->d_inode; -+ IMustLock(root_inode); -+ err = test_add(sb, add, remount); -+ if (unlikely(err < 0)) -+ goto out; -+ if (err) { -+ err = 0; -+ goto out; /* success */ -+ } -+ -+ bend = au_sbend(sb); -+ add_branch = au_br_alloc(sb, bend + 2, add->perm); -+ err = PTR_ERR(add_branch); -+ if (IS_ERR(add_branch)) -+ goto out; -+ -+ err = au_br_init(add_branch, sb, add); -+ if (unlikely(err)) { -+ au_br_do_free(add_branch); -+ goto out; -+ } -+ -+ add_bindex = add->bindex; -+ h_dentry = add->path.dentry; -+ if (!remount) -+ au_br_do_add(sb, h_dentry, add_branch, add_bindex); -+ else { -+ sysaufs_brs_del(sb, add_bindex); -+ au_br_do_add(sb, h_dentry, add_branch, add_bindex); -+ sysaufs_brs_add(sb, add_bindex); -+ } -+ -+ if (!add_bindex) { -+ au_cpup_attr_all(root_inode, /*force*/1); -+ sb->s_maxbytes = h_dentry->d_sb->s_maxbytes; -+ } else -+ au_add_nlink(root_inode, h_dentry->d_inode); -+ -+ /* -+ * this test/set prevents aufs from handling unnecesary inotify events -+ * of xino files, in a case of re-adding a writable branch which was -+ * once detached from aufs. -+ */ -+ if (au_xino_brid(sb) < 0 -+ && au_br_writable(add_branch->br_perm) -+ && !au_test_fs_bad_xino(h_dentry->d_sb) -+ && add_branch->br_xino.xi_file -+ && add_branch->br_xino.xi_file->f_dentry->d_parent == h_dentry) -+ au_xino_brid_set(sb, add_branch->br_id); -+ -+ out: -+ return err; -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+/* -+ * delete a branch -+ */ -+ -+/* to show the line number, do not make it inlined function */ -+#define AuVerbose(do_info, fmt, ...) do { \ -+ if (do_info) \ -+ pr_info(fmt, ##__VA_ARGS__); \ -+} while (0) -+ -+/* -+ * test if the branch is deletable or not. -+ */ -+static int test_dentry_busy(struct dentry *root, aufs_bindex_t bindex, -+ unsigned int sigen) -+{ -+ int err, i, j, ndentry; -+ aufs_bindex_t bstart, bend; -+ unsigned char verbose; -+ struct au_dcsub_pages dpages; -+ struct au_dpage *dpage; -+ struct dentry *d; -+ struct inode *inode; -+ -+ err = au_dpages_init(&dpages, GFP_NOFS); -+ if (unlikely(err)) -+ goto out; -+ err = au_dcsub_pages(&dpages, root, NULL, NULL); -+ if (unlikely(err)) -+ goto out_dpages; -+ -+ verbose = !!au_opt_test(au_mntflags(root->d_sb), VERBOSE); -+ for (i = 0; !err && i < dpages.ndpage; i++) { -+ dpage = dpages.dpages + i; -+ ndentry = dpage->ndentry; -+ for (j = 0; !err && j < ndentry; j++) { -+ d = dpage->dentries[j]; -+ AuDebugOn(!atomic_read(&d->d_count)); -+ inode = d->d_inode; -+ if (au_digen(d) == sigen && au_iigen(inode) == sigen) -+ di_read_lock_child(d, AuLock_IR); -+ else { -+ di_write_lock_child(d); -+ err = au_reval_dpath(d, sigen); -+ if (!err) -+ di_downgrade_lock(d, AuLock_IR); -+ else { -+ di_write_unlock(d); -+ break; -+ } -+ } -+ -+ bstart = au_dbstart(d); -+ bend = au_dbend(d); -+ if (bstart <= bindex -+ && bindex <= bend -+ && au_h_dptr(d, bindex) -+ && (!S_ISDIR(inode->i_mode) || bstart == bend)) { -+ err = -EBUSY; -+ AuVerbose(verbose, "busy %.*s\n", AuDLNPair(d)); -+ } -+ di_read_unlock(d, AuLock_IR); -+ } -+ } -+ -+ out_dpages: -+ au_dpages_free(&dpages); -+ out: -+ return err; -+} -+ -+static int test_inode_busy(struct super_block *sb, aufs_bindex_t bindex, -+ unsigned int sigen) -+{ -+ int err; -+ struct inode *i; -+ aufs_bindex_t bstart, bend; -+ unsigned char verbose; -+ -+ err = 0; -+ verbose = !!au_opt_test(au_mntflags(sb), VERBOSE); -+ list_for_each_entry(i, &sb->s_inodes, i_sb_list) { -+ AuDebugOn(!atomic_read(&i->i_count)); -+ if (!list_empty(&i->i_dentry)) -+ continue; -+ -+ if (au_iigen(i) == sigen) -+ ii_read_lock_child(i); -+ else { -+ ii_write_lock_child(i); -+ err = au_refresh_hinode_self(i, /*do_attr*/1); -+ if (!err) -+ ii_downgrade_lock(i); -+ else { -+ ii_write_unlock(i); -+ break; -+ } -+ } -+ -+ bstart = au_ibstart(i); -+ bend = au_ibend(i); -+ if (bstart <= bindex -+ && bindex <= bend -+ && au_h_iptr(i, bindex) -+ && (!S_ISDIR(i->i_mode) || bstart == bend)) { -+ err = -EBUSY; -+ AuVerbose(verbose, "busy i%lu\n", i->i_ino); -+ ii_read_unlock(i); -+ break; -+ } -+ ii_read_unlock(i); -+ } -+ -+ return err; -+} -+ -+static int test_children_busy(struct dentry *root, aufs_bindex_t bindex) -+{ -+ int err; -+ unsigned int sigen; -+ -+ sigen = au_sigen(root->d_sb); -+ DiMustNoWaiters(root); -+ IiMustNoWaiters(root->d_inode); -+ di_write_unlock(root); -+ err = test_dentry_busy(root, bindex, sigen); -+ if (!err) -+ err = test_inode_busy(root->d_sb, bindex, sigen); -+ di_write_lock_child(root); /* aufs_write_lock() calls ..._child() */ -+ -+ return err; -+} -+ -+static void au_br_do_del_brp(struct au_sbinfo *sbinfo, -+ const aufs_bindex_t bindex, -+ const aufs_bindex_t bend) -+{ -+ struct au_branch **brp, **p; -+ -+ AuRwMustWriteLock(&sbinfo->si_rwsem); -+ -+ brp = sbinfo->si_branch + bindex; -+ if (bindex < bend) -+ memmove(brp, brp + 1, sizeof(*brp) * (bend - bindex)); -+ sbinfo->si_branch[0 + bend] = NULL; -+ sbinfo->si_bend--; -+ -+ p = krealloc(sbinfo->si_branch, sizeof(*p) * bend, GFP_NOFS); -+ if (p) -+ sbinfo->si_branch = p; -+} -+ -+static void au_br_do_del_hdp(struct au_dinfo *dinfo, const aufs_bindex_t bindex, -+ const aufs_bindex_t bend) -+{ -+ struct au_hdentry *hdp, *p; -+ -+ AuRwMustWriteLock(&dinfo->di_rwsem); -+ -+ hdp = dinfo->di_hdentry + bindex; -+ if (bindex < bend) -+ memmove(hdp, hdp + 1, sizeof(*hdp) * (bend - bindex)); -+ dinfo->di_hdentry[0 + bend].hd_dentry = NULL; -+ dinfo->di_bend--; -+ -+ p = krealloc(dinfo->di_hdentry, sizeof(*p) * bend, GFP_NOFS); -+ if (p) -+ dinfo->di_hdentry = p; -+} -+ -+static void au_br_do_del_hip(struct au_iinfo *iinfo, const aufs_bindex_t bindex, -+ const aufs_bindex_t bend) -+{ -+ struct au_hinode *hip, *p; -+ -+ AuRwMustWriteLock(&iinfo->ii_rwsem); -+ -+ hip = iinfo->ii_hinode + bindex; -+ if (bindex < bend) -+ memmove(hip, hip + 1, sizeof(*hip) * (bend - bindex)); -+ iinfo->ii_hinode[0 + bend].hi_inode = NULL; -+ au_hin_init(iinfo->ii_hinode + bend, NULL); -+ iinfo->ii_bend--; -+ -+ p = krealloc(iinfo->ii_hinode, sizeof(*p) * bend, GFP_NOFS); -+ if (p) -+ iinfo->ii_hinode = p; -+} -+ -+static void au_br_do_del(struct super_block *sb, aufs_bindex_t bindex, -+ struct au_branch *br) -+{ -+ aufs_bindex_t bend; -+ struct au_sbinfo *sbinfo; -+ struct dentry *root; -+ struct inode *inode; -+ -+ SiMustWriteLock(sb); -+ -+ root = sb->s_root; -+ inode = root->d_inode; -+ au_plink_block_maintain(sb); -+ sbinfo = au_sbi(sb); -+ bend = sbinfo->si_bend; -+ -+ dput(au_h_dptr(root, bindex)); -+ au_hiput(au_hi(inode, bindex)); -+ au_br_do_free(br); -+ -+ au_br_do_del_brp(sbinfo, bindex, bend); -+ au_br_do_del_hdp(au_di(root), bindex, bend); -+ au_br_do_del_hip(au_ii(inode), bindex, bend); -+} -+ -+int au_br_del(struct super_block *sb, struct au_opt_del *del, int remount) -+{ -+ int err, rerr, i; -+ unsigned int mnt_flags; -+ aufs_bindex_t bindex, bend, br_id; -+ unsigned char do_wh, verbose; -+ struct au_branch *br; -+ struct au_wbr *wbr; -+ -+ err = 0; -+ bindex = au_find_dbindex(sb->s_root, del->h_path.dentry); -+ if (bindex < 0) { -+ if (remount) -+ goto out; /* success */ -+ err = -ENOENT; -+ pr_err("%s no such branch\n", del->pathname); -+ goto out; -+ } -+ AuDbg("bindex b%d\n", bindex); -+ -+ err = -EBUSY; -+ mnt_flags = au_mntflags(sb); -+ verbose = !!au_opt_test(mnt_flags, VERBOSE); -+ bend = au_sbend(sb); -+ if (unlikely(!bend)) { -+ AuVerbose(verbose, "no more branches left\n"); -+ goto out; -+ } -+ br = au_sbr(sb, bindex); -+ i = atomic_read(&br->br_count); -+ if (unlikely(i)) { -+ AuVerbose(verbose, "%d file(s) opened\n", i); -+ goto out; -+ } -+ -+ wbr = br->br_wbr; -+ do_wh = wbr && (wbr->wbr_whbase || wbr->wbr_plink || wbr->wbr_orph); -+ if (do_wh) { -+ /* instead of WbrWhMustWriteLock(wbr) */ -+ SiMustWriteLock(sb); -+ for (i = 0; i < AuBrWh_Last; i++) { -+ dput(wbr->wbr_wh[i]); -+ wbr->wbr_wh[i] = NULL; -+ } -+ } -+ -+ err = test_children_busy(sb->s_root, bindex); -+ if (unlikely(err)) { -+ if (do_wh) -+ goto out_wh; -+ goto out; -+ } -+ -+ err = 0; -+ br_id = br->br_id; -+ if (!remount) -+ au_br_do_del(sb, bindex, br); -+ else { -+ sysaufs_brs_del(sb, bindex); -+ au_br_do_del(sb, bindex, br); -+ sysaufs_brs_add(sb, bindex); -+ } -+ -+ if (!bindex) { -+ au_cpup_attr_all(sb->s_root->d_inode, /*force*/1); -+ sb->s_maxbytes = au_sbr_sb(sb, 0)->s_maxbytes; -+ } else -+ au_sub_nlink(sb->s_root->d_inode, del->h_path.dentry->d_inode); -+ if (au_opt_test(mnt_flags, PLINK)) -+ au_plink_half_refresh(sb, br_id); -+ -+ if (au_xino_brid(sb) == br->br_id) -+ au_xino_brid_set(sb, -1); -+ goto out; /* success */ -+ -+ out_wh: -+ /* revert */ -+ rerr = au_br_init_wh(sb, br, br->br_perm, del->h_path.dentry); -+ if (rerr) -+ pr_warning("failed re-creating base whiteout, %s. (%d)\n", -+ del->pathname, rerr); -+ out: -+ return err; -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+/* -+ * change a branch permission -+ */ -+ -+static void au_warn_ima(void) -+{ -+#ifdef CONFIG_IMA -+ /* since it doesn't support mark_files_ro() */ -+ pr_warning("RW -> RO makes IMA to produce wrong message"); -+#endif -+} -+ -+static int do_need_sigen_inc(int a, int b) -+{ -+ return au_br_whable(a) && !au_br_whable(b); -+} -+ -+static int need_sigen_inc(int old, int new) -+{ -+ return do_need_sigen_inc(old, new) -+ || do_need_sigen_inc(new, old); -+} -+ -+static int au_br_mod_files_ro(struct super_block *sb, aufs_bindex_t bindex) -+{ -+ int err; -+ unsigned long n, ul, bytes, files; -+ aufs_bindex_t bstart; -+ struct file *file, *hf, **a; -+ const int step_bytes = 1024, /* memory allocation unit */ -+ step_files = step_bytes / sizeof(*a); -+ -+ err = -ENOMEM; -+ n = 0; -+ bytes = step_bytes; -+ files = step_files; -+ a = kmalloc(bytes, GFP_NOFS); -+ if (unlikely(!a)) -+ goto out; -+ -+ /* no need file_list_lock() since sbinfo is locked? defered? */ -+ list_for_each_entry(file, &sb->s_files, f_u.fu_list) { -+ if (special_file(file->f_dentry->d_inode->i_mode)) -+ continue; -+ -+ AuDbg("%.*s\n", AuDLNPair(file->f_dentry)); -+ fi_read_lock(file); -+ if (unlikely(au_test_mmapped(file))) { -+ err = -EBUSY; -+ FiMustNoWaiters(file); -+ fi_read_unlock(file); -+ goto out_free; -+ } -+ -+ bstart = au_fbstart(file); -+ if (!S_ISREG(file->f_dentry->d_inode->i_mode) -+ || !(file->f_mode & FMODE_WRITE) -+ || bstart != bindex) { -+ FiMustNoWaiters(file); -+ fi_read_unlock(file); -+ continue; -+ } -+ -+ hf = au_h_fptr(file, bstart); -+ FiMustNoWaiters(file); -+ fi_read_unlock(file); -+ -+ if (n < files) -+ a[n++] = hf; -+ else { -+ void *p; -+ -+ err = -ENOMEM; -+ bytes += step_bytes; -+ files += step_files; -+ p = krealloc(a, bytes, GFP_NOFS); -+ if (p) { -+ a = p; -+ a[n++] = hf; -+ } else -+ goto out_free; -+ } -+ } -+ -+ err = 0; -+ if (n) -+ au_warn_ima(); -+ for (ul = 0; ul < n; ul++) { -+ /* todo: already flushed? */ -+ /* cf. fs/super.c:mark_files_ro() */ -+ hf = a[ul]; -+ hf->f_mode &= ~FMODE_WRITE; -+ if (!file_check_writeable(hf)) { -+ file_release_write(hf); -+ mnt_drop_write(hf->f_vfsmnt); -+ } -+ } -+ -+ out_free: -+ kfree(a); -+ out: -+ return err; -+} -+ -+int au_br_mod(struct super_block *sb, struct au_opt_mod *mod, int remount, -+ int *do_update) -+{ -+ int err, rerr; -+ aufs_bindex_t bindex; -+ struct path path; -+ struct dentry *root; -+ struct au_branch *br; -+ -+ root = sb->s_root; -+ au_plink_block_maintain(sb); -+ bindex = au_find_dbindex(root, mod->h_root); -+ if (bindex < 0) { -+ if (remount) -+ return 0; /* success */ -+ err = -ENOENT; -+ pr_err("%s no such branch\n", mod->path); -+ goto out; -+ } -+ AuDbg("bindex b%d\n", bindex); -+ -+ err = test_br(mod->h_root->d_inode, mod->perm, mod->path); -+ if (unlikely(err)) -+ goto out; -+ -+ br = au_sbr(sb, bindex); -+ if (br->br_perm == mod->perm) -+ return 0; /* success */ -+ -+ if (au_br_writable(br->br_perm)) { -+ /* remove whiteout base */ -+ err = au_br_init_wh(sb, br, mod->perm, mod->h_root); -+ if (unlikely(err)) -+ goto out; -+ -+ if (!au_br_writable(mod->perm)) { -+ /* rw --> ro, file might be mmapped */ -+ DiMustNoWaiters(root); -+ IiMustNoWaiters(root->d_inode); -+ di_write_unlock(root); -+ err = au_br_mod_files_ro(sb, bindex); -+ /* aufs_write_lock() calls ..._child() */ -+ di_write_lock_child(root); -+ -+ if (unlikely(err)) { -+ rerr = -ENOMEM; -+ br->br_wbr = kmalloc(sizeof(*br->br_wbr), -+ GFP_NOFS); -+ if (br->br_wbr) { -+ path.mnt = br->br_mnt; -+ path.dentry = mod->h_root; -+ rerr = au_wbr_init(br, sb, br->br_perm, -+ &path); -+ } -+ if (unlikely(rerr)) { -+ AuIOErr("nested error %d (%d)\n", -+ rerr, err); -+ br->br_perm = mod->perm; -+ } -+ } -+ } -+ } else if (au_br_writable(mod->perm)) { -+ /* ro --> rw */ -+ err = -ENOMEM; -+ br->br_wbr = kmalloc(sizeof(*br->br_wbr), GFP_NOFS); -+ if (br->br_wbr) { -+ path.mnt = br->br_mnt; -+ path.dentry = mod->h_root; -+ err = au_wbr_init(br, sb, mod->perm, &path); -+ if (unlikely(err)) { -+ kfree(br->br_wbr); -+ br->br_wbr = NULL; -+ } -+ } -+ } -+ -+ if (!err) { -+ *do_update |= need_sigen_inc(br->br_perm, mod->perm); -+ br->br_perm = mod->perm; -+ } -+ -+ out: -+ return err; -+} -diff --git a/fs/aufs/branch.h b/fs/aufs/branch.h -new file mode 100644 -index 0000000..1a7219c ---- /dev/null -+++ b/fs/aufs/branch.h -@@ -0,0 +1,219 @@ -+/* -+ * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * -+ * This program, aufs is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ */ -+ -+/* -+ * branch filesystems and xino for them -+ */ -+ -+#ifndef __AUFS_BRANCH_H__ -+#define __AUFS_BRANCH_H__ -+ -+#ifdef __KERNEL__ -+ -+#include -+#include -+#include -+#include "rwsem.h" -+#include "super.h" -+ -+/* ---------------------------------------------------------------------- */ -+ -+/* a xino file */ -+struct au_xino_file { -+ struct file *xi_file; -+ struct mutex xi_nondir_mtx; -+ -+ /* todo: make xino files an array to support huge inode number */ -+ -+#ifdef CONFIG_DEBUG_FS -+ struct dentry *xi_dbgaufs; -+#endif -+}; -+ -+/* members for writable branch only */ -+enum {AuBrWh_BASE, AuBrWh_PLINK, AuBrWh_ORPH, AuBrWh_Last}; -+struct au_wbr { -+ struct au_rwsem wbr_wh_rwsem; -+ struct dentry *wbr_wh[AuBrWh_Last]; -+ atomic_t wbr_wh_running; -+#define wbr_whbase wbr_wh[AuBrWh_BASE] /* whiteout base */ -+#define wbr_plink wbr_wh[AuBrWh_PLINK] /* pseudo-link dir */ -+#define wbr_orph wbr_wh[AuBrWh_ORPH] /* dir for orphans */ -+ -+ /* mfs mode */ -+ unsigned long long wbr_bytes; -+}; -+ -+/* protected by superblock rwsem */ -+struct au_branch { -+ struct au_xino_file br_xino; -+ -+ aufs_bindex_t br_id; -+ -+ int br_perm; -+ struct vfsmount *br_mnt; -+ atomic_t br_count; -+ -+ struct au_wbr *br_wbr; -+ -+ /* xino truncation */ -+ blkcnt_t br_xino_upper; /* watermark in blocks */ -+ atomic_t br_xino_running; -+ -+#ifdef CONFIG_SYSFS -+ /* an entry under sysfs per mount-point */ -+ char br_name[8]; -+ struct attribute br_attr; -+#endif -+}; -+ -+/* ---------------------------------------------------------------------- */ -+ -+/* branch permission and attribute */ -+enum { -+ AuBrPerm_RW, /* writable, linkable wh */ -+ AuBrPerm_RO, /* readonly, no wh */ -+ AuBrPerm_RR, /* natively readonly, no wh */ -+ -+ AuBrPerm_RWNoLinkWH, /* un-linkable whiteouts */ -+ -+ AuBrPerm_ROWH, /* whiteout-able */ -+ AuBrPerm_RRWH, /* whiteout-able */ -+ -+ AuBrPerm_Last -+}; -+ -+static inline int au_br_writable(int brperm) -+{ -+ return brperm == AuBrPerm_RW || brperm == AuBrPerm_RWNoLinkWH; -+} -+ -+static inline int au_br_whable(int brperm) -+{ -+ return brperm == AuBrPerm_RW -+ || brperm == AuBrPerm_ROWH -+ || brperm == AuBrPerm_RRWH; -+} -+ -+static inline int au_br_rdonly(struct au_branch *br) -+{ -+ return ((br->br_mnt->mnt_sb->s_flags & MS_RDONLY) -+ || !au_br_writable(br->br_perm)) -+ ? -EROFS : 0; -+} -+ -+static inline int au_br_hinotifyable(int brperm __maybe_unused) -+{ -+#ifdef CONFIG_AUFS_HINOTIFY -+ return brperm != AuBrPerm_RR && brperm != AuBrPerm_RRWH; -+#else -+ return 0; -+#endif -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+/* branch.c */ -+struct au_sbinfo; -+void au_br_free(struct au_sbinfo *sinfo); -+int au_br_index(struct super_block *sb, aufs_bindex_t br_id); -+struct au_opt_add; -+int au_br_add(struct super_block *sb, struct au_opt_add *add, int remount); -+struct au_opt_del; -+int au_br_del(struct super_block *sb, struct au_opt_del *del, int remount); -+struct au_opt_mod; -+int au_br_mod(struct super_block *sb, struct au_opt_mod *mod, int remount, -+ int *do_update); -+ -+/* xino.c */ -+static const loff_t au_loff_max = LLONG_MAX; -+ -+int au_xib_trunc(struct super_block *sb); -+ssize_t xino_fread(au_readf_t func, struct file *file, void *buf, size_t size, -+ loff_t *pos); -+ssize_t xino_fwrite(au_writef_t func, struct file *file, void *buf, size_t size, -+ loff_t *pos); -+struct file *au_xino_create2(struct file *base_file, struct file *copy_src); -+struct file *au_xino_create(struct super_block *sb, char *fname, int silent); -+ino_t au_xino_new_ino(struct super_block *sb); -+int au_xino_write0(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, -+ ino_t ino); -+int au_xino_write(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, -+ ino_t ino); -+int au_xino_read(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, -+ ino_t *ino); -+int au_xino_br(struct super_block *sb, struct au_branch *br, ino_t hino, -+ struct file *base_file, int do_test); -+int au_xino_trunc(struct super_block *sb, aufs_bindex_t bindex); -+ -+struct au_opt_xino; -+int au_xino_set(struct super_block *sb, struct au_opt_xino *xino, int remount); -+void au_xino_clr(struct super_block *sb); -+struct file *au_xino_def(struct super_block *sb); -+int au_xino_path(struct seq_file *seq, struct file *file); -+ -+/* ---------------------------------------------------------------------- */ -+ -+/* Superblock to branch */ -+static inline -+aufs_bindex_t au_sbr_id(struct super_block *sb, aufs_bindex_t bindex) -+{ -+ return au_sbr(sb, bindex)->br_id; -+} -+ -+static inline -+struct vfsmount *au_sbr_mnt(struct super_block *sb, aufs_bindex_t bindex) -+{ -+ return au_sbr(sb, bindex)->br_mnt; -+} -+ -+static inline -+struct super_block *au_sbr_sb(struct super_block *sb, aufs_bindex_t bindex) -+{ -+ return au_sbr_mnt(sb, bindex)->mnt_sb; -+} -+ -+static inline void au_sbr_put(struct super_block *sb, aufs_bindex_t bindex) -+{ -+ atomic_dec_return(&au_sbr(sb, bindex)->br_count); -+} -+ -+static inline int au_sbr_perm(struct super_block *sb, aufs_bindex_t bindex) -+{ -+ return au_sbr(sb, bindex)->br_perm; -+} -+ -+static inline int au_sbr_whable(struct super_block *sb, aufs_bindex_t bindex) -+{ -+ return au_br_whable(au_sbr_perm(sb, bindex)); -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+/* -+ * wbr_wh_read_lock, wbr_wh_write_lock -+ * wbr_wh_read_unlock, wbr_wh_write_unlock, wbr_wh_downgrade_lock -+ */ -+AuSimpleRwsemFuncs(wbr_wh, struct au_wbr *wbr, &wbr->wbr_wh_rwsem); -+ -+#define WbrWhMustNoWaiters(wbr) AuRwMustNoWaiters(&wbr->wbr_wh_rwsem) -+#define WbrWhMustAnyLock(wbr) AuRwMustAnyLock(&wbr->wbr_wh_rwsem) -+#define WbrWhMustWriteLock(wbr) AuRwMustWriteLock(&wbr->wbr_wh_rwsem) -+ -+#endif /* __KERNEL__ */ -+#endif /* __AUFS_BRANCH_H__ */ -diff --git a/fs/aufs/conf.mk b/fs/aufs/conf.mk -new file mode 100644 -index 0000000..9939c03 ---- /dev/null -+++ b/fs/aufs/conf.mk -@@ -0,0 +1,31 @@ -+ -+AuConfStr = CONFIG_AUFS_FS=${CONFIG_AUFS_FS} -+ -+define AuConf -+ifdef ${1} -+AuConfStr += ${1}=${${1}} -+endif -+endef -+ -+$(foreach i, BRANCH_MAX_127 BRANCH_MAX_511 BRANCH_MAX_1023 BRANCH_MAX_32767 \ -+ HINOTIFY \ -+ EXPORT INO_T_64 \ -+ RDU \ -+ SHWH \ -+ BR_RAMFS \ -+ BR_FUSE POLL \ -+ BDEV_LOOP \ -+ DEBUG MAGIC_SYSRQ, \ -+ $(eval $(call AuConf,CONFIG_AUFS_${i}))) -+ -+AuConfName = ${obj}/conf.str -+${AuConfName}.tmp: FORCE -+ @echo ${AuConfStr} | tr ' ' '\n' | sed -e 's/^/"/' -e 's/$$/\\n"/' > $@ -+${AuConfName}: ${AuConfName}.tmp -+ @diff -q $< $@ > /dev/null 2>&1 || { \ -+ echo ' GEN ' $@; \ -+ cp -p $< $@; \ -+ } -+FORCE: -+clean-files += ${AuConfName} ${AuConfName}.tmp -+${obj}/sysfs.o: ${AuConfName} -diff --git a/fs/aufs/cpup.c b/fs/aufs/cpup.c -new file mode 100644 -index 0000000..1219aad ---- /dev/null -+++ b/fs/aufs/cpup.c -@@ -0,0 +1,1048 @@ -+/* -+ * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * -+ * This program, aufs is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ */ -+ -+/* -+ * copy-up functions, see wbr_policy.c for copy-down -+ */ -+ -+#include -+#include -+#include -+#include -+#include "aufs.h" -+ -+void au_cpup_attr_flags(struct inode *dst, struct inode *src) -+{ -+ const unsigned int mask = S_DEAD | S_SWAPFILE | S_PRIVATE -+ | S_NOATIME | S_NOCMTIME; -+ -+ dst->i_flags |= src->i_flags & ~mask; -+ if (au_test_fs_notime(dst->i_sb)) -+ dst->i_flags |= S_NOATIME | S_NOCMTIME; -+} -+ -+void au_cpup_attr_timesizes(struct inode *inode) -+{ -+ struct inode *h_inode; -+ -+ h_inode = au_h_iptr(inode, au_ibstart(inode)); -+ fsstack_copy_attr_times(inode, h_inode); -+ vfsub_copy_inode_size(inode, h_inode); -+} -+ -+void au_cpup_attr_nlink(struct inode *inode, int force) -+{ -+ struct inode *h_inode; -+ struct super_block *sb; -+ aufs_bindex_t bindex, bend; -+ -+ sb = inode->i_sb; -+ bindex = au_ibstart(inode); -+ h_inode = au_h_iptr(inode, bindex); -+ if (!force -+ && !S_ISDIR(h_inode->i_mode) -+ && au_opt_test(au_mntflags(sb), PLINK) -+ && au_plink_test(inode)) -+ return; -+ -+ inode->i_nlink = h_inode->i_nlink; -+ -+ /* -+ * fewer nlink makes find(1) noisy, but larger nlink doesn't. -+ * it may includes whplink directory. -+ */ -+ if (S_ISDIR(h_inode->i_mode)) { -+ bend = au_ibend(inode); -+ for (bindex++; bindex <= bend; bindex++) { -+ h_inode = au_h_iptr(inode, bindex); -+ if (h_inode) -+ au_add_nlink(inode, h_inode); -+ } -+ } -+} -+ -+void au_cpup_attr_changeable(struct inode *inode) -+{ -+ struct inode *h_inode; -+ -+ h_inode = au_h_iptr(inode, au_ibstart(inode)); -+ inode->i_mode = h_inode->i_mode; -+ inode->i_uid = h_inode->i_uid; -+ inode->i_gid = h_inode->i_gid; -+ au_cpup_attr_timesizes(inode); -+ au_cpup_attr_flags(inode, h_inode); -+} -+ -+void au_cpup_igen(struct inode *inode, struct inode *h_inode) -+{ -+ struct au_iinfo *iinfo = au_ii(inode); -+ -+ IiMustWriteLock(inode); -+ -+ iinfo->ii_higen = h_inode->i_generation; -+ iinfo->ii_hsb1 = h_inode->i_sb; -+} -+ -+void au_cpup_attr_all(struct inode *inode, int force) -+{ -+ struct inode *h_inode; -+ -+ h_inode = au_h_iptr(inode, au_ibstart(inode)); -+ au_cpup_attr_changeable(inode); -+ if (inode->i_nlink > 0) -+ au_cpup_attr_nlink(inode, force); -+ inode->i_rdev = h_inode->i_rdev; -+ inode->i_blkbits = h_inode->i_blkbits; -+ au_cpup_igen(inode, h_inode); -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+/* Note: dt_dentry and dt_h_dentry are not dget/dput-ed */ -+ -+/* keep the timestamps of the parent dir when cpup */ -+void au_dtime_store(struct au_dtime *dt, struct dentry *dentry, -+ struct path *h_path) -+{ -+ struct inode *h_inode; -+ -+ dt->dt_dentry = dentry; -+ dt->dt_h_path = *h_path; -+ h_inode = h_path->dentry->d_inode; -+ dt->dt_atime = h_inode->i_atime; -+ dt->dt_mtime = h_inode->i_mtime; -+ /* smp_mb(); */ -+} -+ -+void au_dtime_revert(struct au_dtime *dt) -+{ -+ struct iattr attr; -+ int err; -+ -+ attr.ia_atime = dt->dt_atime; -+ attr.ia_mtime = dt->dt_mtime; -+ attr.ia_valid = ATTR_FORCE | ATTR_MTIME | ATTR_MTIME_SET -+ | ATTR_ATIME | ATTR_ATIME_SET; -+ -+ err = vfsub_notify_change(&dt->dt_h_path, &attr); -+ if (unlikely(err)) -+ pr_warning("restoring timestamps failed(%d). ignored\n", err); -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+static noinline_for_stack -+int cpup_iattr(struct dentry *dst, aufs_bindex_t bindex, struct dentry *h_src) -+{ -+ int err, sbits; -+ struct iattr ia; -+ struct path h_path; -+ struct inode *h_isrc, *h_idst; -+ -+ h_path.dentry = au_h_dptr(dst, bindex); -+ h_idst = h_path.dentry->d_inode; -+ h_path.mnt = au_sbr_mnt(dst->d_sb, bindex); -+ h_isrc = h_src->d_inode; -+ ia.ia_valid = ATTR_FORCE | ATTR_UID | ATTR_GID -+ | ATTR_ATIME | ATTR_MTIME -+ | ATTR_ATIME_SET | ATTR_MTIME_SET; -+ ia.ia_uid = h_isrc->i_uid; -+ ia.ia_gid = h_isrc->i_gid; -+ ia.ia_atime = h_isrc->i_atime; -+ ia.ia_mtime = h_isrc->i_mtime; -+ if (h_idst->i_mode != h_isrc->i_mode -+ && !S_ISLNK(h_idst->i_mode)) { -+ ia.ia_valid |= ATTR_MODE; -+ ia.ia_mode = h_isrc->i_mode; -+ } -+ sbits = !!(h_isrc->i_mode & (S_ISUID | S_ISGID)); -+ au_cpup_attr_flags(h_idst, h_isrc); -+ err = vfsub_notify_change(&h_path, &ia); -+ -+ /* is this nfs only? */ -+ if (!err && sbits && au_test_nfs(h_path.dentry->d_sb)) { -+ ia.ia_valid = ATTR_FORCE | ATTR_MODE; -+ ia.ia_mode = h_isrc->i_mode; -+ err = vfsub_notify_change(&h_path, &ia); -+ } -+ -+ return err; -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+static int au_do_copy_file(struct file *dst, struct file *src, loff_t len, -+ char *buf, unsigned long blksize) -+{ -+ int err; -+ size_t sz, rbytes, wbytes; -+ unsigned char all_zero; -+ char *p, *zp; -+ struct mutex *h_mtx; -+ /* reduce stack usage */ -+ struct iattr *ia; -+ -+ zp = page_address(ZERO_PAGE(0)); -+ if (unlikely(!zp)) -+ return -ENOMEM; /* possible? */ -+ -+ err = 0; -+ all_zero = 0; -+ while (len) { -+ AuDbg("len %lld\n", len); -+ sz = blksize; -+ if (len < blksize) -+ sz = len; -+ -+ rbytes = 0; -+ /* todo: signal_pending? */ -+ while (!rbytes || err == -EAGAIN || err == -EINTR) { -+ rbytes = vfsub_read_k(src, buf, sz, &src->f_pos); -+ err = rbytes; -+ } -+ if (unlikely(err < 0)) -+ break; -+ -+ all_zero = 0; -+ if (len >= rbytes && rbytes == blksize) -+ all_zero = !memcmp(buf, zp, rbytes); -+ if (!all_zero) { -+ wbytes = rbytes; -+ p = buf; -+ while (wbytes) { -+ size_t b; -+ -+ b = vfsub_write_k(dst, p, wbytes, &dst->f_pos); -+ err = b; -+ /* todo: signal_pending? */ -+ if (unlikely(err == -EAGAIN || err == -EINTR)) -+ continue; -+ if (unlikely(err < 0)) -+ break; -+ wbytes -= b; -+ p += b; -+ } -+ } else { -+ loff_t res; -+ -+ AuLabel(hole); -+ res = vfsub_llseek(dst, rbytes, SEEK_CUR); -+ err = res; -+ if (unlikely(res < 0)) -+ break; -+ } -+ len -= rbytes; -+ err = 0; -+ } -+ -+ /* the last block may be a hole */ -+ if (!err && all_zero) { -+ AuLabel(last hole); -+ -+ err = 1; -+ if (au_test_nfs(dst->f_dentry->d_sb)) { -+ /* nfs requires this step to make last hole */ -+ /* is this only nfs? */ -+ do { -+ /* todo: signal_pending? */ -+ err = vfsub_write_k(dst, "\0", 1, &dst->f_pos); -+ } while (err == -EAGAIN || err == -EINTR); -+ if (err == 1) -+ dst->f_pos--; -+ } -+ -+ if (err == 1) { -+ ia = (void *)buf; -+ ia->ia_size = dst->f_pos; -+ ia->ia_valid = ATTR_SIZE | ATTR_FILE; -+ ia->ia_file = dst; -+ h_mtx = &dst->f_dentry->d_inode->i_mutex; -+ mutex_lock_nested(h_mtx, AuLsc_I_CHILD2); -+ err = vfsub_notify_change(&dst->f_path, ia); -+ mutex_unlock(h_mtx); -+ } -+ } -+ -+ return err; -+} -+ -+int au_copy_file(struct file *dst, struct file *src, loff_t len) -+{ -+ int err; -+ unsigned long blksize; -+ unsigned char do_kfree; -+ char *buf; -+ -+ err = -ENOMEM; -+ blksize = dst->f_dentry->d_sb->s_blocksize; -+ if (!blksize || PAGE_SIZE < blksize) -+ blksize = PAGE_SIZE; -+ AuDbg("blksize %lu\n", blksize); -+ do_kfree = (blksize != PAGE_SIZE && blksize >= sizeof(struct iattr *)); -+ if (do_kfree) -+ buf = kmalloc(blksize, GFP_NOFS); -+ else -+ buf = (void *)__get_free_page(GFP_NOFS); -+ if (unlikely(!buf)) -+ goto out; -+ -+ if (len > (1 << 22)) -+ AuDbg("copying a large file %lld\n", (long long)len); -+ -+ src->f_pos = 0; -+ dst->f_pos = 0; -+ err = au_do_copy_file(dst, src, len, buf, blksize); -+ if (do_kfree) -+ kfree(buf); -+ else -+ free_page((unsigned long)buf); -+ -+ out: -+ return err; -+} -+ -+/* -+ * to support a sparse file which is opened with O_APPEND, -+ * we need to close the file. -+ */ -+static int au_cp_regular(struct dentry *dentry, aufs_bindex_t bdst, -+ aufs_bindex_t bsrc, loff_t len) -+{ -+ int err, i; -+ enum { SRC, DST }; -+ struct { -+ aufs_bindex_t bindex; -+ unsigned int flags; -+ struct dentry *dentry; -+ struct file *file; -+ void *label, *label_file; -+ } *f, file[] = { -+ { -+ .bindex = bsrc, -+ .flags = O_RDONLY | O_NOATIME | O_LARGEFILE, -+ .file = NULL, -+ .label = &&out, -+ .label_file = &&out_src -+ }, -+ { -+ .bindex = bdst, -+ .flags = O_WRONLY | O_NOATIME | O_LARGEFILE, -+ .file = NULL, -+ .label = &&out_src, -+ .label_file = &&out_dst -+ } -+ }; -+ struct super_block *sb; -+ -+ /* bsrc branch can be ro/rw. */ -+ sb = dentry->d_sb; -+ f = file; -+ for (i = 0; i < 2; i++, f++) { -+ f->dentry = au_h_dptr(dentry, f->bindex); -+ f->file = au_h_open(dentry, f->bindex, f->flags, /*file*/NULL); -+ err = PTR_ERR(f->file); -+ if (IS_ERR(f->file)) -+ goto *f->label; -+ err = -EINVAL; -+ if (unlikely(!f->file->f_op)) -+ goto *f->label_file; -+ } -+ -+ /* try stopping to update while we copyup */ -+ IMustLock(file[SRC].dentry->d_inode); -+ err = au_copy_file(file[DST].file, file[SRC].file, len); -+ -+ out_dst: -+ fput(file[DST].file); -+ au_sbr_put(sb, file[DST].bindex); -+ out_src: -+ fput(file[SRC].file); -+ au_sbr_put(sb, file[SRC].bindex); -+ out: -+ return err; -+} -+ -+static int au_do_cpup_regular(struct dentry *dentry, aufs_bindex_t bdst, -+ aufs_bindex_t bsrc, loff_t len, -+ struct inode *h_dir, struct path *h_path) -+{ -+ int err, rerr; -+ loff_t l; -+ -+ err = 0; -+ l = i_size_read(au_h_iptr(dentry->d_inode, bsrc)); -+ if (len == -1 || l < len) -+ len = l; -+ if (len) -+ err = au_cp_regular(dentry, bdst, bsrc, len); -+ if (!err) -+ goto out; /* success */ -+ -+ rerr = vfsub_unlink(h_dir, h_path, /*force*/0); -+ if (rerr) { -+ AuIOErr("failed unlinking cpup-ed %.*s(%d, %d)\n", -+ AuDLNPair(h_path->dentry), err, rerr); -+ err = -EIO; -+ } -+ -+ out: -+ return err; -+} -+ -+static int au_do_cpup_symlink(struct path *h_path, struct dentry *h_src, -+ struct inode *h_dir) -+{ -+ int err, symlen; -+ mm_segment_t old_fs; -+ char *sym; -+ -+ err = -ENOSYS; -+ if (unlikely(!h_src->d_inode->i_op->readlink)) -+ goto out; -+ -+ err = -ENOMEM; -+ sym = __getname(); -+ if (unlikely(!sym)) -+ goto out; -+ -+ old_fs = get_fs(); -+ set_fs(KERNEL_DS); -+ symlen = h_src->d_inode->i_op->readlink(h_src, (char __user *)sym, -+ PATH_MAX); -+ err = symlen; -+ set_fs(old_fs); -+ -+ if (symlen > 0) { -+ sym[symlen] = 0; -+ err = vfsub_symlink(h_dir, h_path, sym); -+ } -+ __putname(sym); -+ -+ out: -+ return err; -+} -+ -+/* return with the lower dst inode is locked */ -+static noinline_for_stack -+int cpup_entry(struct dentry *dentry, aufs_bindex_t bdst, -+ aufs_bindex_t bsrc, loff_t len, unsigned int flags, -+ struct dentry *dst_parent) -+{ -+ int err; -+ umode_t mode; -+ unsigned int mnt_flags; -+ unsigned char isdir; -+ const unsigned char do_dt = !!au_ftest_cpup(flags, DTIME); -+ struct au_dtime dt; -+ struct path h_path; -+ struct dentry *h_src, *h_dst, *h_parent; -+ struct inode *h_inode, *h_dir; -+ struct super_block *sb; -+ -+ /* bsrc branch can be ro/rw. */ -+ h_src = au_h_dptr(dentry, bsrc); -+ h_inode = h_src->d_inode; -+ AuDebugOn(h_inode != au_h_iptr(dentry->d_inode, bsrc)); -+ -+ /* try stopping to be referenced while we are creating */ -+ h_dst = au_h_dptr(dentry, bdst); -+ h_parent = h_dst->d_parent; /* dir inode is locked */ -+ h_dir = h_parent->d_inode; -+ IMustLock(h_dir); -+ AuDebugOn(h_parent != h_dst->d_parent); -+ -+ sb = dentry->d_sb; -+ h_path.mnt = au_sbr_mnt(sb, bdst); -+ if (do_dt) { -+ h_path.dentry = h_parent; -+ au_dtime_store(&dt, dst_parent, &h_path); -+ } -+ h_path.dentry = h_dst; -+ -+ isdir = 0; -+ mode = h_inode->i_mode; -+ switch (mode & S_IFMT) { -+ case S_IFREG: -+ /* try stopping to update while we are referencing */ -+ IMustLock(h_inode); -+ err = vfsub_create(h_dir, &h_path, mode | S_IWUSR); -+ if (!err) -+ err = au_do_cpup_regular -+ (dentry, bdst, bsrc, len, -+ au_h_iptr(dst_parent->d_inode, bdst), &h_path); -+ break; -+ case S_IFDIR: -+ isdir = 1; -+ err = vfsub_mkdir(h_dir, &h_path, mode); -+ if (!err) { -+ /* -+ * strange behaviour from the users view, -+ * particularry setattr case -+ */ -+ if (au_ibstart(dst_parent->d_inode) == bdst) -+ au_cpup_attr_nlink(dst_parent->d_inode, -+ /*force*/1); -+ au_cpup_attr_nlink(dentry->d_inode, /*force*/1); -+ } -+ break; -+ case S_IFLNK: -+ err = au_do_cpup_symlink(&h_path, h_src, h_dir); -+ break; -+ case S_IFCHR: -+ case S_IFBLK: -+ AuDebugOn(!capable(CAP_MKNOD)); -+ /*FALLTHROUGH*/ -+ case S_IFIFO: -+ case S_IFSOCK: -+ err = vfsub_mknod(h_dir, &h_path, mode, h_inode->i_rdev); -+ break; -+ default: -+ AuIOErr("Unknown inode type 0%o\n", mode); -+ err = -EIO; -+ } -+ -+ mnt_flags = au_mntflags(sb); -+ if (!au_opt_test(mnt_flags, UDBA_NONE) -+ && !isdir -+ && au_opt_test(mnt_flags, XINO) -+ && h_inode->i_nlink == 1 -+ /* todo: unnecessary? */ -+ /* && dentry->d_inode->i_nlink == 1 */ -+ && bdst < bsrc -+ && !au_ftest_cpup(flags, KEEPLINO)) -+ au_xino_write(sb, bsrc, h_inode->i_ino, /*ino*/0); -+ /* ignore this error */ -+ -+ if (do_dt) -+ au_dtime_revert(&dt); -+ return err; -+} -+ -+/* -+ * copyup the @dentry from @bsrc to @bdst. -+ * the caller must set the both of lower dentries. -+ * @len is for truncating when it is -1 copyup the entire file. -+ * in link/rename cases, @dst_parent may be different from the real one. -+ */ -+static int au_cpup_single(struct dentry *dentry, aufs_bindex_t bdst, -+ aufs_bindex_t bsrc, loff_t len, unsigned int flags, -+ struct dentry *dst_parent) -+{ -+ int err, rerr; -+ aufs_bindex_t old_ibstart; -+ unsigned char isdir, plink; -+ struct au_dtime dt; -+ struct path h_path; -+ struct dentry *h_src, *h_dst, *h_parent; -+ struct inode *dst_inode, *h_dir, *inode; -+ struct super_block *sb; -+ -+ AuDebugOn(bsrc <= bdst); -+ -+ sb = dentry->d_sb; -+ h_path.mnt = au_sbr_mnt(sb, bdst); -+ h_dst = au_h_dptr(dentry, bdst); -+ h_parent = h_dst->d_parent; /* dir inode is locked */ -+ h_dir = h_parent->d_inode; -+ IMustLock(h_dir); -+ -+ h_src = au_h_dptr(dentry, bsrc); -+ inode = dentry->d_inode; -+ -+ if (!dst_parent) -+ dst_parent = dget_parent(dentry); -+ else -+ dget(dst_parent); -+ -+ plink = !!au_opt_test(au_mntflags(sb), PLINK); -+ dst_inode = au_h_iptr(inode, bdst); -+ if (dst_inode) { -+ if (unlikely(!plink)) { -+ err = -EIO; -+ AuIOErr("i%lu exists on a upper branch " -+ "but plink is disabled\n", inode->i_ino); -+ goto out; -+ } -+ -+ if (dst_inode->i_nlink) { -+ const int do_dt = au_ftest_cpup(flags, DTIME); -+ -+ h_src = au_plink_lkup(inode, bdst); -+ err = PTR_ERR(h_src); -+ if (IS_ERR(h_src)) -+ goto out; -+ if (unlikely(!h_src->d_inode)) { -+ err = -EIO; -+ AuIOErr("i%lu exists on a upper branch " -+ "but plink is broken\n", inode->i_ino); -+ dput(h_src); -+ goto out; -+ } -+ -+ if (do_dt) { -+ h_path.dentry = h_parent; -+ au_dtime_store(&dt, dst_parent, &h_path); -+ } -+ h_path.dentry = h_dst; -+ err = vfsub_link(h_src, h_dir, &h_path); -+ if (do_dt) -+ au_dtime_revert(&dt); -+ dput(h_src); -+ goto out; -+ } else -+ /* todo: cpup_wh_file? */ -+ /* udba work */ -+ au_update_brange(inode, 1); -+ } -+ -+ old_ibstart = au_ibstart(inode); -+ err = cpup_entry(dentry, bdst, bsrc, len, flags, dst_parent); -+ if (unlikely(err)) -+ goto out; -+ dst_inode = h_dst->d_inode; -+ mutex_lock_nested(&dst_inode->i_mutex, AuLsc_I_CHILD2); -+ -+ err = cpup_iattr(dentry, bdst, h_src); -+ isdir = S_ISDIR(dst_inode->i_mode); -+ if (!err) { -+ if (bdst < old_ibstart) -+ au_set_ibstart(inode, bdst); -+ au_set_h_iptr(inode, bdst, au_igrab(dst_inode), -+ au_hi_flags(inode, isdir)); -+ mutex_unlock(&dst_inode->i_mutex); -+ if (!isdir -+ && h_src->d_inode->i_nlink > 1 -+ && plink) -+ au_plink_append(inode, bdst, h_dst); -+ goto out; /* success */ -+ } -+ -+ /* revert */ -+ h_path.dentry = h_parent; -+ mutex_unlock(&dst_inode->i_mutex); -+ au_dtime_store(&dt, dst_parent, &h_path); -+ h_path.dentry = h_dst; -+ if (!isdir) -+ rerr = vfsub_unlink(h_dir, &h_path, /*force*/0); -+ else -+ rerr = vfsub_rmdir(h_dir, &h_path); -+ au_dtime_revert(&dt); -+ if (rerr) { -+ AuIOErr("failed removing broken entry(%d, %d)\n", err, rerr); -+ err = -EIO; -+ } -+ -+ out: -+ dput(dst_parent); -+ return err; -+} -+ -+struct au_cpup_single_args { -+ int *errp; -+ struct dentry *dentry; -+ aufs_bindex_t bdst, bsrc; -+ loff_t len; -+ unsigned int flags; -+ struct dentry *dst_parent; -+}; -+ -+static void au_call_cpup_single(void *args) -+{ -+ struct au_cpup_single_args *a = args; -+ *a->errp = au_cpup_single(a->dentry, a->bdst, a->bsrc, a->len, -+ a->flags, a->dst_parent); -+} -+ -+int au_sio_cpup_single(struct dentry *dentry, aufs_bindex_t bdst, -+ aufs_bindex_t bsrc, loff_t len, unsigned int flags, -+ struct dentry *dst_parent) -+{ -+ int err, wkq_err; -+ umode_t mode; -+ struct dentry *h_dentry; -+ -+ h_dentry = au_h_dptr(dentry, bsrc); -+ mode = h_dentry->d_inode->i_mode & S_IFMT; -+ if ((mode != S_IFCHR && mode != S_IFBLK) -+ || capable(CAP_MKNOD)) -+ err = au_cpup_single(dentry, bdst, bsrc, len, flags, -+ dst_parent); -+ else { -+ struct au_cpup_single_args args = { -+ .errp = &err, -+ .dentry = dentry, -+ .bdst = bdst, -+ .bsrc = bsrc, -+ .len = len, -+ .flags = flags, -+ .dst_parent = dst_parent -+ }; -+ wkq_err = au_wkq_wait(au_call_cpup_single, &args); -+ if (unlikely(wkq_err)) -+ err = wkq_err; -+ } -+ -+ return err; -+} -+ -+/* -+ * copyup the @dentry from the first active lower branch to @bdst, -+ * using au_cpup_single(). -+ */ -+static int au_cpup_simple(struct dentry *dentry, aufs_bindex_t bdst, loff_t len, -+ unsigned int flags) -+{ -+ int err; -+ aufs_bindex_t bsrc, bend; -+ -+ bend = au_dbend(dentry); -+ for (bsrc = bdst + 1; bsrc <= bend; bsrc++) -+ if (au_h_dptr(dentry, bsrc)) -+ break; -+ -+ err = au_lkup_neg(dentry, bdst); -+ if (!err) { -+ err = au_cpup_single(dentry, bdst, bsrc, len, flags, NULL); -+ if (!err) -+ return 0; /* success */ -+ -+ /* revert */ -+ au_set_h_dptr(dentry, bdst, NULL); -+ au_set_dbstart(dentry, bsrc); -+ } -+ -+ return err; -+} -+ -+struct au_cpup_simple_args { -+ int *errp; -+ struct dentry *dentry; -+ aufs_bindex_t bdst; -+ loff_t len; -+ unsigned int flags; -+}; -+ -+static void au_call_cpup_simple(void *args) -+{ -+ struct au_cpup_simple_args *a = args; -+ *a->errp = au_cpup_simple(a->dentry, a->bdst, a->len, a->flags); -+} -+ -+int au_sio_cpup_simple(struct dentry *dentry, aufs_bindex_t bdst, loff_t len, -+ unsigned int flags) -+{ -+ int err, wkq_err; -+ unsigned char do_sio; -+ struct dentry *parent; -+ struct inode *h_dir; -+ -+ parent = dget_parent(dentry); -+ h_dir = au_h_iptr(parent->d_inode, bdst); -+ do_sio = !!au_test_h_perm_sio(h_dir, MAY_EXEC | MAY_WRITE); -+ if (!do_sio) { -+ /* -+ * testing CAP_MKNOD is for generic fs, -+ * but CAP_FSETID is for xfs only, currently. -+ */ -+ umode_t mode = dentry->d_inode->i_mode; -+ do_sio = (((mode & (S_IFCHR | S_IFBLK)) -+ && !capable(CAP_MKNOD)) -+ || ((mode & (S_ISUID | S_ISGID)) -+ && !capable(CAP_FSETID))); -+ } -+ if (!do_sio) -+ err = au_cpup_simple(dentry, bdst, len, flags); -+ else { -+ struct au_cpup_simple_args args = { -+ .errp = &err, -+ .dentry = dentry, -+ .bdst = bdst, -+ .len = len, -+ .flags = flags -+ }; -+ wkq_err = au_wkq_wait(au_call_cpup_simple, &args); -+ if (unlikely(wkq_err)) -+ err = wkq_err; -+ } -+ -+ dput(parent); -+ return err; -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+/* -+ * copyup the deleted file for writing. -+ */ -+static int au_do_cpup_wh(struct dentry *dentry, aufs_bindex_t bdst, -+ struct dentry *wh_dentry, struct file *file, -+ loff_t len) -+{ -+ int err; -+ aufs_bindex_t bstart; -+ struct au_dinfo *dinfo; -+ struct dentry *h_d_dst, *h_d_start; -+ -+ dinfo = au_di(dentry); -+ AuRwMustWriteLock(&dinfo->di_rwsem); -+ -+ bstart = dinfo->di_bstart; -+ h_d_dst = dinfo->di_hdentry[0 + bdst].hd_dentry; -+ dinfo->di_bstart = bdst; -+ dinfo->di_hdentry[0 + bdst].hd_dentry = wh_dentry; -+ h_d_start = dinfo->di_hdentry[0 + bstart].hd_dentry; -+ if (file) -+ dinfo->di_hdentry[0 + bstart].hd_dentry -+ = au_h_fptr(file, au_fbstart(file))->f_dentry; -+ err = au_cpup_single(dentry, bdst, bstart, len, !AuCpup_DTIME, -+ /*h_parent*/NULL); -+ if (!err && file) { -+ err = au_reopen_nondir(file); -+ dinfo->di_hdentry[0 + bstart].hd_dentry = h_d_start; -+ } -+ dinfo->di_hdentry[0 + bdst].hd_dentry = h_d_dst; -+ dinfo->di_bstart = bstart; -+ -+ return err; -+} -+ -+static int au_cpup_wh(struct dentry *dentry, aufs_bindex_t bdst, loff_t len, -+ struct file *file) -+{ -+ int err; -+ struct au_dtime dt; -+ struct dentry *parent, *h_parent, *wh_dentry; -+ struct au_branch *br; -+ struct path h_path; -+ -+ br = au_sbr(dentry->d_sb, bdst); -+ parent = dget_parent(dentry); -+ h_parent = au_h_dptr(parent, bdst); -+ wh_dentry = au_whtmp_lkup(h_parent, br, &dentry->d_name); -+ err = PTR_ERR(wh_dentry); -+ if (IS_ERR(wh_dentry)) -+ goto out; -+ -+ h_path.dentry = h_parent; -+ h_path.mnt = br->br_mnt; -+ au_dtime_store(&dt, parent, &h_path); -+ err = au_do_cpup_wh(dentry, bdst, wh_dentry, file, len); -+ if (unlikely(err)) -+ goto out_wh; -+ -+ dget(wh_dentry); -+ h_path.dentry = wh_dentry; -+ err = vfsub_unlink(h_parent->d_inode, &h_path, /*force*/0); -+ if (unlikely(err)) { -+ AuIOErr("failed remove copied-up tmp file %.*s(%d)\n", -+ AuDLNPair(wh_dentry), err); -+ err = -EIO; -+ } -+ au_dtime_revert(&dt); -+ au_set_hi_wh(dentry->d_inode, bdst, wh_dentry); -+ -+ out_wh: -+ dput(wh_dentry); -+ out: -+ dput(parent); -+ return err; -+} -+ -+struct au_cpup_wh_args { -+ int *errp; -+ struct dentry *dentry; -+ aufs_bindex_t bdst; -+ loff_t len; -+ struct file *file; -+}; -+ -+static void au_call_cpup_wh(void *args) -+{ -+ struct au_cpup_wh_args *a = args; -+ *a->errp = au_cpup_wh(a->dentry, a->bdst, a->len, a->file); -+} -+ -+int au_sio_cpup_wh(struct dentry *dentry, aufs_bindex_t bdst, loff_t len, -+ struct file *file) -+{ -+ int err, wkq_err; -+ struct dentry *parent, *h_orph, *h_parent, *h_dentry; -+ struct inode *dir, *h_dir, *h_tmpdir, *h_inode; -+ struct au_wbr *wbr; -+ -+ parent = dget_parent(dentry); -+ dir = parent->d_inode; -+ h_orph = NULL; -+ h_parent = NULL; -+ h_dir = au_igrab(au_h_iptr(dir, bdst)); -+ h_tmpdir = h_dir; -+ if (!h_dir->i_nlink) { -+ wbr = au_sbr(dentry->d_sb, bdst)->br_wbr; -+ h_orph = wbr->wbr_orph; -+ -+ h_parent = dget(au_h_dptr(parent, bdst)); -+ au_set_h_dptr(parent, bdst, NULL); -+ au_set_h_dptr(parent, bdst, dget(h_orph)); -+ h_tmpdir = h_orph->d_inode; -+ au_set_h_iptr(dir, bdst, NULL, 0); -+ au_set_h_iptr(dir, bdst, au_igrab(h_tmpdir), /*flags*/0); -+ -+ /* this temporary unlock is safe */ -+ if (file) -+ h_dentry = au_h_fptr(file, au_fbstart(file))->f_dentry; -+ else -+ h_dentry = au_h_dptr(dentry, au_dbstart(dentry)); -+ h_inode = h_dentry->d_inode; -+ IMustLock(h_inode); -+ mutex_unlock(&h_inode->i_mutex); -+ mutex_lock_nested(&h_tmpdir->i_mutex, AuLsc_I_PARENT3); -+ mutex_lock_nested(&h_inode->i_mutex, AuLsc_I_CHILD); -+ } -+ -+ if (!au_test_h_perm_sio(h_tmpdir, MAY_EXEC | MAY_WRITE)) -+ err = au_cpup_wh(dentry, bdst, len, file); -+ else { -+ struct au_cpup_wh_args args = { -+ .errp = &err, -+ .dentry = dentry, -+ .bdst = bdst, -+ .len = len, -+ .file = file -+ }; -+ wkq_err = au_wkq_wait(au_call_cpup_wh, &args); -+ if (unlikely(wkq_err)) -+ err = wkq_err; -+ } -+ -+ if (h_orph) { -+ mutex_unlock(&h_tmpdir->i_mutex); -+ au_set_h_iptr(dir, bdst, NULL, 0); -+ au_set_h_iptr(dir, bdst, au_igrab(h_dir), /*flags*/0); -+ au_set_h_dptr(parent, bdst, NULL); -+ au_set_h_dptr(parent, bdst, h_parent); -+ } -+ iput(h_dir); -+ dput(parent); -+ -+ return err; -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+/* -+ * generic routine for both of copy-up and copy-down. -+ */ -+/* cf. revalidate function in file.c */ -+int au_cp_dirs(struct dentry *dentry, aufs_bindex_t bdst, -+ int (*cp)(struct dentry *dentry, aufs_bindex_t bdst, -+ struct dentry *h_parent, void *arg), -+ void *arg) -+{ -+ int err; -+ struct au_pin pin; -+ struct dentry *d, *parent, *h_parent, *real_parent; -+ -+ err = 0; -+ parent = dget_parent(dentry); -+ if (IS_ROOT(parent)) -+ goto out; -+ -+ au_pin_init(&pin, dentry, bdst, AuLsc_DI_PARENT2, AuLsc_I_PARENT2, -+ au_opt_udba(dentry->d_sb), AuPin_MNT_WRITE); -+ -+ /* do not use au_dpage */ -+ real_parent = parent; -+ while (1) { -+ dput(parent); -+ parent = dget_parent(dentry); -+ h_parent = au_h_dptr(parent, bdst); -+ if (h_parent) -+ goto out; /* success */ -+ -+ /* find top dir which is necessary to cpup */ -+ do { -+ d = parent; -+ dput(parent); -+ parent = dget_parent(d); -+ di_read_lock_parent3(parent, !AuLock_IR); -+ h_parent = au_h_dptr(parent, bdst); -+ di_read_unlock(parent, !AuLock_IR); -+ } while (!h_parent); -+ -+ if (d != real_parent) -+ di_write_lock_child3(d); -+ -+ /* somebody else might create while we were sleeping */ -+ if (!au_h_dptr(d, bdst) || !au_h_dptr(d, bdst)->d_inode) { -+ if (au_h_dptr(d, bdst)) -+ au_update_dbstart(d); -+ -+ au_pin_set_dentry(&pin, d); -+ err = au_do_pin(&pin); -+ if (!err) { -+ err = cp(d, bdst, h_parent, arg); -+ au_unpin(&pin); -+ } -+ } -+ -+ if (d != real_parent) -+ di_write_unlock(d); -+ if (unlikely(err)) -+ break; -+ } -+ -+ out: -+ dput(parent); -+ return err; -+} -+ -+static int au_cpup_dir(struct dentry *dentry, aufs_bindex_t bdst, -+ struct dentry *h_parent __maybe_unused , -+ void *arg __maybe_unused) -+{ -+ return au_sio_cpup_simple(dentry, bdst, -1, AuCpup_DTIME); -+} -+ -+int au_cpup_dirs(struct dentry *dentry, aufs_bindex_t bdst) -+{ -+ return au_cp_dirs(dentry, bdst, au_cpup_dir, NULL); -+} -+ -+int au_test_and_cpup_dirs(struct dentry *dentry, aufs_bindex_t bdst) -+{ -+ int err; -+ struct dentry *parent; -+ struct inode *dir; -+ -+ parent = dget_parent(dentry); -+ dir = parent->d_inode; -+ err = 0; -+ if (au_h_iptr(dir, bdst)) -+ goto out; -+ -+ di_read_unlock(parent, AuLock_IR); -+ di_write_lock_parent(parent); -+ /* someone else might change our inode while we were sleeping */ -+ if (!au_h_iptr(dir, bdst)) -+ err = au_cpup_dirs(dentry, bdst); -+ di_downgrade_lock(parent, AuLock_IR); -+ -+ out: -+ dput(parent); -+ return err; -+} -diff --git a/fs/aufs/cpup.h b/fs/aufs/cpup.h -new file mode 100644 -index 0000000..29e2508 ---- /dev/null -+++ b/fs/aufs/cpup.h -@@ -0,0 +1,81 @@ -+/* -+ * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * -+ * This program, aufs is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ */ -+ -+/* -+ * copy-up/down functions -+ */ -+ -+#ifndef __AUFS_CPUP_H__ -+#define __AUFS_CPUP_H__ -+ -+#ifdef __KERNEL__ -+ -+#include -+#include -+#include -+ -+struct inode; -+struct file; -+ -+void au_cpup_attr_flags(struct inode *dst, struct inode *src); -+void au_cpup_attr_timesizes(struct inode *inode); -+void au_cpup_attr_nlink(struct inode *inode, int force); -+void au_cpup_attr_changeable(struct inode *inode); -+void au_cpup_igen(struct inode *inode, struct inode *h_inode); -+void au_cpup_attr_all(struct inode *inode, int force); -+ -+/* ---------------------------------------------------------------------- */ -+ -+/* cpup flags */ -+#define AuCpup_DTIME 1 /* do dtime_store/revert */ -+#define AuCpup_KEEPLINO (1 << 1) /* do not clear the lower xino, -+ for link(2) */ -+#define au_ftest_cpup(flags, name) ((flags) & AuCpup_##name) -+#define au_fset_cpup(flags, name) { (flags) |= AuCpup_##name; } -+#define au_fclr_cpup(flags, name) { (flags) &= ~AuCpup_##name; } -+ -+int au_copy_file(struct file *dst, struct file *src, loff_t len); -+int au_sio_cpup_single(struct dentry *dentry, aufs_bindex_t bdst, -+ aufs_bindex_t bsrc, loff_t len, unsigned int flags, -+ struct dentry *dst_parent); -+int au_sio_cpup_simple(struct dentry *dentry, aufs_bindex_t bdst, loff_t len, -+ unsigned int flags); -+int au_sio_cpup_wh(struct dentry *dentry, aufs_bindex_t bdst, loff_t len, -+ struct file *file); -+ -+int au_cp_dirs(struct dentry *dentry, aufs_bindex_t bdst, -+ int (*cp)(struct dentry *dentry, aufs_bindex_t bdst, -+ struct dentry *h_parent, void *arg), -+ void *arg); -+int au_cpup_dirs(struct dentry *dentry, aufs_bindex_t bdst); -+int au_test_and_cpup_dirs(struct dentry *dentry, aufs_bindex_t bdst); -+ -+/* ---------------------------------------------------------------------- */ -+ -+/* keep timestamps when copyup */ -+struct au_dtime { -+ struct dentry *dt_dentry; -+ struct path dt_h_path; -+ struct timespec dt_atime, dt_mtime; -+}; -+void au_dtime_store(struct au_dtime *dt, struct dentry *dentry, -+ struct path *h_path); -+void au_dtime_revert(struct au_dtime *dt); -+ -+#endif /* __KERNEL__ */ -+#endif /* __AUFS_CPUP_H__ */ -diff --git a/fs/aufs/dbgaufs.c b/fs/aufs/dbgaufs.c -new file mode 100644 -index 0000000..9573b70 ---- /dev/null -+++ b/fs/aufs/dbgaufs.c -@@ -0,0 +1,331 @@ -+/* -+ * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * -+ * This program, aufs is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ */ -+ -+/* -+ * debugfs interface -+ */ -+ -+#include -+#include "aufs.h" -+ -+#ifndef CONFIG_SYSFS -+#error DEBUG_FS depends upon SYSFS -+#endif -+ -+static struct dentry *dbgaufs; -+static const mode_t dbgaufs_mode = S_IRUSR | S_IRGRP | S_IROTH; -+ -+/* 20 is max digits length of ulong 64 */ -+struct dbgaufs_arg { -+ int n; -+ char a[20 * 4]; -+}; -+ -+/* -+ * common function for all XINO files -+ */ -+static int dbgaufs_xi_release(struct inode *inode __maybe_unused, -+ struct file *file) -+{ -+ kfree(file->private_data); -+ return 0; -+} -+ -+static int dbgaufs_xi_open(struct file *xf, struct file *file, int do_fcnt) -+{ -+ int err; -+ struct kstat st; -+ struct dbgaufs_arg *p; -+ -+ err = -ENOMEM; -+ p = kmalloc(sizeof(*p), GFP_NOFS); -+ if (unlikely(!p)) -+ goto out; -+ -+ err = 0; -+ p->n = 0; -+ file->private_data = p; -+ if (!xf) -+ goto out; -+ -+ err = vfs_getattr(xf->f_vfsmnt, xf->f_dentry, &st); -+ if (!err) { -+ if (do_fcnt) -+ p->n = snprintf -+ (p->a, sizeof(p->a), "%ld, %llux%lu %lld\n", -+ (long)file_count(xf), st.blocks, st.blksize, -+ (long long)st.size); -+ else -+ p->n = snprintf(p->a, sizeof(p->a), "%llux%lu %lld\n", -+ st.blocks, st.blksize, -+ (long long)st.size); -+ AuDebugOn(p->n >= sizeof(p->a)); -+ } else { -+ p->n = snprintf(p->a, sizeof(p->a), "err %d\n", err); -+ err = 0; -+ } -+ -+ out: -+ return err; -+ -+} -+ -+static ssize_t dbgaufs_xi_read(struct file *file, char __user *buf, -+ size_t count, loff_t *ppos) -+{ -+ struct dbgaufs_arg *p; -+ -+ p = file->private_data; -+ return simple_read_from_buffer(buf, count, ppos, p->a, p->n); -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+static int dbgaufs_xib_open(struct inode *inode, struct file *file) -+{ -+ int err; -+ struct au_sbinfo *sbinfo; -+ struct super_block *sb; -+ -+ sbinfo = inode->i_private; -+ sb = sbinfo->si_sb; -+ si_noflush_read_lock(sb); -+ err = dbgaufs_xi_open(sbinfo->si_xib, file, /*do_fcnt*/0); -+ si_read_unlock(sb); -+ return err; -+} -+ -+static const struct file_operations dbgaufs_xib_fop = { -+ .open = dbgaufs_xib_open, -+ .release = dbgaufs_xi_release, -+ .read = dbgaufs_xi_read -+}; -+ -+/* ---------------------------------------------------------------------- */ -+ -+#define DbgaufsXi_PREFIX "xi" -+ -+static int dbgaufs_xino_open(struct inode *inode, struct file *file) -+{ -+ int err; -+ long l; -+ struct au_sbinfo *sbinfo; -+ struct super_block *sb; -+ struct file *xf; -+ struct qstr *name; -+ -+ err = -ENOENT; -+ xf = NULL; -+ name = &file->f_dentry->d_name; -+ if (unlikely(name->len < sizeof(DbgaufsXi_PREFIX) -+ || memcmp(name->name, DbgaufsXi_PREFIX, -+ sizeof(DbgaufsXi_PREFIX) - 1))) -+ goto out; -+ err = strict_strtol(name->name + sizeof(DbgaufsXi_PREFIX) - 1, 10, &l); -+ if (unlikely(err)) -+ goto out; -+ -+ sbinfo = inode->i_private; -+ sb = sbinfo->si_sb; -+ si_noflush_read_lock(sb); -+ if (l <= au_sbend(sb)) { -+ xf = au_sbr(sb, (aufs_bindex_t)l)->br_xino.xi_file; -+ err = dbgaufs_xi_open(xf, file, /*do_fcnt*/1); -+ } else -+ err = -ENOENT; -+ si_read_unlock(sb); -+ -+ out: -+ return err; -+} -+ -+static const struct file_operations dbgaufs_xino_fop = { -+ .open = dbgaufs_xino_open, -+ .release = dbgaufs_xi_release, -+ .read = dbgaufs_xi_read -+}; -+ -+void dbgaufs_brs_del(struct super_block *sb, aufs_bindex_t bindex) -+{ -+ aufs_bindex_t bend; -+ struct au_branch *br; -+ struct au_xino_file *xi; -+ -+ if (!au_sbi(sb)->si_dbgaufs) -+ return; -+ -+ bend = au_sbend(sb); -+ for (; bindex <= bend; bindex++) { -+ br = au_sbr(sb, bindex); -+ xi = &br->br_xino; -+ if (xi->xi_dbgaufs) { -+ debugfs_remove(xi->xi_dbgaufs); -+ xi->xi_dbgaufs = NULL; -+ } -+ } -+} -+ -+void dbgaufs_brs_add(struct super_block *sb, aufs_bindex_t bindex) -+{ -+ struct au_sbinfo *sbinfo; -+ struct dentry *parent; -+ struct au_branch *br; -+ struct au_xino_file *xi; -+ aufs_bindex_t bend; -+ char name[sizeof(DbgaufsXi_PREFIX) + 5]; /* "xi" bindex NULL */ -+ -+ sbinfo = au_sbi(sb); -+ parent = sbinfo->si_dbgaufs; -+ if (!parent) -+ return; -+ -+ bend = au_sbend(sb); -+ for (; bindex <= bend; bindex++) { -+ snprintf(name, sizeof(name), DbgaufsXi_PREFIX "%d", bindex); -+ br = au_sbr(sb, bindex); -+ xi = &br->br_xino; -+ AuDebugOn(xi->xi_dbgaufs); -+ xi->xi_dbgaufs = debugfs_create_file(name, dbgaufs_mode, parent, -+ sbinfo, &dbgaufs_xino_fop); -+ /* ignore an error */ -+ if (unlikely(!xi->xi_dbgaufs)) -+ AuWarn1("failed %s under debugfs\n", name); -+ } -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+#ifdef CONFIG_AUFS_EXPORT -+static int dbgaufs_xigen_open(struct inode *inode, struct file *file) -+{ -+ int err; -+ struct au_sbinfo *sbinfo; -+ struct super_block *sb; -+ -+ sbinfo = inode->i_private; -+ sb = sbinfo->si_sb; -+ si_noflush_read_lock(sb); -+ err = dbgaufs_xi_open(sbinfo->si_xigen, file, /*do_fcnt*/0); -+ si_read_unlock(sb); -+ return err; -+} -+ -+static const struct file_operations dbgaufs_xigen_fop = { -+ .open = dbgaufs_xigen_open, -+ .release = dbgaufs_xi_release, -+ .read = dbgaufs_xi_read -+}; -+ -+static int dbgaufs_xigen_init(struct au_sbinfo *sbinfo) -+{ -+ int err; -+ -+ /* -+ * This function is a dynamic '__init' fucntion actually, -+ * so the tiny check for si_rwsem is unnecessary. -+ */ -+ /* AuRwMustWriteLock(&sbinfo->si_rwsem); */ -+ -+ err = -EIO; -+ sbinfo->si_dbgaufs_xigen = debugfs_create_file -+ ("xigen", dbgaufs_mode, sbinfo->si_dbgaufs, sbinfo, -+ &dbgaufs_xigen_fop); -+ if (sbinfo->si_dbgaufs_xigen) -+ err = 0; -+ -+ return err; -+} -+#else -+static int dbgaufs_xigen_init(struct au_sbinfo *sbinfo) -+{ -+ return 0; -+} -+#endif /* CONFIG_AUFS_EXPORT */ -+ -+/* ---------------------------------------------------------------------- */ -+ -+void dbgaufs_si_fin(struct au_sbinfo *sbinfo) -+{ -+ /* -+ * This function is a dynamic '__init' fucntion actually, -+ * so the tiny check for si_rwsem is unnecessary. -+ */ -+ /* AuRwMustWriteLock(&sbinfo->si_rwsem); */ -+ -+ debugfs_remove_recursive(sbinfo->si_dbgaufs); -+ sbinfo->si_dbgaufs = NULL; -+ kobject_put(&sbinfo->si_kobj); -+} -+ -+int dbgaufs_si_init(struct au_sbinfo *sbinfo) -+{ -+ int err; -+ char name[SysaufsSiNameLen]; -+ -+ /* -+ * This function is a dynamic '__init' fucntion actually, -+ * so the tiny check for si_rwsem is unnecessary. -+ */ -+ /* AuRwMustWriteLock(&sbinfo->si_rwsem); */ -+ -+ err = -ENOENT; -+ if (!dbgaufs) { -+ AuErr1("/debug/aufs is uninitialized\n"); -+ goto out; -+ } -+ -+ err = -EIO; -+ sysaufs_name(sbinfo, name); -+ sbinfo->si_dbgaufs = debugfs_create_dir(name, dbgaufs); -+ if (unlikely(!sbinfo->si_dbgaufs)) -+ goto out; -+ kobject_get(&sbinfo->si_kobj); -+ -+ sbinfo->si_dbgaufs_xib = debugfs_create_file -+ ("xib", dbgaufs_mode, sbinfo->si_dbgaufs, sbinfo, -+ &dbgaufs_xib_fop); -+ if (unlikely(!sbinfo->si_dbgaufs_xib)) -+ goto out_dir; -+ -+ err = dbgaufs_xigen_init(sbinfo); -+ if (!err) -+ goto out; /* success */ -+ -+ out_dir: -+ dbgaufs_si_fin(sbinfo); -+ out: -+ return err; -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+void dbgaufs_fin(void) -+{ -+ debugfs_remove(dbgaufs); -+} -+ -+int __init dbgaufs_init(void) -+{ -+ int err; -+ -+ err = -EIO; -+ dbgaufs = debugfs_create_dir(AUFS_NAME, NULL); -+ if (dbgaufs) -+ err = 0; -+ return err; -+} -diff --git a/fs/aufs/dbgaufs.h b/fs/aufs/dbgaufs.h -new file mode 100644 -index 0000000..67a7964 ---- /dev/null -+++ b/fs/aufs/dbgaufs.h -@@ -0,0 +1,79 @@ -+/* -+ * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * -+ * This program, aufs is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ */ -+ -+/* -+ * debugfs interface -+ */ -+ -+#ifndef __DBGAUFS_H__ -+#define __DBGAUFS_H__ -+ -+#ifdef __KERNEL__ -+ -+#include -+#include -+ -+struct super_block; -+struct au_sbinfo; -+ -+#ifdef CONFIG_DEBUG_FS -+/* dbgaufs.c */ -+void dbgaufs_brs_del(struct super_block *sb, aufs_bindex_t bindex); -+void dbgaufs_brs_add(struct super_block *sb, aufs_bindex_t bindex); -+void dbgaufs_si_fin(struct au_sbinfo *sbinfo); -+int dbgaufs_si_init(struct au_sbinfo *sbinfo); -+void dbgaufs_fin(void); -+int __init dbgaufs_init(void); -+ -+#else -+ -+static inline -+void dbgaufs_brs_del(struct super_block *sb, aufs_bindex_t bindex) -+{ -+ /* empty */ -+} -+ -+static inline -+void dbgaufs_brs_add(struct super_block *sb, aufs_bindex_t bindex) -+{ -+ /* empty */ -+} -+ -+static inline -+void dbgaufs_si_fin(struct au_sbinfo *sbinfo) -+{ -+ /* empty */ -+} -+ -+static inline -+int dbgaufs_si_init(struct au_sbinfo *sbinfo) -+{ -+ return 0; -+} -+ -+#define dbgaufs_fin() do {} while (0) -+ -+static inline -+int __init dbgaufs_init(void) -+{ -+ return 0; -+} -+#endif /* CONFIG_DEBUG_FS */ -+ -+#endif /* __KERNEL__ */ -+#endif /* __DBGAUFS_H__ */ -diff --git a/fs/aufs/dcsub.c b/fs/aufs/dcsub.c -new file mode 100644 -index 0000000..43a8cb4 ---- /dev/null -+++ b/fs/aufs/dcsub.c -@@ -0,0 +1,223 @@ -+/* -+ * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * -+ * This program, aufs is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ */ -+ -+/* -+ * sub-routines for dentry cache -+ */ -+ -+#include "aufs.h" -+ -+static void au_dpage_free(struct au_dpage *dpage) -+{ -+ int i; -+ struct dentry **p; -+ -+ p = dpage->dentries; -+ for (i = 0; i < dpage->ndentry; i++) -+ dput(*p++); -+ free_page((unsigned long)dpage->dentries); -+} -+ -+int au_dpages_init(struct au_dcsub_pages *dpages, gfp_t gfp) -+{ -+ int err; -+ void *p; -+ -+ err = -ENOMEM; -+ dpages->dpages = kmalloc(sizeof(*dpages->dpages), gfp); -+ if (unlikely(!dpages->dpages)) -+ goto out; -+ -+ p = (void *)__get_free_page(gfp); -+ if (unlikely(!p)) -+ goto out_dpages; -+ -+ dpages->dpages[0].ndentry = 0; -+ dpages->dpages[0].dentries = p; -+ dpages->ndpage = 1; -+ return 0; /* success */ -+ -+ out_dpages: -+ kfree(dpages->dpages); -+ out: -+ return err; -+} -+ -+void au_dpages_free(struct au_dcsub_pages *dpages) -+{ -+ int i; -+ struct au_dpage *p; -+ -+ p = dpages->dpages; -+ for (i = 0; i < dpages->ndpage; i++) -+ au_dpage_free(p++); -+ kfree(dpages->dpages); -+} -+ -+static int au_dpages_append(struct au_dcsub_pages *dpages, -+ struct dentry *dentry, gfp_t gfp) -+{ -+ int err, sz; -+ struct au_dpage *dpage; -+ void *p; -+ -+ dpage = dpages->dpages + dpages->ndpage - 1; -+ sz = PAGE_SIZE / sizeof(dentry); -+ if (unlikely(dpage->ndentry >= sz)) { -+ AuLabel(new dpage); -+ err = -ENOMEM; -+ sz = dpages->ndpage * sizeof(*dpages->dpages); -+ p = au_kzrealloc(dpages->dpages, sz, -+ sz + sizeof(*dpages->dpages), gfp); -+ if (unlikely(!p)) -+ goto out; -+ -+ dpages->dpages = p; -+ dpage = dpages->dpages + dpages->ndpage; -+ p = (void *)__get_free_page(gfp); -+ if (unlikely(!p)) -+ goto out; -+ -+ dpage->ndentry = 0; -+ dpage->dentries = p; -+ dpages->ndpage++; -+ } -+ -+ dpage->dentries[dpage->ndentry++] = dget(dentry); -+ return 0; /* success */ -+ -+ out: -+ return err; -+} -+ -+int au_dcsub_pages(struct au_dcsub_pages *dpages, struct dentry *root, -+ au_dpages_test test, void *arg) -+{ -+ int err; -+ struct dentry *this_parent = root; -+ struct list_head *next; -+ struct super_block *sb = root->d_sb; -+ -+ err = 0; -+ spin_lock(&dcache_lock); -+ repeat: -+ next = this_parent->d_subdirs.next; -+ resume: -+ if (this_parent->d_sb == sb -+ && !IS_ROOT(this_parent) -+ && atomic_read(&this_parent->d_count) -+ && this_parent->d_inode -+ && (!test || test(this_parent, arg))) { -+ err = au_dpages_append(dpages, this_parent, GFP_ATOMIC); -+ if (unlikely(err)) -+ goto out; -+ } -+ -+ while (next != &this_parent->d_subdirs) { -+ struct list_head *tmp = next; -+ struct dentry *dentry = list_entry(tmp, struct dentry, -+ d_u.d_child); -+ next = tmp->next; -+ if (/*d_unhashed(dentry) || */!dentry->d_inode) -+ continue; -+ if (!list_empty(&dentry->d_subdirs)) { -+ this_parent = dentry; -+ goto repeat; -+ } -+ if (dentry->d_sb == sb -+ && atomic_read(&dentry->d_count) -+ && (!test || test(dentry, arg))) { -+ err = au_dpages_append(dpages, dentry, GFP_ATOMIC); -+ if (unlikely(err)) -+ goto out; -+ } -+ } -+ -+ if (this_parent != root) { -+ next = this_parent->d_u.d_child.next; -+ this_parent = this_parent->d_parent; /* dcache_lock is locked */ -+ goto resume; -+ } -+ out: -+ spin_unlock(&dcache_lock); -+ return err; -+} -+ -+int au_dcsub_pages_rev(struct au_dcsub_pages *dpages, struct dentry *dentry, -+ int do_include, au_dpages_test test, void *arg) -+{ -+ int err; -+ -+ err = 0; -+ spin_lock(&dcache_lock); -+ if (do_include && (!test || test(dentry, arg))) { -+ err = au_dpages_append(dpages, dentry, GFP_ATOMIC); -+ if (unlikely(err)) -+ goto out; -+ } -+ while (!IS_ROOT(dentry)) { -+ dentry = dentry->d_parent; /* dcache_lock is locked */ -+ if (!test || test(dentry, arg)) { -+ err = au_dpages_append(dpages, dentry, GFP_ATOMIC); -+ if (unlikely(err)) -+ break; -+ } -+ } -+ -+ out: -+ spin_unlock(&dcache_lock); -+ -+ return err; -+} -+ -+struct dentry *au_test_subdir(struct dentry *d1, struct dentry *d2) -+{ -+ struct dentry *trap, **dentries; -+ int err, i, j; -+ struct au_dcsub_pages dpages; -+ struct au_dpage *dpage; -+ -+ trap = ERR_PTR(-ENOMEM); -+ err = au_dpages_init(&dpages, GFP_NOFS); -+ if (unlikely(err)) -+ goto out; -+ err = au_dcsub_pages_rev(&dpages, d1, /*do_include*/1, NULL, NULL); -+ if (unlikely(err)) -+ goto out_dpages; -+ -+ trap = d1; -+ for (i = 0; !err && i < dpages.ndpage; i++) { -+ dpage = dpages.dpages + i; -+ dentries = dpage->dentries; -+ for (j = 0; !err && j < dpage->ndentry; j++) { -+ struct dentry *d; -+ -+ d = dentries[j]; -+ err = (d == d2); -+ if (!err) -+ trap = d; -+ } -+ } -+ if (!err) -+ trap = NULL; -+ -+ out_dpages: -+ au_dpages_free(&dpages); -+ out: -+ return trap; -+} -diff --git a/fs/aufs/dcsub.h b/fs/aufs/dcsub.h -new file mode 100644 -index 0000000..bb934b4 ---- /dev/null -+++ b/fs/aufs/dcsub.h -@@ -0,0 +1,54 @@ -+/* -+ * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * -+ * This program, aufs is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ */ -+ -+/* -+ * sub-routines for dentry cache -+ */ -+ -+#ifndef __AUFS_DCSUB_H__ -+#define __AUFS_DCSUB_H__ -+ -+#ifdef __KERNEL__ -+ -+#include -+ -+struct dentry; -+ -+struct au_dpage { -+ int ndentry; -+ struct dentry **dentries; -+}; -+ -+struct au_dcsub_pages { -+ int ndpage; -+ struct au_dpage *dpages; -+}; -+ -+/* ---------------------------------------------------------------------- */ -+ -+int au_dpages_init(struct au_dcsub_pages *dpages, gfp_t gfp); -+void au_dpages_free(struct au_dcsub_pages *dpages); -+typedef int (*au_dpages_test)(struct dentry *dentry, void *arg); -+int au_dcsub_pages(struct au_dcsub_pages *dpages, struct dentry *root, -+ au_dpages_test test, void *arg); -+int au_dcsub_pages_rev(struct au_dcsub_pages *dpages, struct dentry *dentry, -+ int do_include, au_dpages_test test, void *arg); -+struct dentry *au_test_subdir(struct dentry *d1, struct dentry *d2); -+ -+#endif /* __KERNEL__ */ -+#endif /* __AUFS_DCSUB_H__ */ -diff --git a/fs/aufs/debug.c b/fs/aufs/debug.c -new file mode 100644 -index 0000000..e34d1c2 ---- /dev/null -+++ b/fs/aufs/debug.c -@@ -0,0 +1,431 @@ -+/* -+ * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * -+ * This program, aufs is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ */ -+ -+/* -+ * debug print functions -+ */ -+ -+#include -+#include -+#include "aufs.h" -+ -+int aufs_debug; -+MODULE_PARM_DESC(debug, "debug print"); -+module_param_named(debug, aufs_debug, int, S_IRUGO | S_IWUSR | S_IWGRP); -+ -+char *au_plevel = KERN_DEBUG; -+#define dpri(fmt, ...) do { \ -+ if (au_debug_test()) \ -+ printk("%s" fmt, au_plevel, ##__VA_ARGS__); \ -+} while (0) -+ -+/* ---------------------------------------------------------------------- */ -+ -+void au_dpri_whlist(struct au_nhash *whlist) -+{ -+ unsigned long ul, n; -+ struct hlist_head *head; -+ struct au_vdir_wh *tpos; -+ struct hlist_node *pos; -+ -+ n = whlist->nh_num; -+ head = whlist->nh_head; -+ for (ul = 0; ul < n; ul++) { -+ hlist_for_each_entry(tpos, pos, head, wh_hash) -+ dpri("b%d, %.*s, %d\n", -+ tpos->wh_bindex, -+ tpos->wh_str.len, tpos->wh_str.name, -+ tpos->wh_str.len); -+ head++; -+ } -+} -+ -+void au_dpri_vdir(struct au_vdir *vdir) -+{ -+ unsigned long ul; -+ union au_vdir_deblk_p p; -+ unsigned char *o; -+ -+ if (!vdir || IS_ERR(vdir)) { -+ dpri("err %ld\n", PTR_ERR(vdir)); -+ return; -+ } -+ -+ dpri("deblk %u, nblk %lu, deblk %p, last{%lu, %p}, ver %lu\n", -+ vdir->vd_deblk_sz, vdir->vd_nblk, vdir->vd_deblk, -+ vdir->vd_last.ul, vdir->vd_last.p.deblk, vdir->vd_version); -+ for (ul = 0; ul < vdir->vd_nblk; ul++) { -+ p.deblk = vdir->vd_deblk[ul]; -+ o = p.deblk; -+ dpri("[%lu]: %p\n", ul, o); -+ } -+} -+ -+static int do_pri_inode(aufs_bindex_t bindex, struct inode *inode, -+ struct dentry *wh) -+{ -+ char *n = NULL; -+ int l = 0; -+ -+ if (!inode || IS_ERR(inode)) { -+ dpri("i%d: err %ld\n", bindex, PTR_ERR(inode)); -+ return -1; -+ } -+ -+ /* the type of i_blocks depends upon CONFIG_LSF */ -+ BUILD_BUG_ON(sizeof(inode->i_blocks) != sizeof(unsigned long) -+ && sizeof(inode->i_blocks) != sizeof(u64)); -+ if (wh) { -+ n = (void *)wh->d_name.name; -+ l = wh->d_name.len; -+ } -+ -+ dpri("i%d: i%lu, %s, cnt %d, nl %u, 0%o, sz %llu, blk %llu," -+ " ct %lld, np %lu, st 0x%lx, f 0x%x, g %x%s%.*s\n", -+ bindex, -+ inode->i_ino, inode->i_sb ? au_sbtype(inode->i_sb) : "??", -+ atomic_read(&inode->i_count), inode->i_nlink, inode->i_mode, -+ i_size_read(inode), (unsigned long long)inode->i_blocks, -+ (long long)timespec_to_ns(&inode->i_ctime) & 0x0ffff, -+ inode->i_mapping ? inode->i_mapping->nrpages : 0, -+ inode->i_state, inode->i_flags, inode->i_generation, -+ l ? ", wh " : "", l, n); -+ return 0; -+} -+ -+void au_dpri_inode(struct inode *inode) -+{ -+ struct au_iinfo *iinfo; -+ aufs_bindex_t bindex; -+ int err; -+ -+ err = do_pri_inode(-1, inode, NULL); -+ if (err || !au_test_aufs(inode->i_sb)) -+ return; -+ -+ iinfo = au_ii(inode); -+ if (!iinfo) -+ return; -+ dpri("i-1: bstart %d, bend %d, gen %d\n", -+ iinfo->ii_bstart, iinfo->ii_bend, au_iigen(inode)); -+ if (iinfo->ii_bstart < 0) -+ return; -+ for (bindex = iinfo->ii_bstart; bindex <= iinfo->ii_bend; bindex++) -+ do_pri_inode(bindex, iinfo->ii_hinode[0 + bindex].hi_inode, -+ iinfo->ii_hinode[0 + bindex].hi_whdentry); -+} -+ -+static int do_pri_dentry(aufs_bindex_t bindex, struct dentry *dentry) -+{ -+ struct dentry *wh = NULL; -+ -+ if (!dentry || IS_ERR(dentry)) { -+ dpri("d%d: err %ld\n", bindex, PTR_ERR(dentry)); -+ return -1; -+ } -+ /* do not call dget_parent() here */ -+ dpri("d%d: %.*s?/%.*s, %s, cnt %d, flags 0x%x\n", -+ bindex, -+ AuDLNPair(dentry->d_parent), AuDLNPair(dentry), -+ dentry->d_sb ? au_sbtype(dentry->d_sb) : "??", -+ atomic_read(&dentry->d_count), dentry->d_flags); -+ if (bindex >= 0 && dentry->d_inode && au_test_aufs(dentry->d_sb)) { -+ struct au_iinfo *iinfo = au_ii(dentry->d_inode); -+ if (iinfo) -+ wh = iinfo->ii_hinode[0 + bindex].hi_whdentry; -+ } -+ do_pri_inode(bindex, dentry->d_inode, wh); -+ return 0; -+} -+ -+void au_dpri_dentry(struct dentry *dentry) -+{ -+ struct au_dinfo *dinfo; -+ aufs_bindex_t bindex; -+ int err; -+ -+ err = do_pri_dentry(-1, dentry); -+ if (err || !au_test_aufs(dentry->d_sb)) -+ return; -+ -+ dinfo = au_di(dentry); -+ if (!dinfo) -+ return; -+ dpri("d-1: bstart %d, bend %d, bwh %d, bdiropq %d, gen %d\n", -+ dinfo->di_bstart, dinfo->di_bend, -+ dinfo->di_bwh, dinfo->di_bdiropq, au_digen(dentry)); -+ if (dinfo->di_bstart < 0) -+ return; -+ for (bindex = dinfo->di_bstart; bindex <= dinfo->di_bend; bindex++) -+ do_pri_dentry(bindex, dinfo->di_hdentry[0 + bindex].hd_dentry); -+} -+ -+static int do_pri_file(aufs_bindex_t bindex, struct file *file) -+{ -+ char a[32]; -+ -+ if (!file || IS_ERR(file)) { -+ dpri("f%d: err %ld\n", bindex, PTR_ERR(file)); -+ return -1; -+ } -+ a[0] = 0; -+ if (bindex < 0 -+ && file->f_dentry -+ && au_test_aufs(file->f_dentry->d_sb) -+ && au_fi(file)) -+ snprintf(a, sizeof(a), ", mmapped %d", au_test_mmapped(file)); -+ dpri("f%d: mode 0x%x, flags 0%o, cnt %ld, pos %llu%s\n", -+ bindex, file->f_mode, file->f_flags, (long)file_count(file), -+ file->f_pos, a); -+ if (file->f_dentry) -+ do_pri_dentry(bindex, file->f_dentry); -+ return 0; -+} -+ -+void au_dpri_file(struct file *file) -+{ -+ struct au_finfo *finfo; -+ aufs_bindex_t bindex; -+ int err; -+ -+ err = do_pri_file(-1, file); -+ if (err || !file->f_dentry || !au_test_aufs(file->f_dentry->d_sb)) -+ return; -+ -+ finfo = au_fi(file); -+ if (!finfo) -+ return; -+ if (finfo->fi_bstart < 0) -+ return; -+ for (bindex = finfo->fi_bstart; bindex <= finfo->fi_bend; bindex++) { -+ struct au_hfile *hf; -+ -+ hf = finfo->fi_hfile + bindex; -+ do_pri_file(bindex, hf ? hf->hf_file : NULL); -+ } -+} -+ -+static int do_pri_br(aufs_bindex_t bindex, struct au_branch *br) -+{ -+ struct vfsmount *mnt; -+ struct super_block *sb; -+ -+ if (!br || IS_ERR(br)) -+ goto out; -+ mnt = br->br_mnt; -+ if (!mnt || IS_ERR(mnt)) -+ goto out; -+ sb = mnt->mnt_sb; -+ if (!sb || IS_ERR(sb)) -+ goto out; -+ -+ dpri("s%d: {perm 0x%x, cnt %d, wbr %p}, " -+ "%s, dev 0x%02x%02x, flags 0x%lx, cnt(BIAS) %d, active %d, " -+ "xino %d\n", -+ bindex, br->br_perm, atomic_read(&br->br_count), br->br_wbr, -+ au_sbtype(sb), MAJOR(sb->s_dev), MINOR(sb->s_dev), -+ sb->s_flags, sb->s_count - S_BIAS, -+ atomic_read(&sb->s_active), !!br->br_xino.xi_file); -+ return 0; -+ -+ out: -+ dpri("s%d: err %ld\n", bindex, PTR_ERR(br)); -+ return -1; -+} -+ -+void au_dpri_sb(struct super_block *sb) -+{ -+ struct au_sbinfo *sbinfo; -+ aufs_bindex_t bindex; -+ int err; -+ /* to reuduce stack size */ -+ struct { -+ struct vfsmount mnt; -+ struct au_branch fake; -+ } *a; -+ -+ /* this function can be called from magic sysrq */ -+ a = kzalloc(sizeof(*a), GFP_ATOMIC); -+ if (unlikely(!a)) { -+ dpri("no memory\n"); -+ return; -+ } -+ -+ a->mnt.mnt_sb = sb; -+ a->fake.br_perm = 0; -+ a->fake.br_mnt = &a->mnt; -+ a->fake.br_xino.xi_file = NULL; -+ atomic_set(&a->fake.br_count, 0); -+ smp_mb(); /* atomic_set */ -+ err = do_pri_br(-1, &a->fake); -+ kfree(a); -+ dpri("dev 0x%x\n", sb->s_dev); -+ if (err || !au_test_aufs(sb)) -+ return; -+ -+ sbinfo = au_sbi(sb); -+ if (!sbinfo) -+ return; -+ dpri("nw %d, gen %u, kobj %d\n", -+ atomic_read(&sbinfo->si_nowait.nw_len), sbinfo->si_generation, -+ atomic_read(&sbinfo->si_kobj.kref.refcount)); -+ for (bindex = 0; bindex <= sbinfo->si_bend; bindex++) -+ do_pri_br(bindex, sbinfo->si_branch[0 + bindex]); -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+void au_dbg_sleep_jiffy(int jiffy) -+{ -+ while (jiffy) -+ jiffy = schedule_timeout_uninterruptible(jiffy); -+} -+ -+void au_dbg_iattr(struct iattr *ia) -+{ -+#define AuBit(name) if (ia->ia_valid & ATTR_ ## name) \ -+ dpri(#name "\n") -+ AuBit(MODE); -+ AuBit(UID); -+ AuBit(GID); -+ AuBit(SIZE); -+ AuBit(ATIME); -+ AuBit(MTIME); -+ AuBit(CTIME); -+ AuBit(ATIME_SET); -+ AuBit(MTIME_SET); -+ AuBit(FORCE); -+ AuBit(ATTR_FLAG); -+ AuBit(KILL_SUID); -+ AuBit(KILL_SGID); -+ AuBit(FILE); -+ AuBit(KILL_PRIV); -+ AuBit(OPEN); -+ AuBit(TIMES_SET); -+#undef AuBit -+ dpri("ia_file %p\n", ia->ia_file); -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+void au_dbg_verify_dir_parent(struct dentry *dentry, unsigned int sigen) -+{ -+ struct dentry *parent; -+ -+ parent = dget_parent(dentry); -+ AuDebugOn(!S_ISDIR(dentry->d_inode->i_mode) -+ || IS_ROOT(dentry) -+ || au_digen(parent) != sigen); -+ dput(parent); -+} -+ -+void au_dbg_verify_nondir_parent(struct dentry *dentry, unsigned int sigen) -+{ -+ struct dentry *parent; -+ -+ parent = dget_parent(dentry); -+ AuDebugOn(S_ISDIR(dentry->d_inode->i_mode) -+ || au_digen(parent) != sigen); -+ dput(parent); -+} -+ -+void au_dbg_verify_gen(struct dentry *parent, unsigned int sigen) -+{ -+ int err, i, j; -+ struct au_dcsub_pages dpages; -+ struct au_dpage *dpage; -+ struct dentry **dentries; -+ -+ err = au_dpages_init(&dpages, GFP_NOFS); -+ AuDebugOn(err); -+ err = au_dcsub_pages_rev(&dpages, parent, /*do_include*/1, NULL, NULL); -+ AuDebugOn(err); -+ for (i = dpages.ndpage - 1; !err && i >= 0; i--) { -+ dpage = dpages.dpages + i; -+ dentries = dpage->dentries; -+ for (j = dpage->ndentry - 1; !err && j >= 0; j--) -+ AuDebugOn(au_digen(dentries[j]) != sigen); -+ } -+ au_dpages_free(&dpages); -+} -+ -+void au_dbg_verify_hf(struct au_finfo *finfo) -+{ -+ struct au_hfile *hf; -+ aufs_bindex_t bend, bindex; -+ -+ if (finfo->fi_bstart >= 0) { -+ bend = finfo->fi_bend; -+ for (bindex = finfo->fi_bstart; bindex <= bend; bindex++) { -+ hf = finfo->fi_hfile + bindex; -+ AuDebugOn(hf->hf_file || hf->hf_br); -+ } -+ } -+} -+ -+void au_dbg_verify_kthread(void) -+{ -+ if (au_test_wkq(current)) { -+ au_dbg_blocked(); -+ BUG(); -+ } -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+void au_debug_sbinfo_init(struct au_sbinfo *sbinfo __maybe_unused) -+{ -+#ifdef AuForceNoPlink -+ au_opt_clr(sbinfo->si_mntflags, PLINK); -+#endif -+#ifdef AuForceNoXino -+ au_opt_clr(sbinfo->si_mntflags, XINO); -+#endif -+#ifdef AuForceNoRefrof -+ au_opt_clr(sbinfo->si_mntflags, REFROF); -+#endif -+#ifdef AuForceHinotify -+ au_opt_set_udba(sbinfo->si_mntflags, UDBA_HINOTIFY); -+#endif -+#ifdef AuForceRd0 -+ sbinfo->si_rdblk = 0; -+ sbinfo->si_rdhash = 0; -+#endif -+} -+ -+int __init au_debug_init(void) -+{ -+ aufs_bindex_t bindex; -+ struct au_vdir_destr destr; -+ -+ bindex = -1; -+ AuDebugOn(bindex >= 0); -+ -+ destr.len = -1; -+ AuDebugOn(destr.len < NAME_MAX); -+ -+#ifdef CONFIG_4KSTACKS -+ pr_warning("CONFIG_4KSTACKS is defined.\n"); -+#endif -+ -+#ifdef AuForceNoBrs -+ sysaufs_brs = 0; -+#endif -+ -+ return 0; -+} -diff --git a/fs/aufs/debug.h b/fs/aufs/debug.h -new file mode 100644 -index 0000000..312e1af ---- /dev/null -+++ b/fs/aufs/debug.h -@@ -0,0 +1,257 @@ -+/* -+ * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * -+ * This program, aufs is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ */ -+ -+/* -+ * debug print functions -+ */ -+ -+#ifndef __AUFS_DEBUG_H__ -+#define __AUFS_DEBUG_H__ -+ -+#ifdef __KERNEL__ -+ -+#include -+#include -+/* #include */ -+#include -+/* #include */ -+#include -+/* #include */ -+/* #include */ -+#include -+#include -+ -+#include -+ -+#ifdef CONFIG_AUFS_DEBUG -+#define AuDebugOn(a) BUG_ON(a) -+ -+/* module parameter */ -+extern int aufs_debug; -+static inline void au_debug(int n) -+{ -+ aufs_debug = n; -+ smp_mb(); -+} -+ -+static inline int au_debug_test(void) -+{ -+ return aufs_debug; -+} -+#else -+#define AuDebugOn(a) do {} while (0) -+#define au_debug() do {} while (0) -+static inline int au_debug_test(void) -+{ -+ return 0; -+} -+#endif /* CONFIG_AUFS_DEBUG */ -+ -+/* ---------------------------------------------------------------------- */ -+ -+/* debug print */ -+ -+#define AuDbg(fmt, ...) do { \ -+ if (au_debug_test()) \ -+ pr_debug("DEBUG: " fmt, ##__VA_ARGS__); \ -+} while (0) -+#define AuLabel(l) AuDbg(#l "\n") -+#define AuIOErr(fmt, ...) pr_err("I/O Error, " fmt, ##__VA_ARGS__) -+#define AuWarn1(fmt, ...) do { \ -+ static unsigned char _c; \ -+ if (!_c++) \ -+ pr_warning(fmt, ##__VA_ARGS__); \ -+} while (0) -+ -+#define AuErr1(fmt, ...) do { \ -+ static unsigned char _c; \ -+ if (!_c++) \ -+ pr_err(fmt, ##__VA_ARGS__); \ -+} while (0) -+ -+#define AuIOErr1(fmt, ...) do { \ -+ static unsigned char _c; \ -+ if (!_c++) \ -+ AuIOErr(fmt, ##__VA_ARGS__); \ -+} while (0) -+ -+#define AuUnsupportMsg "This operation is not supported." \ -+ " Please report this application to aufs-users ML." -+#define AuUnsupport(fmt, ...) do { \ -+ pr_err(AuUnsupportMsg "\n" fmt, ##__VA_ARGS__); \ -+ dump_stack(); \ -+} while (0) -+ -+#define AuTraceErr(e) do { \ -+ if (unlikely((e) < 0)) \ -+ AuDbg("err %d\n", (int)(e)); \ -+} while (0) -+ -+#define AuTraceErrPtr(p) do { \ -+ if (IS_ERR(p)) \ -+ AuDbg("err %ld\n", PTR_ERR(p)); \ -+} while (0) -+ -+/* dirty macros for debug print, use with "%.*s" and caution */ -+#define AuLNPair(qstr) (qstr)->len, (qstr)->name -+#define AuDLNPair(d) AuLNPair(&(d)->d_name) -+ -+/* ---------------------------------------------------------------------- */ -+ -+struct au_sbinfo; -+struct au_finfo; -+struct dentry; -+#ifdef CONFIG_AUFS_DEBUG -+extern char *au_plevel; -+struct au_nhash; -+void au_dpri_whlist(struct au_nhash *whlist); -+struct au_vdir; -+void au_dpri_vdir(struct au_vdir *vdir); -+struct inode; -+void au_dpri_inode(struct inode *inode); -+void au_dpri_dentry(struct dentry *dentry); -+struct file; -+void au_dpri_file(struct file *filp); -+struct super_block; -+void au_dpri_sb(struct super_block *sb); -+ -+void au_dbg_sleep_jiffy(int jiffy); -+struct iattr; -+void au_dbg_iattr(struct iattr *ia); -+ -+void au_dbg_verify_dir_parent(struct dentry *dentry, unsigned int sigen); -+void au_dbg_verify_nondir_parent(struct dentry *dentry, unsigned int sigen); -+void au_dbg_verify_gen(struct dentry *parent, unsigned int sigen); -+void au_dbg_verify_hf(struct au_finfo *finfo); -+void au_dbg_verify_kthread(void); -+ -+int __init au_debug_init(void); -+void au_debug_sbinfo_init(struct au_sbinfo *sbinfo); -+#define AuDbgWhlist(w) do { \ -+ AuDbg(#w "\n"); \ -+ au_dpri_whlist(w); \ -+} while (0) -+ -+#define AuDbgVdir(v) do { \ -+ AuDbg(#v "\n"); \ -+ au_dpri_vdir(v); \ -+} while (0) -+ -+#define AuDbgInode(i) do { \ -+ AuDbg(#i "\n"); \ -+ au_dpri_inode(i); \ -+} while (0) -+ -+#define AuDbgDentry(d) do { \ -+ AuDbg(#d "\n"); \ -+ au_dpri_dentry(d); \ -+} while (0) -+ -+#define AuDbgFile(f) do { \ -+ AuDbg(#f "\n"); \ -+ au_dpri_file(f); \ -+} while (0) -+ -+#define AuDbgSb(sb) do { \ -+ AuDbg(#sb "\n"); \ -+ au_dpri_sb(sb); \ -+} while (0) -+ -+#define AuDbgSleep(sec) do { \ -+ AuDbg("sleep %d sec\n", sec); \ -+ ssleep(sec); \ -+} while (0) -+ -+#define AuDbgSleepJiffy(jiffy) do { \ -+ AuDbg("sleep %d jiffies\n", jiffy); \ -+ au_dbg_sleep_jiffy(jiffy); \ -+} while (0) -+ -+#define AuDbgIAttr(ia) do { \ -+ AuDbg("ia_valid 0x%x\n", (ia)->ia_valid); \ -+ au_dbg_iattr(ia); \ -+} while (0) -+#else -+static inline void au_dbg_verify_dir_parent(struct dentry *dentry, -+ unsigned int sigen) -+{ -+ /* empty */ -+} -+static inline void au_dbg_verify_nondir_parent(struct dentry *dentry, -+ unsigned int sigen) -+{ -+ /* empty */ -+} -+static inline void au_dbg_verify_gen(struct dentry *parent, unsigned int sigen) -+{ -+ /* empty */ -+} -+static inline void au_dbg_verify_hf(struct au_finfo *finfo) -+{ -+ /* empty */ -+} -+static inline void au_dbg_verify_kthread(void) -+{ -+ /* empty */ -+} -+ -+static inline int au_debug_init(void) -+{ -+ return 0; -+} -+static inline void au_debug_sbinfo_init(struct au_sbinfo *sbinfo) -+{ -+ /* empty */ -+} -+#define AuDbgWhlist(w) do {} while (0) -+#define AuDbgVdir(v) do {} while (0) -+#define AuDbgInode(i) do {} while (0) -+#define AuDbgDentry(d) do {} while (0) -+#define AuDbgFile(f) do {} while (0) -+#define AuDbgSb(sb) do {} while (0) -+#define AuDbgSleep(sec) do {} while (0) -+#define AuDbgSleepJiffy(jiffy) do {} while (0) -+#define AuDbgIAttr(ia) do {} while (0) -+#endif /* CONFIG_AUFS_DEBUG */ -+ -+/* ---------------------------------------------------------------------- */ -+ -+#ifdef CONFIG_AUFS_MAGIC_SYSRQ -+int __init au_sysrq_init(void); -+void au_sysrq_fin(void); -+ -+#ifdef CONFIG_HW_CONSOLE -+#define au_dbg_blocked() do { \ -+ WARN_ON(1); \ -+ handle_sysrq('w', vc_cons[fg_console].d->vc_tty); \ -+} while (0) -+#else -+#define au_dbg_blocked() do {} while (0) -+#endif -+ -+#else -+static inline int au_sysrq_init(void) -+{ -+ return 0; -+} -+#define au_sysrq_fin() do {} while (0) -+#define au_dbg_blocked() do {} while (0) -+#endif /* CONFIG_AUFS_MAGIC_SYSRQ */ -+ -+#endif /* __KERNEL__ */ -+#endif /* __AUFS_DEBUG_H__ */ -diff --git a/fs/aufs/dentry.c b/fs/aufs/dentry.c -new file mode 100644 -index 0000000..28525d4 ---- /dev/null -+++ b/fs/aufs/dentry.c -@@ -0,0 +1,880 @@ -+/* -+ * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * -+ * This program, aufs is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ */ -+ -+/* -+ * lookup and dentry operations -+ */ -+ -+#include -+#include "aufs.h" -+ -+static void au_h_nd(struct nameidata *h_nd, struct nameidata *nd) -+{ -+ if (nd) { -+ *h_nd = *nd; -+ -+ /* -+ * gave up supporting LOOKUP_CREATE/OPEN for lower fs, -+ * due to whiteout and branch permission. -+ */ -+ h_nd->flags &= ~(/*LOOKUP_PARENT |*/ LOOKUP_OPEN | LOOKUP_CREATE -+ | LOOKUP_FOLLOW); -+ /* unnecessary? */ -+ h_nd->intent.open.file = NULL; -+ } else -+ memset(h_nd, 0, sizeof(*h_nd)); -+} -+ -+struct au_lkup_one_args { -+ struct dentry **errp; -+ struct qstr *name; -+ struct dentry *h_parent; -+ struct au_branch *br; -+ struct nameidata *nd; -+}; -+ -+struct dentry *au_lkup_one(struct qstr *name, struct dentry *h_parent, -+ struct au_branch *br, struct nameidata *nd) -+{ -+ struct dentry *h_dentry; -+ int err; -+ struct nameidata h_nd; -+ -+ if (au_test_fs_null_nd(h_parent->d_sb)) -+ return vfsub_lookup_one_len(name->name, h_parent, name->len); -+ -+ au_h_nd(&h_nd, nd); -+ h_nd.path.dentry = h_parent; -+ h_nd.path.mnt = br->br_mnt; -+ -+ err = __lookup_one_len(name->name, &h_nd.last, NULL, name->len); -+ h_dentry = ERR_PTR(err); -+ if (!err) { -+ path_get(&h_nd.path); -+ h_dentry = vfsub_lookup_hash(&h_nd); -+ path_put(&h_nd.path); -+ } -+ -+ AuTraceErrPtr(h_dentry); -+ return h_dentry; -+} -+ -+static void au_call_lkup_one(void *args) -+{ -+ struct au_lkup_one_args *a = args; -+ *a->errp = au_lkup_one(a->name, a->h_parent, a->br, a->nd); -+} -+ -+#define AuLkup_ALLOW_NEG 1 -+#define au_ftest_lkup(flags, name) ((flags) & AuLkup_##name) -+#define au_fset_lkup(flags, name) { (flags) |= AuLkup_##name; } -+#define au_fclr_lkup(flags, name) { (flags) &= ~AuLkup_##name; } -+ -+struct au_do_lookup_args { -+ unsigned int flags; -+ mode_t type; -+ struct nameidata *nd; -+}; -+ -+/* -+ * returns positive/negative dentry, NULL or an error. -+ * NULL means whiteout-ed or not-found. -+ */ -+static struct dentry* -+au_do_lookup(struct dentry *h_parent, struct dentry *dentry, -+ aufs_bindex_t bindex, struct qstr *wh_name, -+ struct au_do_lookup_args *args) -+{ -+ struct dentry *h_dentry; -+ struct inode *h_inode, *inode; -+ struct qstr *name; -+ struct au_branch *br; -+ int wh_found, opq; -+ unsigned char wh_able; -+ const unsigned char allow_neg = !!au_ftest_lkup(args->flags, ALLOW_NEG); -+ -+ name = &dentry->d_name; -+ wh_found = 0; -+ br = au_sbr(dentry->d_sb, bindex); -+ wh_able = !!au_br_whable(br->br_perm); -+ if (wh_able) -+ wh_found = au_wh_test(h_parent, wh_name, br, /*try_sio*/0); -+ h_dentry = ERR_PTR(wh_found); -+ if (!wh_found) -+ goto real_lookup; -+ if (unlikely(wh_found < 0)) -+ goto out; -+ -+ /* We found a whiteout */ -+ /* au_set_dbend(dentry, bindex); */ -+ au_set_dbwh(dentry, bindex); -+ if (!allow_neg) -+ return NULL; /* success */ -+ -+ real_lookup: -+ h_dentry = au_lkup_one(name, h_parent, br, args->nd); -+ if (IS_ERR(h_dentry)) -+ goto out; -+ -+ h_inode = h_dentry->d_inode; -+ if (!h_inode) { -+ if (!allow_neg) -+ goto out_neg; -+ } else if (wh_found -+ || (args->type && args->type != (h_inode->i_mode & S_IFMT))) -+ goto out_neg; -+ -+ if (au_dbend(dentry) <= bindex) -+ au_set_dbend(dentry, bindex); -+ if (au_dbstart(dentry) < 0 || bindex < au_dbstart(dentry)) -+ au_set_dbstart(dentry, bindex); -+ au_set_h_dptr(dentry, bindex, h_dentry); -+ -+ inode = dentry->d_inode; -+ if (!h_inode || !S_ISDIR(h_inode->i_mode) || !wh_able -+ || (inode && !S_ISDIR(inode->i_mode))) -+ goto out; /* success */ -+ -+ mutex_lock_nested(&h_inode->i_mutex, AuLsc_I_CHILD); -+ opq = au_diropq_test(h_dentry, br); -+ mutex_unlock(&h_inode->i_mutex); -+ if (opq > 0) -+ au_set_dbdiropq(dentry, bindex); -+ else if (unlikely(opq < 0)) { -+ au_set_h_dptr(dentry, bindex, NULL); -+ h_dentry = ERR_PTR(opq); -+ } -+ goto out; -+ -+ out_neg: -+ dput(h_dentry); -+ h_dentry = NULL; -+ out: -+ return h_dentry; -+} -+ -+static int au_test_shwh(struct super_block *sb, const struct qstr *name) -+{ -+ if (unlikely(!au_opt_test(au_mntflags(sb), SHWH) -+ && !strncmp(name->name, AUFS_WH_PFX, AUFS_WH_PFX_LEN))) -+ return -EPERM; -+ return 0; -+} -+ -+/* -+ * returns the number of lower positive dentries, -+ * otherwise an error. -+ * can be called at unlinking with @type is zero. -+ */ -+int au_lkup_dentry(struct dentry *dentry, aufs_bindex_t bstart, mode_t type, -+ struct nameidata *nd) -+{ -+ int npositive, err; -+ aufs_bindex_t bindex, btail, bdiropq; -+ unsigned char isdir; -+ struct qstr whname; -+ struct au_do_lookup_args args = { -+ .flags = 0, -+ .type = type, -+ .nd = nd -+ }; -+ const struct qstr *name = &dentry->d_name; -+ struct dentry *parent; -+ struct inode *inode; -+ -+ parent = dget_parent(dentry); -+ err = au_test_shwh(dentry->d_sb, name); -+ if (unlikely(err)) -+ goto out; -+ -+ err = au_wh_name_alloc(&whname, name); -+ if (unlikely(err)) -+ goto out; -+ -+ inode = dentry->d_inode; -+ isdir = !!(inode && S_ISDIR(inode->i_mode)); -+ if (!type) -+ au_fset_lkup(args.flags, ALLOW_NEG); -+ -+ npositive = 0; -+ btail = au_dbtaildir(parent); -+ for (bindex = bstart; bindex <= btail; bindex++) { -+ struct dentry *h_parent, *h_dentry; -+ struct inode *h_inode, *h_dir; -+ -+ h_dentry = au_h_dptr(dentry, bindex); -+ if (h_dentry) { -+ if (h_dentry->d_inode) -+ npositive++; -+ if (type != S_IFDIR) -+ break; -+ continue; -+ } -+ h_parent = au_h_dptr(parent, bindex); -+ if (!h_parent) -+ continue; -+ h_dir = h_parent->d_inode; -+ if (!h_dir || !S_ISDIR(h_dir->i_mode)) -+ continue; -+ -+ mutex_lock_nested(&h_dir->i_mutex, AuLsc_I_PARENT); -+ h_dentry = au_do_lookup(h_parent, dentry, bindex, &whname, -+ &args); -+ mutex_unlock(&h_dir->i_mutex); -+ err = PTR_ERR(h_dentry); -+ if (IS_ERR(h_dentry)) -+ goto out_wh; -+ au_fclr_lkup(args.flags, ALLOW_NEG); -+ -+ if (au_dbwh(dentry) >= 0) -+ break; -+ if (!h_dentry) -+ continue; -+ h_inode = h_dentry->d_inode; -+ if (!h_inode) -+ continue; -+ npositive++; -+ if (!args.type) -+ args.type = h_inode->i_mode & S_IFMT; -+ if (args.type != S_IFDIR) -+ break; -+ else if (isdir) { -+ /* the type of lower may be different */ -+ bdiropq = au_dbdiropq(dentry); -+ if (bdiropq >= 0 && bdiropq <= bindex) -+ break; -+ } -+ } -+ -+ if (npositive) { -+ AuLabel(positive); -+ au_update_dbstart(dentry); -+ } -+ err = npositive; -+ if (unlikely(!au_opt_test(au_mntflags(dentry->d_sb), UDBA_NONE) -+ && au_dbstart(dentry) < 0)) -+ /* both of real entry and whiteout found */ -+ err = -EIO; -+ -+ out_wh: -+ kfree(whname.name); -+ out: -+ dput(parent); -+ return err; -+} -+ -+struct dentry *au_sio_lkup_one(struct qstr *name, struct dentry *parent, -+ struct au_branch *br) -+{ -+ struct dentry *dentry; -+ int wkq_err; -+ -+ if (!au_test_h_perm_sio(parent->d_inode, MAY_EXEC)) -+ dentry = au_lkup_one(name, parent, br, /*nd*/NULL); -+ else { -+ struct au_lkup_one_args args = { -+ .errp = &dentry, -+ .name = name, -+ .h_parent = parent, -+ .br = br, -+ .nd = NULL -+ }; -+ -+ wkq_err = au_wkq_wait(au_call_lkup_one, &args); -+ if (unlikely(wkq_err)) -+ dentry = ERR_PTR(wkq_err); -+ } -+ -+ return dentry; -+} -+ -+/* -+ * lookup @dentry on @bindex which should be negative. -+ */ -+int au_lkup_neg(struct dentry *dentry, aufs_bindex_t bindex) -+{ -+ int err; -+ struct dentry *parent, *h_parent, *h_dentry; -+ struct qstr *name; -+ -+ name = &dentry->d_name; -+ parent = dget_parent(dentry); -+ h_parent = au_h_dptr(parent, bindex); -+ h_dentry = au_sio_lkup_one(name, h_parent, -+ au_sbr(dentry->d_sb, bindex)); -+ err = PTR_ERR(h_dentry); -+ if (IS_ERR(h_dentry)) -+ goto out; -+ if (unlikely(h_dentry->d_inode)) { -+ err = -EIO; -+ AuIOErr("b%d %.*s should be negative.\n", -+ bindex, AuDLNPair(h_dentry)); -+ dput(h_dentry); -+ goto out; -+ } -+ -+ if (bindex < au_dbstart(dentry)) -+ au_set_dbstart(dentry, bindex); -+ if (au_dbend(dentry) < bindex) -+ au_set_dbend(dentry, bindex); -+ au_set_h_dptr(dentry, bindex, h_dentry); -+ err = 0; -+ -+ out: -+ dput(parent); -+ return err; -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+/* subset of struct inode */ -+struct au_iattr { -+ unsigned long i_ino; -+ /* unsigned int i_nlink; */ -+ uid_t i_uid; -+ gid_t i_gid; -+ u64 i_version; -+/* -+ loff_t i_size; -+ blkcnt_t i_blocks; -+*/ -+ umode_t i_mode; -+}; -+ -+static void au_iattr_save(struct au_iattr *ia, struct inode *h_inode) -+{ -+ ia->i_ino = h_inode->i_ino; -+ /* ia->i_nlink = h_inode->i_nlink; */ -+ ia->i_uid = h_inode->i_uid; -+ ia->i_gid = h_inode->i_gid; -+ ia->i_version = h_inode->i_version; -+/* -+ ia->i_size = h_inode->i_size; -+ ia->i_blocks = h_inode->i_blocks; -+*/ -+ ia->i_mode = (h_inode->i_mode & S_IFMT); -+} -+ -+static int au_iattr_test(struct au_iattr *ia, struct inode *h_inode) -+{ -+ return ia->i_ino != h_inode->i_ino -+ /* || ia->i_nlink != h_inode->i_nlink */ -+ || ia->i_uid != h_inode->i_uid -+ || ia->i_gid != h_inode->i_gid -+ || ia->i_version != h_inode->i_version -+/* -+ || ia->i_size != h_inode->i_size -+ || ia->i_blocks != h_inode->i_blocks -+*/ -+ || ia->i_mode != (h_inode->i_mode & S_IFMT); -+} -+ -+static int au_h_verify_dentry(struct dentry *h_dentry, struct dentry *h_parent, -+ struct au_branch *br) -+{ -+ int err; -+ struct au_iattr ia; -+ struct inode *h_inode; -+ struct dentry *h_d; -+ struct super_block *h_sb; -+ -+ err = 0; -+ memset(&ia, -1, sizeof(ia)); -+ h_sb = h_dentry->d_sb; -+ h_inode = h_dentry->d_inode; -+ if (h_inode) -+ au_iattr_save(&ia, h_inode); -+ else if (au_test_nfs(h_sb) || au_test_fuse(h_sb)) -+ /* nfs d_revalidate may return 0 for negative dentry */ -+ /* fuse d_revalidate always return 0 for negative dentry */ -+ goto out; -+ -+ /* main purpose is namei.c:cached_lookup() and d_revalidate */ -+ h_d = au_lkup_one(&h_dentry->d_name, h_parent, br, /*nd*/NULL); -+ err = PTR_ERR(h_d); -+ if (IS_ERR(h_d)) -+ goto out; -+ -+ err = 0; -+ if (unlikely(h_d != h_dentry -+ || h_d->d_inode != h_inode -+ || (h_inode && au_iattr_test(&ia, h_inode)))) -+ err = au_busy_or_stale(); -+ dput(h_d); -+ -+ out: -+ AuTraceErr(err); -+ return err; -+} -+ -+int au_h_verify(struct dentry *h_dentry, unsigned int udba, struct inode *h_dir, -+ struct dentry *h_parent, struct au_branch *br) -+{ -+ int err; -+ -+ err = 0; -+ if (udba == AuOpt_UDBA_REVAL) { -+ IMustLock(h_dir); -+ err = (h_dentry->d_parent->d_inode != h_dir); -+ } else if (udba == AuOpt_UDBA_HINOTIFY) -+ err = au_h_verify_dentry(h_dentry, h_parent, br); -+ -+ return err; -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+static void au_do_refresh_hdentry(struct au_hdentry *p, struct au_dinfo *dinfo, -+ struct dentry *parent) -+{ -+ struct dentry *h_d, *h_dp; -+ struct au_hdentry tmp, *q; -+ struct super_block *sb; -+ aufs_bindex_t new_bindex, bindex, bend, bwh, bdiropq; -+ -+ AuRwMustWriteLock(&dinfo->di_rwsem); -+ -+ bend = dinfo->di_bend; -+ bwh = dinfo->di_bwh; -+ bdiropq = dinfo->di_bdiropq; -+ for (bindex = dinfo->di_bstart; bindex <= bend; bindex++, p++) { -+ h_d = p->hd_dentry; -+ if (!h_d) -+ continue; -+ -+ h_dp = dget_parent(h_d); -+ if (h_dp == au_h_dptr(parent, bindex)) { -+ dput(h_dp); -+ continue; -+ } -+ -+ new_bindex = au_find_dbindex(parent, h_dp); -+ dput(h_dp); -+ if (dinfo->di_bwh == bindex) -+ bwh = new_bindex; -+ if (dinfo->di_bdiropq == bindex) -+ bdiropq = new_bindex; -+ if (new_bindex < 0) { -+ au_hdput(p); -+ p->hd_dentry = NULL; -+ continue; -+ } -+ -+ /* swap two lower dentries, and loop again */ -+ q = dinfo->di_hdentry + new_bindex; -+ tmp = *q; -+ *q = *p; -+ *p = tmp; -+ if (tmp.hd_dentry) { -+ bindex--; -+ p--; -+ } -+ } -+ -+ sb = parent->d_sb; -+ dinfo->di_bwh = -1; -+ if (bwh >= 0 && bwh <= au_sbend(sb) && au_sbr_whable(sb, bwh)) -+ dinfo->di_bwh = bwh; -+ -+ dinfo->di_bdiropq = -1; -+ if (bdiropq >= 0 -+ && bdiropq <= au_sbend(sb) -+ && au_sbr_whable(sb, bdiropq)) -+ dinfo->di_bdiropq = bdiropq; -+ -+ bend = au_dbend(parent); -+ p = dinfo->di_hdentry; -+ for (bindex = 0; bindex <= bend; bindex++, p++) -+ if (p->hd_dentry) { -+ dinfo->di_bstart = bindex; -+ break; -+ } -+ -+ p = dinfo->di_hdentry + bend; -+ for (bindex = bend; bindex >= 0; bindex--, p--) -+ if (p->hd_dentry) { -+ dinfo->di_bend = bindex; -+ break; -+ } -+} -+ -+/* -+ * returns the number of found lower positive dentries, -+ * otherwise an error. -+ */ -+int au_refresh_hdentry(struct dentry *dentry, mode_t type) -+{ -+ int npositive, err; -+ unsigned int sigen; -+ aufs_bindex_t bstart; -+ struct au_dinfo *dinfo; -+ struct super_block *sb; -+ struct dentry *parent; -+ -+ DiMustWriteLock(dentry); -+ -+ sb = dentry->d_sb; -+ AuDebugOn(IS_ROOT(dentry)); -+ sigen = au_sigen(sb); -+ parent = dget_parent(dentry); -+ AuDebugOn(au_digen(parent) != sigen -+ || au_iigen(parent->d_inode) != sigen); -+ -+ dinfo = au_di(dentry); -+ err = au_di_realloc(dinfo, au_sbend(sb) + 1); -+ npositive = err; -+ if (unlikely(err)) -+ goto out; -+ au_do_refresh_hdentry(dinfo->di_hdentry + dinfo->di_bstart, dinfo, -+ parent); -+ -+ npositive = 0; -+ bstart = au_dbstart(parent); -+ if (type != S_IFDIR && dinfo->di_bstart == bstart) -+ goto out_dgen; /* success */ -+ -+ npositive = au_lkup_dentry(dentry, bstart, type, /*nd*/NULL); -+ if (npositive < 0) -+ goto out; -+ if (dinfo->di_bwh >= 0 && dinfo->di_bwh <= dinfo->di_bstart) -+ d_drop(dentry); -+ -+ out_dgen: -+ au_update_digen(dentry); -+ out: -+ dput(parent); -+ AuTraceErr(npositive); -+ return npositive; -+} -+ -+static noinline_for_stack -+int au_do_h_d_reval(struct dentry *h_dentry, struct nameidata *nd, -+ struct dentry *dentry, aufs_bindex_t bindex) -+{ -+ int err, valid; -+ int (*reval)(struct dentry *, struct nameidata *); -+ -+ err = 0; -+ reval = NULL; -+ if (h_dentry->d_op) -+ reval = h_dentry->d_op->d_revalidate; -+ if (!reval) -+ goto out; -+ -+ AuDbg("b%d\n", bindex); -+ if (au_test_fs_null_nd(h_dentry->d_sb)) -+ /* it may return tri-state */ -+ valid = reval(h_dentry, NULL); -+ else { -+ struct nameidata h_nd; -+ int locked; -+ struct dentry *parent; -+ -+ au_h_nd(&h_nd, nd); -+ parent = nd->path.dentry; -+ locked = (nd && nd->path.dentry != dentry); -+ if (locked) -+ di_read_lock_parent(parent, AuLock_IR); -+ BUG_ON(bindex > au_dbend(parent)); -+ h_nd.path.dentry = au_h_dptr(parent, bindex); -+ BUG_ON(!h_nd.path.dentry); -+ h_nd.path.mnt = au_sbr(parent->d_sb, bindex)->br_mnt; -+ path_get(&h_nd.path); -+ valid = reval(h_dentry, &h_nd); -+ path_put(&h_nd.path); -+ if (locked) -+ di_read_unlock(parent, AuLock_IR); -+ } -+ -+ if (unlikely(valid < 0)) -+ err = valid; -+ else if (!valid) -+ err = -EINVAL; -+ -+ out: -+ AuTraceErr(err); -+ return err; -+} -+ -+/* todo: remove this */ -+static int h_d_revalidate(struct dentry *dentry, struct inode *inode, -+ struct nameidata *nd, int do_udba) -+{ -+ int err; -+ umode_t mode, h_mode; -+ aufs_bindex_t bindex, btail, bstart, ibs, ibe; -+ unsigned char plus, unhashed, is_root, h_plus; -+ struct inode *first, *h_inode, *h_cached_inode; -+ struct dentry *h_dentry; -+ struct qstr *name, *h_name; -+ -+ err = 0; -+ plus = 0; -+ mode = 0; -+ first = NULL; -+ ibs = -1; -+ ibe = -1; -+ unhashed = !!d_unhashed(dentry); -+ is_root = !!IS_ROOT(dentry); -+ name = &dentry->d_name; -+ -+ /* -+ * Theoretically, REVAL test should be unnecessary in case of INOTIFY. -+ * But inotify doesn't fire some necessary events, -+ * IN_ATTRIB for atime/nlink/pageio -+ * IN_DELETE for NFS dentry -+ * Let's do REVAL test too. -+ */ -+ if (do_udba && inode) { -+ mode = (inode->i_mode & S_IFMT); -+ plus = (inode->i_nlink > 0); -+ first = au_h_iptr(inode, au_ibstart(inode)); -+ ibs = au_ibstart(inode); -+ ibe = au_ibend(inode); -+ } -+ -+ bstart = au_dbstart(dentry); -+ btail = bstart; -+ if (inode && S_ISDIR(inode->i_mode)) -+ btail = au_dbtaildir(dentry); -+ for (bindex = bstart; bindex <= btail; bindex++) { -+ h_dentry = au_h_dptr(dentry, bindex); -+ if (!h_dentry) -+ continue; -+ -+ AuDbg("b%d, %.*s\n", bindex, AuDLNPair(h_dentry)); -+ h_name = &h_dentry->d_name; -+ if (unlikely(do_udba -+ && !is_root -+ && (unhashed != !!d_unhashed(h_dentry) -+ || name->len != h_name->len -+ || memcmp(name->name, h_name->name, name->len)) -+ )) { -+ AuDbg("unhash 0x%x 0x%x, %.*s %.*s\n", -+ unhashed, d_unhashed(h_dentry), -+ AuDLNPair(dentry), AuDLNPair(h_dentry)); -+ goto err; -+ } -+ -+ err = au_do_h_d_reval(h_dentry, nd, dentry, bindex); -+ if (unlikely(err)) -+ /* do not goto err, to keep the errno */ -+ break; -+ -+ /* todo: plink too? */ -+ if (!do_udba) -+ continue; -+ -+ /* UDBA tests */ -+ h_inode = h_dentry->d_inode; -+ if (unlikely(!!inode != !!h_inode)) -+ goto err; -+ -+ h_plus = plus; -+ h_mode = mode; -+ h_cached_inode = h_inode; -+ if (h_inode) { -+ h_mode = (h_inode->i_mode & S_IFMT); -+ h_plus = (h_inode->i_nlink > 0); -+ } -+ if (inode && ibs <= bindex && bindex <= ibe) -+ h_cached_inode = au_h_iptr(inode, bindex); -+ -+ if (unlikely(plus != h_plus -+ || mode != h_mode -+ || h_cached_inode != h_inode)) -+ goto err; -+ continue; -+ -+ err: -+ err = -EINVAL; -+ break; -+ } -+ -+ return err; -+} -+ -+static int simple_reval_dpath(struct dentry *dentry, unsigned int sigen) -+{ -+ int err; -+ struct dentry *parent; -+ struct inode *inode; -+ -+ inode = dentry->d_inode; -+ if (au_digen(dentry) == sigen && au_iigen(inode) == sigen) -+ return 0; -+ -+ parent = dget_parent(dentry); -+ di_read_lock_parent(parent, AuLock_IR); -+ AuDebugOn(au_digen(parent) != sigen -+ || au_iigen(parent->d_inode) != sigen); -+ au_dbg_verify_gen(parent, sigen); -+ -+ /* returns a number of positive dentries */ -+ err = au_refresh_hdentry(dentry, inode->i_mode & S_IFMT); -+ if (err >= 0) -+ err = au_refresh_hinode(inode, dentry); -+ -+ di_read_unlock(parent, AuLock_IR); -+ dput(parent); -+ return err; -+} -+ -+int au_reval_dpath(struct dentry *dentry, unsigned int sigen) -+{ -+ int err; -+ struct dentry *d, *parent; -+ struct inode *inode; -+ -+ if (!au_ftest_si(au_sbi(dentry->d_sb), FAILED_REFRESH_DIRS)) -+ return simple_reval_dpath(dentry, sigen); -+ -+ /* slow loop, keep it simple and stupid */ -+ /* cf: au_cpup_dirs() */ -+ err = 0; -+ parent = NULL; -+ while (au_digen(dentry) != sigen -+ || au_iigen(dentry->d_inode) != sigen) { -+ d = dentry; -+ while (1) { -+ dput(parent); -+ parent = dget_parent(d); -+ if (au_digen(parent) == sigen -+ && au_iigen(parent->d_inode) == sigen) -+ break; -+ d = parent; -+ } -+ -+ inode = d->d_inode; -+ if (d != dentry) -+ di_write_lock_child(d); -+ -+ /* someone might update our dentry while we were sleeping */ -+ if (au_digen(d) != sigen || au_iigen(d->d_inode) != sigen) { -+ di_read_lock_parent(parent, AuLock_IR); -+ /* returns a number of positive dentries */ -+ err = au_refresh_hdentry(d, inode->i_mode & S_IFMT); -+ if (err >= 0) -+ err = au_refresh_hinode(inode, d); -+ di_read_unlock(parent, AuLock_IR); -+ } -+ -+ if (d != dentry) -+ di_write_unlock(d); -+ dput(parent); -+ if (unlikely(err)) -+ break; -+ } -+ -+ return err; -+} -+ -+/* -+ * if valid returns 1, otherwise 0. -+ */ -+static int aufs_d_revalidate(struct dentry *dentry, struct nameidata *nd) -+{ -+ int valid, err; -+ unsigned int sigen; -+ unsigned char do_udba; -+ struct super_block *sb; -+ struct inode *inode; -+ -+ err = -EINVAL; -+ sb = dentry->d_sb; -+ inode = dentry->d_inode; -+ aufs_read_lock(dentry, AuLock_FLUSH | AuLock_DW); -+ sigen = au_sigen(sb); -+ if (au_digen(dentry) != sigen) { -+ AuDebugOn(IS_ROOT(dentry)); -+ if (inode) -+ err = au_reval_dpath(dentry, sigen); -+ if (unlikely(err)) -+ goto out_dgrade; -+ AuDebugOn(au_digen(dentry) != sigen); -+ } -+ if (inode && au_iigen(inode) != sigen) { -+ AuDebugOn(IS_ROOT(dentry)); -+ err = au_refresh_hinode(inode, dentry); -+ if (unlikely(err)) -+ goto out_dgrade; -+ AuDebugOn(au_iigen(inode) != sigen); -+ } -+ di_downgrade_lock(dentry, AuLock_IR); -+ -+ AuDebugOn(au_digen(dentry) != sigen); -+ AuDebugOn(inode && au_iigen(inode) != sigen); -+ err = -EINVAL; -+ do_udba = !au_opt_test(au_mntflags(sb), UDBA_NONE); -+ if (do_udba && inode) { -+ aufs_bindex_t bstart = au_ibstart(inode); -+ -+ if (bstart >= 0 -+ && au_test_higen(inode, au_h_iptr(inode, bstart))) -+ goto out; -+ } -+ -+ err = h_d_revalidate(dentry, inode, nd, do_udba); -+ if (unlikely(!err && do_udba && au_dbstart(dentry) < 0)) -+ /* both of real entry and whiteout found */ -+ err = -EIO; -+ goto out; -+ -+ out_dgrade: -+ di_downgrade_lock(dentry, AuLock_IR); -+ out: -+ aufs_read_unlock(dentry, AuLock_IR); -+ AuTraceErr(err); -+ valid = !err; -+ if (!valid) -+ AuDbg("%.*s invalid\n", AuDLNPair(dentry)); -+ return valid; -+} -+ -+static void aufs_d_release(struct dentry *dentry) -+{ -+ struct au_dinfo *dinfo; -+ aufs_bindex_t bend, bindex; -+ -+ dinfo = dentry->d_fsdata; -+ if (!dinfo) -+ return; -+ -+ /* dentry may not be revalidated */ -+ bindex = dinfo->di_bstart; -+ if (bindex >= 0) { -+ struct au_hdentry *p; -+ -+ bend = dinfo->di_bend; -+ p = dinfo->di_hdentry + bindex; -+ while (bindex++ <= bend) { -+ if (p->hd_dentry) -+ au_hdput(p); -+ p++; -+ } -+ } -+ kfree(dinfo->di_hdentry); -+ AuRwDestroy(&dinfo->di_rwsem); -+ au_cache_free_dinfo(dinfo); -+ au_hin_di_reinit(dentry); -+} -+ -+struct dentry_operations aufs_dop = { -+ .d_revalidate = aufs_d_revalidate, -+ .d_release = aufs_d_release -+}; -diff --git a/fs/aufs/dentry.h b/fs/aufs/dentry.h -new file mode 100644 -index 0000000..b1f9a6e ---- /dev/null -+++ b/fs/aufs/dentry.h -@@ -0,0 +1,231 @@ -+/* -+ * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * -+ * This program, aufs is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ */ -+ -+/* -+ * lookup and dentry operations -+ */ -+ -+#ifndef __AUFS_DENTRY_H__ -+#define __AUFS_DENTRY_H__ -+ -+#ifdef __KERNEL__ -+ -+#include -+#include -+#include "rwsem.h" -+ -+/* make a single member structure for future use */ -+/* todo: remove this structure */ -+struct au_hdentry { -+ struct dentry *hd_dentry; -+}; -+ -+struct au_dinfo { -+ atomic_t di_generation; -+ -+ struct au_rwsem di_rwsem; -+ aufs_bindex_t di_bstart, di_bend, di_bwh, di_bdiropq; -+ struct au_hdentry *di_hdentry; -+}; -+ -+/* ---------------------------------------------------------------------- */ -+ -+/* dentry.c */ -+extern struct dentry_operations aufs_dop; -+struct au_branch; -+struct dentry *au_lkup_one(struct qstr *name, struct dentry *h_parent, -+ struct au_branch *br, struct nameidata *nd); -+struct dentry *au_sio_lkup_one(struct qstr *name, struct dentry *parent, -+ struct au_branch *br); -+int au_h_verify(struct dentry *h_dentry, unsigned int udba, struct inode *h_dir, -+ struct dentry *h_parent, struct au_branch *br); -+ -+int au_lkup_dentry(struct dentry *dentry, aufs_bindex_t bstart, mode_t type, -+ struct nameidata *nd); -+int au_lkup_neg(struct dentry *dentry, aufs_bindex_t bindex); -+int au_refresh_hdentry(struct dentry *dentry, mode_t type); -+int au_reval_dpath(struct dentry *dentry, unsigned int sigen); -+ -+/* dinfo.c */ -+int au_alloc_dinfo(struct dentry *dentry); -+int au_di_realloc(struct au_dinfo *dinfo, int nbr); -+ -+void di_read_lock(struct dentry *d, int flags, unsigned int lsc); -+void di_read_unlock(struct dentry *d, int flags); -+void di_downgrade_lock(struct dentry *d, int flags); -+void di_write_lock(struct dentry *d, unsigned int lsc); -+void di_write_unlock(struct dentry *d); -+void di_write_lock2_child(struct dentry *d1, struct dentry *d2, int isdir); -+void di_write_lock2_parent(struct dentry *d1, struct dentry *d2, int isdir); -+void di_write_unlock2(struct dentry *d1, struct dentry *d2); -+ -+struct dentry *au_h_dptr(struct dentry *dentry, aufs_bindex_t bindex); -+aufs_bindex_t au_dbtail(struct dentry *dentry); -+aufs_bindex_t au_dbtaildir(struct dentry *dentry); -+ -+void au_set_h_dptr(struct dentry *dentry, aufs_bindex_t bindex, -+ struct dentry *h_dentry); -+void au_update_digen(struct dentry *dentry); -+void au_update_dbrange(struct dentry *dentry, int do_put_zero); -+void au_update_dbstart(struct dentry *dentry); -+void au_update_dbend(struct dentry *dentry); -+int au_find_dbindex(struct dentry *dentry, struct dentry *h_dentry); -+ -+/* ---------------------------------------------------------------------- */ -+ -+static inline struct au_dinfo *au_di(struct dentry *dentry) -+{ -+ return dentry->d_fsdata; -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+/* lock subclass for dinfo */ -+enum { -+ AuLsc_DI_CHILD, /* child first */ -+ AuLsc_DI_CHILD2, /* rename(2), link(2), and cpup at hinotify */ -+ AuLsc_DI_CHILD3, /* copyup dirs */ -+ AuLsc_DI_PARENT, -+ AuLsc_DI_PARENT2, -+ AuLsc_DI_PARENT3 -+}; -+ -+/* -+ * di_read_lock_child, di_write_lock_child, -+ * di_read_lock_child2, di_write_lock_child2, -+ * di_read_lock_child3, di_write_lock_child3, -+ * di_read_lock_parent, di_write_lock_parent, -+ * di_read_lock_parent2, di_write_lock_parent2, -+ * di_read_lock_parent3, di_write_lock_parent3, -+ */ -+#define AuReadLockFunc(name, lsc) \ -+static inline void di_read_lock_##name(struct dentry *d, int flags) \ -+{ di_read_lock(d, flags, AuLsc_DI_##lsc); } -+ -+#define AuWriteLockFunc(name, lsc) \ -+static inline void di_write_lock_##name(struct dentry *d) \ -+{ di_write_lock(d, AuLsc_DI_##lsc); } -+ -+#define AuRWLockFuncs(name, lsc) \ -+ AuReadLockFunc(name, lsc) \ -+ AuWriteLockFunc(name, lsc) -+ -+AuRWLockFuncs(child, CHILD); -+AuRWLockFuncs(child2, CHILD2); -+AuRWLockFuncs(child3, CHILD3); -+AuRWLockFuncs(parent, PARENT); -+AuRWLockFuncs(parent2, PARENT2); -+AuRWLockFuncs(parent3, PARENT3); -+ -+#undef AuReadLockFunc -+#undef AuWriteLockFunc -+#undef AuRWLockFuncs -+ -+#define DiMustNoWaiters(d) AuRwMustNoWaiters(&au_di(d)->di_rwsem) -+#define DiMustAnyLock(d) AuRwMustAnyLock(&au_di(d)->di_rwsem) -+#define DiMustWriteLock(d) AuRwMustWriteLock(&au_di(d)->di_rwsem) -+ -+/* ---------------------------------------------------------------------- */ -+ -+/* todo: memory barrier? */ -+static inline unsigned int au_digen(struct dentry *d) -+{ -+ return atomic_read(&au_di(d)->di_generation); -+} -+ -+static inline void au_h_dentry_init(struct au_hdentry *hdentry) -+{ -+ hdentry->hd_dentry = NULL; -+} -+ -+static inline void au_hdput(struct au_hdentry *hd) -+{ -+ dput(hd->hd_dentry); -+} -+ -+static inline aufs_bindex_t au_dbstart(struct dentry *dentry) -+{ -+ DiMustAnyLock(dentry); -+ return au_di(dentry)->di_bstart; -+} -+ -+static inline aufs_bindex_t au_dbend(struct dentry *dentry) -+{ -+ DiMustAnyLock(dentry); -+ return au_di(dentry)->di_bend; -+} -+ -+static inline aufs_bindex_t au_dbwh(struct dentry *dentry) -+{ -+ DiMustAnyLock(dentry); -+ return au_di(dentry)->di_bwh; -+} -+ -+static inline aufs_bindex_t au_dbdiropq(struct dentry *dentry) -+{ -+ DiMustAnyLock(dentry); -+ return au_di(dentry)->di_bdiropq; -+} -+ -+/* todo: hard/soft set? */ -+static inline void au_set_dbstart(struct dentry *dentry, aufs_bindex_t bindex) -+{ -+ DiMustWriteLock(dentry); -+ au_di(dentry)->di_bstart = bindex; -+} -+ -+static inline void au_set_dbend(struct dentry *dentry, aufs_bindex_t bindex) -+{ -+ DiMustWriteLock(dentry); -+ au_di(dentry)->di_bend = bindex; -+} -+ -+static inline void au_set_dbwh(struct dentry *dentry, aufs_bindex_t bindex) -+{ -+ DiMustWriteLock(dentry); -+ /* dbwh can be outside of bstart - bend range */ -+ au_di(dentry)->di_bwh = bindex; -+} -+ -+static inline void au_set_dbdiropq(struct dentry *dentry, aufs_bindex_t bindex) -+{ -+ DiMustWriteLock(dentry); -+ au_di(dentry)->di_bdiropq = bindex; -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+#ifdef CONFIG_AUFS_HINOTIFY -+static inline void au_digen_dec(struct dentry *d) -+{ -+ atomic_dec_return(&au_di(d)->di_generation); -+} -+ -+static inline void au_hin_di_reinit(struct dentry *dentry) -+{ -+ dentry->d_fsdata = NULL; -+} -+#else -+static inline void au_hin_di_reinit(struct dentry *dentry __maybe_unused) -+{ -+ /* empty */ -+} -+#endif /* CONFIG_AUFS_HINOTIFY */ -+ -+#endif /* __KERNEL__ */ -+#endif /* __AUFS_DENTRY_H__ */ -diff --git a/fs/aufs/dinfo.c b/fs/aufs/dinfo.c -new file mode 100644 -index 0000000..0010c99 ---- /dev/null -+++ b/fs/aufs/dinfo.c -@@ -0,0 +1,367 @@ -+/* -+ * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * -+ * This program, aufs is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ */ -+ -+/* -+ * dentry private data -+ */ -+ -+#include "aufs.h" -+ -+int au_alloc_dinfo(struct dentry *dentry) -+{ -+ struct au_dinfo *dinfo; -+ struct super_block *sb; -+ int nbr; -+ -+ dinfo = au_cache_alloc_dinfo(); -+ if (unlikely(!dinfo)) -+ goto out; -+ -+ sb = dentry->d_sb; -+ nbr = au_sbend(sb) + 1; -+ if (nbr <= 0) -+ nbr = 1; -+ dinfo->di_hdentry = kcalloc(nbr, sizeof(*dinfo->di_hdentry), GFP_NOFS); -+ if (unlikely(!dinfo->di_hdentry)) -+ goto out_dinfo; -+ -+ atomic_set(&dinfo->di_generation, au_sigen(sb)); -+ /* smp_mb(); */ /* atomic_set */ -+ au_rw_init_wlock_nested(&dinfo->di_rwsem, AuLsc_DI_CHILD); -+ dinfo->di_bstart = -1; -+ dinfo->di_bend = -1; -+ dinfo->di_bwh = -1; -+ dinfo->di_bdiropq = -1; -+ -+ dentry->d_fsdata = dinfo; -+ dentry->d_op = &aufs_dop; -+ return 0; /* success */ -+ -+ out_dinfo: -+ au_cache_free_dinfo(dinfo); -+ out: -+ return -ENOMEM; -+} -+ -+int au_di_realloc(struct au_dinfo *dinfo, int nbr) -+{ -+ int err, sz; -+ struct au_hdentry *hdp; -+ -+ AuRwMustWriteLock(&dinfo->di_rwsem); -+ -+ err = -ENOMEM; -+ sz = sizeof(*hdp) * (dinfo->di_bend + 1); -+ if (!sz) -+ sz = sizeof(*hdp); -+ hdp = au_kzrealloc(dinfo->di_hdentry, sz, sizeof(*hdp) * nbr, GFP_NOFS); -+ if (hdp) { -+ dinfo->di_hdentry = hdp; -+ err = 0; -+ } -+ -+ return err; -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+static void do_ii_write_lock(struct inode *inode, unsigned int lsc) -+{ -+ switch (lsc) { -+ case AuLsc_DI_CHILD: -+ ii_write_lock_child(inode); -+ break; -+ case AuLsc_DI_CHILD2: -+ ii_write_lock_child2(inode); -+ break; -+ case AuLsc_DI_CHILD3: -+ ii_write_lock_child3(inode); -+ break; -+ case AuLsc_DI_PARENT: -+ ii_write_lock_parent(inode); -+ break; -+ case AuLsc_DI_PARENT2: -+ ii_write_lock_parent2(inode); -+ break; -+ case AuLsc_DI_PARENT3: -+ ii_write_lock_parent3(inode); -+ break; -+ default: -+ BUG(); -+ } -+} -+ -+static void do_ii_read_lock(struct inode *inode, unsigned int lsc) -+{ -+ switch (lsc) { -+ case AuLsc_DI_CHILD: -+ ii_read_lock_child(inode); -+ break; -+ case AuLsc_DI_CHILD2: -+ ii_read_lock_child2(inode); -+ break; -+ case AuLsc_DI_CHILD3: -+ ii_read_lock_child3(inode); -+ break; -+ case AuLsc_DI_PARENT: -+ ii_read_lock_parent(inode); -+ break; -+ case AuLsc_DI_PARENT2: -+ ii_read_lock_parent2(inode); -+ break; -+ case AuLsc_DI_PARENT3: -+ ii_read_lock_parent3(inode); -+ break; -+ default: -+ BUG(); -+ } -+} -+ -+void di_read_lock(struct dentry *d, int flags, unsigned int lsc) -+{ -+ au_rw_read_lock_nested(&au_di(d)->di_rwsem, lsc); -+ if (d->d_inode) { -+ if (au_ftest_lock(flags, IW)) -+ do_ii_write_lock(d->d_inode, lsc); -+ else if (au_ftest_lock(flags, IR)) -+ do_ii_read_lock(d->d_inode, lsc); -+ } -+} -+ -+void di_read_unlock(struct dentry *d, int flags) -+{ -+ if (d->d_inode) { -+ if (au_ftest_lock(flags, IW)) -+ ii_write_unlock(d->d_inode); -+ else if (au_ftest_lock(flags, IR)) -+ ii_read_unlock(d->d_inode); -+ } -+ au_rw_read_unlock(&au_di(d)->di_rwsem); -+} -+ -+void di_downgrade_lock(struct dentry *d, int flags) -+{ -+ if (d->d_inode && au_ftest_lock(flags, IR)) -+ ii_downgrade_lock(d->d_inode); -+ au_rw_dgrade_lock(&au_di(d)->di_rwsem); -+} -+ -+void di_write_lock(struct dentry *d, unsigned int lsc) -+{ -+ au_rw_write_lock_nested(&au_di(d)->di_rwsem, lsc); -+ if (d->d_inode) -+ do_ii_write_lock(d->d_inode, lsc); -+} -+ -+void di_write_unlock(struct dentry *d) -+{ -+ if (d->d_inode) -+ ii_write_unlock(d->d_inode); -+ au_rw_write_unlock(&au_di(d)->di_rwsem); -+} -+ -+void di_write_lock2_child(struct dentry *d1, struct dentry *d2, int isdir) -+{ -+ AuDebugOn(d1 == d2 -+ || d1->d_inode == d2->d_inode -+ || d1->d_sb != d2->d_sb); -+ -+ if (isdir && au_test_subdir(d1, d2)) { -+ di_write_lock_child(d1); -+ di_write_lock_child2(d2); -+ } else { -+ /* there should be no races */ -+ di_write_lock_child(d2); -+ di_write_lock_child2(d1); -+ } -+} -+ -+void di_write_lock2_parent(struct dentry *d1, struct dentry *d2, int isdir) -+{ -+ AuDebugOn(d1 == d2 -+ || d1->d_inode == d2->d_inode -+ || d1->d_sb != d2->d_sb); -+ -+ if (isdir && au_test_subdir(d1, d2)) { -+ di_write_lock_parent(d1); -+ di_write_lock_parent2(d2); -+ } else { -+ /* there should be no races */ -+ di_write_lock_parent(d2); -+ di_write_lock_parent2(d1); -+ } -+} -+ -+void di_write_unlock2(struct dentry *d1, struct dentry *d2) -+{ -+ di_write_unlock(d1); -+ if (d1->d_inode == d2->d_inode) -+ au_rw_write_unlock(&au_di(d2)->di_rwsem); -+ else -+ di_write_unlock(d2); -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+struct dentry *au_h_dptr(struct dentry *dentry, aufs_bindex_t bindex) -+{ -+ struct dentry *d; -+ -+ DiMustAnyLock(dentry); -+ -+ if (au_dbstart(dentry) < 0 || bindex < au_dbstart(dentry)) -+ return NULL; -+ AuDebugOn(bindex < 0); -+ d = au_di(dentry)->di_hdentry[0 + bindex].hd_dentry; -+ AuDebugOn(d && (atomic_read(&d->d_count) <= 0)); -+ return d; -+} -+ -+aufs_bindex_t au_dbtail(struct dentry *dentry) -+{ -+ aufs_bindex_t bend, bwh; -+ -+ bend = au_dbend(dentry); -+ if (0 <= bend) { -+ bwh = au_dbwh(dentry); -+ if (!bwh) -+ return bwh; -+ if (0 < bwh && bwh < bend) -+ return bwh - 1; -+ } -+ return bend; -+} -+ -+aufs_bindex_t au_dbtaildir(struct dentry *dentry) -+{ -+ aufs_bindex_t bend, bopq; -+ -+ bend = au_dbtail(dentry); -+ if (0 <= bend) { -+ bopq = au_dbdiropq(dentry); -+ if (0 <= bopq && bopq < bend) -+ bend = bopq; -+ } -+ return bend; -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+void au_set_h_dptr(struct dentry *dentry, aufs_bindex_t bindex, -+ struct dentry *h_dentry) -+{ -+ struct au_hdentry *hd = au_di(dentry)->di_hdentry + bindex; -+ -+ DiMustWriteLock(dentry); -+ -+ if (hd->hd_dentry) -+ au_hdput(hd); -+ hd->hd_dentry = h_dentry; -+} -+ -+void au_update_digen(struct dentry *dentry) -+{ -+ atomic_set(&au_di(dentry)->di_generation, au_sigen(dentry->d_sb)); -+ /* smp_mb(); */ /* atomic_set */ -+} -+ -+void au_update_dbrange(struct dentry *dentry, int do_put_zero) -+{ -+ struct au_dinfo *dinfo; -+ struct dentry *h_d; -+ -+ DiMustWriteLock(dentry); -+ -+ dinfo = au_di(dentry); -+ if (!dinfo || dinfo->di_bstart < 0) -+ return; -+ -+ if (do_put_zero) { -+ aufs_bindex_t bindex, bend; -+ -+ bend = dinfo->di_bend; -+ for (bindex = dinfo->di_bstart; bindex <= bend; bindex++) { -+ h_d = dinfo->di_hdentry[0 + bindex].hd_dentry; -+ if (h_d && !h_d->d_inode) -+ au_set_h_dptr(dentry, bindex, NULL); -+ } -+ } -+ -+ dinfo->di_bstart = -1; -+ while (++dinfo->di_bstart <= dinfo->di_bend) -+ if (dinfo->di_hdentry[0 + dinfo->di_bstart].hd_dentry) -+ break; -+ if (dinfo->di_bstart > dinfo->di_bend) { -+ dinfo->di_bstart = -1; -+ dinfo->di_bend = -1; -+ return; -+ } -+ -+ dinfo->di_bend++; -+ while (0 <= --dinfo->di_bend) -+ if (dinfo->di_hdentry[0 + dinfo->di_bend].hd_dentry) -+ break; -+ AuDebugOn(dinfo->di_bstart > dinfo->di_bend || dinfo->di_bend < 0); -+} -+ -+void au_update_dbstart(struct dentry *dentry) -+{ -+ aufs_bindex_t bindex, bend; -+ struct dentry *h_dentry; -+ -+ bend = au_dbend(dentry); -+ for (bindex = au_dbstart(dentry); bindex <= bend; bindex++) { -+ h_dentry = au_h_dptr(dentry, bindex); -+ if (!h_dentry) -+ continue; -+ if (h_dentry->d_inode) { -+ au_set_dbstart(dentry, bindex); -+ return; -+ } -+ au_set_h_dptr(dentry, bindex, NULL); -+ } -+} -+ -+void au_update_dbend(struct dentry *dentry) -+{ -+ aufs_bindex_t bindex, bstart; -+ struct dentry *h_dentry; -+ -+ bstart = au_dbstart(dentry); -+ for (bindex = au_dbend(dentry); bindex <= bstart; bindex--) { -+ h_dentry = au_h_dptr(dentry, bindex); -+ if (!h_dentry) -+ continue; -+ if (h_dentry->d_inode) { -+ au_set_dbend(dentry, bindex); -+ return; -+ } -+ au_set_h_dptr(dentry, bindex, NULL); -+ } -+} -+ -+int au_find_dbindex(struct dentry *dentry, struct dentry *h_dentry) -+{ -+ aufs_bindex_t bindex, bend; -+ -+ bend = au_dbend(dentry); -+ for (bindex = au_dbstart(dentry); bindex <= bend; bindex++) -+ if (au_h_dptr(dentry, bindex) == h_dentry) -+ return bindex; -+ return -1; -+} -diff --git a/fs/aufs/dir.c b/fs/aufs/dir.c -new file mode 100644 -index 0000000..bb0eb64 ---- /dev/null -+++ b/fs/aufs/dir.c -@@ -0,0 +1,593 @@ -+/* -+ * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * -+ * This program, aufs is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ */ -+ -+/* -+ * directory operations -+ */ -+ -+#include -+#include -+#include "aufs.h" -+ -+void au_add_nlink(struct inode *dir, struct inode *h_dir) -+{ -+ AuDebugOn(!S_ISDIR(dir->i_mode) || !S_ISDIR(h_dir->i_mode)); -+ -+ dir->i_nlink += h_dir->i_nlink - 2; -+ if (h_dir->i_nlink < 2) -+ dir->i_nlink += 2; -+} -+ -+void au_sub_nlink(struct inode *dir, struct inode *h_dir) -+{ -+ AuDebugOn(!S_ISDIR(dir->i_mode) || !S_ISDIR(h_dir->i_mode)); -+ -+ dir->i_nlink -= h_dir->i_nlink - 2; -+ if (h_dir->i_nlink < 2) -+ dir->i_nlink -= 2; -+} -+ -+loff_t au_dir_size(struct file *file, struct dentry *dentry) -+{ -+ loff_t sz; -+ aufs_bindex_t bindex, bend; -+ struct file *h_file; -+ struct dentry *h_dentry; -+ -+ sz = 0; -+ if (file) { -+ AuDebugOn(!file->f_dentry); -+ AuDebugOn(!file->f_dentry->d_inode); -+ AuDebugOn(!S_ISDIR(file->f_dentry->d_inode->i_mode)); -+ -+ bend = au_fbend(file); -+ for (bindex = au_fbstart(file); -+ bindex <= bend && sz < KMALLOC_MAX_SIZE; -+ bindex++) { -+ h_file = au_h_fptr(file, bindex); -+ if (h_file -+ && h_file->f_dentry -+ && h_file->f_dentry->d_inode) -+ sz += i_size_read(h_file->f_dentry->d_inode); -+ } -+ } else { -+ AuDebugOn(!dentry); -+ AuDebugOn(!dentry->d_inode); -+ AuDebugOn(!S_ISDIR(dentry->d_inode->i_mode)); -+ -+ bend = au_dbtaildir(dentry); -+ for (bindex = au_dbstart(dentry); -+ bindex <= bend && sz < KMALLOC_MAX_SIZE; -+ bindex++) { -+ h_dentry = au_h_dptr(dentry, bindex); -+ if (h_dentry && h_dentry->d_inode) -+ sz += i_size_read(h_dentry->d_inode); -+ } -+ } -+ if (sz < KMALLOC_MAX_SIZE) -+ sz = roundup_pow_of_two(sz); -+ if (sz > KMALLOC_MAX_SIZE) -+ sz = KMALLOC_MAX_SIZE; -+ else if (sz < NAME_MAX) { -+ BUILD_BUG_ON(AUFS_RDBLK_DEF < NAME_MAX); -+ sz = AUFS_RDBLK_DEF; -+ } -+ return sz; -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+static int reopen_dir(struct file *file) -+{ -+ int err; -+ unsigned int flags; -+ aufs_bindex_t bindex, btail, bstart; -+ struct dentry *dentry, *h_dentry; -+ struct file *h_file; -+ -+ /* open all lower dirs */ -+ dentry = file->f_dentry; -+ bstart = au_dbstart(dentry); -+ for (bindex = au_fbstart(file); bindex < bstart; bindex++) -+ au_set_h_fptr(file, bindex, NULL); -+ au_set_fbstart(file, bstart); -+ -+ btail = au_dbtaildir(dentry); -+ for (bindex = au_fbend(file); btail < bindex; bindex--) -+ au_set_h_fptr(file, bindex, NULL); -+ au_set_fbend(file, btail); -+ -+ spin_lock(&file->f_lock); -+ flags = file->f_flags; -+ spin_unlock(&file->f_lock); -+ for (bindex = bstart; bindex <= btail; bindex++) { -+ h_dentry = au_h_dptr(dentry, bindex); -+ if (!h_dentry) -+ continue; -+ h_file = au_h_fptr(file, bindex); -+ if (h_file) -+ continue; -+ -+ h_file = au_h_open(dentry, bindex, flags, file); -+ err = PTR_ERR(h_file); -+ if (IS_ERR(h_file)) -+ goto out; /* close all? */ -+ au_set_h_fptr(file, bindex, h_file); -+ } -+ au_update_figen(file); -+ /* todo: necessary? */ -+ /* file->f_ra = h_file->f_ra; */ -+ err = 0; -+ -+ out: -+ return err; -+} -+ -+static int do_open_dir(struct file *file, int flags) -+{ -+ int err; -+ aufs_bindex_t bindex, btail; -+ struct dentry *dentry, *h_dentry; -+ struct file *h_file; -+ -+ FiMustWriteLock(file); -+ -+ err = 0; -+ dentry = file->f_dentry; -+ au_set_fvdir_cache(file, NULL); -+ au_fi(file)->fi_maintain_plink = 0; -+ file->f_version = dentry->d_inode->i_version; -+ bindex = au_dbstart(dentry); -+ au_set_fbstart(file, bindex); -+ btail = au_dbtaildir(dentry); -+ au_set_fbend(file, btail); -+ for (; !err && bindex <= btail; bindex++) { -+ h_dentry = au_h_dptr(dentry, bindex); -+ if (!h_dentry) -+ continue; -+ -+ h_file = au_h_open(dentry, bindex, flags, file); -+ if (IS_ERR(h_file)) { -+ err = PTR_ERR(h_file); -+ break; -+ } -+ au_set_h_fptr(file, bindex, h_file); -+ } -+ au_update_figen(file); -+ /* todo: necessary? */ -+ /* file->f_ra = h_file->f_ra; */ -+ if (!err) -+ return 0; /* success */ -+ -+ /* close all */ -+ for (bindex = au_fbstart(file); bindex <= btail; bindex++) -+ au_set_h_fptr(file, bindex, NULL); -+ au_set_fbstart(file, -1); -+ au_set_fbend(file, -1); -+ return err; -+} -+ -+static int aufs_open_dir(struct inode *inode __maybe_unused, -+ struct file *file) -+{ -+ return au_do_open(file, do_open_dir); -+} -+ -+static int aufs_release_dir(struct inode *inode __maybe_unused, -+ struct file *file) -+{ -+ struct au_vdir *vdir_cache; -+ struct super_block *sb; -+ struct au_sbinfo *sbinfo; -+ -+ sb = file->f_dentry->d_sb; -+ si_noflush_read_lock(sb); -+ fi_write_lock(file); -+ vdir_cache = au_fvdir_cache(file); -+ if (vdir_cache) -+ au_vdir_free(vdir_cache); -+ if (au_fi(file)->fi_maintain_plink) { -+ sbinfo = au_sbi(sb); -+ /* clear the flag without write-lock */ -+ sbinfo->au_si_status &= ~AuSi_MAINTAIN_PLINK; -+ smp_mb(); -+ wake_up_all(&sbinfo->si_plink_wq); -+ } -+ fi_write_unlock(file); -+ au_finfo_fin(file); -+ si_read_unlock(sb); -+ return 0; -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+static int au_do_fsync_dir_no_file(struct dentry *dentry, int datasync) -+{ -+ int err; -+ aufs_bindex_t bend, bindex; -+ struct inode *inode; -+ struct super_block *sb; -+ -+ err = 0; -+ sb = dentry->d_sb; -+ inode = dentry->d_inode; -+ IMustLock(inode); -+ bend = au_dbend(dentry); -+ for (bindex = au_dbstart(dentry); !err && bindex <= bend; bindex++) { -+ struct path h_path; -+ struct inode *h_inode; -+ -+ if (au_test_ro(sb, bindex, inode)) -+ continue; -+ h_path.dentry = au_h_dptr(dentry, bindex); -+ if (!h_path.dentry) -+ continue; -+ h_inode = h_path.dentry->d_inode; -+ if (!h_inode) -+ continue; -+ -+ /* no mnt_want_write() */ -+ /* cf. fs/nsfd/vfs.c and fs/nfsd/nfs4recover.c */ -+ /* todo: inotiry fired? */ -+ h_path.mnt = au_sbr_mnt(sb, bindex); -+ mutex_lock(&h_inode->i_mutex); -+ err = filemap_fdatawrite(h_inode->i_mapping); -+ AuDebugOn(!h_inode->i_fop); -+ if (!err && h_inode->i_fop->fsync) -+ err = h_inode->i_fop->fsync(NULL, h_path.dentry, -+ datasync); -+ if (!err) -+ err = filemap_fdatawrite(h_inode->i_mapping); -+ if (!err) -+ vfsub_update_h_iattr(&h_path, /*did*/NULL); /*ignore*/ -+ mutex_unlock(&h_inode->i_mutex); -+ } -+ -+ return err; -+} -+ -+static int au_do_fsync_dir(struct file *file, int datasync) -+{ -+ int err; -+ aufs_bindex_t bend, bindex; -+ struct file *h_file; -+ struct super_block *sb; -+ struct inode *inode; -+ struct mutex *h_mtx; -+ -+ err = au_reval_and_lock_fdi(file, reopen_dir, /*wlock*/1); -+ if (unlikely(err)) -+ goto out; -+ -+ sb = file->f_dentry->d_sb; -+ inode = file->f_dentry->d_inode; -+ bend = au_fbend(file); -+ for (bindex = au_fbstart(file); !err && bindex <= bend; bindex++) { -+ h_file = au_h_fptr(file, bindex); -+ if (!h_file || au_test_ro(sb, bindex, inode)) -+ continue; -+ -+ err = vfs_fsync(h_file, h_file->f_dentry, datasync); -+ if (!err) { -+ h_mtx = &h_file->f_dentry->d_inode->i_mutex; -+ mutex_lock(h_mtx); -+ vfsub_update_h_iattr(&h_file->f_path, /*did*/NULL); -+ /*ignore*/ -+ mutex_unlock(h_mtx); -+ } -+ } -+ -+ out: -+ return err; -+} -+ -+/* -+ * @file may be NULL -+ */ -+static int aufs_fsync_dir(struct file *file, struct dentry *dentry, -+ int datasync) -+{ -+ int err; -+ struct super_block *sb; -+ -+ IMustLock(dentry->d_inode); -+ -+ err = 0; -+ sb = dentry->d_sb; -+ si_noflush_read_lock(sb); -+ if (file) -+ err = au_do_fsync_dir(file, datasync); -+ else { -+ di_write_lock_child(dentry); -+ err = au_do_fsync_dir_no_file(dentry, datasync); -+ } -+ au_cpup_attr_timesizes(dentry->d_inode); -+ di_write_unlock(dentry); -+ if (file) -+ fi_write_unlock(file); -+ -+ si_read_unlock(sb); -+ return err; -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+static int aufs_readdir(struct file *file, void *dirent, filldir_t filldir) -+{ -+ int err; -+ struct dentry *dentry; -+ struct inode *inode; -+ struct super_block *sb; -+ -+ dentry = file->f_dentry; -+ inode = dentry->d_inode; -+ IMustLock(inode); -+ -+ sb = dentry->d_sb; -+ si_read_lock(sb, AuLock_FLUSH); -+ err = au_reval_and_lock_fdi(file, reopen_dir, /*wlock*/1); -+ if (unlikely(err)) -+ goto out; -+ err = au_vdir_init(file); -+ di_downgrade_lock(dentry, AuLock_IR); -+ if (unlikely(err)) -+ goto out_unlock; -+ -+ if (!au_test_nfsd(current)) { -+ err = au_vdir_fill_de(file, dirent, filldir); -+ fsstack_copy_attr_atime(inode, -+ au_h_iptr(inode, au_ibstart(inode))); -+ } else { -+ /* -+ * nfsd filldir may call lookup_one_len(), vfs_getattr(), -+ * encode_fh() and others. -+ */ -+ struct inode *h_inode = au_h_iptr(inode, au_ibstart(inode)); -+ -+ di_read_unlock(dentry, AuLock_IR); -+ si_read_unlock(sb); -+ /* lockdep_off(); */ -+ err = au_vdir_fill_de(file, dirent, filldir); -+ /* lockdep_on(); */ -+ fsstack_copy_attr_atime(inode, h_inode); -+ fi_write_unlock(file); -+ -+ AuTraceErr(err); -+ return err; -+ } -+ -+ out_unlock: -+ di_read_unlock(dentry, AuLock_IR); -+ fi_write_unlock(file); -+ out: -+ si_read_unlock(sb); -+ return err; -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+#define AuTestEmpty_WHONLY 1 -+#define AuTestEmpty_CALLED (1 << 1) -+#define AuTestEmpty_SHWH (1 << 2) -+#define au_ftest_testempty(flags, name) ((flags) & AuTestEmpty_##name) -+#define au_fset_testempty(flags, name) { (flags) |= AuTestEmpty_##name; } -+#define au_fclr_testempty(flags, name) { (flags) &= ~AuTestEmpty_##name; } -+ -+#ifndef CONFIG_AUFS_SHWH -+#undef AuTestEmpty_SHWH -+#define AuTestEmpty_SHWH 0 -+#endif -+ -+struct test_empty_arg { -+ struct au_nhash *whlist; -+ unsigned int flags; -+ int err; -+ aufs_bindex_t bindex; -+}; -+ -+static int test_empty_cb(void *__arg, const char *__name, int namelen, -+ loff_t offset __maybe_unused, u64 ino, -+ unsigned int d_type) -+{ -+ struct test_empty_arg *arg = __arg; -+ char *name = (void *)__name; -+ -+ arg->err = 0; -+ au_fset_testempty(arg->flags, CALLED); -+ /* smp_mb(); */ -+ if (name[0] == '.' -+ && (namelen == 1 || (name[1] == '.' && namelen == 2))) -+ goto out; /* success */ -+ -+ if (namelen <= AUFS_WH_PFX_LEN -+ || memcmp(name, AUFS_WH_PFX, AUFS_WH_PFX_LEN)) { -+ if (au_ftest_testempty(arg->flags, WHONLY) -+ && !au_nhash_test_known_wh(arg->whlist, name, namelen)) -+ arg->err = -ENOTEMPTY; -+ goto out; -+ } -+ -+ name += AUFS_WH_PFX_LEN; -+ namelen -= AUFS_WH_PFX_LEN; -+ if (!au_nhash_test_known_wh(arg->whlist, name, namelen)) -+ arg->err = au_nhash_append_wh -+ (arg->whlist, name, namelen, ino, d_type, arg->bindex, -+ au_ftest_testempty(arg->flags, SHWH)); -+ -+ out: -+ /* smp_mb(); */ -+ AuTraceErr(arg->err); -+ return arg->err; -+} -+ -+static int do_test_empty(struct dentry *dentry, struct test_empty_arg *arg) -+{ -+ int err; -+ struct file *h_file; -+ -+ h_file = au_h_open(dentry, arg->bindex, -+ O_RDONLY | O_NONBLOCK | O_DIRECTORY | O_LARGEFILE, -+ /*file*/NULL); -+ err = PTR_ERR(h_file); -+ if (IS_ERR(h_file)) -+ goto out; -+ -+ err = 0; -+ if (!au_opt_test(au_mntflags(dentry->d_sb), UDBA_NONE) -+ && !h_file->f_dentry->d_inode->i_nlink) -+ goto out_put; -+ -+ do { -+ arg->err = 0; -+ au_fclr_testempty(arg->flags, CALLED); -+ /* smp_mb(); */ -+ err = vfsub_readdir(h_file, test_empty_cb, arg); -+ if (err >= 0) -+ err = arg->err; -+ } while (!err && au_ftest_testempty(arg->flags, CALLED)); -+ -+ out_put: -+ fput(h_file); -+ au_sbr_put(dentry->d_sb, arg->bindex); -+ out: -+ return err; -+} -+ -+struct do_test_empty_args { -+ int *errp; -+ struct dentry *dentry; -+ struct test_empty_arg *arg; -+}; -+ -+static void call_do_test_empty(void *args) -+{ -+ struct do_test_empty_args *a = args; -+ *a->errp = do_test_empty(a->dentry, a->arg); -+} -+ -+static int sio_test_empty(struct dentry *dentry, struct test_empty_arg *arg) -+{ -+ int err, wkq_err; -+ struct dentry *h_dentry; -+ struct inode *h_inode; -+ -+ h_dentry = au_h_dptr(dentry, arg->bindex); -+ h_inode = h_dentry->d_inode; -+ mutex_lock_nested(&h_inode->i_mutex, AuLsc_I_CHILD); -+ err = au_test_h_perm_sio(h_inode, MAY_EXEC | MAY_READ); -+ mutex_unlock(&h_inode->i_mutex); -+ if (!err) -+ err = do_test_empty(dentry, arg); -+ else { -+ struct do_test_empty_args args = { -+ .errp = &err, -+ .dentry = dentry, -+ .arg = arg -+ }; -+ unsigned int flags = arg->flags; -+ -+ wkq_err = au_wkq_wait(call_do_test_empty, &args); -+ if (unlikely(wkq_err)) -+ err = wkq_err; -+ arg->flags = flags; -+ } -+ -+ return err; -+} -+ -+int au_test_empty_lower(struct dentry *dentry) -+{ -+ int err; -+ unsigned int rdhash; -+ aufs_bindex_t bindex, bstart, btail; -+ struct au_nhash whlist; -+ struct test_empty_arg arg; -+ -+ SiMustAnyLock(dentry->d_sb); -+ -+ rdhash = au_sbi(dentry->d_sb)->si_rdhash; -+ if (!rdhash) -+ rdhash = au_rdhash_est(au_dir_size(/*file*/NULL, dentry)); -+ err = au_nhash_alloc(&whlist, rdhash, GFP_NOFS); -+ if (unlikely(err)) -+ goto out; -+ -+ arg.flags = 0; -+ arg.whlist = &whlist; -+ bstart = au_dbstart(dentry); -+ if (au_opt_test(au_mntflags(dentry->d_sb), SHWH)) -+ au_fset_testempty(arg.flags, SHWH); -+ arg.bindex = bstart; -+ err = do_test_empty(dentry, &arg); -+ if (unlikely(err)) -+ goto out_whlist; -+ -+ au_fset_testempty(arg.flags, WHONLY); -+ btail = au_dbtaildir(dentry); -+ for (bindex = bstart + 1; !err && bindex <= btail; bindex++) { -+ struct dentry *h_dentry; -+ -+ h_dentry = au_h_dptr(dentry, bindex); -+ if (h_dentry && h_dentry->d_inode) { -+ arg.bindex = bindex; -+ err = do_test_empty(dentry, &arg); -+ } -+ } -+ -+ out_whlist: -+ au_nhash_wh_free(&whlist); -+ out: -+ return err; -+} -+ -+int au_test_empty(struct dentry *dentry, struct au_nhash *whlist) -+{ -+ int err; -+ struct test_empty_arg arg; -+ aufs_bindex_t bindex, btail; -+ -+ err = 0; -+ arg.whlist = whlist; -+ arg.flags = AuTestEmpty_WHONLY; -+ if (au_opt_test(au_mntflags(dentry->d_sb), SHWH)) -+ au_fset_testempty(arg.flags, SHWH); -+ btail = au_dbtaildir(dentry); -+ for (bindex = au_dbstart(dentry); !err && bindex <= btail; bindex++) { -+ struct dentry *h_dentry; -+ -+ h_dentry = au_h_dptr(dentry, bindex); -+ if (h_dentry && h_dentry->d_inode) { -+ arg.bindex = bindex; -+ err = sio_test_empty(dentry, &arg); -+ } -+ } -+ -+ return err; -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+const struct file_operations aufs_dir_fop = { -+ .read = generic_read_dir, -+ .readdir = aufs_readdir, -+ .unlocked_ioctl = aufs_ioctl_dir, -+ .open = aufs_open_dir, -+ .release = aufs_release_dir, -+ .flush = aufs_flush, -+ .fsync = aufs_fsync_dir -+}; -diff --git a/fs/aufs/dir.h b/fs/aufs/dir.h -new file mode 100644 -index 0000000..d90c63f ---- /dev/null -+++ b/fs/aufs/dir.h -@@ -0,0 +1,127 @@ -+/* -+ * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * -+ * This program, aufs is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ */ -+ -+/* -+ * directory operations -+ */ -+ -+#ifndef __AUFS_DIR_H__ -+#define __AUFS_DIR_H__ -+ -+#ifdef __KERNEL__ -+ -+#include -+#include -+ -+/* ---------------------------------------------------------------------- */ -+ -+/* need to be faster and smaller */ -+ -+struct au_nhash { -+ unsigned int nh_num; -+ struct hlist_head *nh_head; -+}; -+ -+struct au_vdir_destr { -+ unsigned char len; -+ unsigned char name[0]; -+} __packed; -+ -+struct au_vdir_dehstr { -+ struct hlist_node hash; -+ struct au_vdir_destr *str; -+}; -+ -+struct au_vdir_de { -+ ino_t de_ino; -+ unsigned char de_type; -+ /* caution: packed */ -+ struct au_vdir_destr de_str; -+} __packed; -+ -+struct au_vdir_wh { -+ struct hlist_node wh_hash; -+#ifdef CONFIG_AUFS_SHWH -+ ino_t wh_ino; -+ aufs_bindex_t wh_bindex; -+ unsigned char wh_type; -+#else -+ aufs_bindex_t wh_bindex; -+#endif -+ /* caution: packed */ -+ struct au_vdir_destr wh_str; -+} __packed; -+ -+union au_vdir_deblk_p { -+ unsigned char *deblk; -+ struct au_vdir_de *de; -+}; -+ -+struct au_vdir { -+ unsigned char **vd_deblk; -+ unsigned long vd_nblk; -+ struct { -+ unsigned long ul; -+ union au_vdir_deblk_p p; -+ } vd_last; -+ -+ unsigned long vd_version; -+ unsigned int vd_deblk_sz; -+ unsigned long vd_jiffy; -+}; -+ -+/* ---------------------------------------------------------------------- */ -+ -+/* dir.c */ -+extern const struct file_operations aufs_dir_fop; -+void au_add_nlink(struct inode *dir, struct inode *h_dir); -+void au_sub_nlink(struct inode *dir, struct inode *h_dir); -+loff_t au_dir_size(struct file *file, struct dentry *dentry); -+int au_test_empty_lower(struct dentry *dentry); -+int au_test_empty(struct dentry *dentry, struct au_nhash *whlist); -+ -+/* vdir.c */ -+unsigned int au_rdhash_est(loff_t sz); -+int au_nhash_alloc(struct au_nhash *nhash, unsigned int num_hash, gfp_t gfp); -+void au_nhash_wh_free(struct au_nhash *whlist); -+int au_nhash_test_longer_wh(struct au_nhash *whlist, aufs_bindex_t btgt, -+ int limit); -+int au_nhash_test_known_wh(struct au_nhash *whlist, char *name, int nlen); -+int au_nhash_append_wh(struct au_nhash *whlist, char *name, int nlen, ino_t ino, -+ unsigned int d_type, aufs_bindex_t bindex, -+ unsigned char shwh); -+void au_vdir_free(struct au_vdir *vdir); -+int au_vdir_init(struct file *file); -+int au_vdir_fill_de(struct file *file, void *dirent, filldir_t filldir); -+ -+/* ioctl.c */ -+long aufs_ioctl_dir(struct file *file, unsigned int cmd, unsigned long arg); -+ -+#ifdef CONFIG_AUFS_RDU -+/* rdu.c */ -+long au_rdu_ioctl(struct file *file, unsigned int cmd, unsigned long arg); -+#else -+static inline long au_rdu_ioctl(struct file *file, unsigned int cmd, -+ unsigned long arg) -+{ -+ return -EINVAL; -+} -+#endif -+ -+#endif /* __KERNEL__ */ -+#endif /* __AUFS_DIR_H__ */ -diff --git a/fs/aufs/export.c b/fs/aufs/export.c -new file mode 100644 -index 0000000..5b5c2c4 ---- /dev/null -+++ b/fs/aufs/export.c -@@ -0,0 +1,746 @@ -+/* -+ * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * -+ * This program, aufs is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ */ -+ -+/* -+ * export via nfs -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include "aufs.h" -+ -+union conv { -+#ifdef CONFIG_AUFS_INO_T_64 -+ __u32 a[2]; -+#else -+ __u32 a[1]; -+#endif -+ ino_t ino; -+}; -+ -+static ino_t decode_ino(__u32 *a) -+{ -+ union conv u; -+ -+ BUILD_BUG_ON(sizeof(u.ino) != sizeof(u.a)); -+ u.a[0] = a[0]; -+#ifdef CONFIG_AUFS_INO_T_64 -+ u.a[1] = a[1]; -+#endif -+ return u.ino; -+} -+ -+static void encode_ino(__u32 *a, ino_t ino) -+{ -+ union conv u; -+ -+ u.ino = ino; -+ a[0] = u.a[0]; -+#ifdef CONFIG_AUFS_INO_T_64 -+ a[1] = u.a[1]; -+#endif -+} -+ -+/* NFS file handle */ -+enum { -+ Fh_br_id, -+ Fh_sigen, -+#ifdef CONFIG_AUFS_INO_T_64 -+ /* support 64bit inode number */ -+ Fh_ino1, -+ Fh_ino2, -+ Fh_dir_ino1, -+ Fh_dir_ino2, -+#else -+ Fh_ino1, -+ Fh_dir_ino1, -+#endif -+ Fh_igen, -+ Fh_h_type, -+ Fh_tail, -+ -+ Fh_ino = Fh_ino1, -+ Fh_dir_ino = Fh_dir_ino1 -+}; -+ -+static int au_test_anon(struct dentry *dentry) -+{ -+ return !!(dentry->d_flags & DCACHE_DISCONNECTED); -+} -+ -+/* ---------------------------------------------------------------------- */ -+/* inode generation external table */ -+ -+int au_xigen_inc(struct inode *inode) -+{ -+ int err; -+ loff_t pos; -+ ssize_t sz; -+ __u32 igen; -+ struct super_block *sb; -+ struct au_sbinfo *sbinfo; -+ -+ err = 0; -+ sb = inode->i_sb; -+ sbinfo = au_sbi(sb); -+ /* -+ * temporary workaround for escaping from SiMustAnyLock() in -+ * au_mntflags(), since this function is called from au_iinfo_fin(). -+ */ -+ if (unlikely(!au_opt_test(sbinfo->si_mntflags, XINO))) -+ goto out; -+ -+ pos = inode->i_ino; -+ pos *= sizeof(igen); -+ igen = inode->i_generation + 1; -+ sz = xino_fwrite(sbinfo->si_xwrite, sbinfo->si_xigen, &igen, -+ sizeof(igen), &pos); -+ if (sz == sizeof(igen)) -+ goto out; /* success */ -+ -+ err = sz; -+ if (unlikely(sz >= 0)) { -+ err = -EIO; -+ AuIOErr("xigen error (%zd)\n", sz); -+ } -+ -+ out: -+ return err; -+} -+ -+int au_xigen_new(struct inode *inode) -+{ -+ int err; -+ loff_t pos; -+ ssize_t sz; -+ struct super_block *sb; -+ struct au_sbinfo *sbinfo; -+ struct file *file; -+ -+ err = 0; -+ /* todo: dirty, at mount time */ -+ if (inode->i_ino == AUFS_ROOT_INO) -+ goto out; -+ sb = inode->i_sb; -+ SiMustAnyLock(sb); -+ if (unlikely(!au_opt_test(au_mntflags(sb), XINO))) -+ goto out; -+ -+ err = -EFBIG; -+ pos = inode->i_ino; -+ if (unlikely(au_loff_max / sizeof(inode->i_generation) - 1 < pos)) { -+ AuIOErr1("too large i%lld\n", pos); -+ goto out; -+ } -+ pos *= sizeof(inode->i_generation); -+ -+ err = 0; -+ sbinfo = au_sbi(sb); -+ file = sbinfo->si_xigen; -+ BUG_ON(!file); -+ -+ if (i_size_read(file->f_dentry->d_inode) -+ < pos + sizeof(inode->i_generation)) { -+ inode->i_generation = atomic_inc_return(&sbinfo->si_xigen_next); -+ sz = xino_fwrite(sbinfo->si_xwrite, file, &inode->i_generation, -+ sizeof(inode->i_generation), &pos); -+ } else -+ sz = xino_fread(sbinfo->si_xread, file, &inode->i_generation, -+ sizeof(inode->i_generation), &pos); -+ if (sz == sizeof(inode->i_generation)) -+ goto out; /* success */ -+ -+ err = sz; -+ if (unlikely(sz >= 0)) { -+ err = -EIO; -+ AuIOErr("xigen error (%zd)\n", sz); -+ } -+ -+ out: -+ return err; -+} -+ -+int au_xigen_set(struct super_block *sb, struct file *base) -+{ -+ int err; -+ struct au_sbinfo *sbinfo; -+ struct file *file; -+ -+ SiMustWriteLock(sb); -+ -+ sbinfo = au_sbi(sb); -+ file = au_xino_create2(base, sbinfo->si_xigen); -+ err = PTR_ERR(file); -+ if (IS_ERR(file)) -+ goto out; -+ err = 0; -+ if (sbinfo->si_xigen) -+ fput(sbinfo->si_xigen); -+ sbinfo->si_xigen = file; -+ -+ out: -+ return err; -+} -+ -+void au_xigen_clr(struct super_block *sb) -+{ -+ struct au_sbinfo *sbinfo; -+ -+ SiMustWriteLock(sb); -+ -+ sbinfo = au_sbi(sb); -+ if (sbinfo->si_xigen) { -+ fput(sbinfo->si_xigen); -+ sbinfo->si_xigen = NULL; -+ } -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+static struct dentry *decode_by_ino(struct super_block *sb, ino_t ino, -+ ino_t dir_ino) -+{ -+ struct dentry *dentry, *d; -+ struct inode *inode; -+ unsigned int sigen; -+ -+ dentry = NULL; -+ inode = ilookup(sb, ino); -+ if (!inode) -+ goto out; -+ -+ dentry = ERR_PTR(-ESTALE); -+ sigen = au_sigen(sb); -+ if (unlikely(is_bad_inode(inode) -+ || IS_DEADDIR(inode) -+ || sigen != au_iigen(inode))) -+ goto out_iput; -+ -+ dentry = NULL; -+ if (!dir_ino || S_ISDIR(inode->i_mode)) -+ dentry = d_find_alias(inode); -+ else { -+ spin_lock(&dcache_lock); -+ list_for_each_entry(d, &inode->i_dentry, d_alias) -+ if (!au_test_anon(d) -+ && d->d_parent->d_inode->i_ino == dir_ino) { -+ dentry = dget_locked(d); -+ break; -+ } -+ spin_unlock(&dcache_lock); -+ } -+ if (unlikely(dentry && sigen != au_digen(dentry))) { -+ dput(dentry); -+ dentry = ERR_PTR(-ESTALE); -+ } -+ -+ out_iput: -+ iput(inode); -+ out: -+ return dentry; -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+/* todo: dirty? */ -+/* if exportfs_decode_fh() passed vfsmount*, we could be happy */ -+static struct vfsmount *au_mnt_get(struct super_block *sb) -+{ -+ struct mnt_namespace *ns; -+ struct vfsmount *pos, *mnt; -+ -+ spin_lock(&vfsmount_lock); -+ /* no get/put ?? */ -+ AuDebugOn(!current->nsproxy); -+ ns = current->nsproxy->mnt_ns; -+ AuDebugOn(!ns); -+ mnt = NULL; -+ /* the order (reverse) will not be a problem */ -+ list_for_each_entry(pos, &ns->list, mnt_list) -+ if (pos->mnt_sb == sb) { -+ mnt = mntget(pos); -+ break; -+ } -+ spin_unlock(&vfsmount_lock); -+ AuDebugOn(!mnt); -+ -+ return mnt; -+} -+ -+struct au_nfsd_si_lock { -+ const unsigned int sigen; -+ const aufs_bindex_t br_id; -+ unsigned char force_lock; -+}; -+ -+static aufs_bindex_t si_nfsd_read_lock(struct super_block *sb, -+ struct au_nfsd_si_lock *nsi_lock) -+{ -+ aufs_bindex_t bindex; -+ -+ si_read_lock(sb, AuLock_FLUSH); -+ -+ /* branch id may be wrapped around */ -+ bindex = au_br_index(sb, nsi_lock->br_id); -+ if (bindex >= 0 && nsi_lock->sigen + AUFS_BRANCH_MAX > au_sigen(sb)) -+ goto out; /* success */ -+ -+ if (!nsi_lock->force_lock) -+ si_read_unlock(sb); -+ bindex = -1; -+ -+ out: -+ return bindex; -+} -+ -+struct find_name_by_ino { -+ int called, found; -+ ino_t ino; -+ char *name; -+ int namelen; -+}; -+ -+static int -+find_name_by_ino(void *arg, const char *name, int namelen, loff_t offset, -+ u64 ino, unsigned int d_type) -+{ -+ struct find_name_by_ino *a = arg; -+ -+ a->called++; -+ if (a->ino != ino) -+ return 0; -+ -+ memcpy(a->name, name, namelen); -+ a->namelen = namelen; -+ a->found = 1; -+ return 1; -+} -+ -+static struct dentry *au_lkup_by_ino(struct path *path, ino_t ino, -+ struct au_nfsd_si_lock *nsi_lock) -+{ -+ struct dentry *dentry, *parent; -+ struct file *file; -+ struct inode *dir; -+ struct find_name_by_ino arg; -+ int err; -+ -+ parent = path->dentry; -+ if (nsi_lock) -+ si_read_unlock(parent->d_sb); -+ path_get(path); -+ file = vfsub_dentry_open(path, au_dir_roflags, current_cred()); -+ dentry = (void *)file; -+ if (IS_ERR(file)) -+ goto out; -+ -+ dentry = ERR_PTR(-ENOMEM); -+ arg.name = __getname(); -+ if (unlikely(!arg.name)) -+ goto out_file; -+ arg.ino = ino; -+ arg.found = 0; -+ do { -+ arg.called = 0; -+ /* smp_mb(); */ -+ err = vfsub_readdir(file, find_name_by_ino, &arg); -+ } while (!err && !arg.found && arg.called); -+ dentry = ERR_PTR(err); -+ if (unlikely(err)) -+ goto out_name; -+ dentry = ERR_PTR(-ENOENT); -+ if (!arg.found) -+ goto out_name; -+ -+ /* do not call au_lkup_one() */ -+ dir = parent->d_inode; -+ mutex_lock(&dir->i_mutex); -+ dentry = vfsub_lookup_one_len(arg.name, parent, arg.namelen); -+ mutex_unlock(&dir->i_mutex); -+ AuTraceErrPtr(dentry); -+ if (IS_ERR(dentry)) -+ goto out_name; -+ AuDebugOn(au_test_anon(dentry)); -+ if (unlikely(!dentry->d_inode)) { -+ dput(dentry); -+ dentry = ERR_PTR(-ENOENT); -+ } -+ -+ out_name: -+ __putname(arg.name); -+ out_file: -+ fput(file); -+ out: -+ if (unlikely(nsi_lock -+ && si_nfsd_read_lock(parent->d_sb, nsi_lock) < 0)) -+ if (!IS_ERR(dentry)) { -+ dput(dentry); -+ dentry = ERR_PTR(-ESTALE); -+ } -+ AuTraceErrPtr(dentry); -+ return dentry; -+} -+ -+static struct dentry *decode_by_dir_ino(struct super_block *sb, ino_t ino, -+ ino_t dir_ino, -+ struct au_nfsd_si_lock *nsi_lock) -+{ -+ struct dentry *dentry; -+ struct path path; -+ -+ if (dir_ino != AUFS_ROOT_INO) { -+ path.dentry = decode_by_ino(sb, dir_ino, 0); -+ dentry = path.dentry; -+ if (!path.dentry || IS_ERR(path.dentry)) -+ goto out; -+ AuDebugOn(au_test_anon(path.dentry)); -+ } else -+ path.dentry = dget(sb->s_root); -+ -+ path.mnt = au_mnt_get(sb); -+ dentry = au_lkup_by_ino(&path, ino, nsi_lock); -+ path_put(&path); -+ -+ out: -+ AuTraceErrPtr(dentry); -+ return dentry; -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+static int h_acceptable(void *expv, struct dentry *dentry) -+{ -+ return 1; -+} -+ -+static char *au_build_path(struct dentry *h_parent, struct path *h_rootpath, -+ char *buf, int len, struct super_block *sb) -+{ -+ char *p; -+ int n; -+ struct path path; -+ -+ p = d_path(h_rootpath, buf, len); -+ if (IS_ERR(p)) -+ goto out; -+ n = strlen(p); -+ -+ path.mnt = h_rootpath->mnt; -+ path.dentry = h_parent; -+ p = d_path(&path, buf, len); -+ if (IS_ERR(p)) -+ goto out; -+ if (n != 1) -+ p += n; -+ -+ path.mnt = au_mnt_get(sb); -+ path.dentry = sb->s_root; -+ p = d_path(&path, buf, len - strlen(p)); -+ mntput(path.mnt); -+ if (IS_ERR(p)) -+ goto out; -+ if (n != 1) -+ p[strlen(p)] = '/'; -+ -+ out: -+ AuTraceErrPtr(p); -+ return p; -+} -+ -+static -+struct dentry *decode_by_path(struct super_block *sb, aufs_bindex_t bindex, -+ ino_t ino, __u32 *fh, int fh_len, -+ struct au_nfsd_si_lock *nsi_lock) -+{ -+ struct dentry *dentry, *h_parent, *root; -+ struct super_block *h_sb; -+ char *pathname, *p; -+ struct vfsmount *h_mnt; -+ struct au_branch *br; -+ int err; -+ struct path path; -+ -+ br = au_sbr(sb, bindex); -+ /* au_br_get(br); */ -+ h_mnt = br->br_mnt; -+ h_sb = h_mnt->mnt_sb; -+ /* todo: call lower fh_to_dentry()? fh_to_parent()? */ -+ h_parent = exportfs_decode_fh(h_mnt, (void *)(fh + Fh_tail), -+ fh_len - Fh_tail, fh[Fh_h_type], -+ h_acceptable, /*context*/NULL); -+ dentry = h_parent; -+ if (unlikely(!h_parent || IS_ERR(h_parent))) { -+ AuWarn1("%s decode_fh failed, %ld\n", -+ au_sbtype(h_sb), PTR_ERR(h_parent)); -+ goto out; -+ } -+ dentry = NULL; -+ if (unlikely(au_test_anon(h_parent))) { -+ AuWarn1("%s decode_fh returned a disconnected dentry\n", -+ au_sbtype(h_sb)); -+ goto out_h_parent; -+ } -+ -+ dentry = ERR_PTR(-ENOMEM); -+ pathname = (void *)__get_free_page(GFP_NOFS); -+ if (unlikely(!pathname)) -+ goto out_h_parent; -+ -+ root = sb->s_root; -+ path.mnt = h_mnt; -+ di_read_lock_parent(root, !AuLock_IR); -+ path.dentry = au_h_dptr(root, bindex); -+ di_read_unlock(root, !AuLock_IR); -+ p = au_build_path(h_parent, &path, pathname, PAGE_SIZE, sb); -+ dentry = (void *)p; -+ if (IS_ERR(p)) -+ goto out_pathname; -+ -+ si_read_unlock(sb); -+ err = vfsub_kern_path(p, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &path); -+ dentry = ERR_PTR(err); -+ if (unlikely(err)) -+ goto out_relock; -+ -+ dentry = ERR_PTR(-ENOENT); -+ AuDebugOn(au_test_anon(path.dentry)); -+ if (unlikely(!path.dentry->d_inode)) -+ goto out_path; -+ -+ if (ino != path.dentry->d_inode->i_ino) -+ dentry = au_lkup_by_ino(&path, ino, /*nsi_lock*/NULL); -+ else -+ dentry = dget(path.dentry); -+ -+ out_path: -+ path_put(&path); -+ out_relock: -+ if (unlikely(si_nfsd_read_lock(sb, nsi_lock) < 0)) -+ if (!IS_ERR(dentry)) { -+ dput(dentry); -+ dentry = ERR_PTR(-ESTALE); -+ } -+ out_pathname: -+ free_page((unsigned long)pathname); -+ out_h_parent: -+ dput(h_parent); -+ out: -+ /* au_br_put(br); */ -+ AuTraceErrPtr(dentry); -+ return dentry; -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+static struct dentry * -+aufs_fh_to_dentry(struct super_block *sb, struct fid *fid, int fh_len, -+ int fh_type) -+{ -+ struct dentry *dentry; -+ __u32 *fh = fid->raw; -+ ino_t ino, dir_ino; -+ aufs_bindex_t bindex; -+ struct au_nfsd_si_lock nsi_lock = { -+ .sigen = fh[Fh_sigen], -+ .br_id = fh[Fh_br_id], -+ .force_lock = 0 -+ }; -+ -+ AuDebugOn(fh_len < Fh_tail); -+ -+ dentry = ERR_PTR(-ESTALE); -+ /* branch id may be wrapped around */ -+ bindex = si_nfsd_read_lock(sb, &nsi_lock); -+ if (unlikely(bindex < 0)) -+ goto out; -+ nsi_lock.force_lock = 1; -+ -+ /* is this inode still cached? */ -+ ino = decode_ino(fh + Fh_ino); -+ AuDebugOn(ino == AUFS_ROOT_INO); -+ dir_ino = decode_ino(fh + Fh_dir_ino); -+ dentry = decode_by_ino(sb, ino, dir_ino); -+ if (IS_ERR(dentry)) -+ goto out_unlock; -+ if (dentry) -+ goto accept; -+ -+ /* is the parent dir cached? */ -+ dentry = decode_by_dir_ino(sb, ino, dir_ino, &nsi_lock); -+ if (IS_ERR(dentry)) -+ goto out_unlock; -+ if (dentry) -+ goto accept; -+ -+ /* lookup path */ -+ dentry = decode_by_path(sb, bindex, ino, fh, fh_len, &nsi_lock); -+ if (IS_ERR(dentry)) -+ goto out_unlock; -+ if (unlikely(!dentry)) -+ /* todo?: make it ESTALE */ -+ goto out_unlock; -+ -+ accept: -+ if (dentry->d_inode->i_generation == fh[Fh_igen]) -+ goto out_unlock; /* success */ -+ -+ dput(dentry); -+ dentry = ERR_PTR(-ESTALE); -+ out_unlock: -+ si_read_unlock(sb); -+ out: -+ AuTraceErrPtr(dentry); -+ return dentry; -+} -+ -+#if 0 /* reserved for future use */ -+/* support subtreecheck option */ -+static struct dentry *aufs_fh_to_parent(struct super_block *sb, struct fid *fid, -+ int fh_len, int fh_type) -+{ -+ struct dentry *parent; -+ __u32 *fh = fid->raw; -+ ino_t dir_ino; -+ -+ dir_ino = decode_ino(fh + Fh_dir_ino); -+ parent = decode_by_ino(sb, dir_ino, 0); -+ if (IS_ERR(parent)) -+ goto out; -+ if (!parent) -+ parent = decode_by_path(sb, au_br_index(sb, fh[Fh_br_id]), -+ dir_ino, fh, fh_len); -+ -+ out: -+ AuTraceErrPtr(parent); -+ return parent; -+} -+#endif -+ -+/* ---------------------------------------------------------------------- */ -+ -+static int aufs_encode_fh(struct dentry *dentry, __u32 *fh, int *max_len, -+ int connectable) -+{ -+ int err; -+ aufs_bindex_t bindex, bend; -+ struct super_block *sb, *h_sb; -+ struct inode *inode; -+ struct dentry *parent, *h_parent; -+ struct au_branch *br; -+ -+ AuDebugOn(au_test_anon(dentry)); -+ -+ parent = NULL; -+ err = -ENOSPC; -+ if (unlikely(*max_len <= Fh_tail)) { -+ AuWarn1("NFSv2 client (max_len %d)?\n", *max_len); -+ goto out; -+ } -+ -+ err = FILEID_ROOT; -+ if (IS_ROOT(dentry)) { -+ AuDebugOn(dentry->d_inode->i_ino != AUFS_ROOT_INO); -+ goto out; -+ } -+ -+ err = -EIO; -+ h_parent = NULL; -+ sb = dentry->d_sb; -+ aufs_read_lock(dentry, AuLock_FLUSH | AuLock_IR); -+ parent = dget_parent(dentry); -+ di_read_lock_parent(parent, !AuLock_IR); -+ inode = dentry->d_inode; -+ AuDebugOn(!inode); -+#ifdef CONFIG_AUFS_DEBUG -+ if (unlikely(!au_opt_test(au_mntflags(sb), XINO))) -+ AuWarn1("NFS-exporting requires xino\n"); -+#endif -+ -+ bend = au_dbtaildir(parent); -+ for (bindex = au_dbstart(parent); bindex <= bend; bindex++) { -+ h_parent = au_h_dptr(parent, bindex); -+ if (h_parent) { -+ dget(h_parent); -+ break; -+ } -+ } -+ if (unlikely(!h_parent)) -+ goto out_unlock; -+ -+ err = -EPERM; -+ br = au_sbr(sb, bindex); -+ h_sb = br->br_mnt->mnt_sb; -+ if (unlikely(!h_sb->s_export_op)) { -+ AuErr1("%s branch is not exportable\n", au_sbtype(h_sb)); -+ goto out_dput; -+ } -+ -+ fh[Fh_br_id] = br->br_id; -+ fh[Fh_sigen] = au_sigen(sb); -+ encode_ino(fh + Fh_ino, inode->i_ino); -+ encode_ino(fh + Fh_dir_ino, parent->d_inode->i_ino); -+ fh[Fh_igen] = inode->i_generation; -+ -+ *max_len -= Fh_tail; -+ fh[Fh_h_type] = exportfs_encode_fh(h_parent, (void *)(fh + Fh_tail), -+ max_len, -+ /*connectable or subtreecheck*/0); -+ err = fh[Fh_h_type]; -+ *max_len += Fh_tail; -+ /* todo: macros? */ -+ if (err != 255) -+ err = 99; -+ else -+ AuWarn1("%s encode_fh failed\n", au_sbtype(h_sb)); -+ -+ out_dput: -+ dput(h_parent); -+ out_unlock: -+ di_read_unlock(parent, !AuLock_IR); -+ dput(parent); -+ aufs_read_unlock(dentry, AuLock_IR); -+ out: -+ if (unlikely(err < 0)) -+ err = 255; -+ return err; -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+static struct export_operations aufs_export_op = { -+ .fh_to_dentry = aufs_fh_to_dentry, -+ /* .fh_to_parent = aufs_fh_to_parent, */ -+ .encode_fh = aufs_encode_fh -+}; -+ -+void au_export_init(struct super_block *sb) -+{ -+ struct au_sbinfo *sbinfo; -+ __u32 u; -+ -+ sb->s_export_op = &aufs_export_op; -+ sbinfo = au_sbi(sb); -+ sbinfo->si_xigen = NULL; -+ get_random_bytes(&u, sizeof(u)); -+ BUILD_BUG_ON(sizeof(u) != sizeof(int)); -+ atomic_set(&sbinfo->si_xigen_next, u); -+} -diff --git a/fs/aufs/f_op.c b/fs/aufs/f_op.c -new file mode 100644 -index 0000000..7601012 ---- /dev/null -+++ b/fs/aufs/f_op.c -@@ -0,0 +1,827 @@ -+/* -+ * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * -+ * This program, aufs is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ */ -+ -+/* -+ * file and vm operations -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include "aufs.h" -+ -+/* common function to regular file and dir */ -+int aufs_flush(struct file *file, fl_owner_t id) -+{ -+ int err; -+ aufs_bindex_t bindex, bend; -+ struct dentry *dentry; -+ struct file *h_file; -+ -+ dentry = file->f_dentry; -+ si_noflush_read_lock(dentry->d_sb); -+ fi_read_lock(file); -+ di_read_lock_child(dentry, AuLock_IW); -+ -+ err = 0; -+ bend = au_fbend(file); -+ for (bindex = au_fbstart(file); !err && bindex <= bend; bindex++) { -+ h_file = au_h_fptr(file, bindex); -+ if (!h_file || !h_file->f_op || !h_file->f_op->flush) -+ continue; -+ -+ err = h_file->f_op->flush(h_file, id); -+ if (!err) -+ vfsub_update_h_iattr(&h_file->f_path, /*did*/NULL); -+ /*ignore*/ -+ } -+ au_cpup_attr_timesizes(dentry->d_inode); -+ -+ di_read_unlock(dentry, AuLock_IW); -+ fi_read_unlock(file); -+ si_read_unlock(dentry->d_sb); -+ return err; -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+static int do_open_nondir(struct file *file, int flags) -+{ -+ int err; -+ aufs_bindex_t bindex; -+ struct file *h_file; -+ struct dentry *dentry; -+ struct au_finfo *finfo; -+ -+ FiMustWriteLock(file); -+ -+ err = 0; -+ dentry = file->f_dentry; -+ finfo = au_fi(file); -+ finfo->fi_h_vm_ops = NULL; -+ finfo->fi_vm_ops = NULL; -+ bindex = au_dbstart(dentry); -+ /* O_TRUNC is processed already */ -+ BUG_ON(au_test_ro(dentry->d_sb, bindex, dentry->d_inode) -+ && (flags & O_TRUNC)); -+ -+ h_file = au_h_open(dentry, bindex, flags, file); -+ if (IS_ERR(h_file)) -+ err = PTR_ERR(h_file); -+ else { -+ au_set_fbstart(file, bindex); -+ au_set_fbend(file, bindex); -+ au_set_h_fptr(file, bindex, h_file); -+ au_update_figen(file); -+ /* todo: necessary? */ -+ /* file->f_ra = h_file->f_ra; */ -+ } -+ return err; -+} -+ -+static int aufs_open_nondir(struct inode *inode __maybe_unused, -+ struct file *file) -+{ -+ return au_do_open(file, do_open_nondir); -+} -+ -+static int aufs_release_nondir(struct inode *inode __maybe_unused, -+ struct file *file) -+{ -+ struct super_block *sb = file->f_dentry->d_sb; -+ -+ si_noflush_read_lock(sb); -+ kfree(au_fi(file)->fi_vm_ops); -+ au_finfo_fin(file); -+ si_read_unlock(sb); -+ return 0; -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+static ssize_t aufs_read(struct file *file, char __user *buf, size_t count, -+ loff_t *ppos) -+{ -+ ssize_t err; -+ struct dentry *dentry; -+ struct file *h_file; -+ struct super_block *sb; -+ -+ dentry = file->f_dentry; -+ sb = dentry->d_sb; -+ si_read_lock(sb, AuLock_FLUSH); -+ err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/0); -+ if (unlikely(err)) -+ goto out; -+ -+ h_file = au_h_fptr(file, au_fbstart(file)); -+ err = vfsub_read_u(h_file, buf, count, ppos); -+ /* todo: necessary? */ -+ /* file->f_ra = h_file->f_ra; */ -+ fsstack_copy_attr_atime(dentry->d_inode, h_file->f_dentry->d_inode); -+ -+ di_read_unlock(dentry, AuLock_IR); -+ fi_read_unlock(file); -+ out: -+ si_read_unlock(sb); -+ return err; -+} -+ -+static ssize_t aufs_write(struct file *file, const char __user *ubuf, -+ size_t count, loff_t *ppos) -+{ -+ ssize_t err; -+ aufs_bindex_t bstart; -+ struct au_pin pin; -+ struct dentry *dentry; -+ struct inode *inode; -+ struct super_block *sb; -+ struct file *h_file; -+ char __user *buf = (char __user *)ubuf; -+ -+ dentry = file->f_dentry; -+ sb = dentry->d_sb; -+ inode = dentry->d_inode; -+ mutex_lock(&inode->i_mutex); -+ si_read_lock(sb, AuLock_FLUSH); -+ -+ err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/1); -+ if (unlikely(err)) -+ goto out; -+ -+ err = au_ready_to_write(file, -1, &pin); -+ di_downgrade_lock(dentry, AuLock_IR); -+ if (unlikely(err)) -+ goto out_unlock; -+ -+ bstart = au_fbstart(file); -+ h_file = au_h_fptr(file, bstart); -+ au_unpin(&pin); -+ err = vfsub_write_u(h_file, buf, count, ppos); -+ au_cpup_attr_timesizes(inode); -+ inode->i_mode = h_file->f_dentry->d_inode->i_mode; -+ -+ out_unlock: -+ di_read_unlock(dentry, AuLock_IR); -+ fi_write_unlock(file); -+ out: -+ si_read_unlock(sb); -+ mutex_unlock(&inode->i_mutex); -+ return err; -+} -+ -+static ssize_t aufs_aio_read(struct kiocb *kio, const struct iovec *iov, -+ unsigned long nv, loff_t pos) -+{ -+ ssize_t err; -+ struct file *file, *h_file; -+ struct dentry *dentry; -+ struct super_block *sb; -+ -+ file = kio->ki_filp; -+ dentry = file->f_dentry; -+ sb = dentry->d_sb; -+ si_read_lock(sb, AuLock_FLUSH); -+ err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/0); -+ if (unlikely(err)) -+ goto out; -+ -+ err = -ENOSYS; -+ h_file = au_h_fptr(file, au_fbstart(file)); -+ if (h_file->f_op && h_file->f_op->aio_read) { -+ err = security_file_permission(h_file, MAY_READ); -+ if (unlikely(err)) -+ goto out_unlock; -+ if (!is_sync_kiocb(kio)) { -+ get_file(h_file); -+ fput(file); -+ } -+ kio->ki_filp = h_file; -+ err = h_file->f_op->aio_read(kio, iov, nv, pos); -+ /* todo: necessary? */ -+ /* file->f_ra = h_file->f_ra; */ -+ fsstack_copy_attr_atime(dentry->d_inode, -+ h_file->f_dentry->d_inode); -+ } else -+ /* currently there is no such fs */ -+ WARN_ON_ONCE(h_file->f_op && h_file->f_op->read); -+ -+ out_unlock: -+ di_read_unlock(dentry, AuLock_IR); -+ fi_read_unlock(file); -+ out: -+ si_read_unlock(sb); -+ return err; -+} -+ -+static ssize_t aufs_aio_write(struct kiocb *kio, const struct iovec *iov, -+ unsigned long nv, loff_t pos) -+{ -+ ssize_t err; -+ aufs_bindex_t bstart; -+ struct au_pin pin; -+ struct dentry *dentry; -+ struct inode *inode; -+ struct super_block *sb; -+ struct file *file, *h_file; -+ -+ file = kio->ki_filp; -+ dentry = file->f_dentry; -+ sb = dentry->d_sb; -+ inode = dentry->d_inode; -+ mutex_lock(&inode->i_mutex); -+ si_read_lock(sb, AuLock_FLUSH); -+ -+ err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/1); -+ if (unlikely(err)) -+ goto out; -+ -+ err = au_ready_to_write(file, -1, &pin); -+ di_downgrade_lock(dentry, AuLock_IR); -+ if (unlikely(err)) -+ goto out_unlock; -+ -+ err = -ENOSYS; -+ bstart = au_fbstart(file); -+ h_file = au_h_fptr(file, bstart); -+ au_unpin(&pin); -+ if (h_file->f_op && h_file->f_op->aio_write) { -+ err = security_file_permission(h_file, MAY_WRITE); -+ if (unlikely(err)) -+ goto out_unlock; -+ if (!is_sync_kiocb(kio)) { -+ get_file(h_file); -+ fput(file); -+ } -+ kio->ki_filp = h_file; -+ err = h_file->f_op->aio_write(kio, iov, nv, pos); -+ au_cpup_attr_timesizes(inode); -+ inode->i_mode = h_file->f_dentry->d_inode->i_mode; -+ } else -+ /* currently there is no such fs */ -+ WARN_ON_ONCE(h_file->f_op && h_file->f_op->write); -+ -+ out_unlock: -+ di_read_unlock(dentry, AuLock_IR); -+ fi_write_unlock(file); -+ out: -+ si_read_unlock(sb); -+ mutex_unlock(&inode->i_mutex); -+ return err; -+} -+ -+static ssize_t aufs_splice_read(struct file *file, loff_t *ppos, -+ struct pipe_inode_info *pipe, size_t len, -+ unsigned int flags) -+{ -+ ssize_t err; -+ struct file *h_file; -+ struct dentry *dentry; -+ struct super_block *sb; -+ -+ dentry = file->f_dentry; -+ sb = dentry->d_sb; -+ si_read_lock(sb, AuLock_FLUSH); -+ err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/0); -+ if (unlikely(err)) -+ goto out; -+ -+ err = -EINVAL; -+ h_file = au_h_fptr(file, au_fbstart(file)); -+ if (au_test_loopback_kthread()) { -+ file->f_mapping = h_file->f_mapping; -+ smp_mb(); /* unnecessary? */ -+ } -+ err = vfsub_splice_to(h_file, ppos, pipe, len, flags); -+ /* todo: necessasry? */ -+ /* file->f_ra = h_file->f_ra; */ -+ fsstack_copy_attr_atime(dentry->d_inode, h_file->f_dentry->d_inode); -+ -+ di_read_unlock(dentry, AuLock_IR); -+ fi_read_unlock(file); -+ -+ out: -+ si_read_unlock(sb); -+ return err; -+} -+ -+static ssize_t -+aufs_splice_write(struct pipe_inode_info *pipe, struct file *file, loff_t *ppos, -+ size_t len, unsigned int flags) -+{ -+ ssize_t err; -+ struct au_pin pin; -+ struct dentry *dentry; -+ struct inode *inode; -+ struct super_block *sb; -+ struct file *h_file; -+ -+ dentry = file->f_dentry; -+ inode = dentry->d_inode; -+ mutex_lock(&inode->i_mutex); -+ sb = dentry->d_sb; -+ si_read_lock(sb, AuLock_FLUSH); -+ -+ err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/1); -+ if (unlikely(err)) -+ goto out; -+ -+ err = au_ready_to_write(file, -1, &pin); -+ di_downgrade_lock(dentry, AuLock_IR); -+ if (unlikely(err)) -+ goto out_unlock; -+ -+ h_file = au_h_fptr(file, au_fbstart(file)); -+ au_unpin(&pin); -+ err = vfsub_splice_from(pipe, h_file, ppos, len, flags); -+ au_cpup_attr_timesizes(inode); -+ inode->i_mode = h_file->f_dentry->d_inode->i_mode; -+ -+ out_unlock: -+ di_read_unlock(dentry, AuLock_IR); -+ fi_write_unlock(file); -+ out: -+ si_read_unlock(sb); -+ mutex_unlock(&inode->i_mutex); -+ return err; -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+static struct file *au_safe_file(struct vm_area_struct *vma) -+{ -+ struct file *file; -+ -+ file = vma->vm_file; -+ if (file->private_data && au_test_aufs(file->f_dentry->d_sb)) -+ return file; -+ return NULL; -+} -+ -+static void au_reset_file(struct vm_area_struct *vma, struct file *file) -+{ -+ vma->vm_file = file; -+ /* smp_mb(); */ /* flush vm_file */ -+} -+ -+static int aufs_fault(struct vm_area_struct *vma, struct vm_fault *vmf) -+{ -+ int err; -+ static DECLARE_WAIT_QUEUE_HEAD(wq); -+ struct file *file, *h_file; -+ struct au_finfo *finfo; -+ -+ /* todo: non-robr mode, user vm_file as it is? */ -+ wait_event(wq, (file = au_safe_file(vma))); -+ -+ /* do not revalidate, no si lock */ -+ finfo = au_fi(file); -+ h_file = finfo->fi_hfile[0 + finfo->fi_bstart].hf_file; -+ AuDebugOn(!h_file || !finfo->fi_h_vm_ops); -+ -+ mutex_lock(&finfo->fi_vm_mtx); -+ vma->vm_file = h_file; -+ err = finfo->fi_h_vm_ops->fault(vma, vmf); -+ /* todo: necessary? */ -+ /* file->f_ra = h_file->f_ra; */ -+ au_reset_file(vma, file); -+ mutex_unlock(&finfo->fi_vm_mtx); -+#if 0 /* def CONFIG_SMP */ -+ /* wake_up_nr(&wq, online_cpu - 1); */ -+ wake_up_all(&wq); -+#else -+ wake_up(&wq); -+#endif -+ -+ return err; -+} -+ -+static int aufs_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) -+{ -+ int err; -+ static DECLARE_WAIT_QUEUE_HEAD(wq); -+ struct file *file, *h_file; -+ struct au_finfo *finfo; -+ -+ wait_event(wq, (file = au_safe_file(vma))); -+ -+ finfo = au_fi(file); -+ h_file = finfo->fi_hfile[0 + finfo->fi_bstart].hf_file; -+ AuDebugOn(!h_file || !finfo->fi_h_vm_ops); -+ -+ mutex_lock(&finfo->fi_vm_mtx); -+ vma->vm_file = h_file; -+ err = finfo->fi_h_vm_ops->page_mkwrite(vma, vmf); -+ au_reset_file(vma, file); -+ mutex_unlock(&finfo->fi_vm_mtx); -+ wake_up(&wq); -+ -+ return err; -+} -+ -+static void aufs_vm_close(struct vm_area_struct *vma) -+{ -+ static DECLARE_WAIT_QUEUE_HEAD(wq); -+ struct file *file, *h_file; -+ struct au_finfo *finfo; -+ -+ wait_event(wq, (file = au_safe_file(vma))); -+ -+ finfo = au_fi(file); -+ h_file = finfo->fi_hfile[0 + finfo->fi_bstart].hf_file; -+ AuDebugOn(!h_file || !finfo->fi_h_vm_ops); -+ -+ mutex_lock(&finfo->fi_vm_mtx); -+ vma->vm_file = h_file; -+ finfo->fi_h_vm_ops->close(vma); -+ au_reset_file(vma, file); -+ mutex_unlock(&finfo->fi_vm_mtx); -+ wake_up(&wq); -+} -+ -+static struct vm_operations_struct aufs_vm_ops = { -+ /* .close and .page_mkwrite are not set by default */ -+ .fault = aufs_fault, -+}; -+ -+/* ---------------------------------------------------------------------- */ -+ -+static unsigned long au_prot_conv(unsigned long flags) -+{ -+ unsigned long prot; -+ -+ prot = 0; -+ if (flags & VM_READ) -+ prot |= PROT_READ; -+ if (flags & VM_WRITE) -+ prot |= PROT_WRITE; -+ if (flags & VM_EXEC) -+ prot |= PROT_EXEC; -+ return prot; -+} -+ -+static struct vm_operations_struct *au_vm_ops(struct file *h_file, -+ struct vm_area_struct *vma) -+{ -+ struct vm_operations_struct *vm_ops; -+ int err; -+ -+ vm_ops = ERR_PTR(-ENODEV); -+ if (!h_file->f_op || !h_file->f_op->mmap) -+ goto out; -+ -+ err = ima_file_mmap(h_file, au_prot_conv(vma->vm_flags)); -+ vm_ops = ERR_PTR(err); -+ if (err) -+ goto out; -+ -+ err = h_file->f_op->mmap(h_file, vma); -+ vm_ops = ERR_PTR(err); -+ if (unlikely(err)) -+ goto out; -+ -+ /* oops, it became 'const' */ -+ vm_ops = (struct vm_operations_struct *)vma->vm_ops; -+ err = do_munmap(current->mm, vma->vm_start, -+ vma->vm_end - vma->vm_start); -+ if (unlikely(err)) { -+ AuIOErr("failed internal unmapping %.*s, %d\n", -+ AuDLNPair(h_file->f_dentry), err); -+ vm_ops = ERR_PTR(-EIO); -+ } -+ -+ out: -+ return vm_ops; -+} -+ -+static int au_custom_vm_ops(struct au_finfo *finfo, struct vm_area_struct *vma) -+{ -+ int err; -+ struct vm_operations_struct *h_ops; -+ -+ AuRwMustAnyLock(&finfo->fi_rwsem); -+ -+ err = 0; -+ h_ops = finfo->fi_h_vm_ops; -+ AuDebugOn(!h_ops); -+ if ((!h_ops->page_mkwrite && !h_ops->close) -+ || finfo->fi_vm_ops) -+ goto out; -+ -+ err = -ENOMEM; -+ finfo->fi_vm_ops = kmemdup(&aufs_vm_ops, sizeof(aufs_vm_ops), GFP_NOFS); -+ if (unlikely(!finfo->fi_vm_ops)) -+ goto out; -+ -+ err = 0; -+ if (h_ops->page_mkwrite) -+ finfo->fi_vm_ops->page_mkwrite = aufs_page_mkwrite; -+ if (h_ops->close) -+ finfo->fi_vm_ops->close = aufs_vm_close; -+ -+ vma->vm_ops = finfo->fi_vm_ops; -+ -+ out: -+ return err; -+} -+ -+static int aufs_mmap(struct file *file, struct vm_area_struct *vma) -+{ -+ int err; -+ unsigned char wlock, mmapped; -+ struct dentry *dentry; -+ struct super_block *sb; -+ struct file *h_file; -+ struct vm_operations_struct *vm_ops; -+ -+ dentry = file->f_dentry; -+ wlock = !!(file->f_mode & FMODE_WRITE) && (vma->vm_flags & VM_SHARED); -+ sb = dentry->d_sb; -+ si_read_lock(sb, AuLock_FLUSH); -+ err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/1); -+ if (unlikely(err)) -+ goto out; -+ -+ mmapped = !!au_test_mmapped(file); -+ if (wlock) { -+ struct au_pin pin; -+ -+ err = au_ready_to_write(file, -1, &pin); -+ di_downgrade_lock(dentry, AuLock_IR); -+ if (unlikely(err)) -+ goto out_unlock; -+ au_unpin(&pin); -+ } else -+ di_downgrade_lock(dentry, AuLock_IR); -+ -+ h_file = au_h_fptr(file, au_fbstart(file)); -+ if (!mmapped && au_test_fs_bad_mapping(h_file->f_dentry->d_sb)) { -+ /* -+ * by this assignment, f_mapping will differs from aufs inode -+ * i_mapping. -+ * if someone else mixes the use of f_dentry->d_inode and -+ * f_mapping->host, then a problem may arise. -+ */ -+ file->f_mapping = h_file->f_mapping; -+ } -+ -+ vm_ops = NULL; -+ if (!mmapped) { -+ vm_ops = au_vm_ops(h_file, vma); -+ err = PTR_ERR(vm_ops); -+ if (IS_ERR(vm_ops)) -+ goto out_unlock; -+ } -+ -+ /* -+ * unnecessary to handle MAP_DENYWRITE and deny_write_access()? -+ * currently MAP_DENYWRITE from userspace is ignored, but elf loader -+ * sets it. when FMODE_EXEC is set (by open_exec() or sys_uselib()), -+ * both of the aufs file and the lower file is deny_write_access()-ed. -+ * finally I hope we can skip handlling MAP_DENYWRITE here. -+ */ -+ err = generic_file_mmap(file, vma); -+ if (unlikely(err)) -+ goto out_unlock; -+ -+ vma->vm_ops = &aufs_vm_ops; -+ if (!mmapped) { -+ struct au_finfo *finfo = au_fi(file); -+ -+ finfo->fi_h_vm_ops = vm_ops; -+ mutex_init(&finfo->fi_vm_mtx); -+ } -+ -+ err = au_custom_vm_ops(au_fi(file), vma); -+ if (unlikely(err)) -+ goto out_unlock; -+ -+ vfsub_file_accessed(h_file); -+ fsstack_copy_attr_atime(dentry->d_inode, h_file->f_dentry->d_inode); -+ -+ out_unlock: -+ di_read_unlock(dentry, AuLock_IR); -+ fi_write_unlock(file); -+ out: -+ si_read_unlock(sb); -+ return err; -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+static int aufs_fsync_nondir(struct file *file, struct dentry *dentry, -+ int datasync) -+{ -+ int err; -+ struct au_pin pin; -+ struct inode *inode; -+ struct file *h_file; -+ struct super_block *sb; -+ -+ inode = dentry->d_inode; -+ IMustLock(file->f_mapping->host); -+ if (inode != file->f_mapping->host) { -+ mutex_unlock(&file->f_mapping->host->i_mutex); -+ mutex_lock(&inode->i_mutex); -+ } -+ IMustLock(inode); -+ -+ sb = dentry->d_sb; -+ si_read_lock(sb, AuLock_FLUSH); -+ -+ err = 0; /* -EBADF; */ /* posix? */ -+ if (unlikely(!(file->f_mode & FMODE_WRITE))) -+ goto out; -+ err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/1); -+ if (unlikely(err)) -+ goto out; -+ -+ err = au_ready_to_write(file, -1, &pin); -+ di_downgrade_lock(dentry, AuLock_IR); -+ if (unlikely(err)) -+ goto out_unlock; -+ au_unpin(&pin); -+ -+ err = -EINVAL; -+ h_file = au_h_fptr(file, au_fbstart(file)); -+ if (h_file->f_op && h_file->f_op->fsync) { -+ struct dentry *h_d; -+ struct mutex *h_mtx; -+ -+ /* -+ * no filemap_fdatawrite() since aufs file has no its own -+ * mapping, but dir. -+ */ -+ h_d = h_file->f_dentry; -+ h_mtx = &h_d->d_inode->i_mutex; -+ mutex_lock_nested(h_mtx, AuLsc_I_CHILD); -+ err = h_file->f_op->fsync(h_file, h_d, datasync); -+ if (!err) -+ vfsub_update_h_iattr(&h_file->f_path, /*did*/NULL); -+ /*ignore*/ -+ au_cpup_attr_timesizes(inode); -+ mutex_unlock(h_mtx); -+ } -+ -+ out_unlock: -+ di_read_unlock(dentry, AuLock_IR); -+ fi_write_unlock(file); -+ out: -+ si_read_unlock(sb); -+ if (inode != file->f_mapping->host) { -+ mutex_unlock(&inode->i_mutex); -+ mutex_lock(&file->f_mapping->host->i_mutex); -+ } -+ return err; -+} -+ -+/* no one supports this operation, currently */ -+#if 0 -+static int aufs_aio_fsync_nondir(struct kiocb *kio, int datasync) -+{ -+ int err; -+ struct au_pin pin; -+ struct dentry *dentry; -+ struct inode *inode; -+ struct file *file, *h_file; -+ struct super_block *sb; -+ -+ file = kio->ki_filp; -+ dentry = file->f_dentry; -+ inode = dentry->d_inode; -+ mutex_lock(&inode->i_mutex); -+ -+ sb = dentry->d_sb; -+ si_read_lock(sb, AuLock_FLUSH); -+ -+ err = 0; /* -EBADF; */ /* posix? */ -+ if (unlikely(!(file->f_mode & FMODE_WRITE))) -+ goto out; -+ err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/1); -+ if (unlikely(err)) -+ goto out; -+ -+ err = au_ready_to_write(file, -1, &pin); -+ di_downgrade_lock(dentry, AuLock_IR); -+ if (unlikely(err)) -+ goto out_unlock; -+ au_unpin(&pin); -+ -+ err = -ENOSYS; -+ h_file = au_h_fptr(file, au_fbstart(file)); -+ if (h_file->f_op && h_file->f_op->aio_fsync) { -+ struct dentry *h_d; -+ struct mutex *h_mtx; -+ -+ h_d = h_file->f_dentry; -+ h_mtx = &h_d->d_inode->i_mutex; -+ if (!is_sync_kiocb(kio)) { -+ get_file(h_file); -+ fput(file); -+ } -+ kio->ki_filp = h_file; -+ err = h_file->f_op->aio_fsync(kio, datasync); -+ mutex_lock_nested(h_mtx, AuLsc_I_CHILD); -+ if (!err) -+ vfsub_update_h_iattr(&h_file->f_path, /*did*/NULL); -+ /*ignore*/ -+ au_cpup_attr_timesizes(inode); -+ mutex_unlock(h_mtx); -+ } -+ -+ out_unlock: -+ di_read_unlock(dentry, AuLock_IR); -+ fi_write_unlock(file); -+ out: -+ si_read_unlock(sb); -+ mutex_unlock(&inode->i_mutex); -+ return err; -+} -+#endif -+ -+static int aufs_fasync(int fd, struct file *file, int flag) -+{ -+ int err; -+ struct file *h_file; -+ struct dentry *dentry; -+ struct super_block *sb; -+ -+ dentry = file->f_dentry; -+ sb = dentry->d_sb; -+ si_read_lock(sb, AuLock_FLUSH); -+ err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/0); -+ if (unlikely(err)) -+ goto out; -+ -+ h_file = au_h_fptr(file, au_fbstart(file)); -+ if (h_file->f_op && h_file->f_op->fasync) -+ err = h_file->f_op->fasync(fd, h_file, flag); -+ -+ di_read_unlock(dentry, AuLock_IR); -+ fi_read_unlock(file); -+ -+ out: -+ si_read_unlock(sb); -+ return err; -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+/* no one supports this operation, currently */ -+#if 0 -+static ssize_t aufs_sendpage(struct file *file, struct page *page, int offset, -+ size_t len, loff_t *pos , int more) -+{ -+} -+#endif -+ -+/* ---------------------------------------------------------------------- */ -+ -+const struct file_operations aufs_file_fop = { -+ /* -+ * while generic_file_llseek/_unlocked() don't use BKL, -+ * don't use it since it operates file->f_mapping->host. -+ * in aufs, it may be a real file and may confuse users by UDBA. -+ */ -+ /* .llseek = generic_file_llseek, */ -+ -+ .read = aufs_read, -+ .write = aufs_write, -+ .aio_read = aufs_aio_read, -+ .aio_write = aufs_aio_write, -+#ifdef CONFIG_AUFS_POLL -+ .poll = aufs_poll, -+#endif -+ .mmap = aufs_mmap, -+ .open = aufs_open_nondir, -+ .flush = aufs_flush, -+ .release = aufs_release_nondir, -+ .fsync = aufs_fsync_nondir, -+ /* .aio_fsync = aufs_aio_fsync_nondir, */ -+ .fasync = aufs_fasync, -+ /* .sendpage = aufs_sendpage, */ -+ .splice_write = aufs_splice_write, -+ .splice_read = aufs_splice_read, -+#if 0 -+ .aio_splice_write = aufs_aio_splice_write, -+ .aio_splice_read = aufs_aio_splice_read -+#endif -+}; -diff --git a/fs/aufs/file.c b/fs/aufs/file.c -new file mode 100644 -index 0000000..a4f33aa ---- /dev/null -+++ b/fs/aufs/file.c -@@ -0,0 +1,591 @@ -+/* -+ * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * -+ * This program, aufs is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ */ -+ -+/* -+ * handling file/dir, and address_space operation -+ */ -+ -+#include -+#include -+#include -+#include -+#include "aufs.h" -+ -+/* drop flags for writing */ -+unsigned int au_file_roflags(unsigned int flags) -+{ -+ flags &= ~(O_WRONLY | O_RDWR | O_APPEND | O_CREAT | O_TRUNC); -+ flags |= O_RDONLY | O_NOATIME; -+ return flags; -+} -+ -+/* common functions to regular file and dir */ -+struct file *au_h_open(struct dentry *dentry, aufs_bindex_t bindex, int flags, -+ struct file *file) -+{ -+ struct file *h_file; -+ struct dentry *h_dentry; -+ struct inode *h_inode; -+ struct super_block *sb; -+ struct au_branch *br; -+ int err, exec_flag; -+ struct path h_path; -+ -+ /* a race condition can happen between open and unlink/rmdir */ -+ h_file = ERR_PTR(-ENOENT); -+ h_dentry = au_h_dptr(dentry, bindex); -+ if (au_test_nfsd(current) && !h_dentry) -+ goto out; -+ h_inode = h_dentry->d_inode; -+ if (au_test_nfsd(current) && !h_inode) -+ goto out; -+ if (unlikely((!d_unhashed(dentry) && d_unhashed(h_dentry)) -+ || !h_inode)) -+ goto out; -+ -+ sb = dentry->d_sb; -+ br = au_sbr(sb, bindex); -+ h_file = ERR_PTR(-EACCES); -+ exec_flag = flags & vfsub_fmode_to_uint(FMODE_EXEC); -+ if (exec_flag && (br->br_mnt->mnt_flags & MNT_NOEXEC)) -+ goto out; -+ -+ /* drop flags for writing */ -+ if (au_test_ro(sb, bindex, dentry->d_inode)) -+ flags = au_file_roflags(flags); -+ flags &= ~O_CREAT; -+ atomic_inc(&br->br_count); -+ h_path.dentry = h_dentry; -+ h_path.mnt = br->br_mnt; -+ path_get(&h_path); -+ h_file = vfsub_dentry_open(&h_path, flags, current_cred()); -+ if (IS_ERR(h_file)) -+ goto out_br; -+ -+ if (exec_flag) { -+ err = deny_write_access(h_file); -+ if (unlikely(err)) { -+ fput(h_file); -+ h_file = ERR_PTR(err); -+ goto out_br; -+ } -+ } -+ fsnotify_open(h_dentry); -+ goto out; /* success */ -+ -+ out_br: -+ atomic_dec(&br->br_count); -+ out: -+ return h_file; -+} -+ -+int au_do_open(struct file *file, int (*open)(struct file *file, int flags)) -+{ -+ int err; -+ unsigned int flags; -+ struct dentry *dentry; -+ struct super_block *sb; -+ -+ dentry = file->f_dentry; -+ sb = dentry->d_sb; -+ si_read_lock(sb, AuLock_FLUSH); -+ err = au_finfo_init(file); -+ if (unlikely(err)) -+ goto out; -+ -+ di_read_lock_child(dentry, AuLock_IR); -+ spin_lock(&file->f_lock); -+ flags = file->f_flags; -+ spin_unlock(&file->f_lock); -+ err = open(file, flags); -+ di_read_unlock(dentry, AuLock_IR); -+ -+ fi_write_unlock(file); -+ if (unlikely(err)) -+ au_finfo_fin(file); -+ out: -+ si_read_unlock(sb); -+ return err; -+} -+ -+int au_reopen_nondir(struct file *file) -+{ -+ int err; -+ unsigned int flags; -+ aufs_bindex_t bstart, bindex, bend; -+ struct dentry *dentry; -+ struct file *h_file, *h_file_tmp; -+ -+ dentry = file->f_dentry; -+ bstart = au_dbstart(dentry); -+ h_file_tmp = NULL; -+ if (au_fbstart(file) == bstart) { -+ h_file = au_h_fptr(file, bstart); -+ if (file->f_mode == h_file->f_mode) -+ return 0; /* success */ -+ h_file_tmp = h_file; -+ get_file(h_file_tmp); -+ au_set_h_fptr(file, bstart, NULL); -+ } -+ AuDebugOn(au_fbstart(file) < bstart -+ || au_fi(file)->fi_hfile[0 + bstart].hf_file); -+ -+ spin_lock(&file->f_lock); -+ flags = file->f_flags & ~O_TRUNC; -+ spin_unlock(&file->f_lock); -+ h_file = au_h_open(dentry, bstart, flags, file); -+ err = PTR_ERR(h_file); -+ if (IS_ERR(h_file)) -+ goto out; /* todo: close all? */ -+ -+ err = 0; -+ au_set_fbstart(file, bstart); -+ au_set_h_fptr(file, bstart, h_file); -+ au_update_figen(file); -+ /* todo: necessary? */ -+ /* file->f_ra = h_file->f_ra; */ -+ -+ /* close lower files */ -+ bend = au_fbend(file); -+ for (bindex = bstart + 1; bindex <= bend; bindex++) -+ au_set_h_fptr(file, bindex, NULL); -+ au_set_fbend(file, bstart); -+ -+ out: -+ if (h_file_tmp) -+ fput(h_file_tmp); -+ return err; -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+static int au_reopen_wh(struct file *file, aufs_bindex_t btgt, -+ struct dentry *hi_wh) -+{ -+ int err; -+ aufs_bindex_t bstart; -+ struct au_dinfo *dinfo; -+ struct dentry *h_dentry; -+ -+ dinfo = au_di(file->f_dentry); -+ AuRwMustWriteLock(&dinfo->di_rwsem); -+ -+ bstart = dinfo->di_bstart; -+ dinfo->di_bstart = btgt; -+ h_dentry = dinfo->di_hdentry[0 + btgt].hd_dentry; -+ dinfo->di_hdentry[0 + btgt].hd_dentry = hi_wh; -+ err = au_reopen_nondir(file); -+ dinfo->di_hdentry[0 + btgt].hd_dentry = h_dentry; -+ dinfo->di_bstart = bstart; -+ -+ return err; -+} -+ -+static int au_ready_to_write_wh(struct file *file, loff_t len, -+ aufs_bindex_t bcpup) -+{ -+ int err; -+ struct inode *inode; -+ struct dentry *dentry, *hi_wh; -+ struct super_block *sb; -+ -+ dentry = file->f_dentry; -+ inode = dentry->d_inode; -+ hi_wh = au_hi_wh(inode, bcpup); -+ if (!hi_wh) -+ err = au_sio_cpup_wh(dentry, bcpup, len, file); -+ else -+ /* already copied-up after unlink */ -+ err = au_reopen_wh(file, bcpup, hi_wh); -+ -+ sb = dentry->d_sb; -+ if (!err && inode->i_nlink > 1 && au_opt_test(au_mntflags(sb), PLINK)) -+ au_plink_append(inode, bcpup, au_h_dptr(dentry, bcpup)); -+ -+ return err; -+} -+ -+/* -+ * prepare the @file for writing. -+ */ -+int au_ready_to_write(struct file *file, loff_t len, struct au_pin *pin) -+{ -+ int err; -+ aufs_bindex_t bstart, bcpup; -+ struct dentry *dentry, *parent, *h_dentry; -+ struct inode *h_inode, *inode; -+ struct super_block *sb; -+ -+ dentry = file->f_dentry; -+ sb = dentry->d_sb; -+ bstart = au_fbstart(file); -+ inode = dentry->d_inode; -+ err = au_test_ro(sb, bstart, inode); -+ if (!err && (au_h_fptr(file, bstart)->f_mode & FMODE_WRITE)) { -+ err = au_pin(pin, dentry, bstart, AuOpt_UDBA_NONE, /*flags*/0); -+ goto out; -+ } -+ -+ /* need to cpup */ -+ parent = dget_parent(dentry); -+ di_write_lock_parent(parent); -+ err = AuWbrCopyup(au_sbi(sb), dentry); -+ bcpup = err; -+ if (unlikely(err < 0)) -+ goto out_dgrade; -+ err = 0; -+ -+ if (!au_h_dptr(parent, bcpup)) { -+ err = au_cpup_dirs(dentry, bcpup); -+ if (unlikely(err)) -+ goto out_dgrade; -+ } -+ -+ err = au_pin(pin, dentry, bcpup, AuOpt_UDBA_NONE, -+ AuPin_DI_LOCKED | AuPin_MNT_WRITE); -+ if (unlikely(err)) -+ goto out_dgrade; -+ -+ h_dentry = au_h_fptr(file, bstart)->f_dentry; -+ h_inode = h_dentry->d_inode; -+ mutex_lock_nested(&h_inode->i_mutex, AuLsc_I_CHILD); -+ if (d_unhashed(dentry) /* || d_unhashed(h_dentry) */ -+ /* || !h_inode->i_nlink */) { -+ err = au_ready_to_write_wh(file, len, bcpup); -+ di_downgrade_lock(parent, AuLock_IR); -+ } else { -+ di_downgrade_lock(parent, AuLock_IR); -+ if (!au_h_dptr(dentry, bcpup)) -+ err = au_sio_cpup_simple(dentry, bcpup, len, -+ AuCpup_DTIME); -+ if (!err) -+ err = au_reopen_nondir(file); -+ } -+ mutex_unlock(&h_inode->i_mutex); -+ -+ if (!err) { -+ au_pin_set_parent_lflag(pin, /*lflag*/0); -+ goto out_dput; /* success */ -+ } -+ au_unpin(pin); -+ goto out_unlock; -+ -+ out_dgrade: -+ di_downgrade_lock(parent, AuLock_IR); -+ out_unlock: -+ di_read_unlock(parent, AuLock_IR); -+ out_dput: -+ dput(parent); -+ out: -+ return err; -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+static int au_file_refresh_by_inode(struct file *file, int *need_reopen) -+{ -+ int err; -+ aufs_bindex_t bstart; -+ struct au_pin pin; -+ struct au_finfo *finfo; -+ struct dentry *dentry, *parent, *hi_wh; -+ struct inode *inode; -+ struct super_block *sb; -+ -+ FiMustWriteLock(file); -+ -+ err = 0; -+ finfo = au_fi(file); -+ dentry = file->f_dentry; -+ sb = dentry->d_sb; -+ inode = dentry->d_inode; -+ bstart = au_ibstart(inode); -+ if (bstart == finfo->fi_bstart) -+ goto out; -+ -+ parent = dget_parent(dentry); -+ if (au_test_ro(sb, bstart, inode)) { -+ di_read_lock_parent(parent, !AuLock_IR); -+ err = AuWbrCopyup(au_sbi(sb), dentry); -+ bstart = err; -+ di_read_unlock(parent, !AuLock_IR); -+ if (unlikely(err < 0)) -+ goto out_parent; -+ err = 0; -+ } -+ -+ di_read_lock_parent(parent, AuLock_IR); -+ hi_wh = au_hi_wh(inode, bstart); -+ if (au_opt_test(au_mntflags(sb), PLINK) -+ && au_plink_test(inode) -+ && !d_unhashed(dentry)) { -+ err = au_test_and_cpup_dirs(dentry, bstart); -+ if (unlikely(err)) -+ goto out_unlock; -+ -+ /* always superio. */ -+ err = au_pin(&pin, dentry, bstart, AuOpt_UDBA_NONE, -+ AuPin_DI_LOCKED | AuPin_MNT_WRITE); -+ if (!err) -+ err = au_sio_cpup_simple(dentry, bstart, -1, -+ AuCpup_DTIME); -+ au_unpin(&pin); -+ } else if (hi_wh) { -+ /* already copied-up after unlink */ -+ err = au_reopen_wh(file, bstart, hi_wh); -+ *need_reopen = 0; -+ } -+ -+ out_unlock: -+ di_read_unlock(parent, AuLock_IR); -+ out_parent: -+ dput(parent); -+ out: -+ return err; -+} -+ -+static void au_do_refresh_file(struct file *file) -+{ -+ aufs_bindex_t bindex, bend, new_bindex, brid; -+ struct au_hfile *p, tmp, *q; -+ struct au_finfo *finfo; -+ struct super_block *sb; -+ -+ FiMustWriteLock(file); -+ -+ sb = file->f_dentry->d_sb; -+ finfo = au_fi(file); -+ p = finfo->fi_hfile + finfo->fi_bstart; -+ brid = p->hf_br->br_id; -+ bend = finfo->fi_bend; -+ for (bindex = finfo->fi_bstart; bindex <= bend; bindex++, p++) { -+ if (!p->hf_file) -+ continue; -+ -+ new_bindex = au_br_index(sb, p->hf_br->br_id); -+ if (new_bindex == bindex) -+ continue; -+ if (new_bindex < 0) { -+ au_set_h_fptr(file, bindex, NULL); -+ continue; -+ } -+ -+ /* swap two lower inode, and loop again */ -+ q = finfo->fi_hfile + new_bindex; -+ tmp = *q; -+ *q = *p; -+ *p = tmp; -+ if (tmp.hf_file) { -+ bindex--; -+ p--; -+ } -+ } -+ -+ p = finfo->fi_hfile; -+ if (!au_test_mmapped(file) && !d_unhashed(file->f_dentry)) { -+ bend = au_sbend(sb); -+ for (finfo->fi_bstart = 0; finfo->fi_bstart <= bend; -+ finfo->fi_bstart++, p++) -+ if (p->hf_file) { -+ if (p->hf_file->f_dentry -+ && p->hf_file->f_dentry->d_inode) -+ break; -+ else -+ au_hfput(p, file); -+ } -+ } else { -+ bend = au_br_index(sb, brid); -+ for (finfo->fi_bstart = 0; finfo->fi_bstart < bend; -+ finfo->fi_bstart++, p++) -+ if (p->hf_file) -+ au_hfput(p, file); -+ bend = au_sbend(sb); -+ } -+ -+ p = finfo->fi_hfile + bend; -+ for (finfo->fi_bend = bend; finfo->fi_bend >= finfo->fi_bstart; -+ finfo->fi_bend--, p--) -+ if (p->hf_file) { -+ if (p->hf_file->f_dentry -+ && p->hf_file->f_dentry->d_inode) -+ break; -+ else -+ au_hfput(p, file); -+ } -+ AuDebugOn(finfo->fi_bend < finfo->fi_bstart); -+} -+ -+/* -+ * after branch manipulating, refresh the file. -+ */ -+static int refresh_file(struct file *file, int (*reopen)(struct file *file)) -+{ -+ int err, need_reopen; -+ struct dentry *dentry; -+ aufs_bindex_t bend, bindex; -+ -+ dentry = file->f_dentry; -+ err = au_fi_realloc(au_fi(file), au_sbend(dentry->d_sb) + 1); -+ if (unlikely(err)) -+ goto out; -+ au_do_refresh_file(file); -+ -+ err = 0; -+ need_reopen = 1; -+ if (!au_test_mmapped(file)) -+ err = au_file_refresh_by_inode(file, &need_reopen); -+ if (!err && need_reopen && !d_unhashed(dentry)) -+ err = reopen(file); -+ if (!err) { -+ au_update_figen(file); -+ return 0; /* success */ -+ } -+ -+ /* error, close all lower files */ -+ bend = au_fbend(file); -+ for (bindex = au_fbstart(file); bindex <= bend; bindex++) -+ au_set_h_fptr(file, bindex, NULL); -+ -+ out: -+ return err; -+} -+ -+/* common function to regular file and dir */ -+int au_reval_and_lock_fdi(struct file *file, int (*reopen)(struct file *file), -+ int wlock) -+{ -+ int err; -+ unsigned int sigen, figen; -+ aufs_bindex_t bstart; -+ unsigned char pseudo_link; -+ struct dentry *dentry; -+ -+ err = 0; -+ dentry = file->f_dentry; -+ sigen = au_sigen(dentry->d_sb); -+ fi_write_lock(file); -+ figen = au_figen(file); -+ di_write_lock_child(dentry); -+ bstart = au_dbstart(dentry); -+ pseudo_link = (bstart != au_ibstart(dentry->d_inode)); -+ if (sigen == figen && !pseudo_link && au_fbstart(file) == bstart) { -+ if (!wlock) { -+ di_downgrade_lock(dentry, AuLock_IR); -+ fi_downgrade_lock(file); -+ } -+ goto out; /* success */ -+ } -+ -+ AuDbg("sigen %d, figen %d\n", sigen, figen); -+ if (sigen != au_digen(dentry) -+ || sigen != au_iigen(dentry->d_inode)) { -+ err = au_reval_dpath(dentry, sigen); -+ if (unlikely(err < 0)) -+ goto out; -+ AuDebugOn(au_digen(dentry) != sigen -+ || au_iigen(dentry->d_inode) != sigen); -+ } -+ -+ err = refresh_file(file, reopen); -+ if (!err) { -+ if (!wlock) { -+ di_downgrade_lock(dentry, AuLock_IR); -+ fi_downgrade_lock(file); -+ } -+ } else { -+ di_write_unlock(dentry); -+ fi_write_unlock(file); -+ } -+ -+ out: -+ return err; -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+/* cf. aufs_nopage() */ -+/* for madvise(2) */ -+static int aufs_readpage(struct file *file __maybe_unused, struct page *page) -+{ -+ unlock_page(page); -+ return 0; -+} -+ -+/* they will never be called. */ -+#ifdef CONFIG_AUFS_DEBUG -+static int aufs_write_begin(struct file *file, struct address_space *mapping, -+ loff_t pos, unsigned len, unsigned flags, -+ struct page **pagep, void **fsdata) -+{ AuUnsupport(); return 0; } -+static int aufs_write_end(struct file *file, struct address_space *mapping, -+ loff_t pos, unsigned len, unsigned copied, -+ struct page *page, void *fsdata) -+{ AuUnsupport(); return 0; } -+static int aufs_writepage(struct page *page, struct writeback_control *wbc) -+{ AuUnsupport(); return 0; } -+static void aufs_sync_page(struct page *page) -+{ AuUnsupport(); } -+ -+static int aufs_set_page_dirty(struct page *page) -+{ AuUnsupport(); return 0; } -+static void aufs_invalidatepage(struct page *page, unsigned long offset) -+{ AuUnsupport(); } -+static int aufs_releasepage(struct page *page, gfp_t gfp) -+{ AuUnsupport(); return 0; } -+static ssize_t aufs_direct_IO(int rw, struct kiocb *iocb, -+ const struct iovec *iov, loff_t offset, -+ unsigned long nr_segs) -+{ AuUnsupport(); return 0; } -+static int aufs_get_xip_mem(struct address_space *mapping, pgoff_t pgoff, -+ int create, void **kmem, unsigned long *pfn) -+{ AuUnsupport(); return 0; } -+static int aufs_migratepage(struct address_space *mapping, struct page *newpage, -+ struct page *page) -+{ AuUnsupport(); return 0; } -+static int aufs_launder_page(struct page *page) -+{ AuUnsupport(); return 0; } -+static int aufs_is_partially_uptodate(struct page *page, -+ read_descriptor_t *desc, -+ unsigned long from) -+{ AuUnsupport(); return 0; } -+static int aufs_error_remove_page(struct address_space *mapping, -+ struct page *page) -+{ AuUnsupport(); return 0; } -+#endif /* CONFIG_AUFS_DEBUG */ -+ -+struct address_space_operations aufs_aop = { -+ .readpage = aufs_readpage, -+#ifdef CONFIG_AUFS_DEBUG -+ .writepage = aufs_writepage, -+ .sync_page = aufs_sync_page, -+ /* no writepages, because of writepage */ -+ .set_page_dirty = aufs_set_page_dirty, -+ /* no readpages, because of readpage */ -+ .write_begin = aufs_write_begin, -+ .write_end = aufs_write_end, -+ /* no bmap, no block device */ -+ .invalidatepage = aufs_invalidatepage, -+ .releasepage = aufs_releasepage, -+ .direct_IO = aufs_direct_IO, /* todo */ -+ .get_xip_mem = aufs_get_xip_mem, /* todo */ -+ .migratepage = aufs_migratepage, -+ .launder_page = aufs_launder_page, -+ .is_partially_uptodate = aufs_is_partially_uptodate, -+ .error_remove_page = aufs_error_remove_page -+#endif /* CONFIG_AUFS_DEBUG */ -+}; -diff --git a/fs/aufs/file.h b/fs/aufs/file.h -new file mode 100644 -index 0000000..79a63fb ---- /dev/null -+++ b/fs/aufs/file.h -@@ -0,0 +1,175 @@ -+/* -+ * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * -+ * This program, aufs is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ */ -+ -+/* -+ * file operations -+ */ -+ -+#ifndef __AUFS_FILE_H__ -+#define __AUFS_FILE_H__ -+ -+#ifdef __KERNEL__ -+ -+#include -+#include -+#include -+#include "rwsem.h" -+ -+struct au_branch; -+struct au_hfile { -+ struct file *hf_file; -+ struct au_branch *hf_br; -+}; -+ -+struct au_vdir; -+struct au_finfo { -+ atomic_t fi_generation; -+ -+ struct au_rwsem fi_rwsem; -+ struct au_hfile *fi_hfile; -+ aufs_bindex_t fi_bstart, fi_bend; -+ -+ union { -+ /* non-dir only */ -+ struct { -+ struct vm_operations_struct *fi_h_vm_ops; -+ struct vm_operations_struct *fi_vm_ops; -+ struct mutex fi_vm_mtx; -+ }; -+ -+ /* dir only */ -+ struct { -+ struct au_vdir *fi_vdir_cache; -+ int fi_maintain_plink; -+ }; -+ }; -+}; -+ -+/* ---------------------------------------------------------------------- */ -+ -+/* file.c */ -+extern struct address_space_operations aufs_aop; -+unsigned int au_file_roflags(unsigned int flags); -+struct file *au_h_open(struct dentry *dentry, aufs_bindex_t bindex, int flags, -+ struct file *file); -+int au_do_open(struct file *file, int (*open)(struct file *file, int flags)); -+int au_reopen_nondir(struct file *file); -+struct au_pin; -+int au_ready_to_write(struct file *file, loff_t len, struct au_pin *pin); -+int au_reval_and_lock_fdi(struct file *file, int (*reopen)(struct file *file), -+ int wlock); -+ -+/* poll.c */ -+#ifdef CONFIG_AUFS_POLL -+unsigned int aufs_poll(struct file *file, poll_table *wait); -+#endif -+ -+/* f_op.c */ -+extern const struct file_operations aufs_file_fop; -+int aufs_flush(struct file *file, fl_owner_t id); -+ -+/* finfo.c */ -+void au_hfput(struct au_hfile *hf, struct file *file); -+void au_set_h_fptr(struct file *file, aufs_bindex_t bindex, -+ struct file *h_file); -+ -+void au_update_figen(struct file *file); -+ -+void au_finfo_fin(struct file *file); -+int au_finfo_init(struct file *file); -+int au_fi_realloc(struct au_finfo *finfo, int nbr); -+ -+/* ---------------------------------------------------------------------- */ -+ -+static inline struct au_finfo *au_fi(struct file *file) -+{ -+ return file->private_data; -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+/* -+ * fi_read_lock, fi_write_lock, -+ * fi_read_unlock, fi_write_unlock, fi_downgrade_lock -+ */ -+AuSimpleRwsemFuncs(fi, struct file *f, &au_fi(f)->fi_rwsem); -+ -+#define FiMustNoWaiters(f) AuRwMustNoWaiters(&au_fi(f)->fi_rwsem) -+#define FiMustAnyLock(f) AuRwMustAnyLock(&au_fi(f)->fi_rwsem) -+#define FiMustWriteLock(f) AuRwMustWriteLock(&au_fi(f)->fi_rwsem) -+ -+/* ---------------------------------------------------------------------- */ -+ -+/* todo: hard/soft set? */ -+static inline aufs_bindex_t au_fbstart(struct file *file) -+{ -+ FiMustAnyLock(file); -+ return au_fi(file)->fi_bstart; -+} -+ -+static inline aufs_bindex_t au_fbend(struct file *file) -+{ -+ FiMustAnyLock(file); -+ return au_fi(file)->fi_bend; -+} -+ -+static inline struct au_vdir *au_fvdir_cache(struct file *file) -+{ -+ FiMustAnyLock(file); -+ return au_fi(file)->fi_vdir_cache; -+} -+ -+static inline void au_set_fbstart(struct file *file, aufs_bindex_t bindex) -+{ -+ FiMustWriteLock(file); -+ au_fi(file)->fi_bstart = bindex; -+} -+ -+static inline void au_set_fbend(struct file *file, aufs_bindex_t bindex) -+{ -+ FiMustWriteLock(file); -+ au_fi(file)->fi_bend = bindex; -+} -+ -+static inline void au_set_fvdir_cache(struct file *file, -+ struct au_vdir *vdir_cache) -+{ -+ FiMustWriteLock(file); -+ au_fi(file)->fi_vdir_cache = vdir_cache; -+} -+ -+static inline struct file *au_h_fptr(struct file *file, aufs_bindex_t bindex) -+{ -+ FiMustAnyLock(file); -+ return au_fi(file)->fi_hfile[0 + bindex].hf_file; -+} -+ -+/* todo: memory barrier? */ -+static inline unsigned int au_figen(struct file *f) -+{ -+ return atomic_read(&au_fi(f)->fi_generation); -+} -+ -+static inline int au_test_mmapped(struct file *f) -+{ -+ /* FiMustAnyLock(f); */ -+ return !!(au_fi(f)->fi_h_vm_ops); -+} -+ -+#endif /* __KERNEL__ */ -+#endif /* __AUFS_FILE_H__ */ -diff --git a/fs/aufs/finfo.c b/fs/aufs/finfo.c -new file mode 100644 -index 0000000..c52d669 ---- /dev/null -+++ b/fs/aufs/finfo.c -@@ -0,0 +1,128 @@ -+/* -+ * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * -+ * This program, aufs is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ */ -+ -+/* -+ * file private data -+ */ -+ -+#include -+#include "aufs.h" -+ -+void au_hfput(struct au_hfile *hf, struct file *file) -+{ -+ if (file->f_flags & vfsub_fmode_to_uint(FMODE_EXEC)) -+ allow_write_access(hf->hf_file); -+ fput(hf->hf_file); -+ hf->hf_file = NULL; -+ atomic_dec_return(&hf->hf_br->br_count); -+ hf->hf_br = NULL; -+} -+ -+void au_set_h_fptr(struct file *file, aufs_bindex_t bindex, struct file *val) -+{ -+ struct au_finfo *finfo = au_fi(file); -+ struct au_hfile *hf; -+ -+ hf = finfo->fi_hfile + bindex; -+ if (hf->hf_file) -+ au_hfput(hf, file); -+ if (val) { -+ hf->hf_file = val; -+ hf->hf_br = au_sbr(file->f_dentry->d_sb, bindex); -+ } -+} -+ -+void au_update_figen(struct file *file) -+{ -+ atomic_set(&au_fi(file)->fi_generation, au_digen(file->f_dentry)); -+ /* smp_mb(); */ /* atomic_set */ -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+void au_finfo_fin(struct file *file) -+{ -+ struct au_finfo *finfo; -+ aufs_bindex_t bindex, bend; -+ -+ fi_write_lock(file); -+ bend = au_fbend(file); -+ bindex = au_fbstart(file); -+ if (bindex >= 0) -+ /* -+ * calls fput() instead of filp_close(), -+ * since no dnotify or lock for the lower file. -+ */ -+ for (; bindex <= bend; bindex++) -+ au_set_h_fptr(file, bindex, NULL); -+ -+ finfo = au_fi(file); -+ au_dbg_verify_hf(finfo); -+ kfree(finfo->fi_hfile); -+ fi_write_unlock(file); -+ AuRwDestroy(&finfo->fi_rwsem); -+ au_cache_free_finfo(finfo); -+} -+ -+int au_finfo_init(struct file *file) -+{ -+ struct au_finfo *finfo; -+ struct dentry *dentry; -+ -+ dentry = file->f_dentry; -+ finfo = au_cache_alloc_finfo(); -+ if (unlikely(!finfo)) -+ goto out; -+ -+ finfo->fi_hfile = kcalloc(au_sbend(dentry->d_sb) + 1, -+ sizeof(*finfo->fi_hfile), GFP_NOFS); -+ if (unlikely(!finfo->fi_hfile)) -+ goto out_finfo; -+ -+ au_rw_init_wlock(&finfo->fi_rwsem); -+ finfo->fi_bstart = -1; -+ finfo->fi_bend = -1; -+ atomic_set(&finfo->fi_generation, au_digen(dentry)); -+ /* smp_mb(); */ /* atomic_set */ -+ -+ file->private_data = finfo; -+ return 0; /* success */ -+ -+ out_finfo: -+ au_cache_free_finfo(finfo); -+ out: -+ return -ENOMEM; -+} -+ -+int au_fi_realloc(struct au_finfo *finfo, int nbr) -+{ -+ int err, sz; -+ struct au_hfile *hfp; -+ -+ err = -ENOMEM; -+ sz = sizeof(*hfp) * (finfo->fi_bend + 1); -+ if (!sz) -+ sz = sizeof(*hfp); -+ hfp = au_kzrealloc(finfo->fi_hfile, sz, sizeof(*hfp) * nbr, GFP_NOFS); -+ if (hfp) { -+ finfo->fi_hfile = hfp; -+ err = 0; -+ } -+ -+ return err; -+} -diff --git a/fs/aufs/fstype.h b/fs/aufs/fstype.h -new file mode 100644 -index 0000000..db859fa ---- /dev/null -+++ b/fs/aufs/fstype.h -@@ -0,0 +1,484 @@ -+/* -+ * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * -+ * This program, aufs is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ */ -+ -+/* -+ * judging filesystem type -+ */ -+ -+#ifndef __AUFS_FSTYPE_H__ -+#define __AUFS_FSTYPE_H__ -+ -+#ifdef __KERNEL__ -+ -+#include -+#include -+#include -+#include -+ -+static inline int au_test_aufs(struct super_block *sb) -+{ -+ return sb->s_magic == AUFS_SUPER_MAGIC; -+} -+ -+static inline const char *au_sbtype(struct super_block *sb) -+{ -+ return sb->s_type->name; -+} -+ -+static inline int au_test_iso9660(struct super_block *sb __maybe_unused) -+{ -+#if defined(CONFIG_ROMFS_FS) || defined(CONFIG_ROMFS_FS_MODULE) -+ return sb->s_magic == ROMFS_MAGIC; -+#else -+ return 0; -+#endif -+} -+ -+static inline int au_test_romfs(struct super_block *sb __maybe_unused) -+{ -+#if defined(CONFIG_ISO9660_FS) || defined(CONFIG_ISO9660_FS_MODULE) -+ return sb->s_magic == ISOFS_SUPER_MAGIC; -+#else -+ return 0; -+#endif -+} -+ -+static inline int au_test_cramfs(struct super_block *sb __maybe_unused) -+{ -+#if defined(CONFIG_CRAMFS) || defined(CONFIG_CRAMFS_MODULE) -+ return sb->s_magic == CRAMFS_MAGIC; -+#endif -+ return 0; -+} -+ -+static inline int au_test_nfs(struct super_block *sb __maybe_unused) -+{ -+#if defined(CONFIG_NFS_FS) || defined(CONFIG_NFS_FS_MODULE) -+ return sb->s_magic == NFS_SUPER_MAGIC; -+#else -+ return 0; -+#endif -+} -+ -+static inline int au_test_fuse(struct super_block *sb __maybe_unused) -+{ -+#if defined(CONFIG_FUSE_FS) || defined(CONFIG_FUSE_FS_MODULE) -+ return sb->s_magic == FUSE_SUPER_MAGIC; -+#else -+ return 0; -+#endif -+} -+ -+static inline int au_test_xfs(struct super_block *sb __maybe_unused) -+{ -+#if defined(CONFIG_XFS_FS) || defined(CONFIG_XFS_FS_MODULE) -+ return sb->s_magic == XFS_SB_MAGIC; -+#else -+ return 0; -+#endif -+} -+ -+static inline int au_test_tmpfs(struct super_block *sb __maybe_unused) -+{ -+#ifdef CONFIG_TMPFS -+ return sb->s_magic == TMPFS_MAGIC; -+#else -+ return 0; -+#endif -+} -+ -+static inline int au_test_ecryptfs(struct super_block *sb __maybe_unused) -+{ -+#if defined(CONFIG_ECRYPT_FS) || defined(CONFIG_ECRYPT_FS_MODULE) -+ return !strcmp(au_sbtype(sb), "ecryptfs"); -+#else -+ return 0; -+#endif -+} -+ -+static inline int au_test_smbfs(struct super_block *sb __maybe_unused) -+{ -+#if defined(CONFIG_SMB_FS) || defined(CONFIG_SMB_FS_MODULE) -+ return sb->s_magic == SMB_SUPER_MAGIC; -+#else -+ return 0; -+#endif -+} -+ -+static inline int au_test_ocfs2(struct super_block *sb __maybe_unused) -+{ -+#if defined(CONFIG_OCFS2_FS) || defined(CONFIG_OCFS2_FS_MODULE) -+ return sb->s_magic == OCFS2_SUPER_MAGIC; -+#else -+ return 0; -+#endif -+} -+ -+static inline int au_test_ocfs2_dlmfs(struct super_block *sb __maybe_unused) -+{ -+#if defined(CONFIG_OCFS2_FS_O2CB) || defined(CONFIG_OCFS2_FS_O2CB_MODULE) -+ return sb->s_magic == DLMFS_MAGIC; -+#else -+ return 0; -+#endif -+} -+ -+static inline int au_test_coda(struct super_block *sb __maybe_unused) -+{ -+#if defined(CONFIG_CODA_FS) || defined(CONFIG_CODA_FS_MODULE) -+ return sb->s_magic == CODA_SUPER_MAGIC; -+#else -+ return 0; -+#endif -+} -+ -+static inline int au_test_v9fs(struct super_block *sb __maybe_unused) -+{ -+#if defined(CONFIG_9P_FS) || defined(CONFIG_9P_FS_MODULE) -+ return sb->s_magic == V9FS_MAGIC; -+#else -+ return 0; -+#endif -+} -+ -+static inline int au_test_ext4(struct super_block *sb __maybe_unused) -+{ -+#if defined(CONFIG_EXT4DEV_FS) || defined(CONFIG_EXT4DEV_FS_MODULE) -+ return sb->s_magic == EXT4_SUPER_MAGIC; -+#else -+ return 0; -+#endif -+} -+ -+static inline int au_test_sysv(struct super_block *sb __maybe_unused) -+{ -+#if defined(CONFIG_SYSV_FS) || defined(CONFIG_SYSV_FS_MODULE) -+ return !strcmp(au_sbtype(sb), "sysv"); -+#else -+ return 0; -+#endif -+} -+ -+static inline int au_test_ramfs(struct super_block *sb) -+{ -+ return sb->s_magic == RAMFS_MAGIC; -+} -+ -+static inline int au_test_ubifs(struct super_block *sb __maybe_unused) -+{ -+#if defined(CONFIG_UBIFS_FS) || defined(CONFIG_UBIFS_FS_MODULE) -+ return sb->s_magic == UBIFS_SUPER_MAGIC; -+#else -+ return 0; -+#endif -+} -+ -+static inline int au_test_procfs(struct super_block *sb __maybe_unused) -+{ -+#ifdef CONFIG_PROC_FS -+ return sb->s_magic == PROC_SUPER_MAGIC; -+#else -+ return 0; -+#endif -+} -+ -+static inline int au_test_sysfs(struct super_block *sb __maybe_unused) -+{ -+#ifdef CONFIG_SYSFS -+ return sb->s_magic == SYSFS_MAGIC; -+#else -+ return 0; -+#endif -+} -+ -+static inline int au_test_configfs(struct super_block *sb __maybe_unused) -+{ -+#if defined(CONFIG_CONFIGFS_FS) || defined(CONFIG_CONFIGFS_FS_MODULE) -+ return sb->s_magic == CONFIGFS_MAGIC; -+#else -+ return 0; -+#endif -+} -+ -+static inline int au_test_minix(struct super_block *sb __maybe_unused) -+{ -+#if defined(CONFIG_MINIX_FS) || defined(CONFIG_MINIX_FS_MODULE) -+ return sb->s_magic == MINIX3_SUPER_MAGIC -+ || sb->s_magic == MINIX2_SUPER_MAGIC -+ || sb->s_magic == MINIX2_SUPER_MAGIC2 -+ || sb->s_magic == MINIX_SUPER_MAGIC -+ || sb->s_magic == MINIX_SUPER_MAGIC2; -+#else -+ return 0; -+#endif -+} -+ -+static inline int au_test_cifs(struct super_block *sb __maybe_unused) -+{ -+#if defined(CONFIG_CIFS_FS) || defined(CONFIGCIFS_FS_MODULE) -+ return sb->s_magic == CIFS_MAGIC_NUMBER; -+#else -+ return 0; -+#endif -+} -+ -+static inline int au_test_fat(struct super_block *sb __maybe_unused) -+{ -+#if defined(CONFIG_FAT_FS) || defined(CONFIG_FAT_FS_MODULE) -+ return sb->s_magic == MSDOS_SUPER_MAGIC; -+#else -+ return 0; -+#endif -+} -+ -+static inline int au_test_msdos(struct super_block *sb) -+{ -+ return au_test_fat(sb); -+} -+ -+static inline int au_test_vfat(struct super_block *sb) -+{ -+ return au_test_fat(sb); -+} -+ -+static inline int au_test_securityfs(struct super_block *sb __maybe_unused) -+{ -+#ifdef CONFIG_SECURITYFS -+ return sb->s_magic == SECURITYFS_MAGIC; -+#else -+ return 0; -+#endif -+} -+ -+static inline int au_test_squashfs(struct super_block *sb __maybe_unused) -+{ -+#if defined(CONFIG_SQUASHFS) || defined(CONFIG_SQUASHFS_MODULE) -+ return sb->s_magic == SQUASHFS_MAGIC; -+#else -+ return 0; -+#endif -+} -+ -+static inline int au_test_btrfs(struct super_block *sb __maybe_unused) -+{ -+#if defined(CONFIG_BTRFS_FS) || defined(CONFIG_BTRFS_FS_MODULE) -+ return sb->s_magic == BTRFS_SUPER_MAGIC; -+#else -+ return 0; -+#endif -+} -+ -+static inline int au_test_xenfs(struct super_block *sb __maybe_unused) -+{ -+#if defined(CONFIG_XENFS) || defined(CONFIG_XENFS_MODULE) -+ return sb->s_magic == XENFS_SUPER_MAGIC; -+#else -+ return 0; -+#endif -+} -+ -+static inline int au_test_debugfs(struct super_block *sb __maybe_unused) -+{ -+#ifdef CONFIG_DEBUG_FS -+ return sb->s_magic == DEBUGFS_MAGIC; -+#else -+ return 0; -+#endif -+} -+ -+static inline int au_test_nilfs(struct super_block *sb __maybe_unused) -+{ -+#if defined(CONFIG_NILFS) || defined(CONFIG_NILFS_MODULE) -+ return sb->s_magic == NILFS_SUPER_MAGIC; -+#else -+ return 0; -+#endif -+} -+ -+/* ---------------------------------------------------------------------- */ -+/* -+ * they can't be an aufs branch. -+ */ -+static inline int au_test_fs_unsuppoted(struct super_block *sb) -+{ -+ return -+#ifndef CONFIG_AUFS_BR_RAMFS -+ au_test_ramfs(sb) || -+#endif -+ au_test_procfs(sb) -+ || au_test_sysfs(sb) -+ || au_test_configfs(sb) -+ || au_test_debugfs(sb) -+ || au_test_securityfs(sb) -+ || au_test_xenfs(sb) -+ || au_test_ecryptfs(sb) -+ /* || !strcmp(au_sbtype(sb), "unionfs") */ -+ || au_test_aufs(sb); /* will be supported in next version */ -+} -+ -+/* -+ * If the filesystem supports NFS-export, then it has to support NULL as -+ * a nameidata parameter for ->create(), ->lookup() and ->d_revalidate(). -+ * We can apply this principle when we handle a lower filesystem. -+ */ -+static inline int au_test_fs_null_nd(struct super_block *sb) -+{ -+ return !!sb->s_export_op; -+} -+ -+static inline int au_test_fs_remote(struct super_block *sb) -+{ -+ return !au_test_tmpfs(sb) -+#ifdef CONFIG_AUFS_BR_RAMFS -+ && !au_test_ramfs(sb) -+#endif -+ && !(sb->s_type->fs_flags & FS_REQUIRES_DEV); -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+/* -+ * Note: these functions (below) are created after reading ->getattr() in all -+ * filesystems under linux/fs. it means we have to do so in every update... -+ */ -+ -+/* -+ * some filesystems require getattr to refresh the inode attributes before -+ * referencing. -+ * in most cases, we can rely on the inode attribute in NFS (or every remote fs) -+ * and leave the work for d_revalidate() -+ */ -+static inline int au_test_fs_refresh_iattr(struct super_block *sb) -+{ -+ return au_test_nfs(sb) -+ || au_test_fuse(sb) -+ /* || au_test_smbfs(sb) */ /* untested */ -+ /* || au_test_ocfs2(sb) */ /* untested */ -+ /* || au_test_btrfs(sb) */ /* untested */ -+ /* || au_test_coda(sb) */ /* untested */ -+ /* || au_test_v9fs(sb) */ /* untested */ -+ ; -+} -+ -+/* -+ * filesystems which don't maintain i_size or i_blocks. -+ */ -+static inline int au_test_fs_bad_iattr_size(struct super_block *sb) -+{ -+ return au_test_xfs(sb) -+ /* || au_test_ext4(sb) */ /* untested */ -+ /* || au_test_ocfs2(sb) */ /* untested */ -+ /* || au_test_ocfs2_dlmfs(sb) */ /* untested */ -+ /* || au_test_sysv(sb) */ /* untested */ -+ /* || au_test_ubifs(sb) */ /* untested */ -+ /* || au_test_minix(sb) */ /* untested */ -+ ; -+} -+ -+/* -+ * filesystems which don't store the correct value in some of their inode -+ * attributes. -+ */ -+static inline int au_test_fs_bad_iattr(struct super_block *sb) -+{ -+ return au_test_fs_bad_iattr_size(sb) -+ /* || au_test_cifs(sb) */ /* untested */ -+ || au_test_fat(sb) -+ || au_test_msdos(sb) -+ || au_test_vfat(sb); -+} -+ -+/* they don't check i_nlink in link(2) */ -+static inline int au_test_fs_no_limit_nlink(struct super_block *sb) -+{ -+ return au_test_tmpfs(sb) -+#ifdef CONFIG_AUFS_BR_RAMFS -+ || au_test_ramfs(sb) -+#endif -+ || au_test_ubifs(sb); -+} -+ -+/* -+ * filesystems which sets S_NOATIME and S_NOCMTIME. -+ */ -+static inline int au_test_fs_notime(struct super_block *sb) -+{ -+ return au_test_nfs(sb) -+ || au_test_fuse(sb) -+ || au_test_ubifs(sb) -+ /* || au_test_cifs(sb) */ /* untested */ -+ ; -+} -+ -+/* -+ * filesystems which requires replacing i_mapping. -+ */ -+static inline int au_test_fs_bad_mapping(struct super_block *sb) -+{ -+ return au_test_fuse(sb) -+ || au_test_ubifs(sb); -+} -+ -+/* temporary support for i#1 in cramfs */ -+static inline int au_test_fs_unique_ino(struct inode *inode) -+{ -+ if (au_test_cramfs(inode->i_sb)) -+ return inode->i_ino != 1; -+ return 1; -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+/* -+ * the filesystem where the xino files placed must support i/o after unlink and -+ * maintain i_size and i_blocks. -+ */ -+static inline int au_test_fs_bad_xino(struct super_block *sb) -+{ -+ return au_test_fs_remote(sb) -+ || au_test_fs_bad_iattr_size(sb) -+#ifdef CONFIG_AUFS_BR_RAMFS -+ || !(au_test_ramfs(sb) || au_test_fs_null_nd(sb)) -+#else -+ || !au_test_fs_null_nd(sb) /* to keep xino code simple */ -+#endif -+ /* don't want unnecessary work for xino */ -+ || au_test_aufs(sb) -+ || au_test_ecryptfs(sb) -+ || au_test_nilfs(sb); -+} -+ -+static inline int au_test_fs_trunc_xino(struct super_block *sb) -+{ -+ return au_test_tmpfs(sb) -+ || au_test_ramfs(sb); -+} -+ -+/* -+ * test if the @sb is real-readonly. -+ */ -+static inline int au_test_fs_rr(struct super_block *sb) -+{ -+ return au_test_squashfs(sb) -+ || au_test_iso9660(sb) -+ || au_test_cramfs(sb) -+ || au_test_romfs(sb); -+} -+ -+#endif /* __KERNEL__ */ -+#endif /* __AUFS_FSTYPE_H__ */ -diff --git a/fs/aufs/hinotify.c b/fs/aufs/hinotify.c -new file mode 100644 -index 0000000..43890bc ---- /dev/null -+++ b/fs/aufs/hinotify.c -@@ -0,0 +1,755 @@ -+/* -+ * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * -+ * This program, aufs is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ */ -+ -+/* -+ * inotify for the lower directories -+ */ -+ -+#include "aufs.h" -+ -+static const __u32 AuHinMask = (IN_MOVE | IN_DELETE | IN_CREATE); -+static struct inotify_handle *au_hin_handle; -+ -+AuCacheFuncs(hinotify, HINOTIFY); -+ -+int au_hin_alloc(struct au_hinode *hinode, struct inode *inode, -+ struct inode *h_inode) -+{ -+ int err; -+ struct au_hinotify *hin; -+ s32 wd; -+ -+ err = -ENOMEM; -+ hin = au_cache_alloc_hinotify(); -+ if (hin) { -+ AuDebugOn(hinode->hi_notify); -+ hinode->hi_notify = hin; -+ hin->hin_aufs_inode = inode; -+ -+ inotify_init_watch(&hin->hin_watch); -+ wd = inotify_add_watch(au_hin_handle, &hin->hin_watch, h_inode, -+ AuHinMask); -+ if (wd >= 0) -+ return 0; /* success */ -+ -+ err = wd; -+ put_inotify_watch(&hin->hin_watch); -+ au_cache_free_hinotify(hin); -+ hinode->hi_notify = NULL; -+ } -+ -+ return err; -+} -+ -+void au_hin_free(struct au_hinode *hinode) -+{ -+ int err; -+ struct au_hinotify *hin; -+ -+ hin = hinode->hi_notify; -+ if (hin) { -+ err = 0; -+ if (atomic_read(&hin->hin_watch.count)) -+ err = inotify_rm_watch(au_hin_handle, &hin->hin_watch); -+ if (unlikely(err)) -+ /* it means the watch is already removed */ -+ pr_warning("failed inotify_rm_watch() %d\n", err); -+ au_cache_free_hinotify(hin); -+ hinode->hi_notify = NULL; -+ } -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+void au_hin_ctl(struct au_hinode *hinode, int do_set) -+{ -+ struct inode *h_inode; -+ struct inotify_watch *watch; -+ -+ if (!hinode->hi_notify) -+ return; -+ -+ h_inode = hinode->hi_inode; -+ IMustLock(h_inode); -+ -+ /* todo: try inotify_find_update_watch()? */ -+ watch = &hinode->hi_notify->hin_watch; -+ mutex_lock(&h_inode->inotify_mutex); -+ /* mutex_lock(&watch->ih->mutex); */ -+ if (do_set) { -+ AuDebugOn(watch->mask & AuHinMask); -+ watch->mask |= AuHinMask; -+ } else { -+ AuDebugOn(!(watch->mask & AuHinMask)); -+ watch->mask &= ~AuHinMask; -+ } -+ /* mutex_unlock(&watch->ih->mutex); */ -+ mutex_unlock(&h_inode->inotify_mutex); -+} -+ -+void au_reset_hinotify(struct inode *inode, unsigned int flags) -+{ -+ aufs_bindex_t bindex, bend; -+ struct inode *hi; -+ struct dentry *iwhdentry; -+ -+ bend = au_ibend(inode); -+ for (bindex = au_ibstart(inode); bindex <= bend; bindex++) { -+ hi = au_h_iptr(inode, bindex); -+ if (!hi) -+ continue; -+ -+ /* mutex_lock_nested(&hi->i_mutex, AuLsc_I_CHILD); */ -+ iwhdentry = au_hi_wh(inode, bindex); -+ if (iwhdentry) -+ dget(iwhdentry); -+ au_igrab(hi); -+ au_set_h_iptr(inode, bindex, NULL, 0); -+ au_set_h_iptr(inode, bindex, au_igrab(hi), -+ flags & ~AuHi_XINO); -+ iput(hi); -+ dput(iwhdentry); -+ /* mutex_unlock(&hi->i_mutex); */ -+ } -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+static int hin_xino(struct inode *inode, struct inode *h_inode) -+{ -+ int err; -+ aufs_bindex_t bindex, bend, bfound, bstart; -+ struct inode *h_i; -+ -+ err = 0; -+ if (unlikely(inode->i_ino == AUFS_ROOT_INO)) { -+ pr_warning("branch root dir was changed\n"); -+ goto out; -+ } -+ -+ bfound = -1; -+ bend = au_ibend(inode); -+ bstart = au_ibstart(inode); -+#if 0 /* reserved for future use */ -+ if (bindex == bend) { -+ /* keep this ino in rename case */ -+ goto out; -+ } -+#endif -+ for (bindex = bstart; bindex <= bend; bindex++) { -+ if (au_h_iptr(inode, bindex) == h_inode) { -+ bfound = bindex; -+ break; -+ } -+ } -+ if (bfound < 0) -+ goto out; -+ -+ for (bindex = bstart; bindex <= bend; bindex++) { -+ h_i = au_h_iptr(inode, bindex); -+ if (!h_i) -+ continue; -+ -+ err = au_xino_write(inode->i_sb, bindex, h_i->i_ino, /*ino*/0); -+ /* ignore this error */ -+ /* bad action? */ -+ } -+ -+ /* children inode number will be broken */ -+ -+ out: -+ AuTraceErr(err); -+ return err; -+} -+ -+static int hin_gen_tree(struct dentry *dentry) -+{ -+ int err, i, j, ndentry; -+ struct au_dcsub_pages dpages; -+ struct au_dpage *dpage; -+ struct dentry **dentries; -+ -+ err = au_dpages_init(&dpages, GFP_NOFS); -+ if (unlikely(err)) -+ goto out; -+ err = au_dcsub_pages(&dpages, dentry, NULL, NULL); -+ if (unlikely(err)) -+ goto out_dpages; -+ -+ for (i = 0; i < dpages.ndpage; i++) { -+ dpage = dpages.dpages + i; -+ dentries = dpage->dentries; -+ ndentry = dpage->ndentry; -+ for (j = 0; j < ndentry; j++) { -+ struct dentry *d; -+ -+ d = dentries[j]; -+ if (IS_ROOT(d)) -+ continue; -+ -+ d_drop(d); -+ au_digen_dec(d); -+ if (d->d_inode) -+ /* todo: reset children xino? -+ cached children only? */ -+ au_iigen_dec(d->d_inode); -+ } -+ } -+ -+ out_dpages: -+ au_dpages_free(&dpages); -+ -+ /* discard children */ -+ dentry_unhash(dentry); -+ dput(dentry); -+ out: -+ return err; -+} -+ -+/* -+ * return 0 if processed. -+ */ -+static int hin_gen_by_inode(char *name, unsigned int nlen, struct inode *inode, -+ const unsigned int isdir) -+{ -+ int err; -+ struct dentry *d; -+ struct qstr *dname; -+ -+ err = 1; -+ if (unlikely(inode->i_ino == AUFS_ROOT_INO)) { -+ pr_warning("branch root dir was changed\n"); -+ err = 0; -+ goto out; -+ } -+ -+ if (!isdir) { -+ AuDebugOn(!name); -+ au_iigen_dec(inode); -+ spin_lock(&dcache_lock); -+ list_for_each_entry(d, &inode->i_dentry, d_alias) { -+ dname = &d->d_name; -+ if (dname->len != nlen -+ && memcmp(dname->name, name, nlen)) -+ continue; -+ err = 0; -+ spin_lock(&d->d_lock); -+ __d_drop(d); -+ au_digen_dec(d); -+ spin_unlock(&d->d_lock); -+ break; -+ } -+ spin_unlock(&dcache_lock); -+ } else { -+ au_fset_si(au_sbi(inode->i_sb), FAILED_REFRESH_DIRS); -+ d = d_find_alias(inode); -+ if (!d) { -+ au_iigen_dec(inode); -+ goto out; -+ } -+ -+ dname = &d->d_name; -+ if (dname->len == nlen && !memcmp(dname->name, name, nlen)) -+ err = hin_gen_tree(d); -+ dput(d); -+ } -+ -+ out: -+ AuTraceErr(err); -+ return err; -+} -+ -+static int hin_gen_by_name(struct dentry *dentry, const unsigned int isdir) -+{ -+ int err; -+ struct inode *inode; -+ -+ inode = dentry->d_inode; -+ if (IS_ROOT(dentry) -+ /* || (inode && inode->i_ino == AUFS_ROOT_INO) */ -+ ) { -+ pr_warning("branch root dir was changed\n"); -+ return 0; -+ } -+ -+ err = 0; -+ if (!isdir) { -+ d_drop(dentry); -+ au_digen_dec(dentry); -+ if (inode) -+ au_iigen_dec(inode); -+ } else { -+ au_fset_si(au_sbi(dentry->d_sb), FAILED_REFRESH_DIRS); -+ if (inode) -+ err = hin_gen_tree(dentry); -+ } -+ -+ AuTraceErr(err); -+ return err; -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+/* hinotify job flags */ -+#define AuHinJob_XINO0 1 -+#define AuHinJob_GEN (1 << 1) -+#define AuHinJob_DIRENT (1 << 2) -+#define AuHinJob_ISDIR (1 << 3) -+#define AuHinJob_TRYXINO0 (1 << 4) -+#define AuHinJob_MNTPNT (1 << 5) -+#define au_ftest_hinjob(flags, name) ((flags) & AuHinJob_##name) -+#define au_fset_hinjob(flags, name) { (flags) |= AuHinJob_##name; } -+#define au_fclr_hinjob(flags, name) { (flags) &= ~AuHinJob_##name; } -+ -+struct hin_job_args { -+ unsigned int flags; -+ struct inode *inode, *h_inode, *dir, *h_dir; -+ struct dentry *dentry; -+ char *h_name; -+ int h_nlen; -+}; -+ -+static int hin_job(struct hin_job_args *a) -+{ -+ const unsigned int isdir = au_ftest_hinjob(a->flags, ISDIR); -+ -+ /* reset xino */ -+ if (au_ftest_hinjob(a->flags, XINO0) && a->inode) -+ hin_xino(a->inode, a->h_inode); /* ignore this error */ -+ -+ if (au_ftest_hinjob(a->flags, TRYXINO0) -+ && a->inode -+ && a->h_inode) { -+ mutex_lock_nested(&a->h_inode->i_mutex, AuLsc_I_CHILD); -+ if (!a->h_inode->i_nlink) -+ hin_xino(a->inode, a->h_inode); /* ignore this error */ -+ mutex_unlock(&a->h_inode->i_mutex); -+ } -+ -+ /* make the generation obsolete */ -+ if (au_ftest_hinjob(a->flags, GEN)) { -+ int err = -1; -+ if (a->inode) -+ err = hin_gen_by_inode(a->h_name, a->h_nlen, a->inode, -+ isdir); -+ if (err && a->dentry) -+ hin_gen_by_name(a->dentry, isdir); -+ /* ignore this error */ -+ } -+ -+ /* make dir entries obsolete */ -+ if (au_ftest_hinjob(a->flags, DIRENT) && a->inode) { -+ struct au_vdir *vdir; -+ -+ vdir = au_ivdir(a->inode); -+ if (vdir) -+ vdir->vd_jiffy = 0; -+ /* IMustLock(a->inode); */ -+ /* a->inode->i_version++; */ -+ } -+ -+ /* can do nothing but warn */ -+ if (au_ftest_hinjob(a->flags, MNTPNT) -+ && a->dentry -+ && d_mountpoint(a->dentry)) -+ pr_warning("mount-point %.*s is removed or renamed\n", -+ AuDLNPair(a->dentry)); -+ -+ return 0; -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+static char *in_name(u32 mask) -+{ -+#ifdef CONFIG_AUFS_DEBUG -+#define test_ret(flag) if (mask & flag) \ -+ return #flag; -+ test_ret(IN_ACCESS); -+ test_ret(IN_MODIFY); -+ test_ret(IN_ATTRIB); -+ test_ret(IN_CLOSE_WRITE); -+ test_ret(IN_CLOSE_NOWRITE); -+ test_ret(IN_OPEN); -+ test_ret(IN_MOVED_FROM); -+ test_ret(IN_MOVED_TO); -+ test_ret(IN_CREATE); -+ test_ret(IN_DELETE); -+ test_ret(IN_DELETE_SELF); -+ test_ret(IN_MOVE_SELF); -+ test_ret(IN_UNMOUNT); -+ test_ret(IN_Q_OVERFLOW); -+ test_ret(IN_IGNORED); -+ return ""; -+#undef test_ret -+#else -+ return "??"; -+#endif -+} -+ -+static struct dentry *lookup_wlock_by_name(char *name, unsigned int nlen, -+ struct inode *dir) -+{ -+ struct dentry *dentry, *d, *parent; -+ struct qstr *dname; -+ -+ parent = d_find_alias(dir); -+ if (!parent) -+ return NULL; -+ -+ dentry = NULL; -+ spin_lock(&dcache_lock); -+ list_for_each_entry(d, &parent->d_subdirs, d_u.d_child) { -+ /* AuDbg("%.*s\n", AuDLNPair(d)); */ -+ dname = &d->d_name; -+ if (dname->len != nlen || memcmp(dname->name, name, nlen)) -+ continue; -+ if (!atomic_read(&d->d_count) || !d->d_fsdata) { -+ spin_lock(&d->d_lock); -+ __d_drop(d); -+ spin_unlock(&d->d_lock); -+ continue; -+ } -+ -+ dentry = dget(d); -+ break; -+ } -+ spin_unlock(&dcache_lock); -+ dput(parent); -+ -+ if (dentry) -+ di_write_lock_child(dentry); -+ -+ return dentry; -+} -+ -+static struct inode *lookup_wlock_by_ino(struct super_block *sb, -+ aufs_bindex_t bindex, ino_t h_ino) -+{ -+ struct inode *inode; -+ ino_t ino; -+ int err; -+ -+ inode = NULL; -+ err = au_xino_read(sb, bindex, h_ino, &ino); -+ if (!err && ino) -+ inode = ilookup(sb, ino); -+ if (!inode) -+ goto out; -+ -+ if (unlikely(inode->i_ino == AUFS_ROOT_INO)) { -+ pr_warning("wrong root branch\n"); -+ iput(inode); -+ inode = NULL; -+ goto out; -+ } -+ -+ ii_write_lock_child(inode); -+ -+ out: -+ return inode; -+} -+ -+enum { CHILD, PARENT }; -+struct postproc_args { -+ struct inode *h_dir, *dir, *h_child_inode; -+ u32 mask; -+ unsigned int flags[2]; -+ unsigned int h_child_nlen; -+ char h_child_name[]; -+}; -+ -+static void postproc(void *_args) -+{ -+ struct postproc_args *a = _args; -+ struct super_block *sb; -+ aufs_bindex_t bindex, bend, bfound; -+ unsigned char xino, try_iput; -+ int err; -+ struct inode *inode; -+ ino_t h_ino; -+ struct hin_job_args args; -+ struct dentry *dentry; -+ struct au_sbinfo *sbinfo; -+ -+ AuDebugOn(!_args); -+ AuDebugOn(!a->h_dir); -+ AuDebugOn(!a->dir); -+ AuDebugOn(!a->mask); -+ AuDbg("mask 0x%x %s, i%lu, hi%lu, hci%lu\n", -+ a->mask, in_name(a->mask), a->dir->i_ino, a->h_dir->i_ino, -+ a->h_child_inode ? a->h_child_inode->i_ino : 0); -+ -+ inode = NULL; -+ dentry = NULL; -+ /* -+ * do not lock a->dir->i_mutex here -+ * because of d_revalidate() may cause a deadlock. -+ */ -+ sb = a->dir->i_sb; -+ AuDebugOn(!sb); -+ sbinfo = au_sbi(sb); -+ AuDebugOn(!sbinfo); -+ /* big aufs lock */ -+ si_noflush_write_lock(sb); -+ -+ ii_read_lock_parent(a->dir); -+ bfound = -1; -+ bend = au_ibend(a->dir); -+ for (bindex = au_ibstart(a->dir); bindex <= bend; bindex++) -+ if (au_h_iptr(a->dir, bindex) == a->h_dir) { -+ bfound = bindex; -+ break; -+ } -+ ii_read_unlock(a->dir); -+ if (unlikely(bfound < 0)) -+ goto out; -+ -+ xino = !!au_opt_test(au_mntflags(sb), XINO); -+ h_ino = 0; -+ if (a->h_child_inode) -+ h_ino = a->h_child_inode->i_ino; -+ -+ if (a->h_child_nlen -+ && (au_ftest_hinjob(a->flags[CHILD], GEN) -+ || au_ftest_hinjob(a->flags[CHILD], MNTPNT))) -+ dentry = lookup_wlock_by_name(a->h_child_name, a->h_child_nlen, -+ a->dir); -+ try_iput = 0; -+ if (dentry) -+ inode = dentry->d_inode; -+ if (xino && !inode && h_ino -+ && (au_ftest_hinjob(a->flags[CHILD], XINO0) -+ || au_ftest_hinjob(a->flags[CHILD], TRYXINO0) -+ || au_ftest_hinjob(a->flags[CHILD], GEN))) { -+ inode = lookup_wlock_by_ino(sb, bfound, h_ino); -+ try_iput = 1; -+ } -+ -+ args.flags = a->flags[CHILD]; -+ args.dentry = dentry; -+ args.inode = inode; -+ args.h_inode = a->h_child_inode; -+ args.dir = a->dir; -+ args.h_dir = a->h_dir; -+ args.h_name = a->h_child_name; -+ args.h_nlen = a->h_child_nlen; -+ err = hin_job(&args); -+ if (dentry) { -+ if (dentry->d_fsdata) -+ di_write_unlock(dentry); -+ dput(dentry); -+ } -+ if (inode && try_iput) { -+ ii_write_unlock(inode); -+ iput(inode); -+ } -+ -+ ii_write_lock_parent(a->dir); -+ args.flags = a->flags[PARENT]; -+ args.dentry = NULL; -+ args.inode = a->dir; -+ args.h_inode = a->h_dir; -+ args.dir = NULL; -+ args.h_dir = NULL; -+ args.h_name = NULL; -+ args.h_nlen = 0; -+ err = hin_job(&args); -+ ii_write_unlock(a->dir); -+ -+ out: -+ au_nwt_done(&sbinfo->si_nowait); -+ si_write_unlock(sb); -+ -+ iput(a->h_child_inode); -+ iput(a->h_dir); -+ iput(a->dir); -+ kfree(a); -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+static void aufs_inotify(struct inotify_watch *watch, u32 wd __maybe_unused, -+ u32 mask, u32 cookie __maybe_unused, -+ const char *h_child_name, struct inode *h_child_inode) -+{ -+ struct au_hinotify *hinotify; -+ struct postproc_args *args; -+ int len, wkq_err; -+ unsigned char isdir, isroot, wh; -+ char *p; -+ struct inode *dir; -+ unsigned int flags[2]; -+ -+ /* if IN_UNMOUNT happens, there must be another bug */ -+ AuDebugOn(mask & IN_UNMOUNT); -+ if (mask & (IN_IGNORED | IN_UNMOUNT)) { -+ put_inotify_watch(watch); -+ return; -+ } -+#ifdef AuDbgHinotify -+ au_debug(1); -+ if (1 || !h_child_name || strcmp(h_child_name, AUFS_XINO_FNAME)) { -+ AuDbg("i%lu, wd %d, mask 0x%x %s, cookie 0x%x, hcname %s," -+ " hi%lu\n", -+ watch->inode->i_ino, wd, mask, in_name(mask), cookie, -+ h_child_name ? h_child_name : "", -+ h_child_inode ? h_child_inode->i_ino : 0); -+ WARN_ON(1); -+ } -+ au_debug(0); -+#endif -+ -+ hinotify = container_of(watch, struct au_hinotify, hin_watch); -+ AuDebugOn(!hinotify || !hinotify->hin_aufs_inode); -+ dir = igrab(hinotify->hin_aufs_inode); -+ if (!dir) -+ return; -+ -+ isroot = (dir->i_ino == AUFS_ROOT_INO); -+ len = 0; -+ wh = 0; -+ if (h_child_name) { -+ len = strlen(h_child_name); -+ if (!memcmp(h_child_name, AUFS_WH_PFX, AUFS_WH_PFX_LEN)) { -+ h_child_name += AUFS_WH_PFX_LEN; -+ len -= AUFS_WH_PFX_LEN; -+ wh = 1; -+ } -+ } -+ -+ isdir = 0; -+ if (h_child_inode) -+ isdir = !!S_ISDIR(h_child_inode->i_mode); -+ flags[PARENT] = AuHinJob_ISDIR; -+ flags[CHILD] = 0; -+ if (isdir) -+ flags[CHILD] = AuHinJob_ISDIR; -+ switch (mask & IN_ALL_EVENTS) { -+ case IN_MOVED_FROM: -+ case IN_MOVED_TO: -+ AuDebugOn(!h_child_name || !h_child_inode); -+ au_fset_hinjob(flags[CHILD], GEN); -+ au_fset_hinjob(flags[CHILD], XINO0); -+ au_fset_hinjob(flags[CHILD], MNTPNT); -+ au_fset_hinjob(flags[PARENT], DIRENT); -+ break; -+ -+ case IN_CREATE: -+ AuDebugOn(!h_child_name || !h_child_inode); -+ au_fset_hinjob(flags[PARENT], DIRENT); -+ au_fset_hinjob(flags[CHILD], GEN); -+ break; -+ -+ case IN_DELETE: -+ /* -+ * aufs never be able to get this child inode. -+ * revalidation should be in d_revalidate() -+ * by checking i_nlink, i_generation or d_unhashed(). -+ */ -+ AuDebugOn(!h_child_name); -+ au_fset_hinjob(flags[PARENT], DIRENT); -+ au_fset_hinjob(flags[CHILD], GEN); -+ au_fset_hinjob(flags[CHILD], TRYXINO0); -+ au_fset_hinjob(flags[CHILD], MNTPNT); -+ break; -+ -+ default: -+ AuDebugOn(1); -+ } -+ -+ if (wh) -+ h_child_inode = NULL; -+ -+ /* iput() and kfree() will be called in postproc() */ -+ /* -+ * inotify_mutex is already acquired and kmalloc/prune_icache may lock -+ * iprune_mutex. strange. -+ */ -+ /* lockdep_off(); */ -+ args = kmalloc(sizeof(*args) + len + 1, GFP_NOFS); -+ /* lockdep_on(); */ -+ if (unlikely(!args)) { -+ AuErr1("no memory\n"); -+ iput(dir); -+ return; -+ } -+ args->flags[PARENT] = flags[PARENT]; -+ args->flags[CHILD] = flags[CHILD]; -+ args->mask = mask; -+ args->dir = dir; -+ args->h_dir = igrab(watch->inode); -+ if (h_child_inode) -+ h_child_inode = igrab(h_child_inode); /* can be NULL */ -+ args->h_child_inode = h_child_inode; -+ args->h_child_nlen = len; -+ if (len) { -+ p = (void *)args; -+ p += sizeof(*args); -+ memcpy(p, h_child_name, len + 1); -+ } -+ -+ /* lockdep_off(); */ -+ wkq_err = au_wkq_nowait(postproc, args, dir->i_sb); -+ /* lockdep_on(); */ -+ if (unlikely(wkq_err)) -+ pr_err("wkq %d\n", wkq_err); -+} -+ -+static void aufs_inotify_destroy(struct inotify_watch *watch __maybe_unused) -+{ -+ return; -+} -+ -+static struct inotify_operations aufs_inotify_ops = { -+ .handle_event = aufs_inotify, -+ .destroy_watch = aufs_inotify_destroy -+}; -+ -+/* ---------------------------------------------------------------------- */ -+ -+static void au_hin_destroy_cache(void) -+{ -+ kmem_cache_destroy(au_cachep[AuCache_HINOTIFY]); -+ au_cachep[AuCache_HINOTIFY] = NULL; -+} -+ -+int __init au_hinotify_init(void) -+{ -+ int err; -+ -+ err = -ENOMEM; -+ au_cachep[AuCache_HINOTIFY] = AuCache(au_hinotify); -+ if (au_cachep[AuCache_HINOTIFY]) { -+ err = 0; -+ au_hin_handle = inotify_init(&aufs_inotify_ops); -+ if (IS_ERR(au_hin_handle)) { -+ err = PTR_ERR(au_hin_handle); -+ au_hin_destroy_cache(); -+ } -+ } -+ AuTraceErr(err); -+ return err; -+} -+ -+void au_hinotify_fin(void) -+{ -+ inotify_destroy(au_hin_handle); -+ if (au_cachep[AuCache_HINOTIFY]) -+ au_hin_destroy_cache(); -+} -diff --git a/fs/aufs/i_op.c b/fs/aufs/i_op.c -new file mode 100644 -index 0000000..a7f3bc7 ---- /dev/null -+++ b/fs/aufs/i_op.c -@@ -0,0 +1,883 @@ -+/* -+ * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * -+ * This program, aufs is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ */ -+ -+/* -+ * inode operations (except add/del/rename) -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include "aufs.h" -+ -+static int h_permission(struct inode *h_inode, int mask, -+ struct vfsmount *h_mnt, int brperm) -+{ -+ int err; -+ const unsigned char write_mask = !!(mask & (MAY_WRITE | MAY_APPEND)); -+ -+ err = -EACCES; -+ if ((write_mask && IS_IMMUTABLE(h_inode)) -+ || ((mask & MAY_EXEC) -+ && S_ISREG(h_inode->i_mode) -+ && ((h_mnt->mnt_flags & MNT_NOEXEC) -+ || !(h_inode->i_mode & S_IXUGO)))) -+ goto out; -+ -+ /* -+ * - skip the lower fs test in the case of write to ro branch. -+ * - nfs dir permission write check is optimized, but a policy for -+ * link/rename requires a real check. -+ */ -+ if ((write_mask && !au_br_writable(brperm)) -+ || (au_test_nfs(h_inode->i_sb) && S_ISDIR(h_inode->i_mode) -+ && write_mask && !(mask & MAY_READ)) -+ || !h_inode->i_op->permission) { -+ /* AuLabel(generic_permission); */ -+ err = generic_permission(h_inode, mask, NULL); -+ } else { -+ /* AuLabel(h_inode->permission); */ -+ err = h_inode->i_op->permission(h_inode, mask); -+ AuTraceErr(err); -+ } -+ -+ if (!err) -+ err = devcgroup_inode_permission(h_inode, mask); -+ if (!err) -+ err = security_inode_permission -+ (h_inode, mask & (MAY_READ | MAY_WRITE | MAY_EXEC -+ | MAY_APPEND)); -+ -+#if 0 -+ if (!err) { -+ /* todo: do we need to call ima_path_check()? */ -+ struct path h_path = { -+ .dentry = -+ .mnt = h_mnt -+ }; -+ err = ima_path_check(&h_path, -+ mask & (MAY_READ | MAY_WRITE | MAY_EXEC), -+ IMA_COUNT_LEAVE); -+ } -+#endif -+ -+ out: -+ return err; -+} -+ -+static int aufs_permission(struct inode *inode, int mask) -+{ -+ int err; -+ aufs_bindex_t bindex, bend; -+ const unsigned char isdir = !!S_ISDIR(inode->i_mode); -+ const unsigned char write_mask = !!(mask & (MAY_WRITE | MAY_APPEND)); -+ struct inode *h_inode; -+ struct super_block *sb; -+ struct au_branch *br; -+ -+ sb = inode->i_sb; -+ si_read_lock(sb, AuLock_FLUSH); -+ ii_read_lock_child(inode); -+ -+ if (!isdir || write_mask) { -+ err = au_busy_or_stale(); -+ h_inode = au_h_iptr(inode, au_ibstart(inode)); -+ if (unlikely(!h_inode -+ || (h_inode->i_mode & S_IFMT) -+ != (inode->i_mode & S_IFMT))) -+ goto out; -+ -+ err = 0; -+ bindex = au_ibstart(inode); -+ br = au_sbr(sb, bindex); -+ err = h_permission(h_inode, mask, br->br_mnt, br->br_perm); -+ if (write_mask && !err) { -+ /* test whether the upper writable branch exists */ -+ err = -EROFS; -+ for (; bindex >= 0; bindex--) -+ if (!au_br_rdonly(au_sbr(sb, bindex))) { -+ err = 0; -+ break; -+ } -+ } -+ goto out; -+ } -+ -+ /* non-write to dir */ -+ err = 0; -+ bend = au_ibend(inode); -+ for (bindex = au_ibstart(inode); !err && bindex <= bend; bindex++) { -+ h_inode = au_h_iptr(inode, bindex); -+ if (h_inode) { -+ err = au_busy_or_stale(); -+ if (unlikely(!S_ISDIR(h_inode->i_mode))) -+ break; -+ -+ br = au_sbr(sb, bindex); -+ err = h_permission(h_inode, mask, br->br_mnt, -+ br->br_perm); -+ } -+ } -+ -+ out: -+ ii_read_unlock(inode); -+ si_read_unlock(sb); -+ return err; -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+static struct dentry *aufs_lookup(struct inode *dir, struct dentry *dentry, -+ struct nameidata *nd) -+{ -+ struct dentry *ret, *parent; -+ struct inode *inode, *h_inode; -+ struct mutex *mtx; -+ struct super_block *sb; -+ int err, npositive; -+ aufs_bindex_t bstart; -+ -+ IMustLock(dir); -+ -+ sb = dir->i_sb; -+ si_read_lock(sb, AuLock_FLUSH); -+ err = au_alloc_dinfo(dentry); -+ ret = ERR_PTR(err); -+ if (unlikely(err)) -+ goto out; -+ -+ parent = dentry->d_parent; /* dir inode is locked */ -+ di_read_lock_parent(parent, AuLock_IR); -+ npositive = au_lkup_dentry(dentry, au_dbstart(parent), /*type*/0, nd); -+ di_read_unlock(parent, AuLock_IR); -+ err = npositive; -+ ret = ERR_PTR(err); -+ if (unlikely(err < 0)) -+ goto out_unlock; -+ -+ inode = NULL; -+ if (npositive) { -+ bstart = au_dbstart(dentry); -+ h_inode = au_h_dptr(dentry, bstart)->d_inode; -+ if (!S_ISDIR(h_inode->i_mode)) { -+ /* -+ * stop 'race'-ing between hardlinks under different -+ * parents. -+ */ -+ mtx = &au_sbr(sb, bstart)->br_xino.xi_nondir_mtx; -+ mutex_lock(mtx); -+ inode = au_new_inode(dentry, /*must_new*/0); -+ mutex_unlock(mtx); -+ } else -+ inode = au_new_inode(dentry, /*must_new*/0); -+ ret = (void *)inode; -+ } -+ if (IS_ERR(inode)) -+ goto out_unlock; -+ -+ ret = d_splice_alias(inode, dentry); -+ if (unlikely(IS_ERR(ret) && inode)) -+ ii_write_unlock(inode); -+ -+ out_unlock: -+ di_write_unlock(dentry); -+ out: -+ si_read_unlock(sb); -+ return ret; -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+static int au_wr_dir_cpup(struct dentry *dentry, struct dentry *parent, -+ const unsigned char add_entry, aufs_bindex_t bcpup, -+ aufs_bindex_t bstart) -+{ -+ int err; -+ struct dentry *h_parent; -+ struct inode *h_dir; -+ -+ if (add_entry) { -+ au_update_dbstart(dentry); -+ IMustLock(parent->d_inode); -+ } else -+ di_write_lock_parent(parent); -+ -+ err = 0; -+ if (!au_h_dptr(parent, bcpup)) { -+ if (bstart < bcpup) -+ err = au_cpdown_dirs(dentry, bcpup); -+ else -+ err = au_cpup_dirs(dentry, bcpup); -+ } -+ if (!err && add_entry) { -+ h_parent = au_h_dptr(parent, bcpup); -+ h_dir = h_parent->d_inode; -+ mutex_lock_nested(&h_dir->i_mutex, AuLsc_I_PARENT); -+ err = au_lkup_neg(dentry, bcpup); -+ /* todo: no unlock here */ -+ mutex_unlock(&h_dir->i_mutex); -+ if (bstart < bcpup && au_dbstart(dentry) < 0) { -+ au_set_dbstart(dentry, 0); -+ au_update_dbrange(dentry, /*do_put_zero*/0); -+ } -+ } -+ -+ if (!add_entry) -+ di_write_unlock(parent); -+ if (!err) -+ err = bcpup; /* success */ -+ -+ return err; -+} -+ -+/* -+ * decide the branch and the parent dir where we will create a new entry. -+ * returns new bindex or an error. -+ * copyup the parent dir if needed. -+ */ -+int au_wr_dir(struct dentry *dentry, struct dentry *src_dentry, -+ struct au_wr_dir_args *args) -+{ -+ int err; -+ aufs_bindex_t bcpup, bstart, src_bstart; -+ const unsigned char add_entry = !!au_ftest_wrdir(args->flags, -+ ADD_ENTRY); -+ struct super_block *sb; -+ struct dentry *parent; -+ struct au_sbinfo *sbinfo; -+ -+ sb = dentry->d_sb; -+ sbinfo = au_sbi(sb); -+ parent = dget_parent(dentry); -+ bstart = au_dbstart(dentry); -+ bcpup = bstart; -+ if (args->force_btgt < 0) { -+ if (src_dentry) { -+ src_bstart = au_dbstart(src_dentry); -+ if (src_bstart < bstart) -+ bcpup = src_bstart; -+ } else if (add_entry) { -+ err = AuWbrCreate(sbinfo, dentry, -+ au_ftest_wrdir(args->flags, ISDIR)); -+ bcpup = err; -+ } -+ -+ if (bcpup < 0 || au_test_ro(sb, bcpup, dentry->d_inode)) { -+ if (add_entry) -+ err = AuWbrCopyup(sbinfo, dentry); -+ else { -+ if (!IS_ROOT(dentry)) { -+ di_read_lock_parent(parent, !AuLock_IR); -+ err = AuWbrCopyup(sbinfo, dentry); -+ di_read_unlock(parent, !AuLock_IR); -+ } else -+ err = AuWbrCopyup(sbinfo, dentry); -+ } -+ bcpup = err; -+ if (unlikely(err < 0)) -+ goto out; -+ } -+ } else { -+ bcpup = args->force_btgt; -+ AuDebugOn(au_test_ro(sb, bcpup, dentry->d_inode)); -+ } -+ AuDbg("bstart %d, bcpup %d\n", bstart, bcpup); -+ if (bstart < bcpup) -+ au_update_dbrange(dentry, /*do_put_zero*/1); -+ -+ err = bcpup; -+ if (bcpup == bstart) -+ goto out; /* success */ -+ -+ /* copyup the new parent into the branch we process */ -+ err = au_wr_dir_cpup(dentry, parent, add_entry, bcpup, bstart); -+ -+ out: -+ dput(parent); -+ return err; -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+struct dentry *au_pinned_h_parent(struct au_pin *pin) -+{ -+ if (pin && pin->parent) -+ return au_h_dptr(pin->parent, pin->bindex); -+ return NULL; -+} -+ -+void au_unpin(struct au_pin *p) -+{ -+ if (au_ftest_pin(p->flags, MNT_WRITE)) -+ mnt_drop_write(p->h_mnt); -+ if (!p->hdir) -+ return; -+ -+ au_hin_imtx_unlock(p->hdir); -+ if (!au_ftest_pin(p->flags, DI_LOCKED)) -+ di_read_unlock(p->parent, AuLock_IR); -+ iput(p->hdir->hi_inode); -+ dput(p->parent); -+ p->parent = NULL; -+ p->hdir = NULL; -+ p->h_mnt = NULL; -+} -+ -+int au_do_pin(struct au_pin *p) -+{ -+ int err; -+ struct super_block *sb; -+ struct dentry *h_dentry, *h_parent; -+ struct au_branch *br; -+ struct inode *h_dir; -+ -+ err = 0; -+ sb = p->dentry->d_sb; -+ br = au_sbr(sb, p->bindex); -+ if (IS_ROOT(p->dentry)) { -+ if (au_ftest_pin(p->flags, MNT_WRITE)) { -+ p->h_mnt = br->br_mnt; -+ err = mnt_want_write(p->h_mnt); -+ if (unlikely(err)) { -+ au_fclr_pin(p->flags, MNT_WRITE); -+ goto out_err; -+ } -+ } -+ goto out; -+ } -+ -+ h_dentry = NULL; -+ if (p->bindex <= au_dbend(p->dentry)) -+ h_dentry = au_h_dptr(p->dentry, p->bindex); -+ -+ p->parent = dget_parent(p->dentry); -+ if (!au_ftest_pin(p->flags, DI_LOCKED)) -+ di_read_lock(p->parent, AuLock_IR, p->lsc_di); -+ -+ h_dir = NULL; -+ h_parent = au_h_dptr(p->parent, p->bindex); -+ p->hdir = au_hi(p->parent->d_inode, p->bindex); -+ if (p->hdir) -+ h_dir = p->hdir->hi_inode; -+ -+ /* udba case */ -+ if (unlikely(!p->hdir || !h_dir)) { -+ if (!au_ftest_pin(p->flags, DI_LOCKED)) -+ di_read_unlock(p->parent, AuLock_IR); -+ dput(p->parent); -+ p->parent = NULL; -+ goto out_err; -+ } -+ -+ au_igrab(h_dir); -+ au_hin_imtx_lock_nested(p->hdir, p->lsc_hi); -+ -+ if (unlikely(p->hdir->hi_inode != h_parent->d_inode)) { -+ err = -EBUSY; -+ goto out_unpin; -+ } -+ if (h_dentry) { -+ err = au_h_verify(h_dentry, p->udba, h_dir, h_parent, br); -+ if (unlikely(err)) { -+ au_fclr_pin(p->flags, MNT_WRITE); -+ goto out_unpin; -+ } -+ } -+ -+ if (au_ftest_pin(p->flags, MNT_WRITE)) { -+ p->h_mnt = br->br_mnt; -+ err = mnt_want_write(p->h_mnt); -+ if (unlikely(err)) { -+ au_fclr_pin(p->flags, MNT_WRITE); -+ goto out_unpin; -+ } -+ } -+ goto out; /* success */ -+ -+ out_unpin: -+ au_unpin(p); -+ out_err: -+ pr_err("err %d\n", err); -+ err = au_busy_or_stale(); -+ out: -+ return err; -+} -+ -+void au_pin_init(struct au_pin *p, struct dentry *dentry, -+ aufs_bindex_t bindex, int lsc_di, int lsc_hi, -+ unsigned int udba, unsigned char flags) -+{ -+ p->dentry = dentry; -+ p->udba = udba; -+ p->lsc_di = lsc_di; -+ p->lsc_hi = lsc_hi; -+ p->flags = flags; -+ p->bindex = bindex; -+ -+ p->parent = NULL; -+ p->hdir = NULL; -+ p->h_mnt = NULL; -+} -+ -+int au_pin(struct au_pin *pin, struct dentry *dentry, aufs_bindex_t bindex, -+ unsigned int udba, unsigned char flags) -+{ -+ au_pin_init(pin, dentry, bindex, AuLsc_DI_PARENT, AuLsc_I_PARENT2, -+ udba, flags); -+ return au_do_pin(pin); -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+#define AuIcpup_DID_CPUP 1 -+#define au_ftest_icpup(flags, name) ((flags) & AuIcpup_##name) -+#define au_fset_icpup(flags, name) { (flags) |= AuIcpup_##name; } -+#define au_fclr_icpup(flags, name) { (flags) &= ~AuIcpup_##name; } -+ -+struct au_icpup_args { -+ unsigned char flags; -+ unsigned char pin_flags; -+ aufs_bindex_t btgt; -+ struct au_pin pin; -+ struct path h_path; -+ struct inode *h_inode; -+}; -+ -+static int au_lock_and_icpup(struct dentry *dentry, struct iattr *ia, -+ struct au_icpup_args *a) -+{ -+ int err; -+ unsigned int udba; -+ loff_t sz; -+ aufs_bindex_t bstart; -+ struct dentry *hi_wh, *parent; -+ struct inode *inode; -+ struct au_wr_dir_args wr_dir_args = { -+ .force_btgt = -1, -+ .flags = 0 -+ }; -+ -+ di_write_lock_child(dentry); -+ bstart = au_dbstart(dentry); -+ inode = dentry->d_inode; -+ if (S_ISDIR(inode->i_mode)) -+ au_fset_wrdir(wr_dir_args.flags, ISDIR); -+ /* plink or hi_wh() case */ -+ if (bstart != au_ibstart(inode)) -+ wr_dir_args.force_btgt = au_ibstart(inode); -+ err = au_wr_dir(dentry, /*src_dentry*/NULL, &wr_dir_args); -+ if (unlikely(err < 0)) -+ goto out_dentry; -+ a->btgt = err; -+ if (err != bstart) -+ au_fset_icpup(a->flags, DID_CPUP); -+ -+ err = 0; -+ a->pin_flags = AuPin_MNT_WRITE; -+ parent = NULL; -+ if (!IS_ROOT(dentry)) { -+ au_fset_pin(a->pin_flags, DI_LOCKED); -+ parent = dget_parent(dentry); -+ di_write_lock_parent(parent); -+ } -+ -+ udba = au_opt_udba(dentry->d_sb); -+ if (d_unhashed(dentry) || (ia->ia_valid & ATTR_FILE)) -+ udba = AuOpt_UDBA_NONE; -+ err = au_pin(&a->pin, dentry, a->btgt, udba, a->pin_flags); -+ if (unlikely(err)) { -+ if (parent) { -+ di_write_unlock(parent); -+ dput(parent); -+ } -+ goto out_dentry; -+ } -+ a->h_path.dentry = au_h_dptr(dentry, bstart); -+ a->h_inode = a->h_path.dentry->d_inode; -+ mutex_lock_nested(&a->h_inode->i_mutex, AuLsc_I_CHILD); -+ sz = -1; -+ if ((ia->ia_valid & ATTR_SIZE) && ia->ia_size < i_size_read(a->h_inode)) -+ sz = ia->ia_size; -+ -+ hi_wh = NULL; -+ if (au_ftest_icpup(a->flags, DID_CPUP) && d_unhashed(dentry)) { -+ hi_wh = au_hi_wh(inode, a->btgt); -+ if (!hi_wh) { -+ err = au_sio_cpup_wh(dentry, a->btgt, sz, /*file*/NULL); -+ if (unlikely(err)) -+ goto out_unlock; -+ hi_wh = au_hi_wh(inode, a->btgt); -+ /* todo: revalidate hi_wh? */ -+ } -+ } -+ -+ if (parent) { -+ au_pin_set_parent_lflag(&a->pin, /*lflag*/0); -+ di_downgrade_lock(parent, AuLock_IR); -+ dput(parent); -+ } -+ if (!au_ftest_icpup(a->flags, DID_CPUP)) -+ goto out; /* success */ -+ -+ if (!d_unhashed(dentry)) { -+ err = au_sio_cpup_simple(dentry, a->btgt, sz, AuCpup_DTIME); -+ if (!err) -+ a->h_path.dentry = au_h_dptr(dentry, a->btgt); -+ } else if (!hi_wh) -+ a->h_path.dentry = au_h_dptr(dentry, a->btgt); -+ else -+ a->h_path.dentry = hi_wh; /* do not dget here */ -+ -+ out_unlock: -+ mutex_unlock(&a->h_inode->i_mutex); -+ a->h_inode = a->h_path.dentry->d_inode; -+ if (!err) { -+ mutex_lock_nested(&a->h_inode->i_mutex, AuLsc_I_CHILD); -+ goto out; /* success */ -+ } -+ -+ au_unpin(&a->pin); -+ -+ out_dentry: -+ di_write_unlock(dentry); -+ out: -+ return err; -+} -+ -+static int aufs_setattr(struct dentry *dentry, struct iattr *ia) -+{ -+ int err; -+ struct inode *inode; -+ struct super_block *sb; -+ struct file *file; -+ struct au_icpup_args *a; -+ -+ err = -ENOMEM; -+ a = kzalloc(sizeof(*a), GFP_NOFS); -+ if (unlikely(!a)) -+ goto out; -+ -+ inode = dentry->d_inode; -+ IMustLock(inode); -+ sb = dentry->d_sb; -+ si_read_lock(sb, AuLock_FLUSH); -+ -+ file = NULL; -+ if (ia->ia_valid & ATTR_FILE) { -+ /* currently ftruncate(2) only */ -+ file = ia->ia_file; -+ fi_write_lock(file); -+ ia->ia_file = au_h_fptr(file, au_fbstart(file)); -+ } -+ -+ if (ia->ia_valid & (ATTR_KILL_SUID | ATTR_KILL_SGID)) -+ ia->ia_valid &= ~ATTR_MODE; -+ -+ err = au_lock_and_icpup(dentry, ia, a); -+ if (unlikely(err < 0)) -+ goto out_si; -+ if (au_ftest_icpup(a->flags, DID_CPUP)) { -+ ia->ia_file = NULL; -+ ia->ia_valid &= ~ATTR_FILE; -+ } -+ -+ a->h_path.mnt = au_sbr_mnt(sb, a->btgt); -+ if (ia->ia_valid & ATTR_SIZE) { -+ struct file *f; -+ -+ if (ia->ia_size < i_size_read(inode)) { -+ /* unmap only */ -+ err = vmtruncate(inode, ia->ia_size); -+ if (unlikely(err)) -+ goto out_unlock; -+ } -+ -+ f = NULL; -+ if (ia->ia_valid & ATTR_FILE) -+ f = ia->ia_file; -+ mutex_unlock(&a->h_inode->i_mutex); -+ err = vfsub_trunc(&a->h_path, ia->ia_size, ia->ia_valid, f); -+ mutex_lock_nested(&a->h_inode->i_mutex, AuLsc_I_CHILD); -+ } else -+ err = vfsub_notify_change(&a->h_path, ia); -+ if (!err) -+ au_cpup_attr_changeable(inode); -+ -+ out_unlock: -+ mutex_unlock(&a->h_inode->i_mutex); -+ au_unpin(&a->pin); -+ di_write_unlock(dentry); -+ out_si: -+ if (file) { -+ fi_write_unlock(file); -+ ia->ia_file = file; -+ ia->ia_valid |= ATTR_FILE; -+ } -+ si_read_unlock(sb); -+ kfree(a); -+ out: -+ return err; -+} -+ -+static int au_getattr_lock_reval(struct dentry *dentry, unsigned int sigen) -+{ -+ int err; -+ struct inode *inode; -+ struct dentry *parent; -+ -+ err = 0; -+ inode = dentry->d_inode; -+ di_write_lock_child(dentry); -+ if (au_digen(dentry) != sigen || au_iigen(inode) != sigen) { -+ parent = dget_parent(dentry); -+ di_read_lock_parent(parent, AuLock_IR); -+ /* returns a number of positive dentries */ -+ err = au_refresh_hdentry(dentry, inode->i_mode & S_IFMT); -+ if (err >= 0) -+ err = au_refresh_hinode(inode, dentry); -+ di_read_unlock(parent, AuLock_IR); -+ dput(parent); -+ } -+ di_downgrade_lock(dentry, AuLock_IR); -+ if (unlikely(err)) -+ di_read_unlock(dentry, AuLock_IR); -+ -+ AuTraceErr(err); -+ return err; -+} -+ -+static void au_refresh_iattr(struct inode *inode, struct kstat *st, -+ unsigned int nlink) -+{ -+ inode->i_mode = st->mode; -+ inode->i_uid = st->uid; -+ inode->i_gid = st->gid; -+ inode->i_atime = st->atime; -+ inode->i_mtime = st->mtime; -+ inode->i_ctime = st->ctime; -+ -+ au_cpup_attr_nlink(inode, /*force*/0); -+ if (S_ISDIR(inode->i_mode)) { -+ inode->i_nlink -= nlink; -+ inode->i_nlink += st->nlink; -+ } -+ -+ spin_lock(&inode->i_lock); -+ inode->i_blocks = st->blocks; -+ i_size_write(inode, st->size); -+ spin_unlock(&inode->i_lock); -+} -+ -+static int aufs_getattr(struct vfsmount *mnt __maybe_unused, -+ struct dentry *dentry, struct kstat *st) -+{ -+ int err; -+ unsigned int mnt_flags; -+ aufs_bindex_t bindex; -+ unsigned char udba_none, positive; -+ struct super_block *sb, *h_sb; -+ struct inode *inode; -+ struct vfsmount *h_mnt; -+ struct dentry *h_dentry; -+ -+ err = 0; -+ sb = dentry->d_sb; -+ inode = dentry->d_inode; -+ si_read_lock(sb, AuLock_FLUSH); -+ mnt_flags = au_mntflags(sb); -+ udba_none = !!au_opt_test(mnt_flags, UDBA_NONE); -+ -+ /* support fstat(2) */ -+ if (!d_unhashed(dentry) && !udba_none) { -+ unsigned int sigen = au_sigen(sb); -+ if (au_digen(dentry) == sigen && au_iigen(inode) == sigen) -+ di_read_lock_child(dentry, AuLock_IR); -+ else { -+ AuDebugOn(IS_ROOT(dentry)); -+ err = au_getattr_lock_reval(dentry, sigen); -+ if (unlikely(err)) -+ goto out; -+ } -+ } else -+ di_read_lock_child(dentry, AuLock_IR); -+ -+ bindex = au_ibstart(inode); -+ h_mnt = au_sbr_mnt(sb, bindex); -+ h_sb = h_mnt->mnt_sb; -+ if (!au_test_fs_bad_iattr(h_sb) && udba_none) -+ goto out_fill; /* success */ -+ -+ h_dentry = NULL; -+ if (au_dbstart(dentry) == bindex) -+ h_dentry = dget(au_h_dptr(dentry, bindex)); -+ else if (au_opt_test(mnt_flags, PLINK) && au_plink_test(inode)) { -+ h_dentry = au_plink_lkup(inode, bindex); -+ if (IS_ERR(h_dentry)) -+ goto out_fill; /* pretending success */ -+ } -+ /* illegally overlapped or something */ -+ if (unlikely(!h_dentry)) -+ goto out_fill; /* pretending success */ -+ -+ positive = !!h_dentry->d_inode; -+ if (positive) -+ err = vfs_getattr(h_mnt, h_dentry, st); -+ dput(h_dentry); -+ if (!err) { -+ if (positive) -+ au_refresh_iattr(inode, st, h_dentry->d_inode->i_nlink); -+ goto out_fill; /* success */ -+ } -+ goto out_unlock; -+ -+ out_fill: -+ generic_fillattr(inode, st); -+ out_unlock: -+ di_read_unlock(dentry, AuLock_IR); -+ out: -+ si_read_unlock(sb); -+ return err; -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+static int h_readlink(struct dentry *dentry, int bindex, char __user *buf, -+ int bufsiz) -+{ -+ int err; -+ struct super_block *sb; -+ struct dentry *h_dentry; -+ -+ err = -EINVAL; -+ h_dentry = au_h_dptr(dentry, bindex); -+ if (unlikely(/* !h_dentry -+ || !h_dentry->d_inode -+ || !h_dentry->d_inode->i_op -+ || */ !h_dentry->d_inode->i_op->readlink)) -+ goto out; -+ -+ err = security_inode_readlink(h_dentry); -+ if (unlikely(err)) -+ goto out; -+ -+ sb = dentry->d_sb; -+ if (!au_test_ro(sb, bindex, dentry->d_inode)) { -+ vfsub_touch_atime(au_sbr_mnt(sb, bindex), h_dentry); -+ fsstack_copy_attr_atime(dentry->d_inode, h_dentry->d_inode); -+ } -+ err = h_dentry->d_inode->i_op->readlink(h_dentry, buf, bufsiz); -+ -+ out: -+ return err; -+} -+ -+static int aufs_readlink(struct dentry *dentry, char __user *buf, int bufsiz) -+{ -+ int err; -+ -+ aufs_read_lock(dentry, AuLock_IR); -+ err = h_readlink(dentry, au_dbstart(dentry), buf, bufsiz); -+ aufs_read_unlock(dentry, AuLock_IR); -+ -+ return err; -+} -+ -+static void *aufs_follow_link(struct dentry *dentry, struct nameidata *nd) -+{ -+ int err; -+ char *buf; -+ mm_segment_t old_fs; -+ -+ err = -ENOMEM; -+ buf = __getname(); -+ if (unlikely(!buf)) -+ goto out; -+ -+ aufs_read_lock(dentry, AuLock_IR); -+ old_fs = get_fs(); -+ set_fs(KERNEL_DS); -+ err = h_readlink(dentry, au_dbstart(dentry), (char __user *)buf, -+ PATH_MAX); -+ set_fs(old_fs); -+ aufs_read_unlock(dentry, AuLock_IR); -+ -+ if (err >= 0) { -+ buf[err] = 0; -+ /* will be freed by put_link */ -+ nd_set_link(nd, buf); -+ return NULL; /* success */ -+ } -+ __putname(buf); -+ -+ out: -+ path_put(&nd->path); -+ AuTraceErr(err); -+ return ERR_PTR(err); -+} -+ -+static void aufs_put_link(struct dentry *dentry __maybe_unused, -+ struct nameidata *nd, void *cookie __maybe_unused) -+{ -+ __putname(nd_get_link(nd)); -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+static void aufs_truncate_range(struct inode *inode __maybe_unused, -+ loff_t start __maybe_unused, -+ loff_t end __maybe_unused) -+{ -+ AuUnsupport(); -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+struct inode_operations aufs_symlink_iop = { -+ .permission = aufs_permission, -+ .setattr = aufs_setattr, -+ .getattr = aufs_getattr, -+ .readlink = aufs_readlink, -+ .follow_link = aufs_follow_link, -+ .put_link = aufs_put_link -+}; -+ -+struct inode_operations aufs_dir_iop = { -+ .create = aufs_create, -+ .lookup = aufs_lookup, -+ .link = aufs_link, -+ .unlink = aufs_unlink, -+ .symlink = aufs_symlink, -+ .mkdir = aufs_mkdir, -+ .rmdir = aufs_rmdir, -+ .mknod = aufs_mknod, -+ .rename = aufs_rename, -+ -+ .permission = aufs_permission, -+ .setattr = aufs_setattr, -+ .getattr = aufs_getattr -+}; -+ -+struct inode_operations aufs_iop = { -+ .permission = aufs_permission, -+ .setattr = aufs_setattr, -+ .getattr = aufs_getattr, -+ .truncate_range = aufs_truncate_range -+}; -diff --git a/fs/aufs/i_op_add.c b/fs/aufs/i_op_add.c -new file mode 100644 -index 0000000..813890f ---- /dev/null -+++ b/fs/aufs/i_op_add.c -@@ -0,0 +1,658 @@ -+/* -+ * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * -+ * This program, aufs is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ */ -+ -+/* -+ * inode operations (add entry) -+ */ -+ -+#include "aufs.h" -+ -+/* -+ * final procedure of adding a new entry, except link(2). -+ * remove whiteout, instantiate, copyup the parent dir's times and size -+ * and update version. -+ * if it failed, re-create the removed whiteout. -+ */ -+static int epilog(struct inode *dir, aufs_bindex_t bindex, -+ struct dentry *wh_dentry, struct dentry *dentry) -+{ -+ int err, rerr; -+ aufs_bindex_t bwh; -+ struct path h_path; -+ struct inode *inode, *h_dir; -+ struct dentry *wh; -+ -+ bwh = -1; -+ if (wh_dentry) { -+ h_dir = wh_dentry->d_parent->d_inode; /* dir inode is locked */ -+ IMustLock(h_dir); -+ AuDebugOn(au_h_iptr(dir, bindex) != h_dir); -+ bwh = au_dbwh(dentry); -+ h_path.dentry = wh_dentry; -+ h_path.mnt = au_sbr_mnt(dir->i_sb, bindex); -+ err = au_wh_unlink_dentry(au_h_iptr(dir, bindex), &h_path, -+ dentry); -+ if (unlikely(err)) -+ goto out; -+ } -+ -+ inode = au_new_inode(dentry, /*must_new*/1); -+ if (!IS_ERR(inode)) { -+ d_instantiate(dentry, inode); -+ dir = dentry->d_parent->d_inode; /* dir inode is locked */ -+ IMustLock(dir); -+ if (au_ibstart(dir) == au_dbstart(dentry)) -+ au_cpup_attr_timesizes(dir); -+ dir->i_version++; -+ return 0; /* success */ -+ } -+ -+ err = PTR_ERR(inode); -+ if (!wh_dentry) -+ goto out; -+ -+ /* revert */ -+ /* dir inode is locked */ -+ wh = au_wh_create(dentry, bwh, wh_dentry->d_parent); -+ rerr = PTR_ERR(wh); -+ if (IS_ERR(wh)) { -+ AuIOErr("%.*s reverting whiteout failed(%d, %d)\n", -+ AuDLNPair(dentry), err, rerr); -+ err = -EIO; -+ } else -+ dput(wh); -+ -+ out: -+ return err; -+} -+ -+/* -+ * simple tests for the adding inode operations. -+ * following the checks in vfs, plus the parent-child relationship. -+ */ -+int au_may_add(struct dentry *dentry, aufs_bindex_t bindex, -+ struct dentry *h_parent, int isdir) -+{ -+ int err; -+ umode_t h_mode; -+ struct dentry *h_dentry; -+ struct inode *h_inode; -+ -+ err = -ENAMETOOLONG; -+ if (unlikely(dentry->d_name.len > AUFS_MAX_NAMELEN)) -+ goto out; -+ -+ h_dentry = au_h_dptr(dentry, bindex); -+ h_inode = h_dentry->d_inode; -+ if (!dentry->d_inode) { -+ err = -EEXIST; -+ if (unlikely(h_inode)) -+ goto out; -+ } else { -+ /* rename(2) case */ -+ err = -EIO; -+ if (unlikely(!h_inode || !h_inode->i_nlink)) -+ goto out; -+ -+ h_mode = h_inode->i_mode; -+ if (!isdir) { -+ err = -EISDIR; -+ if (unlikely(S_ISDIR(h_mode))) -+ goto out; -+ } else if (unlikely(!S_ISDIR(h_mode))) { -+ err = -ENOTDIR; -+ goto out; -+ } -+ } -+ -+ err = -EIO; -+ /* expected parent dir is locked */ -+ if (unlikely(h_parent != h_dentry->d_parent)) -+ goto out; -+ err = 0; -+ -+ out: -+ AuTraceErr(err); -+ return err; -+} -+ -+/* -+ * initial procedure of adding a new entry. -+ * prepare writable branch and the parent dir, lock it, -+ * and lookup whiteout for the new entry. -+ */ -+static struct dentry* -+lock_hdir_lkup_wh(struct dentry *dentry, struct au_dtime *dt, -+ struct dentry *src_dentry, struct au_pin *pin, -+ struct au_wr_dir_args *wr_dir_args) -+{ -+ struct dentry *wh_dentry, *h_parent; -+ struct super_block *sb; -+ struct au_branch *br; -+ int err; -+ unsigned int udba; -+ aufs_bindex_t bcpup; -+ -+ AuDbg("%.*s\n", AuDLNPair(dentry)); -+ -+ err = au_wr_dir(dentry, src_dentry, wr_dir_args); -+ bcpup = err; -+ wh_dentry = ERR_PTR(err); -+ if (unlikely(err < 0)) -+ goto out; -+ -+ sb = dentry->d_sb; -+ udba = au_opt_udba(sb); -+ err = au_pin(pin, dentry, bcpup, udba, -+ AuPin_DI_LOCKED | AuPin_MNT_WRITE); -+ wh_dentry = ERR_PTR(err); -+ if (unlikely(err)) -+ goto out; -+ -+ h_parent = au_pinned_h_parent(pin); -+ if (udba != AuOpt_UDBA_NONE -+ && au_dbstart(dentry) == bcpup) -+ err = au_may_add(dentry, bcpup, h_parent, -+ au_ftest_wrdir(wr_dir_args->flags, ISDIR)); -+ else if (unlikely(dentry->d_name.len > AUFS_MAX_NAMELEN)) -+ err = -ENAMETOOLONG; -+ wh_dentry = ERR_PTR(err); -+ if (unlikely(err)) -+ goto out_unpin; -+ -+ br = au_sbr(sb, bcpup); -+ if (dt) { -+ struct path tmp = { -+ .dentry = h_parent, -+ .mnt = br->br_mnt -+ }; -+ au_dtime_store(dt, au_pinned_parent(pin), &tmp); -+ } -+ -+ wh_dentry = NULL; -+ if (bcpup != au_dbwh(dentry)) -+ goto out; /* success */ -+ -+ wh_dentry = au_wh_lkup(h_parent, &dentry->d_name, br); -+ -+ out_unpin: -+ if (IS_ERR(wh_dentry)) -+ au_unpin(pin); -+ out: -+ return wh_dentry; -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+enum { Mknod, Symlink, Creat }; -+struct simple_arg { -+ int type; -+ union { -+ struct { -+ int mode; -+ struct nameidata *nd; -+ } c; -+ struct { -+ const char *symname; -+ } s; -+ struct { -+ int mode; -+ dev_t dev; -+ } m; -+ } u; -+}; -+ -+static int add_simple(struct inode *dir, struct dentry *dentry, -+ struct simple_arg *arg) -+{ -+ int err; -+ aufs_bindex_t bstart; -+ unsigned char created; -+ struct au_dtime dt; -+ struct au_pin pin; -+ struct path h_path; -+ struct dentry *wh_dentry, *parent; -+ struct inode *h_dir; -+ struct au_wr_dir_args wr_dir_args = { -+ .force_btgt = -1, -+ .flags = AuWrDir_ADD_ENTRY -+ }; -+ -+ AuDbg("%.*s\n", AuDLNPair(dentry)); -+ IMustLock(dir); -+ -+ parent = dentry->d_parent; /* dir inode is locked */ -+ aufs_read_lock(dentry, AuLock_DW); -+ di_write_lock_parent(parent); -+ wh_dentry = lock_hdir_lkup_wh(dentry, &dt, /*src_dentry*/NULL, &pin, -+ &wr_dir_args); -+ err = PTR_ERR(wh_dentry); -+ if (IS_ERR(wh_dentry)) -+ goto out; -+ -+ bstart = au_dbstart(dentry); -+ h_path.dentry = au_h_dptr(dentry, bstart); -+ h_path.mnt = au_sbr_mnt(dentry->d_sb, bstart); -+ h_dir = au_pinned_h_dir(&pin); -+ switch (arg->type) { -+ case Creat: -+ err = vfsub_create(h_dir, &h_path, arg->u.c.mode); -+ break; -+ case Symlink: -+ err = vfsub_symlink(h_dir, &h_path, arg->u.s.symname); -+ break; -+ case Mknod: -+ err = vfsub_mknod(h_dir, &h_path, arg->u.m.mode, arg->u.m.dev); -+ break; -+ default: -+ BUG(); -+ } -+ created = !err; -+ if (!err) -+ err = epilog(dir, bstart, wh_dentry, dentry); -+ -+ /* revert */ -+ if (unlikely(created && err && h_path.dentry->d_inode)) { -+ int rerr; -+ rerr = vfsub_unlink(h_dir, &h_path, /*force*/0); -+ if (rerr) { -+ AuIOErr("%.*s revert failure(%d, %d)\n", -+ AuDLNPair(dentry), err, rerr); -+ err = -EIO; -+ } -+ au_dtime_revert(&dt); -+ d_drop(dentry); -+ } -+ -+ au_unpin(&pin); -+ dput(wh_dentry); -+ -+ out: -+ if (unlikely(err)) { -+ au_update_dbstart(dentry); -+ d_drop(dentry); -+ } -+ di_write_unlock(parent); -+ aufs_read_unlock(dentry, AuLock_DW); -+ return err; -+} -+ -+int aufs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev) -+{ -+ struct simple_arg arg = { -+ .type = Mknod, -+ .u.m = { -+ .mode = mode, -+ .dev = dev -+ } -+ }; -+ return add_simple(dir, dentry, &arg); -+} -+ -+int aufs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) -+{ -+ struct simple_arg arg = { -+ .type = Symlink, -+ .u.s.symname = symname -+ }; -+ return add_simple(dir, dentry, &arg); -+} -+ -+int aufs_create(struct inode *dir, struct dentry *dentry, int mode, -+ struct nameidata *nd) -+{ -+ struct simple_arg arg = { -+ .type = Creat, -+ .u.c = { -+ .mode = mode, -+ .nd = nd -+ } -+ }; -+ return add_simple(dir, dentry, &arg); -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+struct au_link_args { -+ aufs_bindex_t bdst, bsrc; -+ struct au_pin pin; -+ struct path h_path; -+ struct dentry *src_parent, *parent; -+}; -+ -+static int au_cpup_before_link(struct dentry *src_dentry, -+ struct au_link_args *a) -+{ -+ int err; -+ struct dentry *h_src_dentry; -+ struct mutex *h_mtx; -+ -+ di_read_lock_parent(a->src_parent, AuLock_IR); -+ err = au_test_and_cpup_dirs(src_dentry, a->bdst); -+ if (unlikely(err)) -+ goto out; -+ -+ h_src_dentry = au_h_dptr(src_dentry, a->bsrc); -+ h_mtx = &h_src_dentry->d_inode->i_mutex; -+ err = au_pin(&a->pin, src_dentry, a->bdst, -+ au_opt_udba(src_dentry->d_sb), -+ AuPin_DI_LOCKED | AuPin_MNT_WRITE); -+ if (unlikely(err)) -+ goto out; -+ mutex_lock_nested(h_mtx, AuLsc_I_CHILD); -+ err = au_sio_cpup_simple(src_dentry, a->bdst, -1, -+ AuCpup_DTIME /* | AuCpup_KEEPLINO */); -+ mutex_unlock(h_mtx); -+ au_unpin(&a->pin); -+ -+ out: -+ di_read_unlock(a->src_parent, AuLock_IR); -+ return err; -+} -+ -+static int au_cpup_or_link(struct dentry *src_dentry, struct au_link_args *a) -+{ -+ int err; -+ unsigned char plink; -+ struct inode *h_inode, *inode; -+ struct dentry *h_src_dentry; -+ struct super_block *sb; -+ -+ plink = 0; -+ h_inode = NULL; -+ sb = src_dentry->d_sb; -+ inode = src_dentry->d_inode; -+ if (au_ibstart(inode) <= a->bdst) -+ h_inode = au_h_iptr(inode, a->bdst); -+ if (!h_inode || !h_inode->i_nlink) { -+ /* copyup src_dentry as the name of dentry. */ -+ au_set_dbstart(src_dentry, a->bdst); -+ au_set_h_dptr(src_dentry, a->bdst, dget(a->h_path.dentry)); -+ h_inode = au_h_dptr(src_dentry, a->bsrc)->d_inode; -+ mutex_lock_nested(&h_inode->i_mutex, AuLsc_I_CHILD); -+ err = au_sio_cpup_single(src_dentry, a->bdst, a->bsrc, -1, -+ AuCpup_KEEPLINO, a->parent); -+ mutex_unlock(&h_inode->i_mutex); -+ au_set_h_dptr(src_dentry, a->bdst, NULL); -+ au_set_dbstart(src_dentry, a->bsrc); -+ } else { -+ /* the inode of src_dentry already exists on a.bdst branch */ -+ h_src_dentry = d_find_alias(h_inode); -+ if (!h_src_dentry && au_plink_test(inode)) { -+ plink = 1; -+ h_src_dentry = au_plink_lkup(inode, a->bdst); -+ err = PTR_ERR(h_src_dentry); -+ if (IS_ERR(h_src_dentry)) -+ goto out; -+ -+ if (unlikely(!h_src_dentry->d_inode)) { -+ dput(h_src_dentry); -+ h_src_dentry = NULL; -+ } -+ -+ } -+ if (h_src_dentry) { -+ err = vfsub_link(h_src_dentry, au_pinned_h_dir(&a->pin), -+ &a->h_path); -+ dput(h_src_dentry); -+ } else { -+ AuIOErr("no dentry found for hi%lu on b%d\n", -+ h_inode->i_ino, a->bdst); -+ err = -EIO; -+ } -+ } -+ -+ if (!err && !plink) -+ au_plink_append(inode, a->bdst, a->h_path.dentry); -+ -+out: -+ return err; -+} -+ -+int aufs_link(struct dentry *src_dentry, struct inode *dir, -+ struct dentry *dentry) -+{ -+ int err, rerr; -+ struct au_dtime dt; -+ struct au_link_args *a; -+ struct dentry *wh_dentry, *h_src_dentry; -+ struct inode *inode; -+ struct super_block *sb; -+ struct au_wr_dir_args wr_dir_args = { -+ /* .force_btgt = -1, */ -+ .flags = AuWrDir_ADD_ENTRY -+ }; -+ -+ IMustLock(dir); -+ inode = src_dentry->d_inode; -+ IMustLock(inode); -+ -+ err = -ENOENT; -+ if (unlikely(!inode->i_nlink)) -+ goto out; -+ -+ err = -ENOMEM; -+ a = kzalloc(sizeof(*a), GFP_NOFS); -+ if (unlikely(!a)) -+ goto out; -+ -+ a->parent = dentry->d_parent; /* dir inode is locked */ -+ aufs_read_and_write_lock2(dentry, src_dentry, /*AuLock_FLUSH*/0); -+ a->src_parent = dget_parent(src_dentry); -+ wr_dir_args.force_btgt = au_dbstart(src_dentry); -+ -+ di_write_lock_parent(a->parent); -+ wr_dir_args.force_btgt = au_wbr(dentry, wr_dir_args.force_btgt); -+ wh_dentry = lock_hdir_lkup_wh(dentry, &dt, src_dentry, &a->pin, -+ &wr_dir_args); -+ err = PTR_ERR(wh_dentry); -+ if (IS_ERR(wh_dentry)) -+ goto out_unlock; -+ -+ err = 0; -+ sb = dentry->d_sb; -+ a->bdst = au_dbstart(dentry); -+ a->h_path.dentry = au_h_dptr(dentry, a->bdst); -+ a->h_path.mnt = au_sbr_mnt(sb, a->bdst); -+ a->bsrc = au_dbstart(src_dentry); -+ if (au_opt_test(au_mntflags(sb), PLINK)) { -+ if (a->bdst < a->bsrc -+ /* && h_src_dentry->d_sb != a->h_path.dentry->d_sb */) -+ err = au_cpup_or_link(src_dentry, a); -+ else { -+ h_src_dentry = au_h_dptr(src_dentry, a->bdst); -+ err = vfsub_link(h_src_dentry, au_pinned_h_dir(&a->pin), -+ &a->h_path); -+ } -+ } else { -+ /* -+ * copyup src_dentry to the branch we process, -+ * and then link(2) to it. -+ */ -+ if (a->bdst < a->bsrc -+ /* && h_src_dentry->d_sb != a->h_path.dentry->d_sb */) { -+ au_unpin(&a->pin); -+ di_write_unlock(a->parent); -+ err = au_cpup_before_link(src_dentry, a); -+ di_write_lock_parent(a->parent); -+ if (!err) -+ err = au_pin(&a->pin, dentry, a->bdst, -+ au_opt_udba(sb), -+ AuPin_DI_LOCKED | AuPin_MNT_WRITE); -+ if (unlikely(err)) -+ goto out_wh; -+ } -+ if (!err) { -+ h_src_dentry = au_h_dptr(src_dentry, a->bdst); -+ err = -ENOENT; -+ if (h_src_dentry && h_src_dentry->d_inode) -+ err = vfsub_link(h_src_dentry, -+ au_pinned_h_dir(&a->pin), -+ &a->h_path); -+ } -+ } -+ if (unlikely(err)) -+ goto out_unpin; -+ -+ if (wh_dentry) { -+ a->h_path.dentry = wh_dentry; -+ err = au_wh_unlink_dentry(au_pinned_h_dir(&a->pin), &a->h_path, -+ dentry); -+ if (unlikely(err)) -+ goto out_revert; -+ } -+ -+ dir->i_version++; -+ if (au_ibstart(dir) == au_dbstart(dentry)) -+ au_cpup_attr_timesizes(dir); -+ inc_nlink(inode); -+ inode->i_ctime = dir->i_ctime; -+ if (!d_unhashed(a->h_path.dentry)) -+ d_instantiate(dentry, au_igrab(inode)); -+ else -+ /* some filesystem calls d_drop() */ -+ d_drop(dentry); -+ goto out_unpin; /* success */ -+ -+ out_revert: -+ rerr = vfsub_unlink(au_pinned_h_dir(&a->pin), &a->h_path, /*force*/0); -+ if (!rerr) -+ goto out_dt; -+ AuIOErr("%.*s reverting failed(%d, %d)\n", -+ AuDLNPair(dentry), err, rerr); -+ err = -EIO; -+ out_dt: -+ d_drop(dentry); -+ au_dtime_revert(&dt); -+ out_unpin: -+ au_unpin(&a->pin); -+ out_wh: -+ dput(wh_dentry); -+ out_unlock: -+ if (unlikely(err)) { -+ au_update_dbstart(dentry); -+ d_drop(dentry); -+ } -+ di_write_unlock(a->parent); -+ dput(a->src_parent); -+ aufs_read_and_write_unlock2(dentry, src_dentry); -+ kfree(a); -+ out: -+ return err; -+} -+ -+int aufs_mkdir(struct inode *dir, struct dentry *dentry, int mode) -+{ -+ int err, rerr; -+ aufs_bindex_t bindex; -+ unsigned char diropq; -+ struct path h_path; -+ struct dentry *wh_dentry, *parent, *opq_dentry; -+ struct mutex *h_mtx; -+ struct super_block *sb; -+ struct { -+ struct au_pin pin; -+ struct au_dtime dt; -+ } *a; /* reduce the stack usage */ -+ struct au_wr_dir_args wr_dir_args = { -+ .force_btgt = -1, -+ .flags = AuWrDir_ADD_ENTRY | AuWrDir_ISDIR -+ }; -+ -+ IMustLock(dir); -+ -+ err = -ENOMEM; -+ a = kmalloc(sizeof(*a), GFP_NOFS); -+ if (unlikely(!a)) -+ goto out; -+ -+ aufs_read_lock(dentry, AuLock_DW); -+ parent = dentry->d_parent; /* dir inode is locked */ -+ di_write_lock_parent(parent); -+ wh_dentry = lock_hdir_lkup_wh(dentry, &a->dt, /*src_dentry*/NULL, -+ &a->pin, &wr_dir_args); -+ err = PTR_ERR(wh_dentry); -+ if (IS_ERR(wh_dentry)) -+ goto out_free; -+ -+ sb = dentry->d_sb; -+ bindex = au_dbstart(dentry); -+ h_path.dentry = au_h_dptr(dentry, bindex); -+ h_path.mnt = au_sbr_mnt(sb, bindex); -+ err = vfsub_mkdir(au_pinned_h_dir(&a->pin), &h_path, mode); -+ if (unlikely(err)) -+ goto out_unlock; -+ -+ /* make the dir opaque */ -+ diropq = 0; -+ h_mtx = &h_path.dentry->d_inode->i_mutex; -+ if (wh_dentry -+ || au_opt_test(au_mntflags(sb), ALWAYS_DIROPQ)) { -+ mutex_lock_nested(h_mtx, AuLsc_I_CHILD); -+ opq_dentry = au_diropq_create(dentry, bindex); -+ mutex_unlock(h_mtx); -+ err = PTR_ERR(opq_dentry); -+ if (IS_ERR(opq_dentry)) -+ goto out_dir; -+ dput(opq_dentry); -+ diropq = 1; -+ } -+ -+ err = epilog(dir, bindex, wh_dentry, dentry); -+ if (!err) { -+ inc_nlink(dir); -+ goto out_unlock; /* success */ -+ } -+ -+ /* revert */ -+ if (diropq) { -+ AuLabel(revert opq); -+ mutex_lock_nested(h_mtx, AuLsc_I_CHILD); -+ rerr = au_diropq_remove(dentry, bindex); -+ mutex_unlock(h_mtx); -+ if (rerr) { -+ AuIOErr("%.*s reverting diropq failed(%d, %d)\n", -+ AuDLNPair(dentry), err, rerr); -+ err = -EIO; -+ } -+ } -+ -+ out_dir: -+ AuLabel(revert dir); -+ rerr = vfsub_rmdir(au_pinned_h_dir(&a->pin), &h_path); -+ if (rerr) { -+ AuIOErr("%.*s reverting dir failed(%d, %d)\n", -+ AuDLNPair(dentry), err, rerr); -+ err = -EIO; -+ } -+ d_drop(dentry); -+ au_dtime_revert(&a->dt); -+ out_unlock: -+ au_unpin(&a->pin); -+ dput(wh_dentry); -+ out_free: -+ if (unlikely(err)) { -+ au_update_dbstart(dentry); -+ d_drop(dentry); -+ } -+ di_write_unlock(parent); -+ aufs_read_unlock(dentry, AuLock_DW); -+ kfree(a); -+ out: -+ return err; -+} -diff --git a/fs/aufs/i_op_del.c b/fs/aufs/i_op_del.c -new file mode 100644 -index 0000000..d47ddfb ---- /dev/null -+++ b/fs/aufs/i_op_del.c -@@ -0,0 +1,470 @@ -+/* -+ * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * -+ * This program, aufs is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ */ -+ -+/* -+ * inode operations (del entry) -+ */ -+ -+#include "aufs.h" -+ -+/* -+ * decide if a new whiteout for @dentry is necessary or not. -+ * when it is necessary, prepare the parent dir for the upper branch whose -+ * branch index is @bcpup for creation. the actual creation of the whiteout will -+ * be done by caller. -+ * return value: -+ * 0: wh is unnecessary -+ * plus: wh is necessary -+ * minus: error -+ */ -+int au_wr_dir_need_wh(struct dentry *dentry, int isdir, aufs_bindex_t *bcpup) -+{ -+ int need_wh, err; -+ aufs_bindex_t bstart; -+ struct super_block *sb; -+ -+ sb = dentry->d_sb; -+ bstart = au_dbstart(dentry); -+ if (*bcpup < 0) { -+ *bcpup = bstart; -+ if (au_test_ro(sb, bstart, dentry->d_inode)) { -+ err = AuWbrCopyup(au_sbi(sb), dentry); -+ *bcpup = err; -+ if (unlikely(err < 0)) -+ goto out; -+ } -+ } else -+ AuDebugOn(bstart < *bcpup -+ || au_test_ro(sb, *bcpup, dentry->d_inode)); -+ AuDbg("bcpup %d, bstart %d\n", *bcpup, bstart); -+ -+ if (*bcpup != bstart) { -+ err = au_cpup_dirs(dentry, *bcpup); -+ if (unlikely(err)) -+ goto out; -+ need_wh = 1; -+ } else { -+ aufs_bindex_t old_bend, new_bend, bdiropq = -1; -+ -+ old_bend = au_dbend(dentry); -+ if (isdir) { -+ bdiropq = au_dbdiropq(dentry); -+ au_set_dbdiropq(dentry, -1); -+ } -+ need_wh = au_lkup_dentry(dentry, bstart + 1, /*type*/0, -+ /*nd*/NULL); -+ err = need_wh; -+ if (isdir) -+ au_set_dbdiropq(dentry, bdiropq); -+ if (unlikely(err < 0)) -+ goto out; -+ new_bend = au_dbend(dentry); -+ if (!need_wh && old_bend != new_bend) { -+ au_set_h_dptr(dentry, new_bend, NULL); -+ au_set_dbend(dentry, old_bend); -+ } -+ } -+ AuDbg("need_wh %d\n", need_wh); -+ err = need_wh; -+ -+ out: -+ return err; -+} -+ -+/* -+ * simple tests for the del-entry operations. -+ * following the checks in vfs, plus the parent-child relationship. -+ */ -+int au_may_del(struct dentry *dentry, aufs_bindex_t bindex, -+ struct dentry *h_parent, int isdir) -+{ -+ int err; -+ umode_t h_mode; -+ struct dentry *h_dentry, *h_latest; -+ struct inode *h_inode; -+ -+ h_dentry = au_h_dptr(dentry, bindex); -+ h_inode = h_dentry->d_inode; -+ if (dentry->d_inode) { -+ err = -ENOENT; -+ if (unlikely(!h_inode || !h_inode->i_nlink)) -+ goto out; -+ -+ h_mode = h_inode->i_mode; -+ if (!isdir) { -+ err = -EISDIR; -+ if (unlikely(S_ISDIR(h_mode))) -+ goto out; -+ } else if (unlikely(!S_ISDIR(h_mode))) { -+ err = -ENOTDIR; -+ goto out; -+ } -+ } else { -+ /* rename(2) case */ -+ err = -EIO; -+ if (unlikely(h_inode)) -+ goto out; -+ } -+ -+ err = -ENOENT; -+ /* expected parent dir is locked */ -+ if (unlikely(h_parent != h_dentry->d_parent)) -+ goto out; -+ err = 0; -+ -+ /* -+ * rmdir a dir may break the consistency on some filesystem. -+ * let's try heavy test. -+ */ -+ err = -EACCES; -+ if (unlikely(au_test_h_perm(h_parent->d_inode, MAY_EXEC | MAY_WRITE))) -+ goto out; -+ -+ h_latest = au_sio_lkup_one(&dentry->d_name, h_parent, -+ au_sbr(dentry->d_sb, bindex)); -+ err = -EIO; -+ if (IS_ERR(h_latest)) -+ goto out; -+ if (h_latest == h_dentry) -+ err = 0; -+ dput(h_latest); -+ -+ out: -+ return err; -+} -+ -+/* -+ * decide the branch where we operate for @dentry. the branch index will be set -+ * @rbcpup. after diciding it, 'pin' it and store the timestamps of the parent -+ * dir for reverting. -+ * when a new whiteout is necessary, create it. -+ */ -+static struct dentry* -+lock_hdir_create_wh(struct dentry *dentry, int isdir, aufs_bindex_t *rbcpup, -+ struct au_dtime *dt, struct au_pin *pin) -+{ -+ struct dentry *wh_dentry; -+ struct super_block *sb; -+ struct path h_path; -+ int err, need_wh; -+ unsigned int udba; -+ aufs_bindex_t bcpup; -+ -+ need_wh = au_wr_dir_need_wh(dentry, isdir, rbcpup); -+ wh_dentry = ERR_PTR(need_wh); -+ if (unlikely(need_wh < 0)) -+ goto out; -+ -+ sb = dentry->d_sb; -+ udba = au_opt_udba(sb); -+ bcpup = *rbcpup; -+ err = au_pin(pin, dentry, bcpup, udba, -+ AuPin_DI_LOCKED | AuPin_MNT_WRITE); -+ wh_dentry = ERR_PTR(err); -+ if (unlikely(err)) -+ goto out; -+ -+ h_path.dentry = au_pinned_h_parent(pin); -+ if (udba != AuOpt_UDBA_NONE -+ && au_dbstart(dentry) == bcpup) { -+ err = au_may_del(dentry, bcpup, h_path.dentry, isdir); -+ wh_dentry = ERR_PTR(err); -+ if (unlikely(err)) -+ goto out_unpin; -+ } -+ -+ h_path.mnt = au_sbr_mnt(sb, bcpup); -+ au_dtime_store(dt, au_pinned_parent(pin), &h_path); -+ wh_dentry = NULL; -+ if (!need_wh) -+ goto out; /* success, no need to create whiteout */ -+ -+ wh_dentry = au_wh_create(dentry, bcpup, h_path.dentry); -+ if (!IS_ERR(wh_dentry)) -+ goto out; /* success */ -+ /* returns with the parent is locked and wh_dentry is dget-ed */ -+ -+ out_unpin: -+ au_unpin(pin); -+ out: -+ return wh_dentry; -+} -+ -+/* -+ * when removing a dir, rename it to a unique temporary whiteout-ed name first -+ * in order to be revertible and save time for removing many child whiteouts -+ * under the dir. -+ * returns 1 when there are too many child whiteout and caller should remove -+ * them asynchronously. returns 0 when the number of children is enough small to -+ * remove now or the branch fs is a remote fs. -+ * otherwise return an error. -+ */ -+static int renwh_and_rmdir(struct dentry *dentry, aufs_bindex_t bindex, -+ struct au_nhash *whlist, struct inode *dir) -+{ -+ int rmdir_later, err, dirwh; -+ struct dentry *h_dentry; -+ struct super_block *sb; -+ -+ sb = dentry->d_sb; -+ SiMustAnyLock(sb); -+ h_dentry = au_h_dptr(dentry, bindex); -+ err = au_whtmp_ren(h_dentry, au_sbr(sb, bindex)); -+ if (unlikely(err)) -+ goto out; -+ -+ /* stop monitoring */ -+ au_hin_free(au_hi(dentry->d_inode, bindex)); -+ -+ if (!au_test_fs_remote(h_dentry->d_sb)) { -+ dirwh = au_sbi(sb)->si_dirwh; -+ rmdir_later = (dirwh <= 1); -+ if (!rmdir_later) -+ rmdir_later = au_nhash_test_longer_wh(whlist, bindex, -+ dirwh); -+ if (rmdir_later) -+ return rmdir_later; -+ } -+ -+ err = au_whtmp_rmdir(dir, bindex, h_dentry, whlist); -+ if (unlikely(err)) { -+ AuIOErr("rmdir %.*s, b%d failed, %d. ignored\n", -+ AuDLNPair(h_dentry), bindex, err); -+ err = 0; -+ } -+ -+ out: -+ AuTraceErr(err); -+ return err; -+} -+ -+/* -+ * final procedure for deleting a entry. -+ * maintain dentry and iattr. -+ */ -+static void epilog(struct inode *dir, struct dentry *dentry, -+ aufs_bindex_t bindex) -+{ -+ struct inode *inode; -+ -+ inode = dentry->d_inode; -+ d_drop(dentry); -+ inode->i_ctime = dir->i_ctime; -+ -+ if (atomic_read(&dentry->d_count) == 1) { -+ au_set_h_dptr(dentry, au_dbstart(dentry), NULL); -+ au_update_dbstart(dentry); -+ } -+ if (au_ibstart(dir) == bindex) -+ au_cpup_attr_timesizes(dir); -+ dir->i_version++; -+} -+ -+/* -+ * when an error happened, remove the created whiteout and revert everything. -+ */ -+static int do_revert(int err, struct inode *dir, aufs_bindex_t bwh, -+ struct dentry *wh_dentry, struct dentry *dentry, -+ struct au_dtime *dt) -+{ -+ int rerr; -+ struct path h_path = { -+ .dentry = wh_dentry, -+ .mnt = au_sbr_mnt(dir->i_sb, bwh) -+ }; -+ -+ rerr = au_wh_unlink_dentry(au_h_iptr(dir, bwh), &h_path, dentry); -+ if (!rerr) { -+ au_set_dbwh(dentry, bwh); -+ au_dtime_revert(dt); -+ return 0; -+ } -+ -+ AuIOErr("%.*s reverting whiteout failed(%d, %d)\n", -+ AuDLNPair(dentry), err, rerr); -+ return -EIO; -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+int aufs_unlink(struct inode *dir, struct dentry *dentry) -+{ -+ int err; -+ aufs_bindex_t bwh, bindex, bstart; -+ struct au_dtime dt; -+ struct au_pin pin; -+ struct path h_path; -+ struct inode *inode, *h_dir; -+ struct dentry *parent, *wh_dentry; -+ -+ IMustLock(dir); -+ inode = dentry->d_inode; -+ if (unlikely(!inode)) -+ return -ENOENT; /* possible? */ -+ IMustLock(inode); -+ -+ aufs_read_lock(dentry, AuLock_DW); -+ parent = dentry->d_parent; /* dir inode is locked */ -+ di_write_lock_parent(parent); -+ -+ bstart = au_dbstart(dentry); -+ bwh = au_dbwh(dentry); -+ bindex = -1; -+ wh_dentry = lock_hdir_create_wh(dentry, /*isdir*/0, &bindex, &dt, &pin); -+ err = PTR_ERR(wh_dentry); -+ if (IS_ERR(wh_dentry)) -+ goto out; -+ -+ h_path.mnt = au_sbr_mnt(dentry->d_sb, bstart); -+ h_path.dentry = au_h_dptr(dentry, bstart); -+ dget(h_path.dentry); -+ if (bindex == bstart) { -+ h_dir = au_pinned_h_dir(&pin); -+ err = vfsub_unlink(h_dir, &h_path, /*force*/0); -+ } else { -+ /* dir inode is locked */ -+ h_dir = wh_dentry->d_parent->d_inode; -+ IMustLock(h_dir); -+ err = 0; -+ } -+ -+ if (!err) { -+ drop_nlink(inode); -+ epilog(dir, dentry, bindex); -+ -+ /* update target timestamps */ -+ if (bindex == bstart) { -+ vfsub_update_h_iattr(&h_path, /*did*/NULL); /*ignore*/ -+ inode->i_ctime = h_path.dentry->d_inode->i_ctime; -+ } else -+ /* todo: this timestamp may be reverted later */ -+ inode->i_ctime = h_dir->i_ctime; -+ goto out_unlock; /* success */ -+ } -+ -+ /* revert */ -+ if (wh_dentry) { -+ int rerr; -+ -+ rerr = do_revert(err, dir, bwh, wh_dentry, dentry, &dt); -+ if (rerr) -+ err = rerr; -+ } -+ -+ out_unlock: -+ au_unpin(&pin); -+ dput(wh_dentry); -+ dput(h_path.dentry); -+ out: -+ di_write_unlock(parent); -+ aufs_read_unlock(dentry, AuLock_DW); -+ return err; -+} -+ -+int aufs_rmdir(struct inode *dir, struct dentry *dentry) -+{ -+ int err, rmdir_later; -+ aufs_bindex_t bwh, bindex, bstart; -+ struct au_dtime dt; -+ struct au_pin pin; -+ struct inode *inode; -+ struct dentry *parent, *wh_dentry, *h_dentry; -+ struct au_whtmp_rmdir *args; -+ -+ IMustLock(dir); -+ inode = dentry->d_inode; -+ err = -ENOENT; /* possible? */ -+ if (unlikely(!inode)) -+ goto out; -+ IMustLock(inode); -+ -+ aufs_read_lock(dentry, AuLock_DW | AuLock_FLUSH); -+ err = -ENOMEM; -+ args = au_whtmp_rmdir_alloc(dir->i_sb, GFP_NOFS); -+ if (unlikely(!args)) -+ goto out_unlock; -+ -+ parent = dentry->d_parent; /* dir inode is locked */ -+ di_write_lock_parent(parent); -+ err = au_test_empty(dentry, &args->whlist); -+ if (unlikely(err)) -+ goto out_args; -+ -+ bstart = au_dbstart(dentry); -+ bwh = au_dbwh(dentry); -+ bindex = -1; -+ wh_dentry = lock_hdir_create_wh(dentry, /*isdir*/1, &bindex, &dt, &pin); -+ err = PTR_ERR(wh_dentry); -+ if (IS_ERR(wh_dentry)) -+ goto out_args; -+ -+ h_dentry = au_h_dptr(dentry, bstart); -+ dget(h_dentry); -+ rmdir_later = 0; -+ if (bindex == bstart) { -+ err = renwh_and_rmdir(dentry, bstart, &args->whlist, dir); -+ if (err > 0) { -+ rmdir_later = err; -+ err = 0; -+ } -+ } else { -+ /* stop monitoring */ -+ au_hin_free(au_hi(inode, bstart)); -+ -+ /* dir inode is locked */ -+ IMustLock(wh_dentry->d_parent->d_inode); -+ err = 0; -+ } -+ -+ if (!err) { -+ clear_nlink(inode); -+ au_set_dbdiropq(dentry, -1); -+ epilog(dir, dentry, bindex); -+ -+ if (rmdir_later) { -+ au_whtmp_kick_rmdir(dir, bstart, h_dentry, args); -+ args = NULL; -+ } -+ -+ goto out_unpin; /* success */ -+ } -+ -+ /* revert */ -+ AuLabel(revert); -+ if (wh_dentry) { -+ int rerr; -+ -+ rerr = do_revert(err, dir, bwh, wh_dentry, dentry, &dt); -+ if (rerr) -+ err = rerr; -+ } -+ -+ out_unpin: -+ au_unpin(&pin); -+ dput(wh_dentry); -+ dput(h_dentry); -+ out_args: -+ di_write_unlock(parent); -+ if (args) -+ au_whtmp_rmdir_free(args); -+ out_unlock: -+ aufs_read_unlock(dentry, AuLock_DW); -+ out: -+ AuTraceErr(err); -+ return err; -+} -diff --git a/fs/aufs/i_op_ren.c b/fs/aufs/i_op_ren.c -new file mode 100644 -index 0000000..b107f93 ---- /dev/null -+++ b/fs/aufs/i_op_ren.c -@@ -0,0 +1,961 @@ -+/* -+ * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * -+ * This program, aufs is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ */ -+ -+/* -+ * inode operation (rename entry) -+ * todo: this is crazy monster -+ */ -+ -+#include "aufs.h" -+ -+enum { AuSRC, AuDST, AuSrcDst }; -+enum { AuPARENT, AuCHILD, AuParentChild }; -+ -+#define AuRen_ISDIR 1 -+#define AuRen_ISSAMEDIR (1 << 1) -+#define AuRen_WHSRC (1 << 2) -+#define AuRen_WHDST (1 << 3) -+#define AuRen_MNT_WRITE (1 << 4) -+#define AuRen_DT_DSTDIR (1 << 5) -+#define AuRen_DIROPQ (1 << 6) -+#define AuRen_CPUP (1 << 7) -+#define au_ftest_ren(flags, name) ((flags) & AuRen_##name) -+#define au_fset_ren(flags, name) { (flags) |= AuRen_##name; } -+#define au_fclr_ren(flags, name) { (flags) &= ~AuRen_##name; } -+ -+struct au_ren_args { -+ struct { -+ struct dentry *dentry, *h_dentry, *parent, *h_parent, -+ *wh_dentry; -+ struct inode *dir, *inode; -+ struct au_hinode *hdir; -+ struct au_dtime dt[AuParentChild]; -+ aufs_bindex_t bstart; -+ } sd[AuSrcDst]; -+ -+#define src_dentry sd[AuSRC].dentry -+#define src_dir sd[AuSRC].dir -+#define src_inode sd[AuSRC].inode -+#define src_h_dentry sd[AuSRC].h_dentry -+#define src_parent sd[AuSRC].parent -+#define src_h_parent sd[AuSRC].h_parent -+#define src_wh_dentry sd[AuSRC].wh_dentry -+#define src_hdir sd[AuSRC].hdir -+#define src_h_dir sd[AuSRC].hdir->hi_inode -+#define src_dt sd[AuSRC].dt -+#define src_bstart sd[AuSRC].bstart -+ -+#define dst_dentry sd[AuDST].dentry -+#define dst_dir sd[AuDST].dir -+#define dst_inode sd[AuDST].inode -+#define dst_h_dentry sd[AuDST].h_dentry -+#define dst_parent sd[AuDST].parent -+#define dst_h_parent sd[AuDST].h_parent -+#define dst_wh_dentry sd[AuDST].wh_dentry -+#define dst_hdir sd[AuDST].hdir -+#define dst_h_dir sd[AuDST].hdir->hi_inode -+#define dst_dt sd[AuDST].dt -+#define dst_bstart sd[AuDST].bstart -+ -+ struct dentry *h_trap; -+ struct au_branch *br; -+ struct au_hinode *src_hinode; -+ struct path h_path; -+ struct au_nhash whlist; -+ aufs_bindex_t btgt; -+ -+ unsigned int flags; -+ -+ struct au_whtmp_rmdir *thargs; -+ struct dentry *h_dst; -+}; -+ -+/* ---------------------------------------------------------------------- */ -+ -+/* -+ * functions for reverting. -+ * when an error happened in a single rename systemcall, we should revert -+ * everything as if nothing happend. -+ * we don't need to revert the copied-up/down the parent dir since they are -+ * harmless. -+ */ -+ -+#define RevertFailure(fmt, ...) do { \ -+ AuIOErr("revert failure: " fmt " (%d, %d)\n", \ -+ ##__VA_ARGS__, err, rerr); \ -+ err = -EIO; \ -+} while (0) -+ -+static void au_ren_rev_diropq(int err, struct au_ren_args *a) -+{ -+ int rerr; -+ -+ au_hin_imtx_lock_nested(a->src_hinode, AuLsc_I_CHILD); -+ rerr = au_diropq_remove(a->src_dentry, a->btgt); -+ au_hin_imtx_unlock(a->src_hinode); -+ if (rerr) -+ RevertFailure("remove diropq %.*s", AuDLNPair(a->src_dentry)); -+} -+ -+ -+static void au_ren_rev_rename(int err, struct au_ren_args *a) -+{ -+ int rerr; -+ -+ a->h_path.dentry = au_lkup_one(&a->src_dentry->d_name, a->src_h_parent, -+ a->br, /*nd*/NULL); -+ rerr = PTR_ERR(a->h_path.dentry); -+ if (IS_ERR(a->h_path.dentry)) { -+ RevertFailure("au_lkup_one %.*s", AuDLNPair(a->src_dentry)); -+ return; -+ } -+ -+ rerr = vfsub_rename(a->dst_h_dir, -+ au_h_dptr(a->src_dentry, a->btgt), -+ a->src_h_dir, &a->h_path); -+ d_drop(a->h_path.dentry); -+ dput(a->h_path.dentry); -+ /* au_set_h_dptr(a->src_dentry, a->btgt, NULL); */ -+ if (rerr) -+ RevertFailure("rename %.*s", AuDLNPair(a->src_dentry)); -+} -+ -+static void au_ren_rev_cpup(int err, struct au_ren_args *a) -+{ -+ int rerr; -+ -+ a->h_path.dentry = a->dst_h_dentry; -+ rerr = vfsub_unlink(a->dst_h_dir, &a->h_path, /*force*/0); -+ au_set_h_dptr(a->src_dentry, a->btgt, NULL); -+ au_set_dbstart(a->src_dentry, a->src_bstart); -+ if (rerr) -+ RevertFailure("unlink %.*s", AuDLNPair(a->dst_h_dentry)); -+} -+ -+ -+static void au_ren_rev_whtmp(int err, struct au_ren_args *a) -+{ -+ int rerr; -+ -+ a->h_path.dentry = au_lkup_one(&a->dst_dentry->d_name, a->dst_h_parent, -+ a->br, /*nd*/NULL); -+ rerr = PTR_ERR(a->h_path.dentry); -+ if (IS_ERR(a->h_path.dentry)) { -+ RevertFailure("lookup %.*s", AuDLNPair(a->dst_dentry)); -+ return; -+ } -+ if (a->h_path.dentry->d_inode) { -+ d_drop(a->h_path.dentry); -+ dput(a->h_path.dentry); -+ return; -+ } -+ -+ rerr = vfsub_rename(a->dst_h_dir, a->h_dst, a->dst_h_dir, &a->h_path); -+ d_drop(a->h_path.dentry); -+ dput(a->h_path.dentry); -+ if (!rerr) { -+ au_set_h_dptr(a->dst_dentry, a->btgt, NULL); -+ au_set_h_dptr(a->dst_dentry, a->btgt, dget(a->h_dst)); -+ } else -+ RevertFailure("rename %.*s", AuDLNPair(a->h_dst)); -+} -+ -+static void au_ren_rev_whsrc(int err, struct au_ren_args *a) -+{ -+ int rerr; -+ -+ a->h_path.dentry = a->src_wh_dentry; -+ rerr = au_wh_unlink_dentry(a->src_h_dir, &a->h_path, a->src_dentry); -+ if (rerr) -+ RevertFailure("unlink %.*s", AuDLNPair(a->src_wh_dentry)); -+} -+ -+static void au_ren_rev_drop(struct au_ren_args *a) -+{ -+ struct dentry *d, *h_d; -+ int i; -+ aufs_bindex_t bend, bindex; -+ -+ for (i = 0; i < AuSrcDst; i++) { -+ d = a->sd[i].dentry; -+ d_drop(d); -+ bend = au_dbend(d); -+ for (bindex = au_dbstart(d); bindex <= bend; bindex++) { -+ h_d = au_h_dptr(d, bindex); -+ if (h_d) -+ d_drop(h_d); -+ } -+ } -+ -+ au_update_dbstart(a->dst_dentry); -+ if (a->thargs) -+ d_drop(a->h_dst); -+} -+#undef RevertFailure -+ -+/* ---------------------------------------------------------------------- */ -+ -+/* -+ * when we have to copyup the renaming entry, do it with the rename-target name -+ * in order to minimize the cost (the later actual rename is unnecessary). -+ * otherwise rename it on the target branch. -+ */ -+static int au_ren_or_cpup(struct au_ren_args *a) -+{ -+ int err; -+ struct dentry *d; -+ -+ d = a->src_dentry; -+ if (au_dbstart(d) == a->btgt) { -+ a->h_path.dentry = a->dst_h_dentry; -+ if (au_ftest_ren(a->flags, DIROPQ) -+ && au_dbdiropq(d) == a->btgt) -+ au_fclr_ren(a->flags, DIROPQ); -+ AuDebugOn(au_dbstart(d) != a->btgt); -+ err = vfsub_rename(a->src_h_dir, au_h_dptr(d, a->btgt), -+ a->dst_h_dir, &a->h_path); -+ } else { -+ struct mutex *h_mtx = &a->src_h_dentry->d_inode->i_mutex; -+ -+ au_fset_ren(a->flags, CPUP); -+ mutex_lock_nested(h_mtx, AuLsc_I_CHILD); -+ au_set_dbstart(d, a->btgt); -+ au_set_h_dptr(d, a->btgt, dget(a->dst_h_dentry)); -+ err = au_sio_cpup_single(d, a->btgt, a->src_bstart, -1, -+ !AuCpup_DTIME, a->dst_parent); -+ if (unlikely(err)) { -+ au_set_h_dptr(d, a->btgt, NULL); -+ au_set_dbstart(d, a->src_bstart); -+ } -+ mutex_unlock(h_mtx); -+ } -+ -+ return err; -+} -+ -+/* cf. aufs_rmdir() */ -+static int au_ren_del_whtmp(struct au_ren_args *a) -+{ -+ int err; -+ struct inode *dir; -+ -+ dir = a->dst_dir; -+ SiMustAnyLock(dir->i_sb); -+ if (!au_nhash_test_longer_wh(&a->whlist, a->btgt, -+ au_sbi(dir->i_sb)->si_dirwh) -+ || au_test_fs_remote(a->h_dst->d_sb)) { -+ err = au_whtmp_rmdir(dir, a->btgt, a->h_dst, &a->whlist); -+ if (unlikely(err)) -+ pr_warning("failed removing whtmp dir %.*s (%d), " -+ "ignored.\n", AuDLNPair(a->h_dst), err); -+ } else { -+ au_nhash_wh_free(&a->thargs->whlist); -+ a->thargs->whlist = a->whlist; -+ a->whlist.nh_num = 0; -+ au_whtmp_kick_rmdir(dir, a->btgt, a->h_dst, a->thargs); -+ dput(a->h_dst); -+ a->thargs = NULL; -+ } -+ -+ return 0; -+} -+ -+/* make it 'opaque' dir. */ -+static int au_ren_diropq(struct au_ren_args *a) -+{ -+ int err; -+ struct dentry *diropq; -+ -+ err = 0; -+ a->src_hinode = au_hi(a->src_inode, a->btgt); -+ au_hin_imtx_lock_nested(a->src_hinode, AuLsc_I_CHILD); -+ diropq = au_diropq_create(a->src_dentry, a->btgt); -+ au_hin_imtx_unlock(a->src_hinode); -+ if (IS_ERR(diropq)) -+ err = PTR_ERR(diropq); -+ dput(diropq); -+ -+ return err; -+} -+ -+static int do_rename(struct au_ren_args *a) -+{ -+ int err; -+ struct dentry *d, *h_d; -+ -+ /* prepare workqueue args for asynchronous rmdir */ -+ h_d = a->dst_h_dentry; -+ if (au_ftest_ren(a->flags, ISDIR) && h_d->d_inode) { -+ err = -ENOMEM; -+ a->thargs = au_whtmp_rmdir_alloc(a->src_dentry->d_sb, GFP_NOFS); -+ if (unlikely(!a->thargs)) -+ goto out; -+ a->h_dst = dget(h_d); -+ } -+ -+ /* create whiteout for src_dentry */ -+ if (au_ftest_ren(a->flags, WHSRC)) { -+ a->src_wh_dentry -+ = au_wh_create(a->src_dentry, a->btgt, a->src_h_parent); -+ err = PTR_ERR(a->src_wh_dentry); -+ if (IS_ERR(a->src_wh_dentry)) -+ goto out_thargs; -+ } -+ -+ /* lookup whiteout for dentry */ -+ if (au_ftest_ren(a->flags, WHDST)) { -+ h_d = au_wh_lkup(a->dst_h_parent, &a->dst_dentry->d_name, -+ a->br); -+ err = PTR_ERR(h_d); -+ if (IS_ERR(h_d)) -+ goto out_whsrc; -+ if (!h_d->d_inode) -+ dput(h_d); -+ else -+ a->dst_wh_dentry = h_d; -+ } -+ -+ /* rename dentry to tmpwh */ -+ if (a->thargs) { -+ err = au_whtmp_ren(a->dst_h_dentry, a->br); -+ if (unlikely(err)) -+ goto out_whdst; -+ -+ d = a->dst_dentry; -+ au_set_h_dptr(d, a->btgt, NULL); -+ err = au_lkup_neg(d, a->btgt); -+ if (unlikely(err)) -+ goto out_whtmp; -+ a->dst_h_dentry = au_h_dptr(d, a->btgt); -+ } -+ -+ /* cpup src */ -+ if (a->dst_h_dentry->d_inode && a->src_bstart != a->btgt) { -+ struct mutex *h_mtx = &a->src_h_dentry->d_inode->i_mutex; -+ -+ mutex_lock_nested(h_mtx, AuLsc_I_CHILD); -+ err = au_sio_cpup_simple(a->src_dentry, a->btgt, -1, -+ !AuCpup_DTIME); -+ mutex_unlock(h_mtx); -+ if (unlikely(err)) -+ goto out_whtmp; -+ } -+ -+ /* rename by vfs_rename or cpup */ -+ d = a->dst_dentry; -+ if (au_ftest_ren(a->flags, ISDIR) -+ && (a->dst_wh_dentry -+ || au_dbdiropq(d) == a->btgt -+ /* hide the lower to keep xino */ -+ || a->btgt < au_dbend(d) -+ || au_opt_test(au_mntflags(d->d_sb), ALWAYS_DIROPQ))) -+ au_fset_ren(a->flags, DIROPQ); -+ err = au_ren_or_cpup(a); -+ if (unlikely(err)) -+ /* leave the copied-up one */ -+ goto out_whtmp; -+ -+ /* make dir opaque */ -+ if (au_ftest_ren(a->flags, DIROPQ)) { -+ err = au_ren_diropq(a); -+ if (unlikely(err)) -+ goto out_rename; -+ } -+ -+ /* update target timestamps */ -+ AuDebugOn(au_dbstart(a->src_dentry) != a->btgt); -+ a->h_path.dentry = au_h_dptr(a->src_dentry, a->btgt); -+ vfsub_update_h_iattr(&a->h_path, /*did*/NULL); /*ignore*/ -+ a->src_inode->i_ctime = a->h_path.dentry->d_inode->i_ctime; -+ -+ /* remove whiteout for dentry */ -+ if (a->dst_wh_dentry) { -+ a->h_path.dentry = a->dst_wh_dentry; -+ err = au_wh_unlink_dentry(a->dst_h_dir, &a->h_path, -+ a->dst_dentry); -+ if (unlikely(err)) -+ goto out_diropq; -+ } -+ -+ /* remove whtmp */ -+ if (a->thargs) -+ au_ren_del_whtmp(a); /* ignore this error */ -+ -+ err = 0; -+ goto out_success; -+ -+ out_diropq: -+ if (au_ftest_ren(a->flags, DIROPQ)) -+ au_ren_rev_diropq(err, a); -+ out_rename: -+ if (!au_ftest_ren(a->flags, CPUP)) -+ au_ren_rev_rename(err, a); -+ else -+ au_ren_rev_cpup(err, a); -+ out_whtmp: -+ if (a->thargs) -+ au_ren_rev_whtmp(err, a); -+ out_whdst: -+ dput(a->dst_wh_dentry); -+ a->dst_wh_dentry = NULL; -+ out_whsrc: -+ if (a->src_wh_dentry) -+ au_ren_rev_whsrc(err, a); -+ au_ren_rev_drop(a); -+ out_success: -+ dput(a->src_wh_dentry); -+ dput(a->dst_wh_dentry); -+ out_thargs: -+ if (a->thargs) { -+ dput(a->h_dst); -+ au_whtmp_rmdir_free(a->thargs); -+ a->thargs = NULL; -+ } -+ out: -+ return err; -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+/* -+ * test if @dentry dir can be rename destination or not. -+ * success means, it is a logically empty dir. -+ */ -+static int may_rename_dstdir(struct dentry *dentry, struct au_nhash *whlist) -+{ -+ return au_test_empty(dentry, whlist); -+} -+ -+/* -+ * test if @dentry dir can be rename source or not. -+ * if it can, return 0 and @children is filled. -+ * success means, -+ * - it is a logically empty dir. -+ * - or, it exists on writable branch and has no children including whiteouts -+ * on the lower branch. -+ */ -+static int may_rename_srcdir(struct dentry *dentry, aufs_bindex_t btgt) -+{ -+ int err; -+ unsigned int rdhash; -+ aufs_bindex_t bstart; -+ -+ bstart = au_dbstart(dentry); -+ if (bstart != btgt) { -+ struct au_nhash whlist; -+ -+ SiMustAnyLock(dentry->d_sb); -+ rdhash = au_sbi(dentry->d_sb)->si_rdhash; -+ if (!rdhash) -+ rdhash = au_rdhash_est(au_dir_size(/*file*/NULL, -+ dentry)); -+ err = au_nhash_alloc(&whlist, rdhash, GFP_NOFS); -+ if (unlikely(err)) -+ goto out; -+ err = au_test_empty(dentry, &whlist); -+ au_nhash_wh_free(&whlist); -+ goto out; -+ } -+ -+ if (bstart == au_dbtaildir(dentry)) -+ return 0; /* success */ -+ -+ err = au_test_empty_lower(dentry); -+ -+ out: -+ if (err == -ENOTEMPTY) { -+ AuWarn1("renaming dir who has child(ren) on multiple branches," -+ " is not supported\n"); -+ err = -EXDEV; -+ } -+ return err; -+} -+ -+/* side effect: sets whlist and h_dentry */ -+static int au_ren_may_dir(struct au_ren_args *a) -+{ -+ int err; -+ unsigned int rdhash; -+ struct dentry *d; -+ -+ d = a->dst_dentry; -+ SiMustAnyLock(d->d_sb); -+ -+ err = 0; -+ if (au_ftest_ren(a->flags, ISDIR) && a->dst_inode) { -+ rdhash = au_sbi(d->d_sb)->si_rdhash; -+ if (!rdhash) -+ rdhash = au_rdhash_est(au_dir_size(/*file*/NULL, d)); -+ err = au_nhash_alloc(&a->whlist, rdhash, GFP_NOFS); -+ if (unlikely(err)) -+ goto out; -+ -+ au_set_dbstart(d, a->dst_bstart); -+ err = may_rename_dstdir(d, &a->whlist); -+ au_set_dbstart(d, a->btgt); -+ } -+ a->dst_h_dentry = au_h_dptr(d, au_dbstart(d)); -+ if (unlikely(err)) -+ goto out; -+ -+ d = a->src_dentry; -+ a->src_h_dentry = au_h_dptr(d, au_dbstart(d)); -+ if (au_ftest_ren(a->flags, ISDIR)) { -+ err = may_rename_srcdir(d, a->btgt); -+ if (unlikely(err)) { -+ au_nhash_wh_free(&a->whlist); -+ a->whlist.nh_num = 0; -+ } -+ } -+ out: -+ return err; -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+/* -+ * simple tests for rename. -+ * following the checks in vfs, plus the parent-child relationship. -+ */ -+static int au_may_ren(struct au_ren_args *a) -+{ -+ int err, isdir; -+ struct inode *h_inode; -+ -+ if (a->src_bstart == a->btgt) { -+ err = au_may_del(a->src_dentry, a->btgt, a->src_h_parent, -+ au_ftest_ren(a->flags, ISDIR)); -+ if (unlikely(err)) -+ goto out; -+ err = -EINVAL; -+ if (unlikely(a->src_h_dentry == a->h_trap)) -+ goto out; -+ } -+ -+ err = 0; -+ if (a->dst_bstart != a->btgt) -+ goto out; -+ -+ err = -EIO; -+ h_inode = a->dst_h_dentry->d_inode; -+ isdir = !!au_ftest_ren(a->flags, ISDIR); -+ if (!a->dst_dentry->d_inode) { -+ if (unlikely(h_inode)) -+ goto out; -+ err = au_may_add(a->dst_dentry, a->btgt, a->dst_h_parent, -+ isdir); -+ } else { -+ if (unlikely(!h_inode || !h_inode->i_nlink)) -+ goto out; -+ err = au_may_del(a->dst_dentry, a->btgt, a->dst_h_parent, -+ isdir); -+ if (unlikely(err)) -+ goto out; -+ err = -ENOTEMPTY; -+ if (unlikely(a->dst_h_dentry == a->h_trap)) -+ goto out; -+ err = 0; -+ } -+ -+ out: -+ if (unlikely(err == -ENOENT || err == -EEXIST)) -+ err = -EIO; -+ AuTraceErr(err); -+ return err; -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+/* -+ * locking order -+ * (VFS) -+ * - src_dir and dir by lock_rename() -+ * - inode if exitsts -+ * (aufs) -+ * - lock all -+ * + src_dentry and dentry by aufs_read_and_write_lock2() which calls, -+ * + si_read_lock -+ * + di_write_lock2_child() -+ * + di_write_lock_child() -+ * + ii_write_lock_child() -+ * + di_write_lock_child2() -+ * + ii_write_lock_child2() -+ * + src_parent and parent -+ * + di_write_lock_parent() -+ * + ii_write_lock_parent() -+ * + di_write_lock_parent2() -+ * + ii_write_lock_parent2() -+ * + lower src_dir and dir by vfsub_lock_rename() -+ * + verify the every relationships between child and parent. if any -+ * of them failed, unlock all and return -EBUSY. -+ */ -+static void au_ren_unlock(struct au_ren_args *a) -+{ -+ struct super_block *sb; -+ -+ sb = a->dst_dentry->d_sb; -+ if (au_ftest_ren(a->flags, MNT_WRITE)) -+ mnt_drop_write(a->br->br_mnt); -+ vfsub_unlock_rename(a->src_h_parent, a->src_hdir, -+ a->dst_h_parent, a->dst_hdir); -+} -+ -+static int au_ren_lock(struct au_ren_args *a) -+{ -+ int err; -+ unsigned int udba; -+ -+ err = 0; -+ a->src_h_parent = au_h_dptr(a->src_parent, a->btgt); -+ a->src_hdir = au_hi(a->src_dir, a->btgt); -+ a->dst_h_parent = au_h_dptr(a->dst_parent, a->btgt); -+ a->dst_hdir = au_hi(a->dst_dir, a->btgt); -+ a->h_trap = vfsub_lock_rename(a->src_h_parent, a->src_hdir, -+ a->dst_h_parent, a->dst_hdir); -+ udba = au_opt_udba(a->src_dentry->d_sb); -+ if (unlikely(a->src_hdir->hi_inode != a->src_h_parent->d_inode -+ || a->dst_hdir->hi_inode != a->dst_h_parent->d_inode)) -+ err = au_busy_or_stale(); -+ if (!err && au_dbstart(a->src_dentry) == a->btgt) -+ err = au_h_verify(a->src_h_dentry, udba, -+ a->src_h_parent->d_inode, a->src_h_parent, -+ a->br); -+ if (!err && au_dbstart(a->dst_dentry) == a->btgt) -+ err = au_h_verify(a->dst_h_dentry, udba, -+ a->dst_h_parent->d_inode, a->dst_h_parent, -+ a->br); -+ if (!err) { -+ err = mnt_want_write(a->br->br_mnt); -+ if (unlikely(err)) -+ goto out_unlock; -+ au_fset_ren(a->flags, MNT_WRITE); -+ goto out; /* success */ -+ } -+ -+ err = au_busy_or_stale(); -+ -+ out_unlock: -+ au_ren_unlock(a); -+ out: -+ return err; -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+static void au_ren_refresh_dir(struct au_ren_args *a) -+{ -+ struct inode *dir; -+ -+ dir = a->dst_dir; -+ dir->i_version++; -+ if (au_ftest_ren(a->flags, ISDIR)) { -+ /* is this updating defined in POSIX? */ -+ au_cpup_attr_timesizes(a->src_inode); -+ au_cpup_attr_nlink(dir, /*force*/1); -+ if (a->dst_inode) { -+ clear_nlink(a->dst_inode); -+ au_cpup_attr_timesizes(a->dst_inode); -+ } -+ } -+ if (au_ibstart(dir) == a->btgt) -+ au_cpup_attr_timesizes(dir); -+ -+ if (au_ftest_ren(a->flags, ISSAMEDIR)) -+ return; -+ -+ dir = a->src_dir; -+ dir->i_version++; -+ if (au_ftest_ren(a->flags, ISDIR)) -+ au_cpup_attr_nlink(dir, /*force*/1); -+ if (au_ibstart(dir) == a->btgt) -+ au_cpup_attr_timesizes(dir); -+} -+ -+static void au_ren_refresh(struct au_ren_args *a) -+{ -+ aufs_bindex_t bend, bindex; -+ struct dentry *d, *h_d; -+ struct inode *i, *h_i; -+ struct super_block *sb; -+ -+ d = a->src_dentry; -+ au_set_dbwh(d, -1); -+ bend = au_dbend(d); -+ for (bindex = a->btgt + 1; bindex <= bend; bindex++) { -+ h_d = au_h_dptr(d, bindex); -+ if (h_d) -+ au_set_h_dptr(d, bindex, NULL); -+ } -+ au_set_dbend(d, a->btgt); -+ -+ sb = d->d_sb; -+ i = a->src_inode; -+ if (au_opt_test(au_mntflags(sb), PLINK) && au_plink_test(i)) -+ return; /* success */ -+ -+ bend = au_ibend(i); -+ for (bindex = a->btgt + 1; bindex <= bend; bindex++) { -+ h_i = au_h_iptr(i, bindex); -+ if (h_i) { -+ au_xino_write(sb, bindex, h_i->i_ino, /*ino*/0); -+ /* ignore this error */ -+ au_set_h_iptr(i, bindex, NULL, 0); -+ } -+ } -+ au_set_ibend(i, a->btgt); -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+/* mainly for link(2) and rename(2) */ -+int au_wbr(struct dentry *dentry, aufs_bindex_t btgt) -+{ -+ aufs_bindex_t bdiropq, bwh; -+ struct dentry *parent; -+ struct au_branch *br; -+ -+ parent = dentry->d_parent; -+ IMustLock(parent->d_inode); /* dir is locked */ -+ -+ bdiropq = au_dbdiropq(parent); -+ bwh = au_dbwh(dentry); -+ br = au_sbr(dentry->d_sb, btgt); -+ if (au_br_rdonly(br) -+ || (0 <= bdiropq && bdiropq < btgt) -+ || (0 <= bwh && bwh < btgt)) -+ btgt = -1; -+ -+ AuDbg("btgt %d\n", btgt); -+ return btgt; -+} -+ -+/* sets src_bstart, dst_bstart and btgt */ -+static int au_ren_wbr(struct au_ren_args *a) -+{ -+ int err; -+ struct au_wr_dir_args wr_dir_args = { -+ /* .force_btgt = -1, */ -+ .flags = AuWrDir_ADD_ENTRY -+ }; -+ -+ a->src_bstart = au_dbstart(a->src_dentry); -+ a->dst_bstart = au_dbstart(a->dst_dentry); -+ if (au_ftest_ren(a->flags, ISDIR)) -+ au_fset_wrdir(wr_dir_args.flags, ISDIR); -+ wr_dir_args.force_btgt = a->src_bstart; -+ if (a->dst_inode && a->dst_bstart < a->src_bstart) -+ wr_dir_args.force_btgt = a->dst_bstart; -+ wr_dir_args.force_btgt = au_wbr(a->dst_dentry, wr_dir_args.force_btgt); -+ err = au_wr_dir(a->dst_dentry, a->src_dentry, &wr_dir_args); -+ a->btgt = err; -+ -+ return err; -+} -+ -+static void au_ren_dt(struct au_ren_args *a) -+{ -+ a->h_path.dentry = a->src_h_parent; -+ au_dtime_store(a->src_dt + AuPARENT, a->src_parent, &a->h_path); -+ if (!au_ftest_ren(a->flags, ISSAMEDIR)) { -+ a->h_path.dentry = a->dst_h_parent; -+ au_dtime_store(a->dst_dt + AuPARENT, a->dst_parent, &a->h_path); -+ } -+ -+ au_fclr_ren(a->flags, DT_DSTDIR); -+ if (!au_ftest_ren(a->flags, ISDIR)) -+ return; -+ -+ a->h_path.dentry = a->src_h_dentry; -+ au_dtime_store(a->src_dt + AuCHILD, a->src_dentry, &a->h_path); -+ if (a->dst_h_dentry->d_inode) { -+ au_fset_ren(a->flags, DT_DSTDIR); -+ a->h_path.dentry = a->dst_h_dentry; -+ au_dtime_store(a->dst_dt + AuCHILD, a->dst_dentry, &a->h_path); -+ } -+} -+ -+static void au_ren_rev_dt(int err, struct au_ren_args *a) -+{ -+ struct dentry *h_d; -+ struct mutex *h_mtx; -+ -+ au_dtime_revert(a->src_dt + AuPARENT); -+ if (!au_ftest_ren(a->flags, ISSAMEDIR)) -+ au_dtime_revert(a->dst_dt + AuPARENT); -+ -+ if (au_ftest_ren(a->flags, ISDIR) && err != -EIO) { -+ h_d = a->src_dt[AuCHILD].dt_h_path.dentry; -+ h_mtx = &h_d->d_inode->i_mutex; -+ mutex_lock_nested(h_mtx, AuLsc_I_CHILD); -+ au_dtime_revert(a->src_dt + AuCHILD); -+ mutex_unlock(h_mtx); -+ -+ if (au_ftest_ren(a->flags, DT_DSTDIR)) { -+ h_d = a->dst_dt[AuCHILD].dt_h_path.dentry; -+ h_mtx = &h_d->d_inode->i_mutex; -+ mutex_lock_nested(h_mtx, AuLsc_I_CHILD); -+ au_dtime_revert(a->dst_dt + AuCHILD); -+ mutex_unlock(h_mtx); -+ } -+ } -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+int aufs_rename(struct inode *_src_dir, struct dentry *_src_dentry, -+ struct inode *_dst_dir, struct dentry *_dst_dentry) -+{ -+ int err; -+ /* reduce stack space */ -+ struct au_ren_args *a; -+ -+ AuDbg("%.*s, %.*s\n", AuDLNPair(_src_dentry), AuDLNPair(_dst_dentry)); -+ IMustLock(_src_dir); -+ IMustLock(_dst_dir); -+ -+ err = -ENOMEM; -+ BUILD_BUG_ON(sizeof(*a) > PAGE_SIZE); -+ a = kzalloc(sizeof(*a), GFP_NOFS); -+ if (unlikely(!a)) -+ goto out; -+ -+ a->src_dir = _src_dir; -+ a->src_dentry = _src_dentry; -+ a->src_inode = a->src_dentry->d_inode; -+ a->src_parent = a->src_dentry->d_parent; /* dir inode is locked */ -+ a->dst_dir = _dst_dir; -+ a->dst_dentry = _dst_dentry; -+ a->dst_inode = a->dst_dentry->d_inode; -+ a->dst_parent = a->dst_dentry->d_parent; /* dir inode is locked */ -+ if (a->dst_inode) { -+ IMustLock(a->dst_inode); -+ au_igrab(a->dst_inode); -+ } -+ -+ err = -ENOTDIR; -+ if (S_ISDIR(a->src_inode->i_mode)) { -+ au_fset_ren(a->flags, ISDIR); -+ if (unlikely(a->dst_inode && !S_ISDIR(a->dst_inode->i_mode))) -+ goto out_free; -+ aufs_read_and_write_lock2(a->dst_dentry, a->src_dentry, -+ AuLock_DIR | AuLock_FLUSH); -+ } else -+ aufs_read_and_write_lock2(a->dst_dentry, a->src_dentry, -+ AuLock_FLUSH); -+ -+ au_fset_ren(a->flags, ISSAMEDIR); /* temporary */ -+ di_write_lock_parent(a->dst_parent); -+ -+ /* which branch we process */ -+ err = au_ren_wbr(a); -+ if (unlikely(err < 0)) -+ goto out_unlock; -+ a->br = au_sbr(a->dst_dentry->d_sb, a->btgt); -+ a->h_path.mnt = a->br->br_mnt; -+ -+ /* are they available to be renamed */ -+ err = au_ren_may_dir(a); -+ if (unlikely(err)) -+ goto out_children; -+ -+ /* prepare the writable parent dir on the same branch */ -+ if (a->dst_bstart == a->btgt) { -+ au_fset_ren(a->flags, WHDST); -+ } else { -+ err = au_cpup_dirs(a->dst_dentry, a->btgt); -+ if (unlikely(err)) -+ goto out_children; -+ } -+ -+ if (a->src_dir != a->dst_dir) { -+ /* -+ * this temporary unlock is safe, -+ * because both dir->i_mutex are locked. -+ */ -+ di_write_unlock(a->dst_parent); -+ di_write_lock_parent(a->src_parent); -+ err = au_wr_dir_need_wh(a->src_dentry, -+ au_ftest_ren(a->flags, ISDIR), -+ &a->btgt); -+ di_write_unlock(a->src_parent); -+ di_write_lock2_parent(a->src_parent, a->dst_parent, /*isdir*/1); -+ au_fclr_ren(a->flags, ISSAMEDIR); -+ } else -+ err = au_wr_dir_need_wh(a->src_dentry, -+ au_ftest_ren(a->flags, ISDIR), -+ &a->btgt); -+ if (unlikely(err < 0)) -+ goto out_children; -+ if (err) -+ au_fset_ren(a->flags, WHSRC); -+ -+ /* lock them all */ -+ err = au_ren_lock(a); -+ if (unlikely(err)) -+ goto out_children; -+ -+ if (!au_opt_test(au_mntflags(a->dst_dir->i_sb), UDBA_NONE)) -+ err = au_may_ren(a); -+ else if (unlikely(a->dst_dentry->d_name.len > AUFS_MAX_NAMELEN)) -+ err = -ENAMETOOLONG; -+ if (unlikely(err)) -+ goto out_hdir; -+ -+ /* store timestamps to be revertible */ -+ au_ren_dt(a); -+ -+ /* here we go */ -+ err = do_rename(a); -+ if (unlikely(err)) -+ goto out_dt; -+ -+ /* update dir attributes */ -+ au_ren_refresh_dir(a); -+ -+ /* dput/iput all lower dentries */ -+ au_ren_refresh(a); -+ -+ goto out_hdir; /* success */ -+ -+ out_dt: -+ au_ren_rev_dt(err, a); -+ out_hdir: -+ au_ren_unlock(a); -+ out_children: -+ au_nhash_wh_free(&a->whlist); -+ out_unlock: -+ if (unlikely(err && au_ftest_ren(a->flags, ISDIR))) { -+ au_update_dbstart(a->dst_dentry); -+ d_drop(a->dst_dentry); -+ } -+ if (!err) -+ d_move(a->src_dentry, a->dst_dentry); -+ if (au_ftest_ren(a->flags, ISSAMEDIR)) -+ di_write_unlock(a->dst_parent); -+ else -+ di_write_unlock2(a->src_parent, a->dst_parent); -+ aufs_read_and_write_unlock2(a->dst_dentry, a->src_dentry); -+ out_free: -+ iput(a->dst_inode); -+ if (a->thargs) -+ au_whtmp_rmdir_free(a->thargs); -+ kfree(a); -+ out: -+ AuTraceErr(err); -+ return err; -+} -diff --git a/fs/aufs/iinfo.c b/fs/aufs/iinfo.c -new file mode 100644 -index 0000000..072ddfc ---- /dev/null -+++ b/fs/aufs/iinfo.c -@@ -0,0 +1,283 @@ -+/* -+ * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * -+ * This program, aufs is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ */ -+ -+/* -+ * inode private data -+ */ -+ -+#include "aufs.h" -+ -+struct inode *au_h_iptr(struct inode *inode, aufs_bindex_t bindex) -+{ -+ struct inode *h_inode; -+ -+ IiMustAnyLock(inode); -+ -+ h_inode = au_ii(inode)->ii_hinode[0 + bindex].hi_inode; -+ AuDebugOn(h_inode && atomic_read(&h_inode->i_count) <= 0); -+ return h_inode; -+} -+ -+/* todo: hard/soft set? */ -+void au_set_ibstart(struct inode *inode, aufs_bindex_t bindex) -+{ -+ struct au_iinfo *iinfo = au_ii(inode); -+ struct inode *h_inode; -+ -+ IiMustWriteLock(inode); -+ -+ iinfo->ii_bstart = bindex; -+ h_inode = iinfo->ii_hinode[bindex + 0].hi_inode; -+ if (h_inode) -+ au_cpup_igen(inode, h_inode); -+} -+ -+void au_hiput(struct au_hinode *hinode) -+{ -+ au_hin_free(hinode); -+ dput(hinode->hi_whdentry); -+ iput(hinode->hi_inode); -+} -+ -+unsigned int au_hi_flags(struct inode *inode, int isdir) -+{ -+ unsigned int flags; -+ const unsigned int mnt_flags = au_mntflags(inode->i_sb); -+ -+ flags = 0; -+ if (au_opt_test(mnt_flags, XINO)) -+ au_fset_hi(flags, XINO); -+ if (isdir && au_opt_test(mnt_flags, UDBA_HINOTIFY)) -+ au_fset_hi(flags, HINOTIFY); -+ return flags; -+} -+ -+void au_set_h_iptr(struct inode *inode, aufs_bindex_t bindex, -+ struct inode *h_inode, unsigned int flags) -+{ -+ struct au_hinode *hinode; -+ struct inode *hi; -+ struct au_iinfo *iinfo = au_ii(inode); -+ -+ IiMustWriteLock(inode); -+ -+ hinode = iinfo->ii_hinode + bindex; -+ hi = hinode->hi_inode; -+ AuDebugOn(h_inode && atomic_read(&h_inode->i_count) <= 0); -+ AuDebugOn(h_inode && hi); -+ -+ if (hi) -+ au_hiput(hinode); -+ hinode->hi_inode = h_inode; -+ if (h_inode) { -+ int err; -+ struct super_block *sb = inode->i_sb; -+ struct au_branch *br; -+ -+ if (bindex == iinfo->ii_bstart) -+ au_cpup_igen(inode, h_inode); -+ br = au_sbr(sb, bindex); -+ hinode->hi_id = br->br_id; -+ if (au_ftest_hi(flags, XINO)) { -+ err = au_xino_write(sb, bindex, h_inode->i_ino, -+ inode->i_ino); -+ if (unlikely(err)) -+ AuIOErr1("failed au_xino_write() %d\n", err); -+ } -+ -+ if (au_ftest_hi(flags, HINOTIFY) -+ && au_br_hinotifyable(br->br_perm)) { -+ err = au_hin_alloc(hinode, inode, h_inode); -+ if (unlikely(err)) -+ AuIOErr1("au_hin_alloc() %d\n", err); -+ } -+ } -+} -+ -+void au_set_hi_wh(struct inode *inode, aufs_bindex_t bindex, -+ struct dentry *h_wh) -+{ -+ struct au_hinode *hinode; -+ -+ IiMustWriteLock(inode); -+ -+ hinode = au_ii(inode)->ii_hinode + bindex; -+ AuDebugOn(hinode->hi_whdentry); -+ hinode->hi_whdentry = h_wh; -+} -+ -+void au_update_iigen(struct inode *inode) -+{ -+ atomic_set(&au_ii(inode)->ii_generation, au_sigen(inode->i_sb)); -+ /* smp_mb(); */ /* atomic_set */ -+} -+ -+/* it may be called at remount time, too */ -+void au_update_brange(struct inode *inode, int do_put_zero) -+{ -+ struct au_iinfo *iinfo; -+ -+ iinfo = au_ii(inode); -+ if (!iinfo || iinfo->ii_bstart < 0) -+ return; -+ -+ IiMustWriteLock(inode); -+ -+ if (do_put_zero) { -+ aufs_bindex_t bindex; -+ -+ for (bindex = iinfo->ii_bstart; bindex <= iinfo->ii_bend; -+ bindex++) { -+ struct inode *h_i; -+ -+ h_i = iinfo->ii_hinode[0 + bindex].hi_inode; -+ if (h_i && !h_i->i_nlink) -+ au_set_h_iptr(inode, bindex, NULL, 0); -+ } -+ } -+ -+ iinfo->ii_bstart = -1; -+ while (++iinfo->ii_bstart <= iinfo->ii_bend) -+ if (iinfo->ii_hinode[0 + iinfo->ii_bstart].hi_inode) -+ break; -+ if (iinfo->ii_bstart > iinfo->ii_bend) { -+ iinfo->ii_bstart = -1; -+ iinfo->ii_bend = -1; -+ return; -+ } -+ -+ iinfo->ii_bend++; -+ while (0 <= --iinfo->ii_bend) -+ if (iinfo->ii_hinode[0 + iinfo->ii_bend].hi_inode) -+ break; -+ AuDebugOn(iinfo->ii_bstart > iinfo->ii_bend || iinfo->ii_bend < 0); -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+int au_iinfo_init(struct inode *inode) -+{ -+ struct au_iinfo *iinfo; -+ struct super_block *sb; -+ int nbr, i; -+ -+ sb = inode->i_sb; -+ iinfo = &(container_of(inode, struct au_icntnr, vfs_inode)->iinfo); -+ nbr = au_sbend(sb) + 1; -+ if (unlikely(nbr <= 0)) -+ nbr = 1; -+ iinfo->ii_hinode = kcalloc(nbr, sizeof(*iinfo->ii_hinode), GFP_NOFS); -+ if (iinfo->ii_hinode) { -+ for (i = 0; i < nbr; i++) -+ iinfo->ii_hinode[i].hi_id = -1; -+ -+ atomic_set(&iinfo->ii_generation, au_sigen(sb)); -+ /* smp_mb(); */ /* atomic_set */ -+ au_rw_init(&iinfo->ii_rwsem); -+ iinfo->ii_bstart = -1; -+ iinfo->ii_bend = -1; -+ iinfo->ii_vdir = NULL; -+ return 0; -+ } -+ return -ENOMEM; -+} -+ -+int au_ii_realloc(struct au_iinfo *iinfo, int nbr) -+{ -+ int err, sz; -+ struct au_hinode *hip; -+ -+ AuRwMustWriteLock(&iinfo->ii_rwsem); -+ -+ err = -ENOMEM; -+ sz = sizeof(*hip) * (iinfo->ii_bend + 1); -+ if (!sz) -+ sz = sizeof(*hip); -+ hip = au_kzrealloc(iinfo->ii_hinode, sz, sizeof(*hip) * nbr, GFP_NOFS); -+ if (hip) { -+ iinfo->ii_hinode = hip; -+ err = 0; -+ } -+ -+ return err; -+} -+ -+static int au_iinfo_write0(struct super_block *sb, struct au_hinode *hinode, -+ ino_t ino) -+{ -+ int err; -+ aufs_bindex_t bindex; -+ unsigned char locked; -+ -+ err = 0; -+ locked = !!si_noflush_read_trylock(sb); -+ bindex = au_br_index(sb, hinode->hi_id); -+ if (bindex >= 0) -+ err = au_xino_write0(sb, bindex, hinode->hi_inode->i_ino, ino); -+ /* error action? */ -+ if (locked) -+ si_read_unlock(sb); -+ return err; -+} -+ -+void au_iinfo_fin(struct inode *inode) -+{ -+ ino_t ino; -+ aufs_bindex_t bend; -+ unsigned char unlinked = !inode->i_nlink; -+ struct au_iinfo *iinfo; -+ struct au_hinode *hi; -+ struct super_block *sb; -+ -+ if (unlinked) { -+ int err = au_xigen_inc(inode); -+ if (unlikely(err)) -+ AuWarn1("failed resetting i_generation, %d\n", err); -+ } -+ -+ iinfo = au_ii(inode); -+ /* bad_inode case */ -+ if (!iinfo) -+ return; -+ -+ if (iinfo->ii_vdir) -+ au_vdir_free(iinfo->ii_vdir); -+ -+ if (iinfo->ii_bstart >= 0) { -+ sb = inode->i_sb; -+ ino = 0; -+ if (unlinked) -+ ino = inode->i_ino; -+ hi = iinfo->ii_hinode + iinfo->ii_bstart; -+ bend = iinfo->ii_bend; -+ while (iinfo->ii_bstart++ <= bend) { -+ if (hi->hi_inode) { -+ if (unlinked || !hi->hi_inode->i_nlink) { -+ au_iinfo_write0(sb, hi, ino); -+ /* ignore this error */ -+ ino = 0; -+ } -+ au_hiput(hi); -+ } -+ hi++; -+ } -+ } -+ -+ kfree(iinfo->ii_hinode); -+ AuRwDestroy(&iinfo->ii_rwsem); -+} -diff --git a/fs/aufs/inode.c b/fs/aufs/inode.c -new file mode 100644 -index 0000000..3f146a6 ---- /dev/null -+++ b/fs/aufs/inode.c -@@ -0,0 +1,414 @@ -+/* -+ * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * -+ * This program, aufs is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ */ -+ -+/* -+ * inode functions -+ */ -+ -+#include "aufs.h" -+ -+struct inode *au_igrab(struct inode *inode) -+{ -+ if (inode) { -+ AuDebugOn(!atomic_read(&inode->i_count)); -+ atomic_inc_return(&inode->i_count); -+ } -+ return inode; -+} -+ -+static void au_refresh_hinode_attr(struct inode *inode, int do_version) -+{ -+ au_cpup_attr_all(inode, /*force*/0); -+ au_update_iigen(inode); -+ if (do_version) -+ inode->i_version++; -+} -+ -+int au_refresh_hinode_self(struct inode *inode, int do_attr) -+{ -+ int err; -+ aufs_bindex_t bindex, new_bindex; -+ unsigned char update; -+ struct inode *first; -+ struct au_hinode *p, *q, tmp; -+ struct super_block *sb; -+ struct au_iinfo *iinfo; -+ -+ IiMustWriteLock(inode); -+ -+ update = 0; -+ sb = inode->i_sb; -+ iinfo = au_ii(inode); -+ err = au_ii_realloc(iinfo, au_sbend(sb) + 1); -+ if (unlikely(err)) -+ goto out; -+ -+ p = iinfo->ii_hinode + iinfo->ii_bstart; -+ first = p->hi_inode; -+ err = 0; -+ for (bindex = iinfo->ii_bstart; bindex <= iinfo->ii_bend; -+ bindex++, p++) { -+ if (!p->hi_inode) -+ continue; -+ -+ new_bindex = au_br_index(sb, p->hi_id); -+ if (new_bindex == bindex) -+ continue; -+ -+ if (new_bindex < 0) { -+ update++; -+ au_hiput(p); -+ p->hi_inode = NULL; -+ continue; -+ } -+ -+ if (new_bindex < iinfo->ii_bstart) -+ iinfo->ii_bstart = new_bindex; -+ if (iinfo->ii_bend < new_bindex) -+ iinfo->ii_bend = new_bindex; -+ /* swap two lower inode, and loop again */ -+ q = iinfo->ii_hinode + new_bindex; -+ tmp = *q; -+ *q = *p; -+ *p = tmp; -+ if (tmp.hi_inode) { -+ bindex--; -+ p--; -+ } -+ } -+ au_update_brange(inode, /*do_put_zero*/0); -+ if (do_attr) -+ au_refresh_hinode_attr(inode, update && S_ISDIR(inode->i_mode)); -+ -+ out: -+ return err; -+} -+ -+int au_refresh_hinode(struct inode *inode, struct dentry *dentry) -+{ -+ int err, update; -+ unsigned int flags; -+ aufs_bindex_t bindex, bend; -+ unsigned char isdir; -+ struct inode *first; -+ struct au_hinode *p; -+ struct au_iinfo *iinfo; -+ -+ err = au_refresh_hinode_self(inode, /*do_attr*/0); -+ if (unlikely(err)) -+ goto out; -+ -+ update = 0; -+ iinfo = au_ii(inode); -+ p = iinfo->ii_hinode + iinfo->ii_bstart; -+ first = p->hi_inode; -+ isdir = S_ISDIR(inode->i_mode); -+ flags = au_hi_flags(inode, isdir); -+ bend = au_dbend(dentry); -+ for (bindex = au_dbstart(dentry); bindex <= bend; bindex++) { -+ struct inode *h_i; -+ struct dentry *h_d; -+ -+ h_d = au_h_dptr(dentry, bindex); -+ if (!h_d || !h_d->d_inode) -+ continue; -+ -+ if (iinfo->ii_bstart <= bindex && bindex <= iinfo->ii_bend) { -+ h_i = au_h_iptr(inode, bindex); -+ if (h_i) { -+ if (h_i == h_d->d_inode) -+ continue; -+ err = -EIO; -+ break; -+ } -+ } -+ if (bindex < iinfo->ii_bstart) -+ iinfo->ii_bstart = bindex; -+ if (iinfo->ii_bend < bindex) -+ iinfo->ii_bend = bindex; -+ au_set_h_iptr(inode, bindex, au_igrab(h_d->d_inode), flags); -+ update = 1; -+ } -+ au_update_brange(inode, /*do_put_zero*/0); -+ -+ if (unlikely(err)) -+ goto out; -+ -+ au_refresh_hinode_attr(inode, update && isdir); -+ -+ out: -+ AuTraceErr(err); -+ return err; -+} -+ -+static int set_inode(struct inode *inode, struct dentry *dentry) -+{ -+ int err; -+ unsigned int flags; -+ umode_t mode; -+ aufs_bindex_t bindex, bstart, btail; -+ unsigned char isdir; -+ struct dentry *h_dentry; -+ struct inode *h_inode; -+ struct au_iinfo *iinfo; -+ -+ IiMustWriteLock(inode); -+ -+ err = 0; -+ isdir = 0; -+ bstart = au_dbstart(dentry); -+ h_inode = au_h_dptr(dentry, bstart)->d_inode; -+ mode = h_inode->i_mode; -+ switch (mode & S_IFMT) { -+ case S_IFREG: -+ btail = au_dbtail(dentry); -+ inode->i_op = &aufs_iop; -+ inode->i_fop = &aufs_file_fop; -+ inode->i_mapping->a_ops = &aufs_aop; -+ break; -+ case S_IFDIR: -+ isdir = 1; -+ btail = au_dbtaildir(dentry); -+ inode->i_op = &aufs_dir_iop; -+ inode->i_fop = &aufs_dir_fop; -+ break; -+ case S_IFLNK: -+ btail = au_dbtail(dentry); -+ inode->i_op = &aufs_symlink_iop; -+ break; -+ case S_IFBLK: -+ case S_IFCHR: -+ case S_IFIFO: -+ case S_IFSOCK: -+ btail = au_dbtail(dentry); -+ inode->i_op = &aufs_iop; -+ init_special_inode(inode, mode, h_inode->i_rdev); -+ break; -+ default: -+ AuIOErr("Unknown file type 0%o\n", mode); -+ err = -EIO; -+ goto out; -+ } -+ -+ /* do not set inotify for whiteouted dirs (SHWH mode) */ -+ flags = au_hi_flags(inode, isdir); -+ if (au_opt_test(au_mntflags(dentry->d_sb), SHWH) -+ && au_ftest_hi(flags, HINOTIFY) -+ && dentry->d_name.len > AUFS_WH_PFX_LEN -+ && !memcmp(dentry->d_name.name, AUFS_WH_PFX, AUFS_WH_PFX_LEN)) -+ au_fclr_hi(flags, HINOTIFY); -+ iinfo = au_ii(inode); -+ iinfo->ii_bstart = bstart; -+ iinfo->ii_bend = btail; -+ for (bindex = bstart; bindex <= btail; bindex++) { -+ h_dentry = au_h_dptr(dentry, bindex); -+ if (h_dentry) -+ au_set_h_iptr(inode, bindex, -+ au_igrab(h_dentry->d_inode), flags); -+ } -+ au_cpup_attr_all(inode, /*force*/1); -+ -+ out: -+ return err; -+} -+ -+/* successful returns with iinfo write_locked */ -+static int reval_inode(struct inode *inode, struct dentry *dentry, int *matched) -+{ -+ int err; -+ aufs_bindex_t bindex, bend; -+ struct inode *h_inode, *h_dinode; -+ -+ *matched = 0; -+ -+ /* -+ * before this function, if aufs got any iinfo lock, it must be only -+ * one, the parent dir. -+ * it can happen by UDBA and the obsoleted inode number. -+ */ -+ err = -EIO; -+ if (unlikely(inode->i_ino == parent_ino(dentry))) -+ goto out; -+ -+ err = 0; -+ ii_write_lock_new_child(inode); -+ h_dinode = au_h_dptr(dentry, au_dbstart(dentry))->d_inode; -+ bend = au_ibend(inode); -+ for (bindex = au_ibstart(inode); bindex <= bend; bindex++) { -+ h_inode = au_h_iptr(inode, bindex); -+ if (h_inode && h_inode == h_dinode) { -+ *matched = 1; -+ err = 0; -+ if (au_iigen(inode) != au_digen(dentry)) -+ err = au_refresh_hinode(inode, dentry); -+ break; -+ } -+ } -+ -+ if (unlikely(err)) -+ ii_write_unlock(inode); -+ out: -+ return err; -+} -+ -+int au_ino(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, -+ unsigned int d_type, ino_t *ino) -+{ -+ int err; -+ struct mutex *mtx; -+ const int isdir = (d_type == DT_DIR); -+ -+ /* prevent hardlinks from race condition */ -+ mtx = NULL; -+ if (!isdir) { -+ mtx = &au_sbr(sb, bindex)->br_xino.xi_nondir_mtx; -+ mutex_lock(mtx); -+ } -+ err = au_xino_read(sb, bindex, h_ino, ino); -+ if (unlikely(err)) -+ goto out; -+ -+ if (!*ino) { -+ err = -EIO; -+ *ino = au_xino_new_ino(sb); -+ if (unlikely(!*ino)) -+ goto out; -+ err = au_xino_write(sb, bindex, h_ino, *ino); -+ if (unlikely(err)) -+ goto out; -+ } -+ -+ out: -+ if (!isdir) -+ mutex_unlock(mtx); -+ return err; -+} -+ -+/* successful returns with iinfo write_locked */ -+/* todo: return with unlocked? */ -+struct inode *au_new_inode(struct dentry *dentry, int must_new) -+{ -+ struct inode *inode; -+ struct dentry *h_dentry; -+ struct super_block *sb; -+ ino_t h_ino, ino; -+ int err, match; -+ aufs_bindex_t bstart; -+ -+ sb = dentry->d_sb; -+ bstart = au_dbstart(dentry); -+ h_dentry = au_h_dptr(dentry, bstart); -+ h_ino = h_dentry->d_inode->i_ino; -+ err = au_xino_read(sb, bstart, h_ino, &ino); -+ inode = ERR_PTR(err); -+ if (unlikely(err)) -+ goto out; -+ new_ino: -+ if (!ino) { -+ ino = au_xino_new_ino(sb); -+ if (unlikely(!ino)) { -+ inode = ERR_PTR(-EIO); -+ goto out; -+ } -+ } -+ -+ AuDbg("i%lu\n", (unsigned long)ino); -+ inode = au_iget_locked(sb, ino); -+ err = PTR_ERR(inode); -+ if (IS_ERR(inode)) -+ goto out; -+ -+ AuDbg("%lx, new %d\n", inode->i_state, !!(inode->i_state & I_NEW)); -+ if (inode->i_state & I_NEW) { -+ ii_write_lock_new_child(inode); -+ err = set_inode(inode, dentry); -+ unlock_new_inode(inode); -+ if (!err) -+ goto out; /* success */ -+ -+ iget_failed(inode); -+ ii_write_unlock(inode); -+ goto out_iput; -+ } else if (!must_new) { -+ err = reval_inode(inode, dentry, &match); -+ if (!err) -+ goto out; /* success */ -+ else if (match) -+ goto out_iput; -+ } -+ -+ if (unlikely(au_test_fs_unique_ino(h_dentry->d_inode))) -+ AuWarn1("Warning: Un-notified UDBA or repeatedly renamed dir," -+ " b%d, %s, %.*s, hi%lu, i%lu.\n", -+ bstart, au_sbtype(h_dentry->d_sb), AuDLNPair(dentry), -+ (unsigned long)h_ino, (unsigned long)ino); -+ ino = 0; -+ err = au_xino_write(sb, bstart, h_ino, /*ino*/0); -+ if (!err) { -+ iput(inode); -+ goto new_ino; -+ } -+ -+ out_iput: -+ iput(inode); -+ inode = ERR_PTR(err); -+ out: -+ return inode; -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+int au_test_ro(struct super_block *sb, aufs_bindex_t bindex, -+ struct inode *inode) -+{ -+ int err; -+ -+ err = au_br_rdonly(au_sbr(sb, bindex)); -+ -+ /* pseudo-link after flushed may happen out of bounds */ -+ if (!err -+ && inode -+ && au_ibstart(inode) <= bindex -+ && bindex <= au_ibend(inode)) { -+ /* -+ * permission check is unnecessary since vfsub routine -+ * will be called later -+ */ -+ struct inode *hi = au_h_iptr(inode, bindex); -+ if (hi) -+ err = IS_IMMUTABLE(hi) ? -EROFS : 0; -+ } -+ -+ return err; -+} -+ -+int au_test_h_perm(struct inode *h_inode, int mask) -+{ -+ if (!current_fsuid()) -+ return 0; -+ return inode_permission(h_inode, mask); -+} -+ -+int au_test_h_perm_sio(struct inode *h_inode, int mask) -+{ -+ if (au_test_nfs(h_inode->i_sb) -+ && (mask & MAY_WRITE) -+ && S_ISDIR(h_inode->i_mode)) -+ mask |= MAY_READ; /* force permission check */ -+ return au_test_h_perm(h_inode, mask); -+} -diff --git a/fs/aufs/inode.h b/fs/aufs/inode.h -new file mode 100644 -index 0000000..1c5559b ---- /dev/null -+++ b/fs/aufs/inode.h -@@ -0,0 +1,497 @@ -+/* -+ * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * -+ * This program, aufs is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ */ -+ -+/* -+ * inode operations -+ */ -+ -+#ifndef __AUFS_INODE_H__ -+#define __AUFS_INODE_H__ -+ -+#ifdef __KERNEL__ -+ -+#include -+#include -+#include -+#include "rwsem.h" -+ -+struct vfsmount; -+ -+struct au_hinotify { -+#ifdef CONFIG_AUFS_HINOTIFY -+ struct inotify_watch hin_watch; -+ struct inode *hin_aufs_inode; /* no get/put */ -+#endif -+}; -+ -+struct au_hinode { -+ struct inode *hi_inode; -+ aufs_bindex_t hi_id; -+#ifdef CONFIG_AUFS_HINOTIFY -+ struct au_hinotify *hi_notify; -+#endif -+ -+ /* reference to the copied-up whiteout with get/put */ -+ struct dentry *hi_whdentry; -+}; -+ -+struct au_vdir; -+struct au_iinfo { -+ atomic_t ii_generation; -+ struct super_block *ii_hsb1; /* no get/put */ -+ -+ struct au_rwsem ii_rwsem; -+ aufs_bindex_t ii_bstart, ii_bend; -+ __u32 ii_higen; -+ struct au_hinode *ii_hinode; -+ struct au_vdir *ii_vdir; -+}; -+ -+struct au_icntnr { -+ struct au_iinfo iinfo; -+ struct inode vfs_inode; -+}; -+ -+/* au_pin flags */ -+#define AuPin_DI_LOCKED 1 -+#define AuPin_MNT_WRITE (1 << 1) -+#define au_ftest_pin(flags, name) ((flags) & AuPin_##name) -+#define au_fset_pin(flags, name) { (flags) |= AuPin_##name; } -+#define au_fclr_pin(flags, name) { (flags) &= ~AuPin_##name; } -+ -+struct au_pin { -+ /* input */ -+ struct dentry *dentry; -+ unsigned int udba; -+ unsigned char lsc_di, lsc_hi, flags; -+ aufs_bindex_t bindex; -+ -+ /* output */ -+ struct dentry *parent; -+ struct au_hinode *hdir; -+ struct vfsmount *h_mnt; -+}; -+ -+/* ---------------------------------------------------------------------- */ -+ -+static inline struct au_iinfo *au_ii(struct inode *inode) -+{ -+ struct au_iinfo *iinfo; -+ -+ iinfo = &(container_of(inode, struct au_icntnr, vfs_inode)->iinfo); -+ if (iinfo->ii_hinode) -+ return iinfo; -+ return NULL; /* debugging bad_inode case */ -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+/* inode.c */ -+struct inode *au_igrab(struct inode *inode); -+int au_refresh_hinode_self(struct inode *inode, int do_attr); -+int au_refresh_hinode(struct inode *inode, struct dentry *dentry); -+int au_ino(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, -+ unsigned int d_type, ino_t *ino); -+struct inode *au_new_inode(struct dentry *dentry, int must_new); -+int au_test_ro(struct super_block *sb, aufs_bindex_t bindex, -+ struct inode *inode); -+int au_test_h_perm(struct inode *h_inode, int mask); -+int au_test_h_perm_sio(struct inode *h_inode, int mask); -+ -+static inline int au_wh_ino(struct super_block *sb, aufs_bindex_t bindex, -+ ino_t h_ino, unsigned int d_type, ino_t *ino) -+{ -+#ifdef CONFIG_AUFS_SHWH -+ return au_ino(sb, bindex, h_ino, d_type, ino); -+#else -+ return 0; -+#endif -+} -+ -+/* i_op.c */ -+extern struct inode_operations aufs_iop, aufs_symlink_iop, aufs_dir_iop; -+ -+/* au_wr_dir flags */ -+#define AuWrDir_ADD_ENTRY 1 -+#define AuWrDir_ISDIR (1 << 1) -+#define au_ftest_wrdir(flags, name) ((flags) & AuWrDir_##name) -+#define au_fset_wrdir(flags, name) { (flags) |= AuWrDir_##name; } -+#define au_fclr_wrdir(flags, name) { (flags) &= ~AuWrDir_##name; } -+ -+struct au_wr_dir_args { -+ aufs_bindex_t force_btgt; -+ unsigned char flags; -+}; -+int au_wr_dir(struct dentry *dentry, struct dentry *src_dentry, -+ struct au_wr_dir_args *args); -+ -+struct dentry *au_pinned_h_parent(struct au_pin *pin); -+void au_pin_init(struct au_pin *pin, struct dentry *dentry, -+ aufs_bindex_t bindex, int lsc_di, int lsc_hi, -+ unsigned int udba, unsigned char flags); -+int au_pin(struct au_pin *pin, struct dentry *dentry, aufs_bindex_t bindex, -+ unsigned int udba, unsigned char flags) __must_check; -+int au_do_pin(struct au_pin *pin) __must_check; -+void au_unpin(struct au_pin *pin); -+ -+/* i_op_add.c */ -+int au_may_add(struct dentry *dentry, aufs_bindex_t bindex, -+ struct dentry *h_parent, int isdir); -+int aufs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev); -+int aufs_symlink(struct inode *dir, struct dentry *dentry, const char *symname); -+int aufs_create(struct inode *dir, struct dentry *dentry, int mode, -+ struct nameidata *nd); -+int aufs_link(struct dentry *src_dentry, struct inode *dir, -+ struct dentry *dentry); -+int aufs_mkdir(struct inode *dir, struct dentry *dentry, int mode); -+ -+/* i_op_del.c */ -+int au_wr_dir_need_wh(struct dentry *dentry, int isdir, aufs_bindex_t *bcpup); -+int au_may_del(struct dentry *dentry, aufs_bindex_t bindex, -+ struct dentry *h_parent, int isdir); -+int aufs_unlink(struct inode *dir, struct dentry *dentry); -+int aufs_rmdir(struct inode *dir, struct dentry *dentry); -+ -+/* i_op_ren.c */ -+int au_wbr(struct dentry *dentry, aufs_bindex_t btgt); -+int aufs_rename(struct inode *src_dir, struct dentry *src_dentry, -+ struct inode *dir, struct dentry *dentry); -+ -+/* iinfo.c */ -+struct inode *au_h_iptr(struct inode *inode, aufs_bindex_t bindex); -+void au_hiput(struct au_hinode *hinode); -+void au_set_ibstart(struct inode *inode, aufs_bindex_t bindex); -+void au_set_hi_wh(struct inode *inode, aufs_bindex_t bindex, -+ struct dentry *h_wh); -+unsigned int au_hi_flags(struct inode *inode, int isdir); -+ -+/* hinode flags */ -+#define AuHi_XINO 1 -+#define AuHi_HINOTIFY (1 << 1) -+#define au_ftest_hi(flags, name) ((flags) & AuHi_##name) -+#define au_fset_hi(flags, name) { (flags) |= AuHi_##name; } -+#define au_fclr_hi(flags, name) { (flags) &= ~AuHi_##name; } -+ -+#ifndef CONFIG_AUFS_HINOTIFY -+#undef AuHi_HINOTIFY -+#define AuHi_HINOTIFY 0 -+#endif -+ -+void au_set_h_iptr(struct inode *inode, aufs_bindex_t bindex, -+ struct inode *h_inode, unsigned int flags); -+ -+void au_update_iigen(struct inode *inode); -+void au_update_brange(struct inode *inode, int do_put_zero); -+ -+int au_iinfo_init(struct inode *inode); -+void au_iinfo_fin(struct inode *inode); -+int au_ii_realloc(struct au_iinfo *iinfo, int nbr); -+ -+/* plink.c */ -+void au_plink_block_maintain(struct super_block *sb); -+#ifdef CONFIG_AUFS_DEBUG -+void au_plink_list(struct super_block *sb); -+#else -+static inline void au_plink_list(struct super_block *sb) -+{ -+ /* nothing */ -+} -+#endif -+int au_plink_test(struct inode *inode); -+struct dentry *au_plink_lkup(struct inode *inode, aufs_bindex_t bindex); -+void au_plink_append(struct inode *inode, aufs_bindex_t bindex, -+ struct dentry *h_dentry); -+void au_plink_put(struct super_block *sb); -+void au_plink_half_refresh(struct super_block *sb, aufs_bindex_t br_id); -+long au_plink_ioctl(struct file *file, unsigned int cmd); -+ -+/* ---------------------------------------------------------------------- */ -+ -+/* lock subclass for iinfo */ -+enum { -+ AuLsc_II_CHILD, /* child first */ -+ AuLsc_II_CHILD2, /* rename(2), link(2), and cpup at hinotify */ -+ AuLsc_II_CHILD3, /* copyup dirs */ -+ AuLsc_II_PARENT, /* see AuLsc_I_PARENT in vfsub.h */ -+ AuLsc_II_PARENT2, -+ AuLsc_II_PARENT3, /* copyup dirs */ -+ AuLsc_II_NEW_CHILD -+}; -+ -+/* -+ * ii_read_lock_child, ii_write_lock_child, -+ * ii_read_lock_child2, ii_write_lock_child2, -+ * ii_read_lock_child3, ii_write_lock_child3, -+ * ii_read_lock_parent, ii_write_lock_parent, -+ * ii_read_lock_parent2, ii_write_lock_parent2, -+ * ii_read_lock_parent3, ii_write_lock_parent3, -+ * ii_read_lock_new_child, ii_write_lock_new_child, -+ */ -+#define AuReadLockFunc(name, lsc) \ -+static inline void ii_read_lock_##name(struct inode *i) \ -+{ \ -+ au_rw_read_lock_nested(&au_ii(i)->ii_rwsem, AuLsc_II_##lsc); \ -+} -+ -+#define AuWriteLockFunc(name, lsc) \ -+static inline void ii_write_lock_##name(struct inode *i) \ -+{ \ -+ au_rw_write_lock_nested(&au_ii(i)->ii_rwsem, AuLsc_II_##lsc); \ -+} -+ -+#define AuRWLockFuncs(name, lsc) \ -+ AuReadLockFunc(name, lsc) \ -+ AuWriteLockFunc(name, lsc) -+ -+AuRWLockFuncs(child, CHILD); -+AuRWLockFuncs(child2, CHILD2); -+AuRWLockFuncs(child3, CHILD3); -+AuRWLockFuncs(parent, PARENT); -+AuRWLockFuncs(parent2, PARENT2); -+AuRWLockFuncs(parent3, PARENT3); -+AuRWLockFuncs(new_child, NEW_CHILD); -+ -+#undef AuReadLockFunc -+#undef AuWriteLockFunc -+#undef AuRWLockFuncs -+ -+/* -+ * ii_read_unlock, ii_write_unlock, ii_downgrade_lock -+ */ -+AuSimpleUnlockRwsemFuncs(ii, struct inode *i, &au_ii(i)->ii_rwsem); -+ -+#define IiMustNoWaiters(i) AuRwMustNoWaiters(&au_ii(i)->ii_rwsem) -+#define IiMustAnyLock(i) AuRwMustAnyLock(&au_ii(i)->ii_rwsem) -+#define IiMustWriteLock(i) AuRwMustWriteLock(&au_ii(i)->ii_rwsem) -+ -+/* ---------------------------------------------------------------------- */ -+ -+static inline unsigned int au_iigen(struct inode *inode) -+{ -+ return atomic_read(&au_ii(inode)->ii_generation); -+} -+ -+/* tiny test for inode number */ -+/* tmpfs generation is too rough */ -+static inline int au_test_higen(struct inode *inode, struct inode *h_inode) -+{ -+ struct au_iinfo *iinfo; -+ -+ iinfo = au_ii(inode); -+ AuRwMustAnyLock(&iinfo->ii_rwsem); -+ return !(iinfo->ii_hsb1 == h_inode->i_sb -+ && iinfo->ii_higen == h_inode->i_generation); -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+static inline aufs_bindex_t au_ii_br_id(struct inode *inode, -+ aufs_bindex_t bindex) -+{ -+ IiMustAnyLock(inode); -+ return au_ii(inode)->ii_hinode[0 + bindex].hi_id; -+} -+ -+static inline aufs_bindex_t au_ibstart(struct inode *inode) -+{ -+ IiMustAnyLock(inode); -+ return au_ii(inode)->ii_bstart; -+} -+ -+static inline aufs_bindex_t au_ibend(struct inode *inode) -+{ -+ IiMustAnyLock(inode); -+ return au_ii(inode)->ii_bend; -+} -+ -+static inline struct au_vdir *au_ivdir(struct inode *inode) -+{ -+ IiMustAnyLock(inode); -+ return au_ii(inode)->ii_vdir; -+} -+ -+static inline struct dentry *au_hi_wh(struct inode *inode, aufs_bindex_t bindex) -+{ -+ IiMustAnyLock(inode); -+ return au_ii(inode)->ii_hinode[0 + bindex].hi_whdentry; -+} -+ -+static inline void au_set_ibend(struct inode *inode, aufs_bindex_t bindex) -+{ -+ IiMustWriteLock(inode); -+ au_ii(inode)->ii_bend = bindex; -+} -+ -+static inline void au_set_ivdir(struct inode *inode, struct au_vdir *vdir) -+{ -+ IiMustWriteLock(inode); -+ au_ii(inode)->ii_vdir = vdir; -+} -+ -+static inline struct au_hinode *au_hi(struct inode *inode, aufs_bindex_t bindex) -+{ -+ IiMustAnyLock(inode); -+ return au_ii(inode)->ii_hinode + bindex; -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+static inline struct dentry *au_pinned_parent(struct au_pin *pin) -+{ -+ if (pin) -+ return pin->parent; -+ return NULL; -+} -+ -+static inline struct inode *au_pinned_h_dir(struct au_pin *pin) -+{ -+ if (pin && pin->hdir) -+ return pin->hdir->hi_inode; -+ return NULL; -+} -+ -+static inline struct au_hinode *au_pinned_hdir(struct au_pin *pin) -+{ -+ if (pin) -+ return pin->hdir; -+ return NULL; -+} -+ -+static inline void au_pin_set_dentry(struct au_pin *pin, struct dentry *dentry) -+{ -+ if (pin) -+ pin->dentry = dentry; -+} -+ -+static inline void au_pin_set_parent_lflag(struct au_pin *pin, -+ unsigned char lflag) -+{ -+ if (pin) { -+ /* dirty macros require brackets */ -+ if (lflag) { -+ au_fset_pin(pin->flags, DI_LOCKED); -+ } else { -+ au_fclr_pin(pin->flags, DI_LOCKED); -+ } -+ } -+} -+ -+static inline void au_pin_set_parent(struct au_pin *pin, struct dentry *parent) -+{ -+ if (pin) { -+ dput(pin->parent); -+ pin->parent = dget(parent); -+ } -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+#ifdef CONFIG_AUFS_HINOTIFY -+/* hinotify.c */ -+int au_hin_alloc(struct au_hinode *hinode, struct inode *inode, -+ struct inode *h_inode); -+void au_hin_free(struct au_hinode *hinode); -+void au_hin_ctl(struct au_hinode *hinode, int do_set); -+void au_reset_hinotify(struct inode *inode, unsigned int flags); -+ -+int __init au_hinotify_init(void); -+void au_hinotify_fin(void); -+ -+static inline -+void au_hin_init(struct au_hinode *hinode, struct au_hinotify *val) -+{ -+ hinode->hi_notify = val; -+} -+ -+static inline void au_iigen_dec(struct inode *inode) -+{ -+ atomic_dec_return(&au_ii(inode)->ii_generation); -+} -+ -+#else -+static inline -+int au_hin_alloc(struct au_hinode *hinode __maybe_unused, -+ struct inode *inode __maybe_unused, -+ struct inode *h_inode __maybe_unused) -+{ -+ return -EOPNOTSUPP; -+} -+ -+static inline void au_hin_free(struct au_hinode *hinode __maybe_unused) -+{ -+ /* nothing */ -+} -+ -+static inline void au_hin_ctl(struct au_hinode *hinode __maybe_unused, -+ int do_set __maybe_unused) -+{ -+ /* nothing */ -+} -+ -+static inline void au_reset_hinotify(struct inode *inode __maybe_unused, -+ unsigned int flags __maybe_unused) -+{ -+ /* nothing */ -+} -+ -+static inline int au_hinotify_init(void) -+{ -+ return 0; -+} -+ -+#define au_hinotify_fin() do {} while (0) -+ -+static inline -+void au_hin_init(struct au_hinode *hinode __maybe_unused, -+ struct au_hinotify *val __maybe_unused) -+{ -+ /* empty */ -+} -+#endif /* CONFIG_AUFS_HINOTIFY */ -+ -+static inline void au_hin_suspend(struct au_hinode *hdir) -+{ -+ au_hin_ctl(hdir, /*do_set*/0); -+} -+ -+static inline void au_hin_resume(struct au_hinode *hdir) -+{ -+ au_hin_ctl(hdir, /*do_set*/1); -+} -+ -+static inline void au_hin_imtx_lock(struct au_hinode *hdir) -+{ -+ mutex_lock(&hdir->hi_inode->i_mutex); -+ au_hin_suspend(hdir); -+} -+ -+static inline void au_hin_imtx_lock_nested(struct au_hinode *hdir, -+ unsigned int sc __maybe_unused) -+{ -+ mutex_lock_nested(&hdir->hi_inode->i_mutex, sc); -+ au_hin_suspend(hdir); -+} -+ -+static inline void au_hin_imtx_unlock(struct au_hinode *hdir) -+{ -+ au_hin_resume(hdir); -+ mutex_unlock(&hdir->hi_inode->i_mutex); -+} -+ -+#endif /* __KERNEL__ */ -+#endif /* __AUFS_INODE_H__ */ -diff --git a/fs/aufs/ioctl.c b/fs/aufs/ioctl.c -new file mode 100644 -index 0000000..012361a ---- /dev/null -+++ b/fs/aufs/ioctl.c -@@ -0,0 +1,47 @@ -+/* -+ * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * -+ * This program, aufs is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ */ -+ -+/* -+ * ioctl -+ * plink-management and readdir in userspace. -+ */ -+ -+#include "aufs.h" -+ -+long aufs_ioctl_dir(struct file *file, unsigned int cmd, unsigned long arg) -+{ -+ long err; -+ -+ switch (cmd) { -+ case AUFS_CTL_PLINK_MAINT: -+ case AUFS_CTL_PLINK_CLEAN: -+ err = au_plink_ioctl(file, cmd); -+ break; -+ -+ case AUFS_CTL_RDU: -+ case AUFS_CTL_RDU_INO: -+ err = au_rdu_ioctl(file, cmd, arg); -+ break; -+ -+ default: -+ err = -EINVAL; -+ } -+ -+ AuTraceErr(err); -+ return err; -+} -diff --git a/fs/aufs/loop.c b/fs/aufs/loop.c -new file mode 100644 -index 0000000..277011f ---- /dev/null -+++ b/fs/aufs/loop.c -@@ -0,0 +1,55 @@ -+/* -+ * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * -+ * This program, aufs is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ */ -+ -+/* -+ * support for loopback block device as a branch -+ */ -+ -+#include -+#include "aufs.h" -+ -+/* -+ * test if two lower dentries have overlapping branches. -+ */ -+int au_test_loopback_overlap(struct super_block *sb, struct dentry *h_d1, -+ struct dentry *h_d2) -+{ -+ struct inode *h_inode; -+ struct loop_device *l; -+ -+ h_inode = h_d1->d_inode; -+ if (MAJOR(h_inode->i_sb->s_dev) != LOOP_MAJOR) -+ return 0; -+ -+ l = h_inode->i_sb->s_bdev->bd_disk->private_data; -+ h_d1 = l->lo_backing_file->f_dentry; -+ /* h_d1 can be local NFS. in this case aufs cannot detect the loop */ -+ if (unlikely(h_d1->d_sb == sb)) -+ return 1; -+ return !!au_test_subdir(h_d1, h_d2); -+} -+ -+/* true if a kernel thread named 'loop[0-9].*' accesses a file */ -+int au_test_loopback_kthread(void) -+{ -+ const char c = current->comm[4]; -+ -+ return current->mm == NULL -+ && '0' <= c && c <= '9' -+ && strncmp(current->comm, "loop", 4) == 0; -+} -diff --git a/fs/aufs/loop.h b/fs/aufs/loop.h -new file mode 100644 -index 0000000..5a0fd87 ---- /dev/null -+++ b/fs/aufs/loop.h -@@ -0,0 +1,51 @@ -+/* -+ * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * -+ * This program, aufs is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ */ -+ -+/* -+ * support for loopback mount as a branch -+ */ -+ -+#ifndef __AUFS_LOOP_H__ -+#define __AUFS_LOOP_H__ -+ -+#ifdef __KERNEL__ -+ -+struct dentry; -+struct super_block; -+ -+#ifdef CONFIG_AUFS_BDEV_LOOP -+/* loop.c */ -+int au_test_loopback_overlap(struct super_block *sb, struct dentry *h_d1, -+ struct dentry *h_d2); -+int au_test_loopback_kthread(void); -+#else -+static inline -+int au_test_loopback_overlap(struct super_block *sb, struct dentry *h_d1, -+ struct dentry *h_d2) -+{ -+ return 0; -+} -+ -+static inline int au_test_loopback_kthread(void) -+{ -+ return 0; -+} -+#endif /* BLK_DEV_LOOP */ -+ -+#endif /* __KERNEL__ */ -+#endif /* __AUFS_LOOP_H__ */ -diff --git a/fs/aufs/magic.mk b/fs/aufs/magic.mk -new file mode 100644 -index 0000000..1e55221 ---- /dev/null -+++ b/fs/aufs/magic.mk -@@ -0,0 +1,48 @@ -+ -+# defined in ${srctree}/fs/fuse/inode.c -+# tristate -+ifdef CONFIG_FUSE_FS -+ccflags-y += -DFUSE_SUPER_MAGIC=0x65735546 -+endif -+ -+# defined in ${srctree}/fs/ocfs2/ocfs2_fs.h -+# tristate -+ifdef CONFIG_OCFS2_FS -+ccflags-y += -DOCFS2_SUPER_MAGIC=0x7461636f -+endif -+ -+# defined in ${srctree}/fs/ocfs2/dlm/userdlm.h -+# tristate -+ifdef CONFIG_OCFS2_FS_O2CB -+ccflags-y += -DDLMFS_MAGIC=0x76a9f425 -+endif -+ -+# defined in ${srctree}/fs/cifs/cifsfs.c -+# tristate -+ifdef CONFIG_CIFS_FS -+ccflags-y += -DCIFS_MAGIC_NUMBER=0xFF534D42 -+endif -+ -+# defined in ${srctree}/fs/xfs/xfs_sb.h -+# tristate -+ifdef CONFIG_XFS_FS -+ccflags-y += -DXFS_SB_MAGIC=0x58465342 -+endif -+ -+# defined in ${srctree}/fs/configfs/mount.c -+# tristate -+ifdef CONFIG_CONFIGFS_FS -+ccflags-y += -DCONFIGFS_MAGIC=0x62656570 -+endif -+ -+# defined in ${srctree}/fs/9p/v9fs.h -+# tristate -+ifdef CONFIG_9P_FS -+ccflags-y += -DV9FS_MAGIC=0x01021997 -+endif -+ -+# defined in ${srctree}/fs/ubifs/ubifs.h -+# tristate -+ifdef CONFIG_UBIFS_FS -+ccflags-y += -DUBIFS_SUPER_MAGIC=0x24051905 -+endif -diff --git a/fs/aufs/module.c b/fs/aufs/module.c -new file mode 100644 -index 0000000..5b3531f ---- /dev/null -+++ b/fs/aufs/module.c -@@ -0,0 +1,174 @@ -+/* -+ * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * -+ * This program, aufs is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ */ -+ -+/* -+ * module global variables and operations -+ */ -+ -+#include -+#include -+#include "aufs.h" -+ -+void *au_kzrealloc(void *p, unsigned int nused, unsigned int new_sz, gfp_t gfp) -+{ -+ if (new_sz <= nused) -+ return p; -+ -+ p = krealloc(p, new_sz, gfp); -+ if (p) -+ memset(p + nused, 0, new_sz - nused); -+ return p; -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+/* -+ * aufs caches -+ */ -+struct kmem_cache *au_cachep[AuCache_Last]; -+static int __init au_cache_init(void) -+{ -+ au_cachep[AuCache_DINFO] = AuCache(au_dinfo); -+ if (au_cachep[AuCache_DINFO]) -+ au_cachep[AuCache_ICNTNR] = AuCache(au_icntnr); -+ if (au_cachep[AuCache_ICNTNR]) -+ au_cachep[AuCache_FINFO] = AuCache(au_finfo); -+ if (au_cachep[AuCache_FINFO]) -+ au_cachep[AuCache_VDIR] = AuCache(au_vdir); -+ if (au_cachep[AuCache_VDIR]) -+ au_cachep[AuCache_DEHSTR] = AuCache(au_vdir_dehstr); -+ if (au_cachep[AuCache_DEHSTR]) -+ return 0; -+ -+ return -ENOMEM; -+} -+ -+static void au_cache_fin(void) -+{ -+ int i; -+ for (i = 0; i < AuCache_Last; i++) -+ if (au_cachep[i]) { -+ kmem_cache_destroy(au_cachep[i]); -+ au_cachep[i] = NULL; -+ } -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+int au_dir_roflags; -+ -+/* -+ * functions for module interface. -+ */ -+MODULE_LICENSE("GPL"); -+/* MODULE_LICENSE("GPL v2"); */ -+MODULE_AUTHOR("Junjiro R. Okajima "); -+MODULE_DESCRIPTION(AUFS_NAME -+ " -- Advanced multi layered unification filesystem"); -+MODULE_VERSION(AUFS_VERSION); -+ -+/* it should be 'byte', but param_set_byte() prints it by "%c" */ -+short aufs_nwkq = AUFS_NWKQ_DEF; -+MODULE_PARM_DESC(nwkq, "the number of workqueue thread, " AUFS_WKQ_NAME); -+module_param_named(nwkq, aufs_nwkq, short, S_IRUGO); -+ -+/* this module parameter has no meaning when SYSFS is disabled */ -+int sysaufs_brs = 1; -+MODULE_PARM_DESC(brs, "use /fs/aufs/si_*/brN"); -+module_param_named(brs, sysaufs_brs, int, S_IRUGO); -+ -+/* ---------------------------------------------------------------------- */ -+ -+static char au_esc_chars[0x20 + 3]; /* 0x01-0x20, backslash, del, and NULL */ -+ -+int au_seq_path(struct seq_file *seq, struct path *path) -+{ -+ return seq_path(seq, path, au_esc_chars); -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+static int __init aufs_init(void) -+{ -+ int err, i; -+ char *p; -+ -+ p = au_esc_chars; -+ for (i = 1; i <= ' '; i++) -+ *p++ = i; -+ *p++ = '\\'; -+ *p++ = '\x7f'; -+ *p = 0; -+ -+ au_dir_roflags = au_file_roflags(O_DIRECTORY | O_LARGEFILE); -+ -+ sysaufs_brs_init(); -+ au_debug_init(); -+ -+ err = -EINVAL; -+ if (unlikely(aufs_nwkq <= 0)) -+ goto out; -+ -+ err = sysaufs_init(); -+ if (unlikely(err)) -+ goto out; -+ err = au_wkq_init(); -+ if (unlikely(err)) -+ goto out_sysaufs; -+ err = au_hinotify_init(); -+ if (unlikely(err)) -+ goto out_wkq; -+ err = au_sysrq_init(); -+ if (unlikely(err)) -+ goto out_hin; -+ err = au_cache_init(); -+ if (unlikely(err)) -+ goto out_sysrq; -+ err = register_filesystem(&aufs_fs_type); -+ if (unlikely(err)) -+ goto out_cache; -+ /* since we define pr_fmt, call printk directly */ -+ printk(KERN_INFO AUFS_NAME " " AUFS_VERSION "\n"); -+ goto out; /* success */ -+ -+ out_cache: -+ au_cache_fin(); -+ out_sysrq: -+ au_sysrq_fin(); -+ out_hin: -+ au_hinotify_fin(); -+ out_wkq: -+ au_wkq_fin(); -+ out_sysaufs: -+ sysaufs_fin(); -+ out: -+ return err; -+} -+ -+static void __exit aufs_exit(void) -+{ -+ unregister_filesystem(&aufs_fs_type); -+ au_cache_fin(); -+ au_sysrq_fin(); -+ au_hinotify_fin(); -+ au_wkq_fin(); -+ sysaufs_fin(); -+} -+ -+module_init(aufs_init); -+module_exit(aufs_exit); -diff --git a/fs/aufs/module.h b/fs/aufs/module.h -new file mode 100644 -index 0000000..cea7bc7 ---- /dev/null -+++ b/fs/aufs/module.h -@@ -0,0 +1,78 @@ -+/* -+ * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * -+ * This program, aufs is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ */ -+ -+/* -+ * module initialization and module-global -+ */ -+ -+#ifndef __AUFS_MODULE_H__ -+#define __AUFS_MODULE_H__ -+ -+#ifdef __KERNEL__ -+ -+#include -+ -+struct path; -+struct seq_file; -+ -+/* module parameters */ -+extern short aufs_nwkq; -+extern int sysaufs_brs; -+ -+/* ---------------------------------------------------------------------- */ -+ -+extern int au_dir_roflags; -+ -+void *au_kzrealloc(void *p, unsigned int nused, unsigned int new_sz, gfp_t gfp); -+int au_seq_path(struct seq_file *seq, struct path *path); -+ -+/* ---------------------------------------------------------------------- */ -+ -+/* kmem cache */ -+enum { -+ AuCache_DINFO, -+ AuCache_ICNTNR, -+ AuCache_FINFO, -+ AuCache_VDIR, -+ AuCache_DEHSTR, -+#ifdef CONFIG_AUFS_HINOTIFY -+ AuCache_HINOTIFY, -+#endif -+ AuCache_Last -+}; -+ -+#define AuCache(type) KMEM_CACHE(type, SLAB_RECLAIM_ACCOUNT) -+ -+extern struct kmem_cache *au_cachep[]; -+ -+#define AuCacheFuncs(name, index) \ -+static inline void *au_cache_alloc_##name(void) \ -+{ return kmem_cache_alloc(au_cachep[AuCache_##index], GFP_NOFS); } \ -+static inline void au_cache_free_##name(void *p) \ -+{ kmem_cache_free(au_cachep[AuCache_##index], p); } -+ -+AuCacheFuncs(dinfo, DINFO); -+AuCacheFuncs(icntnr, ICNTNR); -+AuCacheFuncs(finfo, FINFO); -+AuCacheFuncs(vdir, VDIR); -+AuCacheFuncs(dehstr, DEHSTR); -+ -+/* ---------------------------------------------------------------------- */ -+ -+#endif /* __KERNEL__ */ -+#endif /* __AUFS_MODULE_H__ */ -diff --git a/fs/aufs/opts.c b/fs/aufs/opts.c -new file mode 100644 -index 0000000..4d9b60f ---- /dev/null -+++ b/fs/aufs/opts.c -@@ -0,0 +1,1549 @@ -+/* -+ * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * -+ * This program, aufs is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ */ -+ -+/* -+ * mount options/flags -+ */ -+ -+#include -+#include -+#include /* a distribution requires */ -+#include -+#include "aufs.h" -+ -+/* ---------------------------------------------------------------------- */ -+ -+enum { -+ Opt_br, -+ Opt_add, Opt_del, Opt_mod, Opt_reorder, Opt_append, Opt_prepend, -+ Opt_idel, Opt_imod, Opt_ireorder, -+ Opt_dirwh, Opt_rdcache, Opt_rdblk, Opt_rdhash, Opt_rendir, -+ Opt_rdblk_def, Opt_rdhash_def, -+ Opt_xino, Opt_zxino, Opt_noxino, -+ Opt_trunc_xino, Opt_trunc_xino_v, Opt_notrunc_xino, -+ Opt_trunc_xino_path, Opt_itrunc_xino, -+ Opt_trunc_xib, Opt_notrunc_xib, -+ Opt_shwh, Opt_noshwh, -+ Opt_plink, Opt_noplink, Opt_list_plink, -+ Opt_udba, -+ /* Opt_lock, Opt_unlock, */ -+ Opt_cmd, Opt_cmd_args, -+ Opt_diropq_a, Opt_diropq_w, -+ Opt_warn_perm, Opt_nowarn_perm, -+ Opt_wbr_copyup, Opt_wbr_create, -+ Opt_refrof, Opt_norefrof, -+ Opt_verbose, Opt_noverbose, -+ Opt_sum, Opt_nosum, Opt_wsum, -+ Opt_tail, Opt_ignore, Opt_ignore_silent, Opt_err -+}; -+ -+static match_table_t options = { -+ {Opt_br, "br=%s"}, -+ {Opt_br, "br:%s"}, -+ -+ {Opt_add, "add=%d:%s"}, -+ {Opt_add, "add:%d:%s"}, -+ {Opt_add, "ins=%d:%s"}, -+ {Opt_add, "ins:%d:%s"}, -+ {Opt_append, "append=%s"}, -+ {Opt_append, "append:%s"}, -+ {Opt_prepend, "prepend=%s"}, -+ {Opt_prepend, "prepend:%s"}, -+ -+ {Opt_del, "del=%s"}, -+ {Opt_del, "del:%s"}, -+ /* {Opt_idel, "idel:%d"}, */ -+ {Opt_mod, "mod=%s"}, -+ {Opt_mod, "mod:%s"}, -+ /* {Opt_imod, "imod:%d:%s"}, */ -+ -+ {Opt_dirwh, "dirwh=%d"}, -+ -+ {Opt_xino, "xino=%s"}, -+ {Opt_noxino, "noxino"}, -+ {Opt_trunc_xino, "trunc_xino"}, -+ {Opt_trunc_xino_v, "trunc_xino_v=%d:%d"}, -+ {Opt_notrunc_xino, "notrunc_xino"}, -+ {Opt_trunc_xino_path, "trunc_xino=%s"}, -+ {Opt_itrunc_xino, "itrunc_xino=%d"}, -+ /* {Opt_zxino, "zxino=%s"}, */ -+ {Opt_trunc_xib, "trunc_xib"}, -+ {Opt_notrunc_xib, "notrunc_xib"}, -+ -+ {Opt_plink, "plink"}, -+ {Opt_noplink, "noplink"}, -+#ifdef CONFIG_AUFS_DEBUG -+ {Opt_list_plink, "list_plink"}, -+#endif -+ -+ {Opt_udba, "udba=%s"}, -+ -+ {Opt_diropq_a, "diropq=always"}, -+ {Opt_diropq_a, "diropq=a"}, -+ {Opt_diropq_w, "diropq=whiteouted"}, -+ {Opt_diropq_w, "diropq=w"}, -+ -+ {Opt_warn_perm, "warn_perm"}, -+ {Opt_nowarn_perm, "nowarn_perm"}, -+ -+ /* keep them temporary */ -+ {Opt_ignore_silent, "coo=%s"}, -+ {Opt_ignore_silent, "nodlgt"}, -+ {Opt_ignore_silent, "nodirperm1"}, -+ {Opt_ignore_silent, "clean_plink"}, -+ -+#ifdef CONFIG_AUFS_SHWH -+ {Opt_shwh, "shwh"}, -+#endif -+ {Opt_noshwh, "noshwh"}, -+ -+ {Opt_rendir, "rendir=%d"}, -+ -+ {Opt_refrof, "refrof"}, -+ {Opt_norefrof, "norefrof"}, -+ -+ {Opt_verbose, "verbose"}, -+ {Opt_verbose, "v"}, -+ {Opt_noverbose, "noverbose"}, -+ {Opt_noverbose, "quiet"}, -+ {Opt_noverbose, "q"}, -+ {Opt_noverbose, "silent"}, -+ -+ {Opt_sum, "sum"}, -+ {Opt_nosum, "nosum"}, -+ {Opt_wsum, "wsum"}, -+ -+ {Opt_rdcache, "rdcache=%d"}, -+ {Opt_rdblk, "rdblk=%d"}, -+ {Opt_rdblk_def, "rdblk=def"}, -+ {Opt_rdhash, "rdhash=%d"}, -+ {Opt_rdhash_def, "rdhash=def"}, -+ -+ {Opt_wbr_create, "create=%s"}, -+ {Opt_wbr_create, "create_policy=%s"}, -+ {Opt_wbr_copyup, "cpup=%s"}, -+ {Opt_wbr_copyup, "copyup=%s"}, -+ {Opt_wbr_copyup, "copyup_policy=%s"}, -+ -+ /* internal use for the scripts */ -+ {Opt_ignore_silent, "si=%s"}, -+ -+ {Opt_br, "dirs=%s"}, -+ {Opt_ignore, "debug=%d"}, -+ {Opt_ignore, "delete=whiteout"}, -+ {Opt_ignore, "delete=all"}, -+ {Opt_ignore, "imap=%s"}, -+ -+ /* temporary workaround, due to old mount(8)? */ -+ {Opt_ignore_silent, "relatime"}, -+ -+ {Opt_err, NULL} -+}; -+ -+/* ---------------------------------------------------------------------- */ -+ -+static const char *au_parser_pattern(int val, struct match_token *token) -+{ -+ while (token->pattern) { -+ if (token->token == val) -+ return token->pattern; -+ token++; -+ } -+ BUG(); -+ return "??"; -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+static match_table_t brperms = { -+ {AuBrPerm_RO, AUFS_BRPERM_RO}, -+ {AuBrPerm_RR, AUFS_BRPERM_RR}, -+ {AuBrPerm_RW, AUFS_BRPERM_RW}, -+ -+ {AuBrPerm_ROWH, AUFS_BRPERM_ROWH}, -+ {AuBrPerm_RRWH, AUFS_BRPERM_RRWH}, -+ {AuBrPerm_RWNoLinkWH, AUFS_BRPERM_RWNLWH}, -+ -+ {AuBrPerm_ROWH, "nfsro"}, -+ {AuBrPerm_RO, NULL} -+}; -+ -+static int noinline_for_stack br_perm_val(char *perm) -+{ -+ int val; -+ substring_t args[MAX_OPT_ARGS]; -+ -+ val = match_token(perm, brperms, args); -+ return val; -+} -+ -+const char *au_optstr_br_perm(int brperm) -+{ -+ return au_parser_pattern(brperm, (void *)brperms); -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+static match_table_t udbalevel = { -+ {AuOpt_UDBA_REVAL, "reval"}, -+ {AuOpt_UDBA_NONE, "none"}, -+#ifdef CONFIG_AUFS_HINOTIFY -+ {AuOpt_UDBA_HINOTIFY, "inotify"}, -+#endif -+ {-1, NULL} -+}; -+ -+static int noinline_for_stack udba_val(char *str) -+{ -+ substring_t args[MAX_OPT_ARGS]; -+ -+ return match_token(str, udbalevel, args); -+} -+ -+const char *au_optstr_udba(int udba) -+{ -+ return au_parser_pattern(udba, (void *)udbalevel); -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+static match_table_t au_wbr_create_policy = { -+ {AuWbrCreate_TDP, "tdp"}, -+ {AuWbrCreate_TDP, "top-down-parent"}, -+ {AuWbrCreate_RR, "rr"}, -+ {AuWbrCreate_RR, "round-robin"}, -+ {AuWbrCreate_MFS, "mfs"}, -+ {AuWbrCreate_MFS, "most-free-space"}, -+ {AuWbrCreate_MFSV, "mfs:%d"}, -+ {AuWbrCreate_MFSV, "most-free-space:%d"}, -+ -+ {AuWbrCreate_MFSRR, "mfsrr:%d"}, -+ {AuWbrCreate_MFSRRV, "mfsrr:%d:%d"}, -+ {AuWbrCreate_PMFS, "pmfs"}, -+ {AuWbrCreate_PMFSV, "pmfs:%d"}, -+ -+ {-1, NULL} -+}; -+ -+/* -+ * cf. linux/lib/parser.c and cmdline.c -+ * gave up calling memparse() since it uses simple_strtoull() instead of -+ * strict_...(). -+ */ -+static int noinline_for_stack -+au_match_ull(substring_t *s, unsigned long long *result) -+{ -+ int err; -+ unsigned int len; -+ char a[32]; -+ -+ err = -ERANGE; -+ len = s->to - s->from; -+ if (len + 1 <= sizeof(a)) { -+ memcpy(a, s->from, len); -+ a[len] = '\0'; -+ err = strict_strtoull(a, 0, result); -+ } -+ return err; -+} -+ -+static int au_wbr_mfs_wmark(substring_t *arg, char *str, -+ struct au_opt_wbr_create *create) -+{ -+ int err; -+ unsigned long long ull; -+ -+ err = 0; -+ if (!au_match_ull(arg, &ull)) -+ create->mfsrr_watermark = ull; -+ else { -+ pr_err("bad integer in %s\n", str); -+ err = -EINVAL; -+ } -+ -+ return err; -+} -+ -+static int au_wbr_mfs_sec(substring_t *arg, char *str, -+ struct au_opt_wbr_create *create) -+{ -+ int n, err; -+ -+ err = 0; -+ if (!match_int(arg, &n) && 0 <= n) -+ create->mfs_second = n; -+ else { -+ pr_err("bad integer in %s\n", str); -+ err = -EINVAL; -+ } -+ -+ return err; -+} -+ -+static int noinline_for_stack -+au_wbr_create_val(char *str, struct au_opt_wbr_create *create) -+{ -+ int err, e; -+ substring_t args[MAX_OPT_ARGS]; -+ -+ err = match_token(str, au_wbr_create_policy, args); -+ create->wbr_create = err; -+ switch (err) { -+ case AuWbrCreate_MFSRRV: -+ e = au_wbr_mfs_wmark(&args[0], str, create); -+ if (!e) -+ e = au_wbr_mfs_sec(&args[1], str, create); -+ if (unlikely(e)) -+ err = e; -+ break; -+ case AuWbrCreate_MFSRR: -+ e = au_wbr_mfs_wmark(&args[0], str, create); -+ if (unlikely(e)) { -+ err = e; -+ break; -+ } -+ /*FALLTHROUGH*/ -+ case AuWbrCreate_MFS: -+ case AuWbrCreate_PMFS: -+ create->mfs_second = AUFS_MFS_SECOND_DEF; -+ break; -+ case AuWbrCreate_MFSV: -+ case AuWbrCreate_PMFSV: -+ e = au_wbr_mfs_sec(&args[0], str, create); -+ if (unlikely(e)) -+ err = e; -+ break; -+ } -+ -+ return err; -+} -+ -+const char *au_optstr_wbr_create(int wbr_create) -+{ -+ return au_parser_pattern(wbr_create, (void *)au_wbr_create_policy); -+} -+ -+static match_table_t au_wbr_copyup_policy = { -+ {AuWbrCopyup_TDP, "tdp"}, -+ {AuWbrCopyup_TDP, "top-down-parent"}, -+ {AuWbrCopyup_BUP, "bup"}, -+ {AuWbrCopyup_BUP, "bottom-up-parent"}, -+ {AuWbrCopyup_BU, "bu"}, -+ {AuWbrCopyup_BU, "bottom-up"}, -+ {-1, NULL} -+}; -+ -+static int noinline_for_stack au_wbr_copyup_val(char *str) -+{ -+ substring_t args[MAX_OPT_ARGS]; -+ -+ return match_token(str, au_wbr_copyup_policy, args); -+} -+ -+const char *au_optstr_wbr_copyup(int wbr_copyup) -+{ -+ return au_parser_pattern(wbr_copyup, (void *)au_wbr_copyup_policy); -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+static const int lkup_dirflags = LOOKUP_FOLLOW | LOOKUP_DIRECTORY; -+ -+static void dump_opts(struct au_opts *opts) -+{ -+#ifdef CONFIG_AUFS_DEBUG -+ /* reduce stack space */ -+ union { -+ struct au_opt_add *add; -+ struct au_opt_del *del; -+ struct au_opt_mod *mod; -+ struct au_opt_xino *xino; -+ struct au_opt_xino_itrunc *xino_itrunc; -+ struct au_opt_wbr_create *create; -+ } u; -+ struct au_opt *opt; -+ -+ opt = opts->opt; -+ while (opt->type != Opt_tail) { -+ switch (opt->type) { -+ case Opt_add: -+ u.add = &opt->add; -+ AuDbg("add {b%d, %s, 0x%x, %p}\n", -+ u.add->bindex, u.add->pathname, u.add->perm, -+ u.add->path.dentry); -+ break; -+ case Opt_del: -+ case Opt_idel: -+ u.del = &opt->del; -+ AuDbg("del {%s, %p}\n", -+ u.del->pathname, u.del->h_path.dentry); -+ break; -+ case Opt_mod: -+ case Opt_imod: -+ u.mod = &opt->mod; -+ AuDbg("mod {%s, 0x%x, %p}\n", -+ u.mod->path, u.mod->perm, u.mod->h_root); -+ break; -+ case Opt_append: -+ u.add = &opt->add; -+ AuDbg("append {b%d, %s, 0x%x, %p}\n", -+ u.add->bindex, u.add->pathname, u.add->perm, -+ u.add->path.dentry); -+ break; -+ case Opt_prepend: -+ u.add = &opt->add; -+ AuDbg("prepend {b%d, %s, 0x%x, %p}\n", -+ u.add->bindex, u.add->pathname, u.add->perm, -+ u.add->path.dentry); -+ break; -+ case Opt_dirwh: -+ AuDbg("dirwh %d\n", opt->dirwh); -+ break; -+ case Opt_rdcache: -+ AuDbg("rdcache %d\n", opt->rdcache); -+ break; -+ case Opt_rdblk: -+ AuDbg("rdblk %u\n", opt->rdblk); -+ break; -+ case Opt_rdblk_def: -+ AuDbg("rdblk_def\n"); -+ break; -+ case Opt_rdhash: -+ AuDbg("rdhash %u\n", opt->rdhash); -+ break; -+ case Opt_rdhash_def: -+ AuDbg("rdhash_def\n"); -+ break; -+ case Opt_xino: -+ u.xino = &opt->xino; -+ AuDbg("xino {%s %.*s}\n", -+ u.xino->path, -+ AuDLNPair(u.xino->file->f_dentry)); -+ break; -+ case Opt_trunc_xino: -+ AuLabel(trunc_xino); -+ break; -+ case Opt_notrunc_xino: -+ AuLabel(notrunc_xino); -+ break; -+ case Opt_trunc_xino_path: -+ case Opt_itrunc_xino: -+ u.xino_itrunc = &opt->xino_itrunc; -+ AuDbg("trunc_xino %d\n", u.xino_itrunc->bindex); -+ break; -+ -+ case Opt_noxino: -+ AuLabel(noxino); -+ break; -+ case Opt_trunc_xib: -+ AuLabel(trunc_xib); -+ break; -+ case Opt_notrunc_xib: -+ AuLabel(notrunc_xib); -+ break; -+ case Opt_shwh: -+ AuLabel(shwh); -+ break; -+ case Opt_noshwh: -+ AuLabel(noshwh); -+ break; -+ case Opt_plink: -+ AuLabel(plink); -+ break; -+ case Opt_noplink: -+ AuLabel(noplink); -+ break; -+ case Opt_list_plink: -+ AuLabel(list_plink); -+ break; -+ case Opt_udba: -+ AuDbg("udba %d, %s\n", -+ opt->udba, au_optstr_udba(opt->udba)); -+ break; -+ case Opt_diropq_a: -+ AuLabel(diropq_a); -+ break; -+ case Opt_diropq_w: -+ AuLabel(diropq_w); -+ break; -+ case Opt_warn_perm: -+ AuLabel(warn_perm); -+ break; -+ case Opt_nowarn_perm: -+ AuLabel(nowarn_perm); -+ break; -+ case Opt_refrof: -+ AuLabel(refrof); -+ break; -+ case Opt_norefrof: -+ AuLabel(norefrof); -+ break; -+ case Opt_verbose: -+ AuLabel(verbose); -+ break; -+ case Opt_noverbose: -+ AuLabel(noverbose); -+ break; -+ case Opt_sum: -+ AuLabel(sum); -+ break; -+ case Opt_nosum: -+ AuLabel(nosum); -+ break; -+ case Opt_wsum: -+ AuLabel(wsum); -+ break; -+ case Opt_wbr_create: -+ u.create = &opt->wbr_create; -+ AuDbg("create %d, %s\n", u.create->wbr_create, -+ au_optstr_wbr_create(u.create->wbr_create)); -+ switch (u.create->wbr_create) { -+ case AuWbrCreate_MFSV: -+ case AuWbrCreate_PMFSV: -+ AuDbg("%d sec\n", u.create->mfs_second); -+ break; -+ case AuWbrCreate_MFSRR: -+ AuDbg("%llu watermark\n", -+ u.create->mfsrr_watermark); -+ break; -+ case AuWbrCreate_MFSRRV: -+ AuDbg("%llu watermark, %d sec\n", -+ u.create->mfsrr_watermark, -+ u.create->mfs_second); -+ break; -+ } -+ break; -+ case Opt_wbr_copyup: -+ AuDbg("copyup %d, %s\n", opt->wbr_copyup, -+ au_optstr_wbr_copyup(opt->wbr_copyup)); -+ break; -+ default: -+ BUG(); -+ } -+ opt++; -+ } -+#endif -+} -+ -+void au_opts_free(struct au_opts *opts) -+{ -+ struct au_opt *opt; -+ -+ opt = opts->opt; -+ while (opt->type != Opt_tail) { -+ switch (opt->type) { -+ case Opt_add: -+ case Opt_append: -+ case Opt_prepend: -+ path_put(&opt->add.path); -+ break; -+ case Opt_del: -+ case Opt_idel: -+ path_put(&opt->del.h_path); -+ break; -+ case Opt_mod: -+ case Opt_imod: -+ dput(opt->mod.h_root); -+ break; -+ case Opt_xino: -+ fput(opt->xino.file); -+ break; -+ } -+ opt++; -+ } -+} -+ -+static int opt_add(struct au_opt *opt, char *opt_str, unsigned long sb_flags, -+ aufs_bindex_t bindex) -+{ -+ int err; -+ struct au_opt_add *add = &opt->add; -+ char *p; -+ -+ add->bindex = bindex; -+ add->perm = AuBrPerm_Last; -+ add->pathname = opt_str; -+ p = strchr(opt_str, '='); -+ if (p) { -+ *p++ = 0; -+ if (*p) -+ add->perm = br_perm_val(p); -+ } -+ -+ err = vfsub_kern_path(add->pathname, lkup_dirflags, &add->path); -+ if (!err) { -+ if (!p) { -+ add->perm = AuBrPerm_RO; -+ if (au_test_fs_rr(add->path.dentry->d_sb)) -+ add->perm = AuBrPerm_RR; -+ else if (!bindex && !(sb_flags & MS_RDONLY)) -+ add->perm = AuBrPerm_RW; -+ } -+ opt->type = Opt_add; -+ goto out; -+ } -+ pr_err("lookup failed %s (%d)\n", add->pathname, err); -+ err = -EINVAL; -+ -+ out: -+ return err; -+} -+ -+static int au_opts_parse_del(struct au_opt_del *del, substring_t args[]) -+{ -+ int err; -+ -+ del->pathname = args[0].from; -+ AuDbg("del path %s\n", del->pathname); -+ -+ err = vfsub_kern_path(del->pathname, lkup_dirflags, &del->h_path); -+ if (unlikely(err)) -+ pr_err("lookup failed %s (%d)\n", del->pathname, err); -+ -+ return err; -+} -+ -+#if 0 /* reserved for future use */ -+static int au_opts_parse_idel(struct super_block *sb, aufs_bindex_t bindex, -+ struct au_opt_del *del, substring_t args[]) -+{ -+ int err; -+ struct dentry *root; -+ -+ err = -EINVAL; -+ root = sb->s_root; -+ aufs_read_lock(root, AuLock_FLUSH); -+ if (bindex < 0 || au_sbend(sb) < bindex) { -+ pr_err("out of bounds, %d\n", bindex); -+ goto out; -+ } -+ -+ err = 0; -+ del->h_path.dentry = dget(au_h_dptr(root, bindex)); -+ del->h_path.mnt = mntget(au_sbr_mnt(sb, bindex)); -+ -+ out: -+ aufs_read_unlock(root, !AuLock_IR); -+ return err; -+} -+#endif -+ -+static int noinline_for_stack -+au_opts_parse_mod(struct au_opt_mod *mod, substring_t args[]) -+{ -+ int err; -+ struct path path; -+ char *p; -+ -+ err = -EINVAL; -+ mod->path = args[0].from; -+ p = strchr(mod->path, '='); -+ if (unlikely(!p)) { -+ pr_err("no permssion %s\n", args[0].from); -+ goto out; -+ } -+ -+ *p++ = 0; -+ err = vfsub_kern_path(mod->path, lkup_dirflags, &path); -+ if (unlikely(err)) { -+ pr_err("lookup failed %s (%d)\n", mod->path, err); -+ goto out; -+ } -+ -+ mod->perm = br_perm_val(p); -+ AuDbg("mod path %s, perm 0x%x, %s\n", mod->path, mod->perm, p); -+ mod->h_root = dget(path.dentry); -+ path_put(&path); -+ -+ out: -+ return err; -+} -+ -+#if 0 /* reserved for future use */ -+static int au_opts_parse_imod(struct super_block *sb, aufs_bindex_t bindex, -+ struct au_opt_mod *mod, substring_t args[]) -+{ -+ int err; -+ struct dentry *root; -+ -+ err = -EINVAL; -+ root = sb->s_root; -+ aufs_read_lock(root, AuLock_FLUSH); -+ if (bindex < 0 || au_sbend(sb) < bindex) { -+ pr_err("out of bounds, %d\n", bindex); -+ goto out; -+ } -+ -+ err = 0; -+ mod->perm = br_perm_val(args[1].from); -+ AuDbg("mod path %s, perm 0x%x, %s\n", -+ mod->path, mod->perm, args[1].from); -+ mod->h_root = dget(au_h_dptr(root, bindex)); -+ -+ out: -+ aufs_read_unlock(root, !AuLock_IR); -+ return err; -+} -+#endif -+ -+static int au_opts_parse_xino(struct super_block *sb, struct au_opt_xino *xino, -+ substring_t args[]) -+{ -+ int err; -+ struct file *file; -+ -+ file = au_xino_create(sb, args[0].from, /*silent*/0); -+ err = PTR_ERR(file); -+ if (IS_ERR(file)) -+ goto out; -+ -+ err = -EINVAL; -+ if (unlikely(file->f_dentry->d_sb == sb)) { -+ fput(file); -+ pr_err("%s must be outside\n", args[0].from); -+ goto out; -+ } -+ -+ err = 0; -+ xino->file = file; -+ xino->path = args[0].from; -+ -+ out: -+ return err; -+} -+ -+static int noinline_for_stack -+au_opts_parse_xino_itrunc_path(struct super_block *sb, -+ struct au_opt_xino_itrunc *xino_itrunc, -+ substring_t args[]) -+{ -+ int err; -+ aufs_bindex_t bend, bindex; -+ struct path path; -+ struct dentry *root; -+ -+ err = vfsub_kern_path(args[0].from, lkup_dirflags, &path); -+ if (unlikely(err)) { -+ pr_err("lookup failed %s (%d)\n", args[0].from, err); -+ goto out; -+ } -+ -+ xino_itrunc->bindex = -1; -+ root = sb->s_root; -+ aufs_read_lock(root, AuLock_FLUSH); -+ bend = au_sbend(sb); -+ for (bindex = 0; bindex <= bend; bindex++) { -+ if (au_h_dptr(root, bindex) == path.dentry) { -+ xino_itrunc->bindex = bindex; -+ break; -+ } -+ } -+ aufs_read_unlock(root, !AuLock_IR); -+ path_put(&path); -+ -+ if (unlikely(xino_itrunc->bindex < 0)) { -+ pr_err("no such branch %s\n", args[0].from); -+ err = -EINVAL; -+ } -+ -+ out: -+ return err; -+} -+ -+/* called without aufs lock */ -+int au_opts_parse(struct super_block *sb, char *str, struct au_opts *opts) -+{ -+ int err, n, token; -+ aufs_bindex_t bindex; -+ unsigned char skipped; -+ struct dentry *root; -+ struct au_opt *opt, *opt_tail; -+ char *opt_str; -+ /* reduce the stack space */ -+ union { -+ struct au_opt_xino_itrunc *xino_itrunc; -+ struct au_opt_wbr_create *create; -+ } u; -+ struct { -+ substring_t args[MAX_OPT_ARGS]; -+ } *a; -+ -+ err = -ENOMEM; -+ a = kmalloc(sizeof(*a), GFP_NOFS); -+ if (unlikely(!a)) -+ goto out; -+ -+ root = sb->s_root; -+ err = 0; -+ bindex = 0; -+ opt = opts->opt; -+ opt_tail = opt + opts->max_opt - 1; -+ opt->type = Opt_tail; -+ while (!err && (opt_str = strsep(&str, ",")) && *opt_str) { -+ err = -EINVAL; -+ skipped = 0; -+ token = match_token(opt_str, options, a->args); -+ switch (token) { -+ case Opt_br: -+ err = 0; -+ while (!err && (opt_str = strsep(&a->args[0].from, ":")) -+ && *opt_str) { -+ err = opt_add(opt, opt_str, opts->sb_flags, -+ bindex++); -+ if (unlikely(!err && ++opt > opt_tail)) { -+ err = -E2BIG; -+ break; -+ } -+ opt->type = Opt_tail; -+ skipped = 1; -+ } -+ break; -+ case Opt_add: -+ if (unlikely(match_int(&a->args[0], &n))) { -+ pr_err("bad integer in %s\n", opt_str); -+ break; -+ } -+ bindex = n; -+ err = opt_add(opt, a->args[1].from, opts->sb_flags, -+ bindex); -+ if (!err) -+ opt->type = token; -+ break; -+ case Opt_append: -+ err = opt_add(opt, a->args[0].from, opts->sb_flags, -+ /*dummy bindex*/1); -+ if (!err) -+ opt->type = token; -+ break; -+ case Opt_prepend: -+ err = opt_add(opt, a->args[0].from, opts->sb_flags, -+ /*bindex*/0); -+ if (!err) -+ opt->type = token; -+ break; -+ case Opt_del: -+ err = au_opts_parse_del(&opt->del, a->args); -+ if (!err) -+ opt->type = token; -+ break; -+#if 0 /* reserved for future use */ -+ case Opt_idel: -+ del->pathname = "(indexed)"; -+ if (unlikely(match_int(&args[0], &n))) { -+ pr_err("bad integer in %s\n", opt_str); -+ break; -+ } -+ err = au_opts_parse_idel(sb, n, &opt->del, a->args); -+ if (!err) -+ opt->type = token; -+ break; -+#endif -+ case Opt_mod: -+ err = au_opts_parse_mod(&opt->mod, a->args); -+ if (!err) -+ opt->type = token; -+ break; -+#ifdef IMOD /* reserved for future use */ -+ case Opt_imod: -+ u.mod->path = "(indexed)"; -+ if (unlikely(match_int(&a->args[0], &n))) { -+ pr_err("bad integer in %s\n", opt_str); -+ break; -+ } -+ err = au_opts_parse_imod(sb, n, &opt->mod, a->args); -+ if (!err) -+ opt->type = token; -+ break; -+#endif -+ case Opt_xino: -+ err = au_opts_parse_xino(sb, &opt->xino, a->args); -+ if (!err) -+ opt->type = token; -+ break; -+ -+ case Opt_trunc_xino_path: -+ err = au_opts_parse_xino_itrunc_path -+ (sb, &opt->xino_itrunc, a->args); -+ if (!err) -+ opt->type = token; -+ break; -+ -+ case Opt_itrunc_xino: -+ u.xino_itrunc = &opt->xino_itrunc; -+ if (unlikely(match_int(&a->args[0], &n))) { -+ pr_err("bad integer in %s\n", opt_str); -+ break; -+ } -+ u.xino_itrunc->bindex = n; -+ aufs_read_lock(root, AuLock_FLUSH); -+ if (n < 0 || au_sbend(sb) < n) { -+ pr_err("out of bounds, %d\n", n); -+ aufs_read_unlock(root, !AuLock_IR); -+ break; -+ } -+ aufs_read_unlock(root, !AuLock_IR); -+ err = 0; -+ opt->type = token; -+ break; -+ -+ case Opt_dirwh: -+ if (unlikely(match_int(&a->args[0], &opt->dirwh))) -+ break; -+ err = 0; -+ opt->type = token; -+ break; -+ -+ case Opt_rdcache: -+ if (unlikely(match_int(&a->args[0], &opt->rdcache))) -+ break; -+ err = 0; -+ opt->type = token; -+ break; -+ case Opt_rdblk: -+ if (unlikely(match_int(&a->args[0], &n) -+ || n < 0 -+ || n > KMALLOC_MAX_SIZE)) { -+ pr_err("bad integer in %s\n", opt_str); -+ break; -+ } -+ if (unlikely(n && n < NAME_MAX)) { -+ pr_err("rdblk must be larger than %d\n", -+ NAME_MAX); -+ break; -+ } -+ opt->rdblk = n; -+ err = 0; -+ opt->type = token; -+ break; -+ case Opt_rdhash: -+ if (unlikely(match_int(&a->args[0], &n) -+ || n < 0 -+ || n * sizeof(struct hlist_head) -+ > KMALLOC_MAX_SIZE)) { -+ pr_err("bad integer in %s\n", opt_str); -+ break; -+ } -+ opt->rdhash = n; -+ err = 0; -+ opt->type = token; -+ break; -+ -+ case Opt_trunc_xino: -+ case Opt_notrunc_xino: -+ case Opt_noxino: -+ case Opt_trunc_xib: -+ case Opt_notrunc_xib: -+ case Opt_shwh: -+ case Opt_noshwh: -+ case Opt_plink: -+ case Opt_noplink: -+ case Opt_list_plink: -+ case Opt_diropq_a: -+ case Opt_diropq_w: -+ case Opt_warn_perm: -+ case Opt_nowarn_perm: -+ case Opt_refrof: -+ case Opt_norefrof: -+ case Opt_verbose: -+ case Opt_noverbose: -+ case Opt_sum: -+ case Opt_nosum: -+ case Opt_wsum: -+ case Opt_rdblk_def: -+ case Opt_rdhash_def: -+ err = 0; -+ opt->type = token; -+ break; -+ -+ case Opt_udba: -+ opt->udba = udba_val(a->args[0].from); -+ if (opt->udba >= 0) { -+ err = 0; -+ opt->type = token; -+ } else -+ pr_err("wrong value, %s\n", opt_str); -+ break; -+ -+ case Opt_wbr_create: -+ u.create = &opt->wbr_create; -+ u.create->wbr_create -+ = au_wbr_create_val(a->args[0].from, u.create); -+ if (u.create->wbr_create >= 0) { -+ err = 0; -+ opt->type = token; -+ } else -+ pr_err("wrong value, %s\n", opt_str); -+ break; -+ case Opt_wbr_copyup: -+ opt->wbr_copyup = au_wbr_copyup_val(a->args[0].from); -+ if (opt->wbr_copyup >= 0) { -+ err = 0; -+ opt->type = token; -+ } else -+ pr_err("wrong value, %s\n", opt_str); -+ break; -+ -+ case Opt_ignore: -+ pr_warning("ignored %s\n", opt_str); -+ /*FALLTHROUGH*/ -+ case Opt_ignore_silent: -+ skipped = 1; -+ err = 0; -+ break; -+ case Opt_err: -+ pr_err("unknown option %s\n", opt_str); -+ break; -+ } -+ -+ if (!err && !skipped) { -+ if (unlikely(++opt > opt_tail)) { -+ err = -E2BIG; -+ opt--; -+ opt->type = Opt_tail; -+ break; -+ } -+ opt->type = Opt_tail; -+ } -+ } -+ -+ kfree(a); -+ dump_opts(opts); -+ if (unlikely(err)) -+ au_opts_free(opts); -+ -+ out: -+ return err; -+} -+ -+static int au_opt_wbr_create(struct super_block *sb, -+ struct au_opt_wbr_create *create) -+{ -+ int err; -+ struct au_sbinfo *sbinfo; -+ -+ SiMustWriteLock(sb); -+ -+ err = 1; /* handled */ -+ sbinfo = au_sbi(sb); -+ if (sbinfo->si_wbr_create_ops->fin) { -+ err = sbinfo->si_wbr_create_ops->fin(sb); -+ if (!err) -+ err = 1; -+ } -+ -+ sbinfo->si_wbr_create = create->wbr_create; -+ sbinfo->si_wbr_create_ops = au_wbr_create_ops + create->wbr_create; -+ switch (create->wbr_create) { -+ case AuWbrCreate_MFSRRV: -+ case AuWbrCreate_MFSRR: -+ sbinfo->si_wbr_mfs.mfsrr_watermark = create->mfsrr_watermark; -+ /*FALLTHROUGH*/ -+ case AuWbrCreate_MFS: -+ case AuWbrCreate_MFSV: -+ case AuWbrCreate_PMFS: -+ case AuWbrCreate_PMFSV: -+ sbinfo->si_wbr_mfs.mfs_expire = create->mfs_second * HZ; -+ break; -+ } -+ -+ if (sbinfo->si_wbr_create_ops->init) -+ sbinfo->si_wbr_create_ops->init(sb); /* ignore */ -+ -+ return err; -+} -+ -+/* -+ * returns, -+ * plus: processed without an error -+ * zero: unprocessed -+ */ -+static int au_opt_simple(struct super_block *sb, struct au_opt *opt, -+ struct au_opts *opts) -+{ -+ int err; -+ struct au_sbinfo *sbinfo; -+ -+ SiMustWriteLock(sb); -+ -+ err = 1; /* handled */ -+ sbinfo = au_sbi(sb); -+ switch (opt->type) { -+ case Opt_udba: -+ sbinfo->si_mntflags &= ~AuOptMask_UDBA; -+ sbinfo->si_mntflags |= opt->udba; -+ opts->given_udba |= opt->udba; -+ break; -+ -+ case Opt_plink: -+ au_opt_set(sbinfo->si_mntflags, PLINK); -+ break; -+ case Opt_noplink: -+ if (au_opt_test(sbinfo->si_mntflags, PLINK)) -+ au_plink_put(sb); -+ au_opt_clr(sbinfo->si_mntflags, PLINK); -+ break; -+ case Opt_list_plink: -+ if (au_opt_test(sbinfo->si_mntflags, PLINK)) -+ au_plink_list(sb); -+ break; -+ -+ case Opt_diropq_a: -+ au_opt_set(sbinfo->si_mntflags, ALWAYS_DIROPQ); -+ break; -+ case Opt_diropq_w: -+ au_opt_clr(sbinfo->si_mntflags, ALWAYS_DIROPQ); -+ break; -+ -+ case Opt_warn_perm: -+ au_opt_set(sbinfo->si_mntflags, WARN_PERM); -+ break; -+ case Opt_nowarn_perm: -+ au_opt_clr(sbinfo->si_mntflags, WARN_PERM); -+ break; -+ -+ case Opt_refrof: -+ au_opt_set(sbinfo->si_mntflags, REFROF); -+ break; -+ case Opt_norefrof: -+ au_opt_clr(sbinfo->si_mntflags, REFROF); -+ break; -+ -+ case Opt_verbose: -+ au_opt_set(sbinfo->si_mntflags, VERBOSE); -+ break; -+ case Opt_noverbose: -+ au_opt_clr(sbinfo->si_mntflags, VERBOSE); -+ break; -+ -+ case Opt_sum: -+ au_opt_set(sbinfo->si_mntflags, SUM); -+ break; -+ case Opt_wsum: -+ au_opt_clr(sbinfo->si_mntflags, SUM); -+ au_opt_set(sbinfo->si_mntflags, SUM_W); -+ case Opt_nosum: -+ au_opt_clr(sbinfo->si_mntflags, SUM); -+ au_opt_clr(sbinfo->si_mntflags, SUM_W); -+ break; -+ -+ case Opt_wbr_create: -+ err = au_opt_wbr_create(sb, &opt->wbr_create); -+ break; -+ case Opt_wbr_copyup: -+ sbinfo->si_wbr_copyup = opt->wbr_copyup; -+ sbinfo->si_wbr_copyup_ops = au_wbr_copyup_ops + opt->wbr_copyup; -+ break; -+ -+ case Opt_dirwh: -+ sbinfo->si_dirwh = opt->dirwh; -+ break; -+ -+ case Opt_rdcache: -+ sbinfo->si_rdcache = opt->rdcache * HZ; -+ break; -+ case Opt_rdblk: -+ sbinfo->si_rdblk = opt->rdblk; -+ break; -+ case Opt_rdblk_def: -+ sbinfo->si_rdblk = AUFS_RDBLK_DEF; -+ break; -+ case Opt_rdhash: -+ sbinfo->si_rdhash = opt->rdhash; -+ break; -+ case Opt_rdhash_def: -+ sbinfo->si_rdhash = AUFS_RDHASH_DEF; -+ break; -+ -+ case Opt_shwh: -+ au_opt_set(sbinfo->si_mntflags, SHWH); -+ break; -+ case Opt_noshwh: -+ au_opt_clr(sbinfo->si_mntflags, SHWH); -+ break; -+ -+ case Opt_trunc_xino: -+ au_opt_set(sbinfo->si_mntflags, TRUNC_XINO); -+ break; -+ case Opt_notrunc_xino: -+ au_opt_clr(sbinfo->si_mntflags, TRUNC_XINO); -+ break; -+ -+ case Opt_trunc_xino_path: -+ case Opt_itrunc_xino: -+ err = au_xino_trunc(sb, opt->xino_itrunc.bindex); -+ if (!err) -+ err = 1; -+ break; -+ -+ case Opt_trunc_xib: -+ au_fset_opts(opts->flags, TRUNC_XIB); -+ break; -+ case Opt_notrunc_xib: -+ au_fclr_opts(opts->flags, TRUNC_XIB); -+ break; -+ -+ default: -+ err = 0; -+ break; -+ } -+ -+ return err; -+} -+ -+/* -+ * returns tri-state. -+ * plus: processed without an error -+ * zero: unprocessed -+ * minus: error -+ */ -+static int au_opt_br(struct super_block *sb, struct au_opt *opt, -+ struct au_opts *opts) -+{ -+ int err, do_refresh; -+ -+ err = 0; -+ switch (opt->type) { -+ case Opt_append: -+ opt->add.bindex = au_sbend(sb) + 1; -+ if (opt->add.bindex < 0) -+ opt->add.bindex = 0; -+ goto add; -+ case Opt_prepend: -+ opt->add.bindex = 0; -+ add: -+ case Opt_add: -+ err = au_br_add(sb, &opt->add, -+ au_ftest_opts(opts->flags, REMOUNT)); -+ if (!err) { -+ err = 1; -+ au_fset_opts(opts->flags, REFRESH_DIR); -+ if (au_br_whable(opt->add.perm)) -+ au_fset_opts(opts->flags, REFRESH_NONDIR); -+ } -+ break; -+ -+ case Opt_del: -+ case Opt_idel: -+ err = au_br_del(sb, &opt->del, -+ au_ftest_opts(opts->flags, REMOUNT)); -+ if (!err) { -+ err = 1; -+ au_fset_opts(opts->flags, TRUNC_XIB); -+ au_fset_opts(opts->flags, REFRESH_DIR); -+ au_fset_opts(opts->flags, REFRESH_NONDIR); -+ } -+ break; -+ -+ case Opt_mod: -+ case Opt_imod: -+ err = au_br_mod(sb, &opt->mod, -+ au_ftest_opts(opts->flags, REMOUNT), -+ &do_refresh); -+ if (!err) { -+ err = 1; -+ if (do_refresh) { -+ au_fset_opts(opts->flags, REFRESH_DIR); -+ au_fset_opts(opts->flags, REFRESH_NONDIR); -+ } -+ } -+ break; -+ } -+ -+ return err; -+} -+ -+static int au_opt_xino(struct super_block *sb, struct au_opt *opt, -+ struct au_opt_xino **opt_xino, -+ struct au_opts *opts) -+{ -+ int err; -+ aufs_bindex_t bend, bindex; -+ struct dentry *root, *parent, *h_root; -+ -+ err = 0; -+ switch (opt->type) { -+ case Opt_xino: -+ err = au_xino_set(sb, &opt->xino, -+ !!au_ftest_opts(opts->flags, REMOUNT)); -+ if (unlikely(err)) -+ break; -+ -+ *opt_xino = &opt->xino; -+ au_xino_brid_set(sb, -1); -+ -+ /* safe d_parent access */ -+ parent = opt->xino.file->f_dentry->d_parent; -+ root = sb->s_root; -+ bend = au_sbend(sb); -+ for (bindex = 0; bindex <= bend; bindex++) { -+ h_root = au_h_dptr(root, bindex); -+ if (h_root == parent) { -+ au_xino_brid_set(sb, au_sbr_id(sb, bindex)); -+ break; -+ } -+ } -+ break; -+ -+ case Opt_noxino: -+ au_xino_clr(sb); -+ au_xino_brid_set(sb, -1); -+ *opt_xino = (void *)-1; -+ break; -+ } -+ -+ return err; -+} -+ -+int au_opts_verify(struct super_block *sb, unsigned long sb_flags, -+ unsigned int pending) -+{ -+ int err; -+ aufs_bindex_t bindex, bend; -+ unsigned char do_plink, skip, do_free; -+ struct au_branch *br; -+ struct au_wbr *wbr; -+ struct dentry *root; -+ struct inode *dir, *h_dir; -+ struct au_sbinfo *sbinfo; -+ struct au_hinode *hdir; -+ -+ SiMustAnyLock(sb); -+ -+ sbinfo = au_sbi(sb); -+ AuDebugOn(!(sbinfo->si_mntflags & AuOptMask_UDBA)); -+ -+ if (!(sb_flags & MS_RDONLY)) { -+ if (unlikely(!au_br_writable(au_sbr_perm(sb, 0)))) -+ pr_warning("first branch should be rw\n"); -+ if (unlikely(au_opt_test(sbinfo->si_mntflags, SHWH))) -+ pr_warning("shwh should be used with ro\n"); -+ } -+ -+ if (au_opt_test((sbinfo->si_mntflags | pending), UDBA_HINOTIFY) -+ && !au_opt_test(sbinfo->si_mntflags, XINO)) -+ pr_warning("udba=inotify requires xino\n"); -+ -+ err = 0; -+ root = sb->s_root; -+ dir = sb->s_root->d_inode; -+ do_plink = !!au_opt_test(sbinfo->si_mntflags, PLINK); -+ bend = au_sbend(sb); -+ for (bindex = 0; !err && bindex <= bend; bindex++) { -+ skip = 0; -+ h_dir = au_h_iptr(dir, bindex); -+ br = au_sbr(sb, bindex); -+ do_free = 0; -+ -+ wbr = br->br_wbr; -+ if (wbr) -+ wbr_wh_read_lock(wbr); -+ -+ switch (br->br_perm) { -+ case AuBrPerm_RO: -+ case AuBrPerm_ROWH: -+ case AuBrPerm_RR: -+ case AuBrPerm_RRWH: -+ do_free = !!wbr; -+ skip = (!wbr -+ || (!wbr->wbr_whbase -+ && !wbr->wbr_plink -+ && !wbr->wbr_orph)); -+ break; -+ -+ case AuBrPerm_RWNoLinkWH: -+ /* skip = (!br->br_whbase && !br->br_orph); */ -+ skip = (!wbr || !wbr->wbr_whbase); -+ if (skip && wbr) { -+ if (do_plink) -+ skip = !!wbr->wbr_plink; -+ else -+ skip = !wbr->wbr_plink; -+ } -+ break; -+ -+ case AuBrPerm_RW: -+ /* skip = (br->br_whbase && br->br_ohph); */ -+ skip = (wbr && wbr->wbr_whbase); -+ if (skip) { -+ if (do_plink) -+ skip = !!wbr->wbr_plink; -+ else -+ skip = !wbr->wbr_plink; -+ } -+ break; -+ -+ default: -+ BUG(); -+ } -+ if (wbr) -+ wbr_wh_read_unlock(wbr); -+ -+ if (skip) -+ continue; -+ -+ hdir = au_hi(dir, bindex); -+ au_hin_imtx_lock_nested(hdir, AuLsc_I_PARENT); -+ if (wbr) -+ wbr_wh_write_lock(wbr); -+ err = au_wh_init(au_h_dptr(root, bindex), br, sb); -+ if (wbr) -+ wbr_wh_write_unlock(wbr); -+ au_hin_imtx_unlock(hdir); -+ -+ if (!err && do_free) { -+ kfree(wbr); -+ br->br_wbr = NULL; -+ } -+ } -+ -+ return err; -+} -+ -+int au_opts_mount(struct super_block *sb, struct au_opts *opts) -+{ -+ int err; -+ unsigned int tmp; -+ aufs_bindex_t bend; -+ struct au_opt *opt; -+ struct au_opt_xino *opt_xino, xino; -+ struct au_sbinfo *sbinfo; -+ -+ SiMustWriteLock(sb); -+ -+ err = 0; -+ opt_xino = NULL; -+ opt = opts->opt; -+ while (err >= 0 && opt->type != Opt_tail) -+ err = au_opt_simple(sb, opt++, opts); -+ if (err > 0) -+ err = 0; -+ else if (unlikely(err < 0)) -+ goto out; -+ -+ /* disable xino and udba temporary */ -+ sbinfo = au_sbi(sb); -+ tmp = sbinfo->si_mntflags; -+ au_opt_clr(sbinfo->si_mntflags, XINO); -+ au_opt_set_udba(sbinfo->si_mntflags, UDBA_REVAL); -+ -+ opt = opts->opt; -+ while (err >= 0 && opt->type != Opt_tail) -+ err = au_opt_br(sb, opt++, opts); -+ if (err > 0) -+ err = 0; -+ else if (unlikely(err < 0)) -+ goto out; -+ -+ bend = au_sbend(sb); -+ if (unlikely(bend < 0)) { -+ err = -EINVAL; -+ pr_err("no branches\n"); -+ goto out; -+ } -+ -+ if (au_opt_test(tmp, XINO)) -+ au_opt_set(sbinfo->si_mntflags, XINO); -+ opt = opts->opt; -+ while (!err && opt->type != Opt_tail) -+ err = au_opt_xino(sb, opt++, &opt_xino, opts); -+ if (unlikely(err)) -+ goto out; -+ -+ err = au_opts_verify(sb, sb->s_flags, tmp); -+ if (unlikely(err)) -+ goto out; -+ -+ /* restore xino */ -+ if (au_opt_test(tmp, XINO) && !opt_xino) { -+ xino.file = au_xino_def(sb); -+ err = PTR_ERR(xino.file); -+ if (IS_ERR(xino.file)) -+ goto out; -+ -+ err = au_xino_set(sb, &xino, /*remount*/0); -+ fput(xino.file); -+ if (unlikely(err)) -+ goto out; -+ } -+ -+ /* restore udba */ -+ sbinfo->si_mntflags &= ~AuOptMask_UDBA; -+ sbinfo->si_mntflags |= (tmp & AuOptMask_UDBA); -+ if (au_opt_test(tmp, UDBA_HINOTIFY)) { -+ struct inode *dir = sb->s_root->d_inode; -+ au_reset_hinotify(dir, -+ au_hi_flags(dir, /*isdir*/1) & ~AuHi_XINO); -+ } -+ -+ out: -+ return err; -+} -+ -+int au_opts_remount(struct super_block *sb, struct au_opts *opts) -+{ -+ int err, rerr; -+ struct inode *dir; -+ struct au_opt_xino *opt_xino; -+ struct au_opt *opt; -+ struct au_sbinfo *sbinfo; -+ -+ SiMustWriteLock(sb); -+ -+ dir = sb->s_root->d_inode; -+ sbinfo = au_sbi(sb); -+ err = 0; -+ opt_xino = NULL; -+ opt = opts->opt; -+ while (err >= 0 && opt->type != Opt_tail) { -+ err = au_opt_simple(sb, opt, opts); -+ if (!err) -+ err = au_opt_br(sb, opt, opts); -+ if (!err) -+ err = au_opt_xino(sb, opt, &opt_xino, opts); -+ opt++; -+ } -+ if (err > 0) -+ err = 0; -+ AuTraceErr(err); -+ /* go on even err */ -+ -+ rerr = au_opts_verify(sb, opts->sb_flags, /*pending*/0); -+ if (unlikely(rerr && !err)) -+ err = rerr; -+ -+ if (au_ftest_opts(opts->flags, TRUNC_XIB)) { -+ rerr = au_xib_trunc(sb); -+ if (unlikely(rerr && !err)) -+ err = rerr; -+ } -+ -+ /* will be handled by the caller */ -+ if (!au_ftest_opts(opts->flags, REFRESH_DIR) -+ && (opts->given_udba || au_opt_test(sbinfo->si_mntflags, XINO))) -+ au_fset_opts(opts->flags, REFRESH_DIR); -+ -+ AuDbg("status 0x%x\n", opts->flags); -+ return err; -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+unsigned int au_opt_udba(struct super_block *sb) -+{ -+ return au_mntflags(sb) & AuOptMask_UDBA; -+} -diff --git a/fs/aufs/opts.h b/fs/aufs/opts.h -new file mode 100644 -index 0000000..27439b1 ---- /dev/null -+++ b/fs/aufs/opts.h -@@ -0,0 +1,196 @@ -+/* -+ * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * -+ * This program, aufs is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ */ -+ -+/* -+ * mount options/flags -+ */ -+ -+#ifndef __AUFS_OPTS_H__ -+#define __AUFS_OPTS_H__ -+ -+#ifdef __KERNEL__ -+ -+#include -+#include -+ -+struct file; -+struct super_block; -+ -+/* ---------------------------------------------------------------------- */ -+ -+/* mount flags */ -+#define AuOpt_XINO 1 /* external inode number bitmap -+ and translation table */ -+#define AuOpt_TRUNC_XINO (1 << 1) /* truncate xino files */ -+#define AuOpt_UDBA_NONE (1 << 2) /* users direct branch access */ -+#define AuOpt_UDBA_REVAL (1 << 3) -+#define AuOpt_UDBA_HINOTIFY (1 << 4) -+#define AuOpt_SHWH (1 << 5) /* show whiteout */ -+#define AuOpt_PLINK (1 << 6) /* pseudo-link */ -+#define AuOpt_DIRPERM1 (1 << 7) /* unimplemented */ -+#define AuOpt_REFROF (1 << 8) /* unimplemented */ -+#define AuOpt_ALWAYS_DIROPQ (1 << 9) /* policy to creating diropq */ -+#define AuOpt_SUM (1 << 10) /* summation for statfs(2) */ -+#define AuOpt_SUM_W (1 << 11) /* unimplemented */ -+#define AuOpt_WARN_PERM (1 << 12) /* warn when add-branch */ -+#define AuOpt_VERBOSE (1 << 13) /* busy inode when del-branch */ -+ -+#ifndef CONFIG_AUFS_HINOTIFY -+#undef AuOpt_UDBA_HINOTIFY -+#define AuOpt_UDBA_HINOTIFY 0 -+#endif -+#ifndef CONFIG_AUFS_SHWH -+#undef AuOpt_SHWH -+#define AuOpt_SHWH 0 -+#endif -+ -+#define AuOpt_Def (AuOpt_XINO \ -+ | AuOpt_UDBA_REVAL \ -+ | AuOpt_PLINK \ -+ /* | AuOpt_DIRPERM1 */ \ -+ | AuOpt_WARN_PERM) -+#define AuOptMask_UDBA (AuOpt_UDBA_NONE \ -+ | AuOpt_UDBA_REVAL \ -+ | AuOpt_UDBA_HINOTIFY) -+ -+#define au_opt_test(flags, name) (flags & AuOpt_##name) -+#define au_opt_set(flags, name) do { \ -+ BUILD_BUG_ON(AuOpt_##name & AuOptMask_UDBA); \ -+ ((flags) |= AuOpt_##name); \ -+} while (0) -+#define au_opt_set_udba(flags, name) do { \ -+ (flags) &= ~AuOptMask_UDBA; \ -+ ((flags) |= AuOpt_##name); \ -+} while (0) -+#define au_opt_clr(flags, name) { ((flags) &= ~AuOpt_##name); } -+ -+/* ---------------------------------------------------------------------- */ -+ -+/* policies to select one among multiple writable branches */ -+enum { -+ AuWbrCreate_TDP, /* top down parent */ -+ AuWbrCreate_RR, /* round robin */ -+ AuWbrCreate_MFS, /* most free space */ -+ AuWbrCreate_MFSV, /* mfs with seconds */ -+ AuWbrCreate_MFSRR, /* mfs then rr */ -+ AuWbrCreate_MFSRRV, /* mfs then rr with seconds */ -+ AuWbrCreate_PMFS, /* parent and mfs */ -+ AuWbrCreate_PMFSV, /* parent and mfs with seconds */ -+ -+ AuWbrCreate_Def = AuWbrCreate_TDP -+}; -+ -+enum { -+ AuWbrCopyup_TDP, /* top down parent */ -+ AuWbrCopyup_BUP, /* bottom up parent */ -+ AuWbrCopyup_BU, /* bottom up */ -+ -+ AuWbrCopyup_Def = AuWbrCopyup_TDP -+}; -+ -+/* ---------------------------------------------------------------------- */ -+ -+struct au_opt_add { -+ aufs_bindex_t bindex; -+ char *pathname; -+ int perm; -+ struct path path; -+}; -+ -+struct au_opt_del { -+ char *pathname; -+ struct path h_path; -+}; -+ -+struct au_opt_mod { -+ char *path; -+ int perm; -+ struct dentry *h_root; -+}; -+ -+struct au_opt_xino { -+ char *path; -+ struct file *file; -+}; -+ -+struct au_opt_xino_itrunc { -+ aufs_bindex_t bindex; -+}; -+ -+struct au_opt_wbr_create { -+ int wbr_create; -+ int mfs_second; -+ unsigned long long mfsrr_watermark; -+}; -+ -+struct au_opt { -+ int type; -+ union { -+ struct au_opt_xino xino; -+ struct au_opt_xino_itrunc xino_itrunc; -+ struct au_opt_add add; -+ struct au_opt_del del; -+ struct au_opt_mod mod; -+ int dirwh; -+ int rdcache; -+ unsigned int rdblk; -+ unsigned int rdhash; -+ int udba; -+ struct au_opt_wbr_create wbr_create; -+ int wbr_copyup; -+ }; -+}; -+ -+/* opts flags */ -+#define AuOpts_REMOUNT 1 -+#define AuOpts_REFRESH_DIR (1 << 1) -+#define AuOpts_REFRESH_NONDIR (1 << 2) -+#define AuOpts_TRUNC_XIB (1 << 3) -+#define au_ftest_opts(flags, name) ((flags) & AuOpts_##name) -+#define au_fset_opts(flags, name) { (flags) |= AuOpts_##name; } -+#define au_fclr_opts(flags, name) { (flags) &= ~AuOpts_##name; } -+ -+struct au_opts { -+ struct au_opt *opt; -+ int max_opt; -+ -+ unsigned int given_udba; -+ unsigned int flags; -+ unsigned long sb_flags; -+}; -+ -+/* ---------------------------------------------------------------------- */ -+ -+const char *au_optstr_br_perm(int brperm); -+const char *au_optstr_udba(int udba); -+const char *au_optstr_wbr_copyup(int wbr_copyup); -+const char *au_optstr_wbr_create(int wbr_create); -+ -+void au_opts_free(struct au_opts *opts); -+int au_opts_parse(struct super_block *sb, char *str, struct au_opts *opts); -+int au_opts_verify(struct super_block *sb, unsigned long sb_flags, -+ unsigned int pending); -+int au_opts_mount(struct super_block *sb, struct au_opts *opts); -+int au_opts_remount(struct super_block *sb, struct au_opts *opts); -+ -+unsigned int au_opt_udba(struct super_block *sb); -+ -+/* ---------------------------------------------------------------------- */ -+ -+#endif /* __KERNEL__ */ -+#endif /* __AUFS_OPTS_H__ */ -diff --git a/fs/aufs/plink.c b/fs/aufs/plink.c -new file mode 100644 -index 0000000..074f143 ---- /dev/null -+++ b/fs/aufs/plink.c -@@ -0,0 +1,396 @@ -+/* -+ * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * -+ * This program, aufs is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ */ -+ -+/* -+ * pseudo-link -+ */ -+ -+#include "aufs.h" -+ -+/* -+ * during a user process maintains the pseudo-links, -+ * prohibit adding a new plink and branch manipulation. -+ */ -+void au_plink_block_maintain(struct super_block *sb) -+{ -+ struct au_sbinfo *sbi = au_sbi(sb); -+ -+ SiMustAnyLock(sb); -+ -+ /* gave up wake_up_bit() */ -+ wait_event(sbi->si_plink_wq, !au_ftest_si(sbi, MAINTAIN_PLINK)); -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+struct pseudo_link { -+ struct list_head list; -+ struct inode *inode; -+}; -+ -+#ifdef CONFIG_AUFS_DEBUG -+void au_plink_list(struct super_block *sb) -+{ -+ struct au_sbinfo *sbinfo; -+ struct list_head *plink_list; -+ struct pseudo_link *plink; -+ -+ SiMustAnyLock(sb); -+ -+ sbinfo = au_sbi(sb); -+ AuDebugOn(!au_opt_test(au_mntflags(sb), PLINK)); -+ -+ plink_list = &sbinfo->si_plink.head; -+ spin_lock(&sbinfo->si_plink.spin); -+ list_for_each_entry(plink, plink_list, list) -+ AuDbg("%lu\n", plink->inode->i_ino); -+ spin_unlock(&sbinfo->si_plink.spin); -+} -+#endif -+ -+/* is the inode pseudo-linked? */ -+int au_plink_test(struct inode *inode) -+{ -+ int found; -+ struct au_sbinfo *sbinfo; -+ struct list_head *plink_list; -+ struct pseudo_link *plink; -+ -+ sbinfo = au_sbi(inode->i_sb); -+ AuRwMustAnyLock(&sbinfo->si_rwsem); -+ AuDebugOn(!au_opt_test(au_mntflags(inode->i_sb), PLINK)); -+ -+ found = 0; -+ plink_list = &sbinfo->si_plink.head; -+ spin_lock(&sbinfo->si_plink.spin); -+ list_for_each_entry(plink, plink_list, list) -+ if (plink->inode == inode) { -+ found = 1; -+ break; -+ } -+ spin_unlock(&sbinfo->si_plink.spin); -+ return found; -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+/* -+ * generate a name for plink. -+ * the file will be stored under AUFS_WH_PLINKDIR. -+ */ -+/* 20 is max digits length of ulong 64 */ -+#define PLINK_NAME_LEN ((20 + 1) * 2) -+ -+static int plink_name(char *name, int len, struct inode *inode, -+ aufs_bindex_t bindex) -+{ -+ int rlen; -+ struct inode *h_inode; -+ -+ h_inode = au_h_iptr(inode, bindex); -+ rlen = snprintf(name, len, "%lu.%lu", inode->i_ino, h_inode->i_ino); -+ return rlen; -+} -+ -+/* lookup the plink-ed @inode under the branch at @bindex */ -+struct dentry *au_plink_lkup(struct inode *inode, aufs_bindex_t bindex) -+{ -+ struct dentry *h_dentry, *h_parent; -+ struct au_branch *br; -+ struct inode *h_dir; -+ char a[PLINK_NAME_LEN]; -+ struct qstr tgtname = { -+ .name = a -+ }; -+ -+ br = au_sbr(inode->i_sb, bindex); -+ h_parent = br->br_wbr->wbr_plink; -+ h_dir = h_parent->d_inode; -+ tgtname.len = plink_name(a, sizeof(a), inode, bindex); -+ -+ /* always superio. */ -+ mutex_lock_nested(&h_dir->i_mutex, AuLsc_I_CHILD2); -+ h_dentry = au_sio_lkup_one(&tgtname, h_parent, br); -+ mutex_unlock(&h_dir->i_mutex); -+ return h_dentry; -+} -+ -+/* create a pseudo-link */ -+static int do_whplink(struct qstr *tgt, struct dentry *h_parent, -+ struct dentry *h_dentry, struct au_branch *br) -+{ -+ int err; -+ struct path h_path = { -+ .mnt = br->br_mnt -+ }; -+ struct inode *h_dir; -+ -+ h_dir = h_parent->d_inode; -+ again: -+ h_path.dentry = au_lkup_one(tgt, h_parent, br, /*nd*/NULL); -+ err = PTR_ERR(h_path.dentry); -+ if (IS_ERR(h_path.dentry)) -+ goto out; -+ -+ err = 0; -+ /* wh.plink dir is not monitored */ -+ if (h_path.dentry->d_inode -+ && h_path.dentry->d_inode != h_dentry->d_inode) { -+ err = vfsub_unlink(h_dir, &h_path, /*force*/0); -+ dput(h_path.dentry); -+ h_path.dentry = NULL; -+ if (!err) -+ goto again; -+ } -+ if (!err && !h_path.dentry->d_inode) -+ err = vfsub_link(h_dentry, h_dir, &h_path); -+ dput(h_path.dentry); -+ -+ out: -+ return err; -+} -+ -+struct do_whplink_args { -+ int *errp; -+ struct qstr *tgt; -+ struct dentry *h_parent; -+ struct dentry *h_dentry; -+ struct au_branch *br; -+}; -+ -+static void call_do_whplink(void *args) -+{ -+ struct do_whplink_args *a = args; -+ *a->errp = do_whplink(a->tgt, a->h_parent, a->h_dentry, a->br); -+} -+ -+static int whplink(struct dentry *h_dentry, struct inode *inode, -+ aufs_bindex_t bindex, struct au_branch *br) -+{ -+ int err, wkq_err; -+ struct au_wbr *wbr; -+ struct dentry *h_parent; -+ struct inode *h_dir; -+ char a[PLINK_NAME_LEN]; -+ struct qstr tgtname = { -+ .name = a -+ }; -+ -+ wbr = au_sbr(inode->i_sb, bindex)->br_wbr; -+ h_parent = wbr->wbr_plink; -+ h_dir = h_parent->d_inode; -+ tgtname.len = plink_name(a, sizeof(a), inode, bindex); -+ -+ /* always superio. */ -+ mutex_lock_nested(&h_dir->i_mutex, AuLsc_I_CHILD2); -+ if (!au_test_wkq(current)) { -+ struct do_whplink_args args = { -+ .errp = &err, -+ .tgt = &tgtname, -+ .h_parent = h_parent, -+ .h_dentry = h_dentry, -+ .br = br -+ }; -+ wkq_err = au_wkq_wait(call_do_whplink, &args); -+ if (unlikely(wkq_err)) -+ err = wkq_err; -+ } else -+ err = do_whplink(&tgtname, h_parent, h_dentry, br); -+ mutex_unlock(&h_dir->i_mutex); -+ -+ return err; -+} -+ -+/* free a single plink */ -+static void do_put_plink(struct pseudo_link *plink, int do_del) -+{ -+ iput(plink->inode); -+ if (do_del) -+ list_del(&plink->list); -+ kfree(plink); -+} -+ -+/* -+ * create a new pseudo-link for @h_dentry on @bindex. -+ * the linked inode is held in aufs @inode. -+ */ -+void au_plink_append(struct inode *inode, aufs_bindex_t bindex, -+ struct dentry *h_dentry) -+{ -+ struct super_block *sb; -+ struct au_sbinfo *sbinfo; -+ struct list_head *plink_list; -+ struct pseudo_link *plink; -+ int found, err, cnt; -+ -+ sb = inode->i_sb; -+ sbinfo = au_sbi(sb); -+ AuDebugOn(!au_opt_test(au_mntflags(sb), PLINK)); -+ -+ err = 0; -+ cnt = 0; -+ found = 0; -+ plink_list = &sbinfo->si_plink.head; -+ spin_lock(&sbinfo->si_plink.spin); -+ list_for_each_entry(plink, plink_list, list) { -+ cnt++; -+ if (plink->inode == inode) { -+ found = 1; -+ break; -+ } -+ } -+ if (found) { -+ spin_unlock(&sbinfo->si_plink.spin); -+ return; -+ } -+ -+ plink = NULL; -+ if (!found) { -+ plink = kmalloc(sizeof(*plink), GFP_ATOMIC); -+ if (plink) { -+ plink->inode = au_igrab(inode); -+ list_add(&plink->list, plink_list); -+ cnt++; -+ } else -+ err = -ENOMEM; -+ } -+ spin_unlock(&sbinfo->si_plink.spin); -+ -+ if (!err) { -+ au_plink_block_maintain(sb); -+ err = whplink(h_dentry, inode, bindex, au_sbr(sb, bindex)); -+ } -+ -+ if (unlikely(cnt > AUFS_PLINK_WARN)) -+ AuWarn1("unexpectedly many pseudo links, %d\n", cnt); -+ if (unlikely(err)) { -+ pr_warning("err %d, damaged pseudo link.\n", err); -+ if (!found && plink) -+ do_put_plink(plink, /*do_del*/1); -+ } -+} -+ -+/* free all plinks */ -+void au_plink_put(struct super_block *sb) -+{ -+ struct au_sbinfo *sbinfo; -+ struct list_head *plink_list; -+ struct pseudo_link *plink, *tmp; -+ -+ SiMustWriteLock(sb); -+ -+ sbinfo = au_sbi(sb); -+ AuDebugOn(!au_opt_test(au_mntflags(sb), PLINK)); -+ -+ plink_list = &sbinfo->si_plink.head; -+ /* no spin_lock since sbinfo is write-locked */ -+ list_for_each_entry_safe(plink, tmp, plink_list, list) -+ do_put_plink(plink, 0); -+ INIT_LIST_HEAD(plink_list); -+} -+ -+/* free the plinks on a branch specified by @br_id */ -+void au_plink_half_refresh(struct super_block *sb, aufs_bindex_t br_id) -+{ -+ struct au_sbinfo *sbinfo; -+ struct list_head *plink_list; -+ struct pseudo_link *plink, *tmp; -+ struct inode *inode; -+ aufs_bindex_t bstart, bend, bindex; -+ unsigned char do_put; -+ -+ SiMustWriteLock(sb); -+ -+ sbinfo = au_sbi(sb); -+ AuDebugOn(!au_opt_test(au_mntflags(sb), PLINK)); -+ -+ plink_list = &sbinfo->si_plink.head; -+ /* no spin_lock since sbinfo is write-locked */ -+ list_for_each_entry_safe(plink, tmp, plink_list, list) { -+ do_put = 0; -+ inode = au_igrab(plink->inode); -+ ii_write_lock_child(inode); -+ bstart = au_ibstart(inode); -+ bend = au_ibend(inode); -+ if (bstart >= 0) { -+ for (bindex = bstart; bindex <= bend; bindex++) { -+ if (!au_h_iptr(inode, bindex) -+ || au_ii_br_id(inode, bindex) != br_id) -+ continue; -+ au_set_h_iptr(inode, bindex, NULL, 0); -+ do_put = 1; -+ break; -+ } -+ } else -+ do_put_plink(plink, 1); -+ -+ if (do_put) { -+ for (bindex = bstart; bindex <= bend; bindex++) -+ if (au_h_iptr(inode, bindex)) { -+ do_put = 0; -+ break; -+ } -+ if (do_put) -+ do_put_plink(plink, 1); -+ } -+ ii_write_unlock(inode); -+ iput(inode); -+ } -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+long au_plink_ioctl(struct file *file, unsigned int cmd) -+{ -+ long err; -+ struct super_block *sb; -+ struct au_sbinfo *sbinfo; -+ -+ err = -EACCES; -+ if (!capable(CAP_SYS_ADMIN)) -+ goto out; -+ -+ err = 0; -+ sb = file->f_dentry->d_sb; -+ sbinfo = au_sbi(sb); -+ switch (cmd) { -+ case AUFS_CTL_PLINK_MAINT: -+ /* -+ * pseudo-link maintenance mode, -+ * cleared by aufs_release_dir() -+ */ -+ si_write_lock(sb); -+ if (!au_ftest_si(sbinfo, MAINTAIN_PLINK)) { -+ au_fset_si(sbinfo, MAINTAIN_PLINK); -+ au_fi(file)->fi_maintain_plink = 1; -+ } else -+ err = -EBUSY; -+ si_write_unlock(sb); -+ break; -+ case AUFS_CTL_PLINK_CLEAN: -+ aufs_write_lock(sb->s_root); -+ if (au_opt_test(sbinfo->si_mntflags, PLINK)) -+ au_plink_put(sb); -+ aufs_write_unlock(sb->s_root); -+ break; -+ default: -+ err = -EINVAL; -+ } -+ out: -+ return err; -+} -diff --git a/fs/aufs/poll.c b/fs/aufs/poll.c -new file mode 100644 -index 0000000..1a1ddae ---- /dev/null -+++ b/fs/aufs/poll.c -@@ -0,0 +1,56 @@ -+/* -+ * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * -+ * This program, aufs is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ */ -+ -+/* -+ * poll operation -+ * There is only one filesystem which implements ->poll operation, currently. -+ */ -+ -+#include "aufs.h" -+ -+unsigned int aufs_poll(struct file *file, poll_table *wait) -+{ -+ unsigned int mask; -+ int err; -+ struct file *h_file; -+ struct dentry *dentry; -+ struct super_block *sb; -+ -+ /* We should pretend an error happened. */ -+ mask = POLLERR /* | POLLIN | POLLOUT */; -+ dentry = file->f_dentry; -+ sb = dentry->d_sb; -+ si_read_lock(sb, AuLock_FLUSH); -+ err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/0); -+ if (unlikely(err)) -+ goto out; -+ -+ /* it is not an error if h_file has no operation */ -+ mask = DEFAULT_POLLMASK; -+ h_file = au_h_fptr(file, au_fbstart(file)); -+ if (h_file->f_op && h_file->f_op->poll) -+ mask = h_file->f_op->poll(h_file, wait); -+ -+ di_read_unlock(dentry, AuLock_IR); -+ fi_read_unlock(file); -+ -+ out: -+ si_read_unlock(sb); -+ AuTraceErr((int)mask); -+ return mask; -+} -diff --git a/fs/aufs/rdu.c b/fs/aufs/rdu.c -new file mode 100644 -index 0000000..0a224f4 ---- /dev/null -+++ b/fs/aufs/rdu.c -@@ -0,0 +1,331 @@ -+/* -+ * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * -+ * This program, aufs is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ */ -+ -+/* -+ * readdir in userspace. -+ */ -+ -+#include -+#include -+#include -+#include "aufs.h" -+ -+/* bits for struct aufs_rdu.flags */ -+#define AuRdu_CALLED 1 -+#define AuRdu_CONT (1 << 1) -+#define AuRdu_FULL (1 << 2) -+#define au_ftest_rdu(flags, name) ((flags) & AuRdu_##name) -+#define au_fset_rdu(flags, name) { (flags) |= AuRdu_##name; } -+#define au_fclr_rdu(flags, name) { (flags) &= ~AuRdu_##name; } -+ -+struct au_rdu_arg { -+ struct aufs_rdu *rdu; -+ union au_rdu_ent_ul ent; -+ unsigned long end; -+ -+ struct super_block *sb; -+ int err; -+}; -+ -+static int au_rdu_fill(void *__arg, const char *name, int nlen, -+ loff_t offset, u64 h_ino, unsigned int d_type) -+{ -+ int err, len; -+ struct au_rdu_arg *arg = __arg; -+ struct aufs_rdu *rdu = arg->rdu; -+ struct au_rdu_ent ent; -+ -+ err = 0; -+ arg->err = 0; -+ au_fset_rdu(rdu->cookie.flags, CALLED); -+ len = au_rdu_len(nlen); -+ if (arg->ent.ul + len < arg->end) { -+ ent.ino = h_ino; -+ ent.bindex = rdu->cookie.bindex; -+ ent.type = d_type; -+ ent.nlen = nlen; -+ -+ err = -EFAULT; -+ if (copy_to_user(arg->ent.e, &ent, sizeof(ent))) -+ goto out; -+ if (copy_to_user(arg->ent.e->name, name, nlen)) -+ goto out; -+ /* the terminating NULL */ -+ if (__put_user(0, arg->ent.e->name + nlen)) -+ goto out; -+ err = 0; -+ /* AuDbg("%p, %.*s\n", arg->ent.p, nlen, name); */ -+ arg->ent.ul += len; -+ rdu->rent++; -+ } else { -+ err = -EFAULT; -+ au_fset_rdu(rdu->cookie.flags, FULL); -+ rdu->full = 1; -+ rdu->tail = arg->ent; -+ } -+ -+ out: -+ /* AuTraceErr(err); */ -+ return err; -+} -+ -+static int au_rdu_do(struct file *h_file, struct au_rdu_arg *arg) -+{ -+ int err; -+ loff_t offset; -+ struct au_rdu_cookie *cookie = &arg->rdu->cookie; -+ -+ offset = vfsub_llseek(h_file, cookie->h_pos, SEEK_SET); -+ err = offset; -+ if (unlikely(offset != cookie->h_pos)) -+ goto out; -+ -+ err = 0; -+ do { -+ arg->err = 0; -+ au_fclr_rdu(cookie->flags, CALLED); -+ /* smp_mb(); */ -+ err = vfsub_readdir(h_file, au_rdu_fill, arg); -+ if (err >= 0) -+ err = arg->err; -+ } while (!err -+ && au_ftest_rdu(cookie->flags, CALLED) -+ && !au_ftest_rdu(cookie->flags, FULL)); -+ cookie->h_pos = h_file->f_pos; -+ -+ out: -+ AuTraceErr(err); -+ return err; -+} -+ -+static int au_rdu(struct file *file, struct aufs_rdu *rdu) -+{ -+ int err; -+ aufs_bindex_t bend; -+ struct au_rdu_arg arg; -+ struct dentry *dentry; -+ struct inode *inode; -+ struct file *h_file; -+ struct au_rdu_cookie *cookie = &rdu->cookie; -+ -+ err = !access_ok(VERIFY_WRITE, rdu->ent.e, rdu->sz); -+ if (unlikely(err)) { -+ err = -EFAULT; -+ AuTraceErr(err); -+ goto out; -+ } -+ rdu->rent = 0; -+ rdu->tail = rdu->ent; -+ rdu->full = 0; -+ arg.rdu = rdu; -+ arg.ent = rdu->ent; -+ arg.end = arg.ent.ul; -+ arg.end += rdu->sz; -+ -+ err = -ENOTDIR; -+ if (unlikely(!file->f_op || !file->f_op->readdir)) -+ goto out; -+ -+ err = security_file_permission(file, MAY_READ); -+ AuTraceErr(err); -+ if (unlikely(err)) -+ goto out; -+ -+ dentry = file->f_dentry; -+ inode = dentry->d_inode; -+#if 1 -+ mutex_lock(&inode->i_mutex); -+#else -+ err = mutex_lock_killable(&inode->i_mutex); -+ AuTraceErr(err); -+ if (unlikely(err)) -+ goto out; -+#endif -+ err = -ENOENT; -+ if (unlikely(IS_DEADDIR(inode))) -+ goto out_mtx; -+ -+ arg.sb = inode->i_sb; -+ si_read_lock(arg.sb, AuLock_FLUSH); -+ fi_read_lock(file); -+ -+ err = -EAGAIN; -+ if (unlikely(au_ftest_rdu(cookie->flags, CONT) -+ && cookie->generation != au_figen(file))) -+ goto out_unlock; -+ -+ err = 0; -+ if (!rdu->blk) { -+ rdu->blk = au_sbi(arg.sb)->si_rdblk; -+ if (!rdu->blk) -+ rdu->blk = au_dir_size(file, /*dentry*/NULL); -+ } -+ bend = au_fbstart(file); -+ if (cookie->bindex < bend) -+ cookie->bindex = bend; -+ bend = au_fbend(file); -+ /* AuDbg("b%d, b%d\n", cookie->bindex, bend); */ -+ for (; !err && cookie->bindex <= bend; -+ cookie->bindex++, cookie->h_pos = 0) { -+ h_file = au_h_fptr(file, cookie->bindex); -+ if (!h_file) -+ continue; -+ -+ au_fclr_rdu(cookie->flags, FULL); -+ err = au_rdu_do(h_file, &arg); -+ AuTraceErr(err); -+ if (unlikely(au_ftest_rdu(cookie->flags, FULL) || err)) -+ break; -+ } -+ AuDbg("rent %llu\n", rdu->rent); -+ -+ if (!err && !au_ftest_rdu(cookie->flags, CONT)) { -+ rdu->shwh = !!au_opt_test(au_sbi(arg.sb)->si_mntflags, SHWH); -+ au_fset_rdu(cookie->flags, CONT); -+ cookie->generation = au_figen(file); -+ } -+ -+ ii_read_lock_child(inode); -+ fsstack_copy_attr_atime(inode, au_h_iptr(inode, au_ibstart(inode))); -+ ii_read_unlock(inode); -+ -+ out_unlock: -+ fi_read_unlock(file); -+ si_read_unlock(arg.sb); -+ out_mtx: -+ mutex_unlock(&inode->i_mutex); -+ out: -+ AuTraceErr(err); -+ return err; -+} -+ -+static int au_rdu_ino(struct file *file, struct aufs_rdu *rdu) -+{ -+ int err; -+ ino_t ino; -+ unsigned long long nent; -+ union au_rdu_ent_ul *u; -+ struct au_rdu_ent ent; -+ struct super_block *sb; -+ -+ err = 0; -+ nent = rdu->nent; -+ u = &rdu->ent; -+ sb = file->f_dentry->d_sb; -+ si_read_lock(sb, AuLock_FLUSH); -+ while (nent-- > 0) { -+ err = !access_ok(VERIFY_WRITE, u->e, sizeof(ent)); -+ if (unlikely(err)) { -+ err = -EFAULT; -+ AuTraceErr(err); -+ break; -+ } -+ -+ err = copy_from_user(&ent, u->e, sizeof(ent)); -+ if (unlikely(err)) { -+ err = -EFAULT; -+ AuTraceErr(err); -+ break; -+ } -+ -+ /* AuDbg("b%d, i%llu\n", ent.bindex, ent.ino); */ -+ if (!ent.wh) -+ err = au_ino(sb, ent.bindex, ent.ino, ent.type, &ino); -+ else -+ err = au_wh_ino(sb, ent.bindex, ent.ino, ent.type, -+ &ino); -+ if (unlikely(err)) { -+ AuTraceErr(err); -+ break; -+ } -+ -+ err = __put_user(ino, &u->e->ino); -+ if (unlikely(err)) { -+ err = -EFAULT; -+ AuTraceErr(err); -+ break; -+ } -+ u->ul += au_rdu_len(ent.nlen); -+ } -+ si_read_unlock(sb); -+ -+ return err; -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+static int au_rdu_verify(struct aufs_rdu *rdu) -+{ -+ AuDbg("rdu{%llu, %p, (%u, %u) | %u | %llu, %u, %u | " -+ "%llu, b%d, 0x%x, g%u}\n", -+ rdu->sz, rdu->ent.e, rdu->verify[0], rdu->verify[1], -+ rdu->blk, -+ rdu->rent, rdu->shwh, rdu->full, -+ rdu->cookie.h_pos, rdu->cookie.bindex, rdu->cookie.flags, -+ rdu->cookie.generation); -+ -+ if (rdu->verify[AufsCtlRduV_SZ] == sizeof(*rdu) -+ && rdu->verify[AufsCtlRduV_SZ_PTR] == sizeof(rdu)) -+ return 0; -+ -+ AuDbg("%u:%u, %u:%u\n", -+ rdu->verify[AufsCtlRduV_SZ], (unsigned int)sizeof(*rdu), -+ rdu->verify[AufsCtlRduV_SZ_PTR], (unsigned int)sizeof(rdu)); -+ return -EINVAL; -+} -+ -+long au_rdu_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -+{ -+ long err, e; -+ struct aufs_rdu rdu; -+ void __user *p = (void __user *)arg; -+ -+ err = copy_from_user(&rdu, p, sizeof(rdu)); -+ if (unlikely(err)) { -+ err = -EFAULT; -+ AuTraceErr(err); -+ goto out; -+ } -+ err = au_rdu_verify(&rdu); -+ if (unlikely(err)) -+ goto out; -+ -+ switch (cmd) { -+ case AUFS_CTL_RDU: -+ err = au_rdu(file, &rdu); -+ if (unlikely(err)) -+ break; -+ -+ e = copy_to_user(p, &rdu, sizeof(rdu)); -+ if (unlikely(e)) { -+ err = -EFAULT; -+ AuTraceErr(err); -+ } -+ break; -+ case AUFS_CTL_RDU_INO: -+ err = au_rdu_ino(file, &rdu); -+ break; -+ -+ default: -+ err = -EINVAL; -+ } -+ -+ out: -+ AuTraceErr(err); -+ return err; -+} -diff --git a/fs/aufs/rwsem.h b/fs/aufs/rwsem.h -new file mode 100644 -index 0000000..dfd2c68 ---- /dev/null -+++ b/fs/aufs/rwsem.h -@@ -0,0 +1,186 @@ -+/* -+ * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * -+ * This program, aufs is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ */ -+ -+/* -+ * simple read-write semaphore wrappers -+ */ -+ -+#ifndef __AUFS_RWSEM_H__ -+#define __AUFS_RWSEM_H__ -+ -+#ifdef __KERNEL__ -+ -+#include -+ -+struct au_rwsem { -+ struct rw_semaphore rwsem; -+#ifdef CONFIG_AUFS_DEBUG -+ /* just for debugging, not almighty counter */ -+ atomic_t rcnt, wcnt; -+#endif -+}; -+ -+#ifdef CONFIG_AUFS_DEBUG -+#define AuDbgCntInit(rw) do { \ -+ atomic_set(&(rw)->rcnt, 0); \ -+ atomic_set(&(rw)->wcnt, 0); \ -+ smp_mb(); /* atomic set */ \ -+} while (0) -+ -+#define AuDbgRcntInc(rw) atomic_inc_return(&(rw)->rcnt) -+#define AuDbgRcntDec(rw) WARN_ON(atomic_dec_return(&(rw)->rcnt) < 0) -+#define AuDbgWcntInc(rw) WARN_ON(atomic_inc_return(&(rw)->wcnt) > 1) -+#define AuDbgWcntDec(rw) WARN_ON(atomic_dec_return(&(rw)->wcnt) < 0) -+#else -+#define AuDbgCntInit(rw) do {} while (0) -+#define AuDbgRcntInc(rw) do {} while (0) -+#define AuDbgRcntDec(rw) do {} while (0) -+#define AuDbgWcntInc(rw) do {} while (0) -+#define AuDbgWcntDec(rw) do {} while (0) -+#endif /* CONFIG_AUFS_DEBUG */ -+ -+/* to debug easier, do not make them inlined functions */ -+#define AuRwMustNoWaiters(rw) AuDebugOn(!list_empty(&(rw)->rwsem.wait_list)) -+/* rwsem_is_locked() is unusable */ -+#define AuRwMustReadLock(rw) AuDebugOn(atomic_read(&(rw)->rcnt) <= 0) -+#define AuRwMustWriteLock(rw) AuDebugOn(atomic_read(&(rw)->wcnt) <= 0) -+#define AuRwMustAnyLock(rw) AuDebugOn(atomic_read(&(rw)->rcnt) <= 0 \ -+ && atomic_read(&(rw)->wcnt) <= 0) -+#define AuRwDestroy(rw) AuDebugOn(atomic_read(&(rw)->rcnt) \ -+ || atomic_read(&(rw)->wcnt)) -+ -+static inline void au_rw_init(struct au_rwsem *rw) -+{ -+ AuDbgCntInit(rw); -+ init_rwsem(&rw->rwsem); -+} -+ -+static inline void au_rw_init_wlock(struct au_rwsem *rw) -+{ -+ au_rw_init(rw); -+ down_write(&rw->rwsem); -+ AuDbgWcntInc(rw); -+} -+ -+static inline void au_rw_init_wlock_nested(struct au_rwsem *rw, -+ unsigned int lsc) -+{ -+ au_rw_init(rw); -+ down_write_nested(&rw->rwsem, lsc); -+ AuDbgWcntInc(rw); -+} -+ -+static inline void au_rw_read_lock(struct au_rwsem *rw) -+{ -+ down_read(&rw->rwsem); -+ AuDbgRcntInc(rw); -+} -+ -+static inline void au_rw_read_lock_nested(struct au_rwsem *rw, unsigned int lsc) -+{ -+ down_read_nested(&rw->rwsem, lsc); -+ AuDbgRcntInc(rw); -+} -+ -+static inline void au_rw_read_unlock(struct au_rwsem *rw) -+{ -+ AuRwMustReadLock(rw); -+ AuDbgRcntDec(rw); -+ up_read(&rw->rwsem); -+} -+ -+static inline void au_rw_dgrade_lock(struct au_rwsem *rw) -+{ -+ AuRwMustWriteLock(rw); -+ AuDbgRcntInc(rw); -+ AuDbgWcntDec(rw); -+ downgrade_write(&rw->rwsem); -+} -+ -+static inline void au_rw_write_lock(struct au_rwsem *rw) -+{ -+ down_write(&rw->rwsem); -+ AuDbgWcntInc(rw); -+} -+ -+static inline void au_rw_write_lock_nested(struct au_rwsem *rw, -+ unsigned int lsc) -+{ -+ down_write_nested(&rw->rwsem, lsc); -+ AuDbgWcntInc(rw); -+} -+ -+static inline void au_rw_write_unlock(struct au_rwsem *rw) -+{ -+ AuRwMustWriteLock(rw); -+ AuDbgWcntDec(rw); -+ up_write(&rw->rwsem); -+} -+ -+/* why is not _nested version defined */ -+static inline int au_rw_read_trylock(struct au_rwsem *rw) -+{ -+ int ret = down_read_trylock(&rw->rwsem); -+ if (ret) -+ AuDbgRcntInc(rw); -+ return ret; -+} -+ -+static inline int au_rw_write_trylock(struct au_rwsem *rw) -+{ -+ int ret = down_write_trylock(&rw->rwsem); -+ if (ret) -+ AuDbgWcntInc(rw); -+ return ret; -+} -+ -+#undef AuDbgCntInit -+#undef AuDbgRcntInc -+#undef AuDbgRcntDec -+#undef AuDbgWcntInc -+#undef AuDbgWcntDec -+ -+#define AuSimpleLockRwsemFuncs(prefix, param, rwsem) \ -+static inline void prefix##_read_lock(param) \ -+{ au_rw_read_lock(rwsem); } \ -+static inline void prefix##_write_lock(param) \ -+{ au_rw_write_lock(rwsem); } \ -+static inline int prefix##_read_trylock(param) \ -+{ return au_rw_read_trylock(rwsem); } \ -+static inline int prefix##_write_trylock(param) \ -+{ return au_rw_write_trylock(rwsem); } -+/* why is not _nested version defined */ -+/* static inline void prefix##_read_trylock_nested(param, lsc) -+{ au_rw_read_trylock_nested(rwsem, lsc)); } -+static inline void prefix##_write_trylock_nestd(param, lsc) -+{ au_rw_write_trylock_nested(rwsem, lsc); } */ -+ -+#define AuSimpleUnlockRwsemFuncs(prefix, param, rwsem) \ -+static inline void prefix##_read_unlock(param) \ -+{ au_rw_read_unlock(rwsem); } \ -+static inline void prefix##_write_unlock(param) \ -+{ au_rw_write_unlock(rwsem); } \ -+static inline void prefix##_downgrade_lock(param) \ -+{ au_rw_dgrade_lock(rwsem); } -+ -+#define AuSimpleRwsemFuncs(prefix, param, rwsem) \ -+ AuSimpleLockRwsemFuncs(prefix, param, rwsem) \ -+ AuSimpleUnlockRwsemFuncs(prefix, param, rwsem) -+ -+#endif /* __KERNEL__ */ -+#endif /* __AUFS_RWSEM_H__ */ -diff --git a/fs/aufs/sbinfo.c b/fs/aufs/sbinfo.c -new file mode 100644 -index 0000000..f0650e5 ---- /dev/null -+++ b/fs/aufs/sbinfo.c -@@ -0,0 +1,208 @@ -+/* -+ * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * -+ * This program, aufs is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ */ -+ -+/* -+ * superblock private data -+ */ -+ -+#include "aufs.h" -+ -+/* -+ * they are necessary regardless sysfs is disabled. -+ */ -+void au_si_free(struct kobject *kobj) -+{ -+ struct au_sbinfo *sbinfo; -+ struct super_block *sb; -+ -+ sbinfo = container_of(kobj, struct au_sbinfo, si_kobj); -+ AuDebugOn(!list_empty(&sbinfo->si_plink.head)); -+ -+ sb = sbinfo->si_sb; -+ si_write_lock(sb); -+ au_xino_clr(sb); -+ au_br_free(sbinfo); -+ kfree(sbinfo->si_branch); -+ mutex_destroy(&sbinfo->si_xib_mtx); -+ si_write_unlock(sb); -+ AuRwDestroy(&sbinfo->si_rwsem); -+ -+ kfree(sbinfo); -+} -+ -+int au_si_alloc(struct super_block *sb) -+{ -+ int err; -+ struct au_sbinfo *sbinfo; -+ -+ err = -ENOMEM; -+ sbinfo = kmalloc(sizeof(*sbinfo), GFP_NOFS); -+ if (unlikely(!sbinfo)) -+ goto out; -+ -+ /* will be reallocated separately */ -+ sbinfo->si_branch = kzalloc(sizeof(*sbinfo->si_branch), GFP_NOFS); -+ if (unlikely(!sbinfo->si_branch)) -+ goto out_sbinfo; -+ -+ memset(&sbinfo->si_kobj, 0, sizeof(sbinfo->si_kobj)); -+ err = sysaufs_si_init(sbinfo); -+ if (unlikely(err)) -+ goto out_br; -+ -+ au_nwt_init(&sbinfo->si_nowait); -+ au_rw_init_wlock(&sbinfo->si_rwsem); -+ sbinfo->si_generation = 0; -+ sbinfo->au_si_status = 0; -+ sbinfo->si_bend = -1; -+ sbinfo->si_last_br_id = 0; -+ -+ sbinfo->si_wbr_copyup = AuWbrCopyup_Def; -+ sbinfo->si_wbr_create = AuWbrCreate_Def; -+ sbinfo->si_wbr_copyup_ops = au_wbr_copyup_ops + AuWbrCopyup_Def; -+ sbinfo->si_wbr_create_ops = au_wbr_create_ops + AuWbrCreate_Def; -+ -+ sbinfo->si_mntflags = AuOpt_Def; -+ -+ sbinfo->si_xread = NULL; -+ sbinfo->si_xwrite = NULL; -+ sbinfo->si_xib = NULL; -+ mutex_init(&sbinfo->si_xib_mtx); -+ sbinfo->si_xib_buf = NULL; -+ sbinfo->si_xino_brid = -1; -+ /* leave si_xib_last_pindex and si_xib_next_bit */ -+ -+ sbinfo->si_rdcache = AUFS_RDCACHE_DEF * HZ; -+ sbinfo->si_rdblk = AUFS_RDBLK_DEF; -+ sbinfo->si_rdhash = AUFS_RDHASH_DEF; -+ sbinfo->si_dirwh = AUFS_DIRWH_DEF; -+ -+ au_spl_init(&sbinfo->si_plink); -+ init_waitqueue_head(&sbinfo->si_plink_wq); -+ -+ /* leave other members for sysaufs and si_mnt. */ -+ sbinfo->si_sb = sb; -+ sb->s_fs_info = sbinfo; -+ au_debug_sbinfo_init(sbinfo); -+ return 0; /* success */ -+ -+ out_br: -+ kfree(sbinfo->si_branch); -+ out_sbinfo: -+ kfree(sbinfo); -+ out: -+ return err; -+} -+ -+int au_sbr_realloc(struct au_sbinfo *sbinfo, int nbr) -+{ -+ int err, sz; -+ struct au_branch **brp; -+ -+ AuRwMustWriteLock(&sbinfo->si_rwsem); -+ -+ err = -ENOMEM; -+ sz = sizeof(*brp) * (sbinfo->si_bend + 1); -+ if (unlikely(!sz)) -+ sz = sizeof(*brp); -+ brp = au_kzrealloc(sbinfo->si_branch, sz, sizeof(*brp) * nbr, GFP_NOFS); -+ if (brp) { -+ sbinfo->si_branch = brp; -+ err = 0; -+ } -+ -+ return err; -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+unsigned int au_sigen_inc(struct super_block *sb) -+{ -+ unsigned int gen; -+ -+ SiMustWriteLock(sb); -+ -+ gen = ++au_sbi(sb)->si_generation; -+ au_update_digen(sb->s_root); -+ au_update_iigen(sb->s_root->d_inode); -+ sb->s_root->d_inode->i_version++; -+ return gen; -+} -+ -+aufs_bindex_t au_new_br_id(struct super_block *sb) -+{ -+ aufs_bindex_t br_id; -+ int i; -+ struct au_sbinfo *sbinfo; -+ -+ SiMustWriteLock(sb); -+ -+ sbinfo = au_sbi(sb); -+ for (i = 0; i <= AUFS_BRANCH_MAX; i++) { -+ br_id = ++sbinfo->si_last_br_id; -+ if (br_id && au_br_index(sb, br_id) < 0) -+ return br_id; -+ } -+ -+ return -1; -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+/* dentry and super_block lock. call at entry point */ -+void aufs_read_lock(struct dentry *dentry, int flags) -+{ -+ si_read_lock(dentry->d_sb, flags); -+ if (au_ftest_lock(flags, DW)) -+ di_write_lock_child(dentry); -+ else -+ di_read_lock_child(dentry, flags); -+} -+ -+void aufs_read_unlock(struct dentry *dentry, int flags) -+{ -+ if (au_ftest_lock(flags, DW)) -+ di_write_unlock(dentry); -+ else -+ di_read_unlock(dentry, flags); -+ si_read_unlock(dentry->d_sb); -+} -+ -+void aufs_write_lock(struct dentry *dentry) -+{ -+ si_write_lock(dentry->d_sb); -+ di_write_lock_child(dentry); -+} -+ -+void aufs_write_unlock(struct dentry *dentry) -+{ -+ di_write_unlock(dentry); -+ si_write_unlock(dentry->d_sb); -+} -+ -+void aufs_read_and_write_lock2(struct dentry *d1, struct dentry *d2, int flags) -+{ -+ si_read_lock(d1->d_sb, flags); -+ di_write_lock2_child(d1, d2, au_ftest_lock(flags, DIR)); -+} -+ -+void aufs_read_and_write_unlock2(struct dentry *d1, struct dentry *d2) -+{ -+ di_write_unlock2(d1, d2); -+ si_read_unlock(d1->d_sb); -+} -diff --git a/fs/aufs/spl.h b/fs/aufs/spl.h -new file mode 100644 -index 0000000..bcbbd9a ---- /dev/null -+++ b/fs/aufs/spl.h -@@ -0,0 +1,57 @@ -+/* -+ * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * -+ * This program, aufs is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ */ -+ -+/* -+ * simple list protected by a spinlock -+ */ -+ -+#ifndef __AUFS_SPL_H__ -+#define __AUFS_SPL_H__ -+ -+#ifdef __KERNEL__ -+ -+#include -+#include -+ -+struct au_splhead { -+ spinlock_t spin; -+ struct list_head head; -+}; -+ -+static inline void au_spl_init(struct au_splhead *spl) -+{ -+ spin_lock_init(&spl->spin); -+ INIT_LIST_HEAD(&spl->head); -+} -+ -+static inline void au_spl_add(struct list_head *list, struct au_splhead *spl) -+{ -+ spin_lock(&spl->spin); -+ list_add(list, &spl->head); -+ spin_unlock(&spl->spin); -+} -+ -+static inline void au_spl_del(struct list_head *list, struct au_splhead *spl) -+{ -+ spin_lock(&spl->spin); -+ list_del(list); -+ spin_unlock(&spl->spin); -+} -+ -+#endif /* __KERNEL__ */ -+#endif /* __AUFS_SPL_H__ */ -diff --git a/fs/aufs/super.c b/fs/aufs/super.c -new file mode 100644 -index 0000000..10d30f2 ---- /dev/null -+++ b/fs/aufs/super.c -@@ -0,0 +1,876 @@ -+/* -+ * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * -+ * This program, aufs is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ */ -+ -+/* -+ * mount and super_block operations -+ */ -+ -+#include -+#include -+#include -+#include -+#include "aufs.h" -+ -+/* -+ * super_operations -+ */ -+static struct inode *aufs_alloc_inode(struct super_block *sb __maybe_unused) -+{ -+ struct au_icntnr *c; -+ -+ c = au_cache_alloc_icntnr(); -+ if (c) { -+ inode_init_once(&c->vfs_inode); -+ c->vfs_inode.i_version = 1; /* sigen(sb); */ -+ c->iinfo.ii_hinode = NULL; -+ return &c->vfs_inode; -+ } -+ return NULL; -+} -+ -+static void aufs_destroy_inode(struct inode *inode) -+{ -+ au_iinfo_fin(inode); -+ au_cache_free_icntnr(container_of(inode, struct au_icntnr, vfs_inode)); -+} -+ -+struct inode *au_iget_locked(struct super_block *sb, ino_t ino) -+{ -+ struct inode *inode; -+ int err; -+ -+ inode = iget_locked(sb, ino); -+ if (unlikely(!inode)) { -+ inode = ERR_PTR(-ENOMEM); -+ goto out; -+ } -+ if (!(inode->i_state & I_NEW)) -+ goto out; -+ -+ err = au_xigen_new(inode); -+ if (!err) -+ err = au_iinfo_init(inode); -+ if (!err) -+ inode->i_version++; -+ else { -+ iget_failed(inode); -+ inode = ERR_PTR(err); -+ } -+ -+ out: -+ /* never return NULL */ -+ AuDebugOn(!inode); -+ AuTraceErrPtr(inode); -+ return inode; -+} -+ -+/* lock free root dinfo */ -+static int au_show_brs(struct seq_file *seq, struct super_block *sb) -+{ -+ int err; -+ aufs_bindex_t bindex, bend; -+ struct path path; -+ struct au_hdentry *hd; -+ struct au_branch *br; -+ -+ err = 0; -+ bend = au_sbend(sb); -+ hd = au_di(sb->s_root)->di_hdentry; -+ for (bindex = 0; !err && bindex <= bend; bindex++) { -+ br = au_sbr(sb, bindex); -+ path.mnt = br->br_mnt; -+ path.dentry = hd[bindex].hd_dentry; -+ err = au_seq_path(seq, &path); -+ if (err > 0) -+ err = seq_printf(seq, "=%s", -+ au_optstr_br_perm(br->br_perm)); -+ if (!err && bindex != bend) -+ err = seq_putc(seq, ':'); -+ } -+ -+ return err; -+} -+ -+static void au_show_wbr_create(struct seq_file *m, int v, -+ struct au_sbinfo *sbinfo) -+{ -+ const char *pat; -+ -+ AuRwMustAnyLock(&sbinfo->si_rwsem); -+ -+ seq_printf(m, ",create="); -+ pat = au_optstr_wbr_create(v); -+ switch (v) { -+ case AuWbrCreate_TDP: -+ case AuWbrCreate_RR: -+ case AuWbrCreate_MFS: -+ case AuWbrCreate_PMFS: -+ seq_printf(m, pat); -+ break; -+ case AuWbrCreate_MFSV: -+ seq_printf(m, /*pat*/"mfs:%lu", -+ sbinfo->si_wbr_mfs.mfs_expire / HZ); -+ break; -+ case AuWbrCreate_PMFSV: -+ seq_printf(m, /*pat*/"pmfs:%lu", -+ sbinfo->si_wbr_mfs.mfs_expire / HZ); -+ break; -+ case AuWbrCreate_MFSRR: -+ seq_printf(m, /*pat*/"mfsrr:%llu", -+ sbinfo->si_wbr_mfs.mfsrr_watermark); -+ break; -+ case AuWbrCreate_MFSRRV: -+ seq_printf(m, /*pat*/"mfsrr:%llu:%lu", -+ sbinfo->si_wbr_mfs.mfsrr_watermark, -+ sbinfo->si_wbr_mfs.mfs_expire / HZ); -+ break; -+ } -+} -+ -+static int au_show_xino(struct seq_file *seq, struct vfsmount *mnt) -+{ -+#ifdef CONFIG_SYSFS -+ return 0; -+#else -+ int err; -+ const int len = sizeof(AUFS_XINO_FNAME) - 1; -+ aufs_bindex_t bindex, brid; -+ struct super_block *sb; -+ struct qstr *name; -+ struct file *f; -+ struct dentry *d, *h_root; -+ -+ AuRwMustAnyLock(&sbinfo->si_rwsem); -+ -+ err = 0; -+ sb = mnt->mnt_sb; -+ f = au_sbi(sb)->si_xib; -+ if (!f) -+ goto out; -+ -+ /* stop printing the default xino path on the first writable branch */ -+ h_root = NULL; -+ brid = au_xino_brid(sb); -+ if (brid >= 0) { -+ bindex = au_br_index(sb, brid); -+ h_root = au_di(sb->s_root)->di_hdentry[0 + bindex].hd_dentry; -+ } -+ d = f->f_dentry; -+ name = &d->d_name; -+ /* safe ->d_parent because the file is unlinked */ -+ if (d->d_parent == h_root -+ && name->len == len -+ && !memcmp(name->name, AUFS_XINO_FNAME, len)) -+ goto out; -+ -+ seq_puts(seq, ",xino="); -+ err = au_xino_path(seq, f); -+ -+ out: -+ return err; -+#endif -+} -+ -+/* seq_file will re-call me in case of too long string */ -+static int aufs_show_options(struct seq_file *m, struct vfsmount *mnt) -+{ -+ int err, n; -+ unsigned int mnt_flags, v; -+ struct super_block *sb; -+ struct au_sbinfo *sbinfo; -+ -+#define AuBool(name, str) do { \ -+ v = au_opt_test(mnt_flags, name); \ -+ if (v != au_opt_test(AuOpt_Def, name)) \ -+ seq_printf(m, ",%s" #str, v ? "" : "no"); \ -+} while (0) -+ -+#define AuStr(name, str) do { \ -+ v = mnt_flags & AuOptMask_##name; \ -+ if (v != (AuOpt_Def & AuOptMask_##name)) \ -+ seq_printf(m, "," #str "=%s", au_optstr_##str(v)); \ -+} while (0) -+ -+#define AuUInt(name, str, val) do { \ -+ if (val != AUFS_##name##_DEF) \ -+ seq_printf(m, "," #str "=%u", val); \ -+} while (0) -+ -+ /* lock free root dinfo */ -+ sb = mnt->mnt_sb; -+ si_noflush_read_lock(sb); -+ sbinfo = au_sbi(sb); -+ seq_printf(m, ",si=%lx", sysaufs_si_id(sbinfo)); -+ -+ mnt_flags = au_mntflags(sb); -+ if (au_opt_test(mnt_flags, XINO)) { -+ err = au_show_xino(m, mnt); -+ if (unlikely(err)) -+ goto out; -+ } else -+ seq_puts(m, ",noxino"); -+ -+ AuBool(TRUNC_XINO, trunc_xino); -+ AuStr(UDBA, udba); -+ AuBool(SHWH, shwh); -+ AuBool(PLINK, plink); -+ /* AuBool(DIRPERM1, dirperm1); */ -+ /* AuBool(REFROF, refrof); */ -+ -+ v = sbinfo->si_wbr_create; -+ if (v != AuWbrCreate_Def) -+ au_show_wbr_create(m, v, sbinfo); -+ -+ v = sbinfo->si_wbr_copyup; -+ if (v != AuWbrCopyup_Def) -+ seq_printf(m, ",cpup=%s", au_optstr_wbr_copyup(v)); -+ -+ v = au_opt_test(mnt_flags, ALWAYS_DIROPQ); -+ if (v != au_opt_test(AuOpt_Def, ALWAYS_DIROPQ)) -+ seq_printf(m, ",diropq=%c", v ? 'a' : 'w'); -+ -+ AuUInt(DIRWH, dirwh, sbinfo->si_dirwh); -+ -+ n = sbinfo->si_rdcache / HZ; -+ AuUInt(RDCACHE, rdcache, n); -+ -+ AuUInt(RDBLK, rdblk, sbinfo->si_rdblk); -+ AuUInt(RDHASH, rdhash, sbinfo->si_rdhash); -+ -+ AuBool(SUM, sum); -+ /* AuBool(SUM_W, wsum); */ -+ AuBool(WARN_PERM, warn_perm); -+ AuBool(VERBOSE, verbose); -+ -+ out: -+ /* be sure to print "br:" last */ -+ if (!sysaufs_brs) { -+ seq_puts(m, ",br:"); -+ au_show_brs(m, sb); -+ } -+ si_read_unlock(sb); -+ return 0; -+ -+#undef Deleted -+#undef AuBool -+#undef AuStr -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+/* sum mode which returns the summation for statfs(2) */ -+ -+static u64 au_add_till_max(u64 a, u64 b) -+{ -+ u64 old; -+ -+ old = a; -+ a += b; -+ if (old < a) -+ return a; -+ return ULLONG_MAX; -+} -+ -+static int au_statfs_sum(struct super_block *sb, struct kstatfs *buf) -+{ -+ int err; -+ u64 blocks, bfree, bavail, files, ffree; -+ aufs_bindex_t bend, bindex, i; -+ unsigned char shared; -+ struct vfsmount *h_mnt; -+ struct super_block *h_sb; -+ -+ blocks = 0; -+ bfree = 0; -+ bavail = 0; -+ files = 0; -+ ffree = 0; -+ -+ err = 0; -+ bend = au_sbend(sb); -+ for (bindex = bend; bindex >= 0; bindex--) { -+ h_mnt = au_sbr_mnt(sb, bindex); -+ h_sb = h_mnt->mnt_sb; -+ shared = 0; -+ for (i = bindex + 1; !shared && i <= bend; i++) -+ shared = (au_sbr_sb(sb, i) == h_sb); -+ if (shared) -+ continue; -+ -+ /* sb->s_root for NFS is unreliable */ -+ err = vfs_statfs(h_mnt->mnt_root, buf); -+ if (unlikely(err)) -+ goto out; -+ -+ blocks = au_add_till_max(blocks, buf->f_blocks); -+ bfree = au_add_till_max(bfree, buf->f_bfree); -+ bavail = au_add_till_max(bavail, buf->f_bavail); -+ files = au_add_till_max(files, buf->f_files); -+ ffree = au_add_till_max(ffree, buf->f_ffree); -+ } -+ -+ buf->f_blocks = blocks; -+ buf->f_bfree = bfree; -+ buf->f_bavail = bavail; -+ buf->f_files = files; -+ buf->f_ffree = ffree; -+ -+ out: -+ return err; -+} -+ -+static int aufs_statfs(struct dentry *dentry, struct kstatfs *buf) -+{ -+ int err; -+ struct super_block *sb; -+ -+ /* lock free root dinfo */ -+ sb = dentry->d_sb; -+ si_noflush_read_lock(sb); -+ if (!au_opt_test(au_mntflags(sb), SUM)) -+ /* sb->s_root for NFS is unreliable */ -+ err = vfs_statfs(au_sbr_mnt(sb, 0)->mnt_root, buf); -+ else -+ err = au_statfs_sum(sb, buf); -+ si_read_unlock(sb); -+ -+ if (!err) { -+ buf->f_type = AUFS_SUPER_MAGIC; -+ buf->f_namelen = AUFS_MAX_NAMELEN; -+ memset(&buf->f_fsid, 0, sizeof(buf->f_fsid)); -+ } -+ /* buf->f_bsize = buf->f_blocks = buf->f_bfree = buf->f_bavail = -1; */ -+ -+ return err; -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+/* try flushing the lower fs at aufs remount/unmount time */ -+ -+static void au_fsync_br(struct super_block *sb) -+{ -+ aufs_bindex_t bend, bindex; -+ int brperm; -+ struct au_branch *br; -+ struct super_block *h_sb; -+ -+ bend = au_sbend(sb); -+ for (bindex = 0; bindex < bend; bindex++) { -+ br = au_sbr(sb, bindex); -+ brperm = br->br_perm; -+ if (brperm == AuBrPerm_RR || brperm == AuBrPerm_RRWH) -+ continue; -+ h_sb = br->br_mnt->mnt_sb; -+ if (bdev_read_only(h_sb->s_bdev)) -+ continue; -+ -+ /* lockdep_off(); */ -+ down_write(&h_sb->s_umount); -+ shrink_dcache_sb(h_sb); -+ sync_filesystem(h_sb); -+ up_write(&h_sb->s_umount); -+ /* lockdep_on(); */ -+ } -+} -+ -+/* -+ * this IS NOT for super_operations. -+ * I guess it will be reverted someday. -+ */ -+static void aufs_umount_begin(struct super_block *sb) -+{ -+ struct au_sbinfo *sbinfo; -+ -+ sbinfo = au_sbi(sb); -+ if (!sbinfo) -+ return; -+ -+ si_write_lock(sb); -+ au_fsync_br(sb); -+ if (au_opt_test(au_mntflags(sb), PLINK)) -+ au_plink_put(sb); -+ if (sbinfo->si_wbr_create_ops->fin) -+ sbinfo->si_wbr_create_ops->fin(sb); -+ si_write_unlock(sb); -+} -+ -+/* final actions when unmounting a file system */ -+static void aufs_put_super(struct super_block *sb) -+{ -+ struct au_sbinfo *sbinfo; -+ -+ sbinfo = au_sbi(sb); -+ if (!sbinfo) -+ return; -+ -+ aufs_umount_begin(sb); -+ dbgaufs_si_fin(sbinfo); -+ kobject_put(&sbinfo->si_kobj); -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+/* -+ * refresh dentry and inode at remount time. -+ */ -+static int do_refresh(struct dentry *dentry, mode_t type, -+ unsigned int dir_flags) -+{ -+ int err; -+ struct dentry *parent; -+ -+ di_write_lock_child(dentry); -+ parent = dget_parent(dentry); -+ di_read_lock_parent(parent, AuLock_IR); -+ -+ /* returns the number of positive dentries */ -+ err = au_refresh_hdentry(dentry, type); -+ if (err >= 0) { -+ struct inode *inode = dentry->d_inode; -+ err = au_refresh_hinode(inode, dentry); -+ if (!err && type == S_IFDIR) -+ au_reset_hinotify(inode, dir_flags); -+ } -+ if (unlikely(err)) -+ pr_err("unrecoverable error %d, %.*s\n", -+ err, AuDLNPair(dentry)); -+ -+ di_read_unlock(parent, AuLock_IR); -+ dput(parent); -+ di_write_unlock(dentry); -+ -+ return err; -+} -+ -+static int test_dir(struct dentry *dentry, void *arg __maybe_unused) -+{ -+ return S_ISDIR(dentry->d_inode->i_mode); -+} -+ -+/* gave up consolidating with refresh_nondir() */ -+static int refresh_dir(struct dentry *root, unsigned int sigen) -+{ -+ int err, i, j, ndentry, e; -+ struct au_dcsub_pages dpages; -+ struct au_dpage *dpage; -+ struct dentry **dentries; -+ struct inode *inode; -+ const unsigned int flags = au_hi_flags(root->d_inode, /*isdir*/1); -+ -+ err = 0; -+ list_for_each_entry(inode, &root->d_sb->s_inodes, i_sb_list) -+ if (S_ISDIR(inode->i_mode) && au_iigen(inode) != sigen) { -+ ii_write_lock_child(inode); -+ e = au_refresh_hinode_self(inode, /*do_attr*/1); -+ ii_write_unlock(inode); -+ if (unlikely(e)) { -+ AuDbg("e %d, i%lu\n", e, inode->i_ino); -+ if (!err) -+ err = e; -+ /* go on even if err */ -+ } -+ } -+ -+ e = au_dpages_init(&dpages, GFP_NOFS); -+ if (unlikely(e)) { -+ if (!err) -+ err = e; -+ goto out; -+ } -+ e = au_dcsub_pages(&dpages, root, test_dir, NULL); -+ if (unlikely(e)) { -+ if (!err) -+ err = e; -+ goto out_dpages; -+ } -+ -+ for (i = 0; !e && i < dpages.ndpage; i++) { -+ dpage = dpages.dpages + i; -+ dentries = dpage->dentries; -+ ndentry = dpage->ndentry; -+ for (j = 0; !e && j < ndentry; j++) { -+ struct dentry *d; -+ -+ d = dentries[j]; -+ au_dbg_verify_dir_parent(d, sigen); -+ if (au_digen(d) != sigen) { -+ e = do_refresh(d, S_IFDIR, flags); -+ if (unlikely(e && !err)) -+ err = e; -+ /* break on err */ -+ } -+ } -+ } -+ -+ out_dpages: -+ au_dpages_free(&dpages); -+ out: -+ return err; -+} -+ -+static int test_nondir(struct dentry *dentry, void *arg __maybe_unused) -+{ -+ return !S_ISDIR(dentry->d_inode->i_mode); -+} -+ -+static int refresh_nondir(struct dentry *root, unsigned int sigen, -+ int do_dentry) -+{ -+ int err, i, j, ndentry, e; -+ struct au_dcsub_pages dpages; -+ struct au_dpage *dpage; -+ struct dentry **dentries; -+ struct inode *inode; -+ -+ err = 0; -+ list_for_each_entry(inode, &root->d_sb->s_inodes, i_sb_list) -+ if (!S_ISDIR(inode->i_mode) && au_iigen(inode) != sigen) { -+ ii_write_lock_child(inode); -+ e = au_refresh_hinode_self(inode, /*do_attr*/1); -+ ii_write_unlock(inode); -+ if (unlikely(e)) { -+ AuDbg("e %d, i%lu\n", e, inode->i_ino); -+ if (!err) -+ err = e; -+ /* go on even if err */ -+ } -+ } -+ -+ if (!do_dentry) -+ goto out; -+ -+ e = au_dpages_init(&dpages, GFP_NOFS); -+ if (unlikely(e)) { -+ if (!err) -+ err = e; -+ goto out; -+ } -+ e = au_dcsub_pages(&dpages, root, test_nondir, NULL); -+ if (unlikely(e)) { -+ if (!err) -+ err = e; -+ goto out_dpages; -+ } -+ -+ for (i = 0; i < dpages.ndpage; i++) { -+ dpage = dpages.dpages + i; -+ dentries = dpage->dentries; -+ ndentry = dpage->ndentry; -+ for (j = 0; j < ndentry; j++) { -+ struct dentry *d; -+ -+ d = dentries[j]; -+ au_dbg_verify_nondir_parent(d, sigen); -+ inode = d->d_inode; -+ if (inode && au_digen(d) != sigen) { -+ e = do_refresh(d, inode->i_mode & S_IFMT, -+ /*dir_flags*/0); -+ if (unlikely(e && !err)) -+ err = e; -+ /* go on even err */ -+ } -+ } -+ } -+ -+ out_dpages: -+ au_dpages_free(&dpages); -+ out: -+ return err; -+} -+ -+static void au_remount_refresh(struct super_block *sb, unsigned int flags) -+{ -+ int err; -+ unsigned int sigen; -+ struct au_sbinfo *sbinfo; -+ struct dentry *root; -+ struct inode *inode; -+ -+ au_sigen_inc(sb); -+ sigen = au_sigen(sb); -+ sbinfo = au_sbi(sb); -+ au_fclr_si(sbinfo, FAILED_REFRESH_DIRS); -+ -+ root = sb->s_root; -+ DiMustNoWaiters(root); -+ inode = root->d_inode; -+ IiMustNoWaiters(inode); -+ au_reset_hinotify(inode, au_hi_flags(inode, /*isdir*/1)); -+ di_write_unlock(root); -+ -+ err = refresh_dir(root, sigen); -+ if (unlikely(err)) { -+ au_fset_si(sbinfo, FAILED_REFRESH_DIRS); -+ pr_warning("Refreshing directories failed, ignored (%d)\n", -+ err); -+ } -+ -+ if (au_ftest_opts(flags, REFRESH_NONDIR)) { -+ err = refresh_nondir(root, sigen, !err); -+ if (unlikely(err)) -+ pr_warning("Refreshing non-directories failed, ignored" -+ "(%d)\n", err); -+ } -+ -+ /* aufs_write_lock() calls ..._child() */ -+ di_write_lock_child(root); -+ au_cpup_attr_all(root->d_inode, /*force*/1); -+} -+ -+/* stop extra interpretation of errno in mount(8), and strange error messages */ -+static int cvt_err(int err) -+{ -+ AuTraceErr(err); -+ -+ switch (err) { -+ case -ENOENT: -+ case -ENOTDIR: -+ case -EEXIST: -+ case -EIO: -+ err = -EINVAL; -+ } -+ return err; -+} -+ -+static int aufs_remount_fs(struct super_block *sb, int *flags, char *data) -+{ -+ int err; -+ struct au_opts opts; -+ struct dentry *root; -+ struct inode *inode; -+ struct au_sbinfo *sbinfo; -+ -+ err = 0; -+ root = sb->s_root; -+ if (!data || !*data) { -+ aufs_write_lock(root); -+ err = au_opts_verify(sb, *flags, /*pending*/0); -+ if (!err) -+ au_fsync_br(sb); -+ aufs_write_unlock(root); -+ goto out; -+ } -+ -+ err = -ENOMEM; -+ memset(&opts, 0, sizeof(opts)); -+ opts.opt = (void *)__get_free_page(GFP_NOFS); -+ if (unlikely(!opts.opt)) -+ goto out; -+ opts.max_opt = PAGE_SIZE / sizeof(*opts.opt); -+ opts.flags = AuOpts_REMOUNT; -+ opts.sb_flags = *flags; -+ -+ /* parse it before aufs lock */ -+ err = au_opts_parse(sb, data, &opts); -+ if (unlikely(err)) -+ goto out_opts; -+ -+ sbinfo = au_sbi(sb); -+ inode = root->d_inode; -+ mutex_lock(&inode->i_mutex); -+ aufs_write_lock(root); -+ au_fsync_br(sb); -+ -+ /* au_opts_remount() may return an error */ -+ err = au_opts_remount(sb, &opts); -+ au_opts_free(&opts); -+ -+ if (au_ftest_opts(opts.flags, REFRESH_DIR) -+ || au_ftest_opts(opts.flags, REFRESH_NONDIR)) -+ au_remount_refresh(sb, opts.flags); -+ -+ aufs_write_unlock(root); -+ mutex_unlock(&inode->i_mutex); -+ -+ out_opts: -+ free_page((unsigned long)opts.opt); -+ out: -+ err = cvt_err(err); -+ AuTraceErr(err); -+ return err; -+} -+ -+static const struct super_operations aufs_sop = { -+ .alloc_inode = aufs_alloc_inode, -+ .destroy_inode = aufs_destroy_inode, -+ .drop_inode = generic_delete_inode, -+ .show_options = aufs_show_options, -+ .statfs = aufs_statfs, -+ .put_super = aufs_put_super, -+ .remount_fs = aufs_remount_fs -+}; -+ -+/* ---------------------------------------------------------------------- */ -+ -+static int alloc_root(struct super_block *sb) -+{ -+ int err; -+ struct inode *inode; -+ struct dentry *root; -+ -+ err = -ENOMEM; -+ inode = au_iget_locked(sb, AUFS_ROOT_INO); -+ err = PTR_ERR(inode); -+ if (IS_ERR(inode)) -+ goto out; -+ -+ inode->i_op = &aufs_dir_iop; -+ inode->i_fop = &aufs_dir_fop; -+ inode->i_mode = S_IFDIR; -+ inode->i_nlink = 2; -+ unlock_new_inode(inode); -+ -+ root = d_alloc_root(inode); -+ if (unlikely(!root)) -+ goto out_iput; -+ err = PTR_ERR(root); -+ if (IS_ERR(root)) -+ goto out_iput; -+ -+ err = au_alloc_dinfo(root); -+ if (!err) { -+ sb->s_root = root; -+ return 0; /* success */ -+ } -+ dput(root); -+ goto out; /* do not iput */ -+ -+ out_iput: -+ iget_failed(inode); -+ iput(inode); -+ out: -+ return err; -+ -+} -+ -+static int aufs_fill_super(struct super_block *sb, void *raw_data, -+ int silent __maybe_unused) -+{ -+ int err; -+ struct au_opts opts; -+ struct dentry *root; -+ struct inode *inode; -+ char *arg = raw_data; -+ -+ if (unlikely(!arg || !*arg)) { -+ err = -EINVAL; -+ pr_err("no arg\n"); -+ goto out; -+ } -+ -+ err = -ENOMEM; -+ memset(&opts, 0, sizeof(opts)); -+ opts.opt = (void *)__get_free_page(GFP_NOFS); -+ if (unlikely(!opts.opt)) -+ goto out; -+ opts.max_opt = PAGE_SIZE / sizeof(*opts.opt); -+ opts.sb_flags = sb->s_flags; -+ -+ err = au_si_alloc(sb); -+ if (unlikely(err)) -+ goto out_opts; -+ -+ /* all timestamps always follow the ones on the branch */ -+ sb->s_flags |= MS_NOATIME | MS_NODIRATIME; -+ sb->s_op = &aufs_sop; -+ sb->s_magic = AUFS_SUPER_MAGIC; -+ sb->s_maxbytes = 0; -+ au_export_init(sb); -+ -+ err = alloc_root(sb); -+ if (unlikely(err)) { -+ si_write_unlock(sb); -+ goto out_info; -+ } -+ root = sb->s_root; -+ inode = root->d_inode; -+ -+ /* -+ * actually we can parse options regardless aufs lock here. -+ * but at remount time, parsing must be done before aufs lock. -+ * so we follow the same rule. -+ */ -+ ii_write_lock_parent(inode); -+ aufs_write_unlock(root); -+ err = au_opts_parse(sb, arg, &opts); -+ if (unlikely(err)) -+ goto out_root; -+ -+ /* lock vfs_inode first, then aufs. */ -+ mutex_lock(&inode->i_mutex); -+ inode->i_op = &aufs_dir_iop; -+ inode->i_fop = &aufs_dir_fop; -+ aufs_write_lock(root); -+ err = au_opts_mount(sb, &opts); -+ au_opts_free(&opts); -+ if (unlikely(err)) -+ goto out_unlock; -+ aufs_write_unlock(root); -+ mutex_unlock(&inode->i_mutex); -+ goto out_opts; /* success */ -+ -+ out_unlock: -+ aufs_write_unlock(root); -+ mutex_unlock(&inode->i_mutex); -+ out_root: -+ dput(root); -+ sb->s_root = NULL; -+ out_info: -+ kobject_put(&au_sbi(sb)->si_kobj); -+ sb->s_fs_info = NULL; -+ out_opts: -+ free_page((unsigned long)opts.opt); -+ out: -+ AuTraceErr(err); -+ err = cvt_err(err); -+ AuTraceErr(err); -+ return err; -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+static int aufs_get_sb(struct file_system_type *fs_type, int flags, -+ const char *dev_name __maybe_unused, void *raw_data, -+ struct vfsmount *mnt) -+{ -+ int err; -+ struct super_block *sb; -+ -+ /* all timestamps always follow the ones on the branch */ -+ /* mnt->mnt_flags |= MNT_NOATIME | MNT_NODIRATIME; */ -+ err = get_sb_nodev(fs_type, flags, raw_data, aufs_fill_super, mnt); -+ if (!err) { -+ sb = mnt->mnt_sb; -+ si_write_lock(sb); -+ sysaufs_brs_add(sb, 0); -+ si_write_unlock(sb); -+ } -+ return err; -+} -+ -+struct file_system_type aufs_fs_type = { -+ .name = AUFS_FSTYPE, -+ .fs_flags = -+ FS_RENAME_DOES_D_MOVE /* a race between rename and others */ -+ | FS_REVAL_DOT, /* for NFS branch and udba */ -+ .get_sb = aufs_get_sb, -+ .kill_sb = generic_shutdown_super, -+ /* no need to __module_get() and module_put(). */ -+ .owner = THIS_MODULE, -+}; -diff --git a/fs/aufs/super.h b/fs/aufs/super.h -new file mode 100644 -index 0000000..63d3ad1 ---- /dev/null -+++ b/fs/aufs/super.h -@@ -0,0 +1,384 @@ -+/* -+ * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * -+ * This program, aufs is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ */ -+ -+/* -+ * super_block operations -+ */ -+ -+#ifndef __AUFS_SUPER_H__ -+#define __AUFS_SUPER_H__ -+ -+#ifdef __KERNEL__ -+ -+#include -+#include -+#include "rwsem.h" -+#include "spl.h" -+#include "wkq.h" -+ -+typedef ssize_t (*au_readf_t)(struct file *, char __user *, size_t, loff_t *); -+typedef ssize_t (*au_writef_t)(struct file *, const char __user *, size_t, -+ loff_t *); -+ -+/* policies to select one among multiple writable branches */ -+struct au_wbr_copyup_operations { -+ int (*copyup)(struct dentry *dentry); -+}; -+ -+struct au_wbr_create_operations { -+ int (*create)(struct dentry *dentry, int isdir); -+ int (*init)(struct super_block *sb); -+ int (*fin)(struct super_block *sb); -+}; -+ -+struct au_wbr_mfs { -+ struct mutex mfs_lock; /* protect this structure */ -+ unsigned long mfs_jiffy; -+ unsigned long mfs_expire; -+ aufs_bindex_t mfs_bindex; -+ -+ unsigned long long mfsrr_bytes; -+ unsigned long long mfsrr_watermark; -+}; -+ -+struct au_branch; -+struct au_sbinfo { -+ /* nowait tasks in the system-wide workqueue */ -+ struct au_nowait_tasks si_nowait; -+ -+ struct au_rwsem si_rwsem; -+ -+ /* branch management */ -+ unsigned int si_generation; -+ -+ /* see above flags */ -+ unsigned char au_si_status; -+ -+ aufs_bindex_t si_bend; -+ aufs_bindex_t si_last_br_id; -+ struct au_branch **si_branch; -+ -+ /* policy to select a writable branch */ -+ unsigned char si_wbr_copyup; -+ unsigned char si_wbr_create; -+ struct au_wbr_copyup_operations *si_wbr_copyup_ops; -+ struct au_wbr_create_operations *si_wbr_create_ops; -+ -+ /* round robin */ -+ atomic_t si_wbr_rr_next; -+ -+ /* most free space */ -+ struct au_wbr_mfs si_wbr_mfs; -+ -+ /* mount flags */ -+ /* include/asm-ia64/siginfo.h defines a macro named si_flags */ -+ unsigned int si_mntflags; -+ -+ /* external inode number (bitmap and translation table) */ -+ au_readf_t si_xread; -+ au_writef_t si_xwrite; -+ struct file *si_xib; -+ struct mutex si_xib_mtx; /* protect xib members */ -+ unsigned long *si_xib_buf; -+ unsigned long si_xib_last_pindex; -+ int si_xib_next_bit; -+ aufs_bindex_t si_xino_brid; -+ /* reserved for future use */ -+ /* unsigned long long si_xib_limit; */ /* Max xib file size */ -+ -+#ifdef CONFIG_AUFS_EXPORT -+ /* i_generation */ -+ struct file *si_xigen; -+ atomic_t si_xigen_next; -+#endif -+ -+ /* vdir parameters */ -+ unsigned long si_rdcache; /* max cache time in HZ */ -+ unsigned int si_rdblk; /* deblk size */ -+ unsigned int si_rdhash; /* hash size */ -+ -+ /* -+ * If the number of whiteouts are larger than si_dirwh, leave all of -+ * them after au_whtmp_ren to reduce the cost of rmdir(2). -+ * future fsck.aufs or kernel thread will remove them later. -+ * Otherwise, remove all whiteouts and the dir in rmdir(2). -+ */ -+ unsigned int si_dirwh; -+ -+ /* -+ * rename(2) a directory with all children. -+ */ -+ /* reserved for future use */ -+ /* int si_rendir; */ -+ -+ /* pseudo_link list */ -+ struct au_splhead si_plink; -+ wait_queue_head_t si_plink_wq; -+ -+ /* -+ * sysfs and lifetime management. -+ * this is not a small structure and it may be a waste of memory in case -+ * of sysfs is disabled, particulary when many aufs-es are mounted. -+ * but using sysfs is majority. -+ */ -+ struct kobject si_kobj; -+#ifdef CONFIG_DEBUG_FS -+ struct dentry *si_dbgaufs, *si_dbgaufs_xib; -+#ifdef CONFIG_AUFS_EXPORT -+ struct dentry *si_dbgaufs_xigen; -+#endif -+#endif -+ -+ /* dirty, necessary for unmounting, sysfs and sysrq */ -+ struct super_block *si_sb; -+}; -+ -+/* sbinfo status flags */ -+/* -+ * set true when refresh_dirs() failed at remount time. -+ * then try refreshing dirs at access time again. -+ * if it is false, refreshing dirs at access time is unnecesary -+ */ -+#define AuSi_FAILED_REFRESH_DIRS 1 -+#define AuSi_MAINTAIN_PLINK (1 << 1) /* ioctl */ -+static inline unsigned char au_do_ftest_si(struct au_sbinfo *sbi, -+ unsigned int flag) -+{ -+ AuRwMustAnyLock(&sbi->si_rwsem); -+ return sbi->au_si_status & flag; -+} -+#define au_ftest_si(sbinfo, name) au_do_ftest_si(sbinfo, AuSi_##name) -+#define au_fset_si(sbinfo, name) do { \ -+ AuRwMustWriteLock(&(sbinfo)->si_rwsem); \ -+ (sbinfo)->au_si_status |= AuSi_##name; \ -+} while (0) -+#define au_fclr_si(sbinfo, name) do { \ -+ AuRwMustWriteLock(&(sbinfo)->si_rwsem); \ -+ (sbinfo)->au_si_status &= ~AuSi_##name; \ -+} while (0) -+ -+/* ---------------------------------------------------------------------- */ -+ -+/* policy to select one among writable branches */ -+#define AuWbrCopyup(sbinfo, ...) \ -+ ((sbinfo)->si_wbr_copyup_ops->copyup(__VA_ARGS__)) -+#define AuWbrCreate(sbinfo, ...) \ -+ ((sbinfo)->si_wbr_create_ops->create(__VA_ARGS__)) -+ -+/* flags for si_read_lock()/aufs_read_lock()/di_read_lock() */ -+#define AuLock_DW 1 /* write-lock dentry */ -+#define AuLock_IR (1 << 1) /* read-lock inode */ -+#define AuLock_IW (1 << 2) /* write-lock inode */ -+#define AuLock_FLUSH (1 << 3) /* wait for 'nowait' tasks */ -+#define AuLock_DIR (1 << 4) /* target is a dir */ -+#define au_ftest_lock(flags, name) ((flags) & AuLock_##name) -+#define au_fset_lock(flags, name) { (flags) |= AuLock_##name; } -+#define au_fclr_lock(flags, name) { (flags) &= ~AuLock_##name; } -+ -+/* ---------------------------------------------------------------------- */ -+ -+/* super.c */ -+extern struct file_system_type aufs_fs_type; -+struct inode *au_iget_locked(struct super_block *sb, ino_t ino); -+ -+/* sbinfo.c */ -+void au_si_free(struct kobject *kobj); -+int au_si_alloc(struct super_block *sb); -+int au_sbr_realloc(struct au_sbinfo *sbinfo, int nbr); -+ -+unsigned int au_sigen_inc(struct super_block *sb); -+aufs_bindex_t au_new_br_id(struct super_block *sb); -+ -+void aufs_read_lock(struct dentry *dentry, int flags); -+void aufs_read_unlock(struct dentry *dentry, int flags); -+void aufs_write_lock(struct dentry *dentry); -+void aufs_write_unlock(struct dentry *dentry); -+void aufs_read_and_write_lock2(struct dentry *d1, struct dentry *d2, int isdir); -+void aufs_read_and_write_unlock2(struct dentry *d1, struct dentry *d2); -+ -+/* wbr_policy.c */ -+extern struct au_wbr_copyup_operations au_wbr_copyup_ops[]; -+extern struct au_wbr_create_operations au_wbr_create_ops[]; -+int au_cpdown_dirs(struct dentry *dentry, aufs_bindex_t bdst); -+ -+/* ---------------------------------------------------------------------- */ -+ -+static inline struct au_sbinfo *au_sbi(struct super_block *sb) -+{ -+ return sb->s_fs_info; -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+#ifdef CONFIG_AUFS_EXPORT -+void au_export_init(struct super_block *sb); -+ -+static inline int au_test_nfsd(struct task_struct *tsk) -+{ -+ return !tsk->mm && !strcmp(tsk->comm, "nfsd"); -+} -+ -+int au_xigen_inc(struct inode *inode); -+int au_xigen_new(struct inode *inode); -+int au_xigen_set(struct super_block *sb, struct file *base); -+void au_xigen_clr(struct super_block *sb); -+ -+static inline int au_busy_or_stale(void) -+{ -+ if (!au_test_nfsd(current)) -+ return -EBUSY; -+ return -ESTALE; -+} -+#else -+static inline void au_export_init(struct super_block *sb) -+{ -+ /* nothing */ -+} -+ -+static inline int au_test_nfsd(struct task_struct *tsk) -+{ -+ return 0; -+} -+ -+static inline int au_xigen_inc(struct inode *inode) -+{ -+ return 0; -+} -+ -+static inline int au_xigen_new(struct inode *inode) -+{ -+ return 0; -+} -+ -+static inline int au_xigen_set(struct super_block *sb, struct file *base) -+{ -+ return 0; -+} -+ -+static inline void au_xigen_clr(struct super_block *sb) -+{ -+ /* empty */ -+} -+ -+static inline int au_busy_or_stale(void) -+{ -+ return -EBUSY; -+} -+#endif /* CONFIG_AUFS_EXPORT */ -+ -+/* ---------------------------------------------------------------------- */ -+ -+static inline void dbgaufs_si_null(struct au_sbinfo *sbinfo) -+{ -+ /* -+ * This function is a dynamic '__init' fucntion actually, -+ * so the tiny check for si_rwsem is unnecessary. -+ */ -+ /* AuRwMustWriteLock(&sbinfo->si_rwsem); */ -+#ifdef CONFIG_DEBUG_FS -+ sbinfo->si_dbgaufs = NULL; -+ sbinfo->si_dbgaufs_xib = NULL; -+#ifdef CONFIG_AUFS_EXPORT -+ sbinfo->si_dbgaufs_xigen = NULL; -+#endif -+#endif -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+/* lock superblock. mainly for entry point functions */ -+/* -+ * si_noflush_read_lock, si_noflush_write_lock, -+ * si_read_unlock, si_write_unlock, si_downgrade_lock -+ */ -+AuSimpleLockRwsemFuncs(si_noflush, struct super_block *sb, -+ &au_sbi(sb)->si_rwsem); -+AuSimpleUnlockRwsemFuncs(si, struct super_block *sb, &au_sbi(sb)->si_rwsem); -+ -+#define SiMustNoWaiters(sb) AuRwMustNoWaiters(&au_sbi(sb)->si_rwsem) -+#define SiMustAnyLock(sb) AuRwMustAnyLock(&au_sbi(sb)->si_rwsem) -+#define SiMustWriteLock(sb) AuRwMustWriteLock(&au_sbi(sb)->si_rwsem) -+ -+static inline void si_read_lock(struct super_block *sb, int flags) -+{ -+ if (au_ftest_lock(flags, FLUSH)) -+ au_nwt_flush(&au_sbi(sb)->si_nowait); -+ si_noflush_read_lock(sb); -+} -+ -+static inline void si_write_lock(struct super_block *sb) -+{ -+ au_nwt_flush(&au_sbi(sb)->si_nowait); -+ si_noflush_write_lock(sb); -+} -+ -+static inline int si_read_trylock(struct super_block *sb, int flags) -+{ -+ if (au_ftest_lock(flags, FLUSH)) -+ au_nwt_flush(&au_sbi(sb)->si_nowait); -+ return si_noflush_read_trylock(sb); -+} -+ -+static inline int si_write_trylock(struct super_block *sb, int flags) -+{ -+ if (au_ftest_lock(flags, FLUSH)) -+ au_nwt_flush(&au_sbi(sb)->si_nowait); -+ return si_noflush_write_trylock(sb); -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+static inline aufs_bindex_t au_sbend(struct super_block *sb) -+{ -+ SiMustAnyLock(sb); -+ return au_sbi(sb)->si_bend; -+} -+ -+static inline unsigned int au_mntflags(struct super_block *sb) -+{ -+ SiMustAnyLock(sb); -+ return au_sbi(sb)->si_mntflags; -+} -+ -+static inline unsigned int au_sigen(struct super_block *sb) -+{ -+ SiMustAnyLock(sb); -+ return au_sbi(sb)->si_generation; -+} -+ -+static inline struct au_branch *au_sbr(struct super_block *sb, -+ aufs_bindex_t bindex) -+{ -+ SiMustAnyLock(sb); -+ return au_sbi(sb)->si_branch[0 + bindex]; -+} -+ -+static inline void au_xino_brid_set(struct super_block *sb, aufs_bindex_t brid) -+{ -+ SiMustWriteLock(sb); -+ au_sbi(sb)->si_xino_brid = brid; -+} -+ -+static inline aufs_bindex_t au_xino_brid(struct super_block *sb) -+{ -+ SiMustAnyLock(sb); -+ return au_sbi(sb)->si_xino_brid; -+} -+ -+#endif /* __KERNEL__ */ -+#endif /* __AUFS_SUPER_H__ */ -diff --git a/fs/aufs/sysaufs.c b/fs/aufs/sysaufs.c -new file mode 100644 -index 0000000..b796330 ---- /dev/null -+++ b/fs/aufs/sysaufs.c -@@ -0,0 +1,104 @@ -+/* -+ * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * -+ * This program, aufs is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ */ -+ -+/* -+ * sysfs interface and lifetime management -+ * they are necessary regardless sysfs is disabled. -+ */ -+ -+#include -+#include -+#include -+#include "aufs.h" -+ -+unsigned long sysaufs_si_mask; -+struct kset *sysaufs_ket; -+ -+#define AuSiAttr(_name) { \ -+ .attr = { .name = __stringify(_name), .mode = 0444 }, \ -+ .show = sysaufs_si_##_name, \ -+} -+ -+static struct sysaufs_si_attr sysaufs_si_attr_xi_path = AuSiAttr(xi_path); -+struct attribute *sysaufs_si_attrs[] = { -+ &sysaufs_si_attr_xi_path.attr, -+ NULL, -+}; -+ -+static struct sysfs_ops au_sbi_ops = { -+ .show = sysaufs_si_show -+}; -+ -+static struct kobj_type au_sbi_ktype = { -+ .release = au_si_free, -+ .sysfs_ops = &au_sbi_ops, -+ .default_attrs = sysaufs_si_attrs -+}; -+ -+/* ---------------------------------------------------------------------- */ -+ -+int sysaufs_si_init(struct au_sbinfo *sbinfo) -+{ -+ int err; -+ -+ sbinfo->si_kobj.kset = sysaufs_ket; -+ /* cf. sysaufs_name() */ -+ err = kobject_init_and_add -+ (&sbinfo->si_kobj, &au_sbi_ktype, /*&sysaufs_ket->kobj*/NULL, -+ SysaufsSiNamePrefix "%lx", sysaufs_si_id(sbinfo)); -+ -+ dbgaufs_si_null(sbinfo); -+ if (!err) { -+ err = dbgaufs_si_init(sbinfo); -+ if (unlikely(err)) -+ kobject_put(&sbinfo->si_kobj); -+ } -+ return err; -+} -+ -+void sysaufs_fin(void) -+{ -+ dbgaufs_fin(); -+ sysfs_remove_group(&sysaufs_ket->kobj, sysaufs_attr_group); -+ kset_unregister(sysaufs_ket); -+} -+ -+int __init sysaufs_init(void) -+{ -+ int err; -+ -+ do { -+ get_random_bytes(&sysaufs_si_mask, sizeof(sysaufs_si_mask)); -+ } while (!sysaufs_si_mask); -+ -+ sysaufs_ket = kset_create_and_add(AUFS_NAME, NULL, fs_kobj); -+ err = PTR_ERR(sysaufs_ket); -+ if (IS_ERR(sysaufs_ket)) -+ goto out; -+ err = sysfs_create_group(&sysaufs_ket->kobj, sysaufs_attr_group); -+ if (unlikely(err)) { -+ kset_unregister(sysaufs_ket); -+ goto out; -+ } -+ -+ err = dbgaufs_init(); -+ if (unlikely(err)) -+ sysaufs_fin(); -+ out: -+ return err; -+} -diff --git a/fs/aufs/sysaufs.h b/fs/aufs/sysaufs.h -new file mode 100644 -index 0000000..379033a ---- /dev/null -+++ b/fs/aufs/sysaufs.h -@@ -0,0 +1,120 @@ -+/* -+ * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * -+ * This program, aufs is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ */ -+ -+/* -+ * sysfs interface and mount lifetime management -+ */ -+ -+#ifndef __SYSAUFS_H__ -+#define __SYSAUFS_H__ -+ -+#ifdef __KERNEL__ -+ -+#include -+#include -+#include "module.h" -+ -+struct super_block; -+struct au_sbinfo; -+ -+struct sysaufs_si_attr { -+ struct attribute attr; -+ int (*show)(struct seq_file *seq, struct super_block *sb); -+}; -+ -+/* ---------------------------------------------------------------------- */ -+ -+/* sysaufs.c */ -+extern unsigned long sysaufs_si_mask; -+extern struct kset *sysaufs_ket; -+extern struct attribute *sysaufs_si_attrs[]; -+int sysaufs_si_init(struct au_sbinfo *sbinfo); -+int __init sysaufs_init(void); -+void sysaufs_fin(void); -+ -+/* ---------------------------------------------------------------------- */ -+ -+/* some people doesn't like to show a pointer in kernel */ -+static inline unsigned long sysaufs_si_id(struct au_sbinfo *sbinfo) -+{ -+ return sysaufs_si_mask ^ (unsigned long)sbinfo; -+} -+ -+#define SysaufsSiNamePrefix "si_" -+#define SysaufsSiNameLen (sizeof(SysaufsSiNamePrefix) + 16) -+static inline void sysaufs_name(struct au_sbinfo *sbinfo, char *name) -+{ -+ snprintf(name, SysaufsSiNameLen, SysaufsSiNamePrefix "%lx", -+ sysaufs_si_id(sbinfo)); -+} -+ -+struct au_branch; -+#ifdef CONFIG_SYSFS -+/* sysfs.c */ -+extern struct attribute_group *sysaufs_attr_group; -+ -+int sysaufs_si_xi_path(struct seq_file *seq, struct super_block *sb); -+ssize_t sysaufs_si_show(struct kobject *kobj, struct attribute *attr, -+ char *buf); -+ -+void sysaufs_br_init(struct au_branch *br); -+void sysaufs_brs_add(struct super_block *sb, aufs_bindex_t bindex); -+void sysaufs_brs_del(struct super_block *sb, aufs_bindex_t bindex); -+ -+#define sysaufs_brs_init() do {} while (0) -+ -+#else -+#define sysaufs_attr_group NULL -+ -+static inline -+int sysaufs_si_xi_path(struct seq_file *seq, struct super_block *sb) -+{ -+ return 0; -+} -+ -+static inline -+ssize_t sysaufs_si_show(struct kobject *kobj, struct attribute *attr, -+ char *buf) -+{ -+ return 0; -+} -+ -+static inline void sysaufs_br_init(struct au_branch *br) -+{ -+ /* empty */ -+} -+ -+static inline void sysaufs_brs_add(struct super_block *sb, aufs_bindex_t bindex) -+{ -+ /* nothing */ -+} -+ -+static inline void sysaufs_brs_del(struct super_block *sb, aufs_bindex_t bindex) -+{ -+ /* nothing */ -+} -+ -+static inline void sysaufs_brs_init(void) -+{ -+ sysaufs_brs = 0; -+} -+ -+#endif /* CONFIG_SYSFS */ -+ -+#endif /* __KERNEL__ */ -+#endif /* __SYSAUFS_H__ */ -diff --git a/fs/aufs/sysfs.c b/fs/aufs/sysfs.c -new file mode 100644 -index 0000000..956bbb9 ---- /dev/null -+++ b/fs/aufs/sysfs.c -@@ -0,0 +1,248 @@ -+/* -+ * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * -+ * This program, aufs is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ */ -+ -+/* -+ * sysfs interface -+ */ -+ -+#include -+#include -+#include -+#include -+#include "aufs.h" -+ -+#ifdef CONFIG_AUFS_FS_MODULE -+/* this entry violates the "one line per file" policy of sysfs */ -+static ssize_t config_show(struct kobject *kobj, struct kobj_attribute *attr, -+ char *buf) -+{ -+ ssize_t err; -+ static char *conf = -+/* this file is generated at compiling */ -+#include "conf.str" -+ ; -+ -+ err = snprintf(buf, PAGE_SIZE, conf); -+ if (unlikely(err >= PAGE_SIZE)) -+ err = -EFBIG; -+ return err; -+} -+ -+static struct kobj_attribute au_config_attr = __ATTR_RO(config); -+#endif -+ -+static struct attribute *au_attr[] = { -+#ifdef CONFIG_AUFS_FS_MODULE -+ &au_config_attr.attr, -+#endif -+ NULL, /* need to NULL terminate the list of attributes */ -+}; -+ -+static struct attribute_group sysaufs_attr_group_body = { -+ .attrs = au_attr -+}; -+ -+struct attribute_group *sysaufs_attr_group = &sysaufs_attr_group_body; -+ -+/* ---------------------------------------------------------------------- */ -+ -+int sysaufs_si_xi_path(struct seq_file *seq, struct super_block *sb) -+{ -+ int err; -+ -+ SiMustAnyLock(sb); -+ -+ err = 0; -+ if (au_opt_test(au_mntflags(sb), XINO)) { -+ err = au_xino_path(seq, au_sbi(sb)->si_xib); -+ seq_putc(seq, '\n'); -+ } -+ return err; -+} -+ -+/* -+ * the lifetime of branch is independent from the entry under sysfs. -+ * sysfs handles the lifetime of the entry, and never call ->show() after it is -+ * unlinked. -+ */ -+static int sysaufs_si_br(struct seq_file *seq, struct super_block *sb, -+ aufs_bindex_t bindex) -+{ -+ struct path path; -+ struct dentry *root; -+ struct au_branch *br; -+ -+ AuDbg("b%d\n", bindex); -+ -+ root = sb->s_root; -+ di_read_lock_parent(root, !AuLock_IR); -+ br = au_sbr(sb, bindex); -+ path.mnt = br->br_mnt; -+ path.dentry = au_h_dptr(root, bindex); -+ au_seq_path(seq, &path); -+ di_read_unlock(root, !AuLock_IR); -+ seq_printf(seq, "=%s\n", au_optstr_br_perm(br->br_perm)); -+ return 0; -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+static struct seq_file *au_seq(char *p, ssize_t len) -+{ -+ struct seq_file *seq; -+ -+ seq = kzalloc(sizeof(*seq), GFP_NOFS); -+ if (seq) { -+ /* mutex_init(&seq.lock); */ -+ seq->buf = p; -+ seq->size = len; -+ return seq; /* success */ -+ } -+ -+ seq = ERR_PTR(-ENOMEM); -+ return seq; -+} -+ -+#define SysaufsBr_PREFIX "br" -+ -+/* todo: file size may exceed PAGE_SIZE */ -+ssize_t sysaufs_si_show(struct kobject *kobj, struct attribute *attr, -+ char *buf) -+{ -+ ssize_t err; -+ long l; -+ aufs_bindex_t bend; -+ struct au_sbinfo *sbinfo; -+ struct super_block *sb; -+ struct seq_file *seq; -+ char *name; -+ struct attribute **cattr; -+ -+ sbinfo = container_of(kobj, struct au_sbinfo, si_kobj); -+ sb = sbinfo->si_sb; -+ -+ /* -+ * prevent a race condition between sysfs and aufs. -+ * for instance, sysfs_file_read() calls sysfs_get_active_two() which -+ * prohibits maintaining the sysfs entries. -+ * hew we acquire read lock after sysfs_get_active_two(). -+ * on the other hand, the remount process may maintain the sysfs/aufs -+ * entries after acquiring write lock. -+ * it can cause a deadlock. -+ * simply we gave up processing read here. -+ */ -+ err = -EBUSY; -+ if (unlikely(!si_noflush_read_trylock(sb))) -+ goto out; -+ -+ seq = au_seq(buf, PAGE_SIZE); -+ err = PTR_ERR(seq); -+ if (IS_ERR(seq)) -+ goto out_unlock; -+ -+ name = (void *)attr->name; -+ cattr = sysaufs_si_attrs; -+ while (*cattr) { -+ if (!strcmp(name, (*cattr)->name)) { -+ err = container_of(*cattr, struct sysaufs_si_attr, attr) -+ ->show(seq, sb); -+ goto out_seq; -+ } -+ cattr++; -+ } -+ -+ bend = au_sbend(sb); -+ if (!strncmp(name, SysaufsBr_PREFIX, sizeof(SysaufsBr_PREFIX) - 1)) { -+ name += sizeof(SysaufsBr_PREFIX) - 1; -+ err = strict_strtol(name, 10, &l); -+ if (!err) { -+ if (l <= bend) -+ err = sysaufs_si_br(seq, sb, (aufs_bindex_t)l); -+ else -+ err = -ENOENT; -+ } -+ goto out_seq; -+ } -+ BUG(); -+ -+ out_seq: -+ if (!err) { -+ err = seq->count; -+ /* sysfs limit */ -+ if (unlikely(err == PAGE_SIZE)) -+ err = -EFBIG; -+ } -+ kfree(seq); -+ out_unlock: -+ si_read_unlock(sb); -+ out: -+ return err; -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+void sysaufs_br_init(struct au_branch *br) -+{ -+ br->br_attr.name = br->br_name; -+ br->br_attr.mode = S_IRUGO; -+ br->br_attr.owner = THIS_MODULE; -+} -+ -+void sysaufs_brs_del(struct super_block *sb, aufs_bindex_t bindex) -+{ -+ struct au_branch *br; -+ struct kobject *kobj; -+ aufs_bindex_t bend; -+ -+ dbgaufs_brs_del(sb, bindex); -+ -+ if (!sysaufs_brs) -+ return; -+ -+ kobj = &au_sbi(sb)->si_kobj; -+ bend = au_sbend(sb); -+ for (; bindex <= bend; bindex++) { -+ br = au_sbr(sb, bindex); -+ sysfs_remove_file(kobj, &br->br_attr); -+ } -+} -+ -+void sysaufs_brs_add(struct super_block *sb, aufs_bindex_t bindex) -+{ -+ int err; -+ aufs_bindex_t bend; -+ struct kobject *kobj; -+ struct au_branch *br; -+ -+ dbgaufs_brs_add(sb, bindex); -+ -+ if (!sysaufs_brs) -+ return; -+ -+ kobj = &au_sbi(sb)->si_kobj; -+ bend = au_sbend(sb); -+ for (; bindex <= bend; bindex++) { -+ br = au_sbr(sb, bindex); -+ snprintf(br->br_name, sizeof(br->br_name), SysaufsBr_PREFIX -+ "%d", bindex); -+ err = sysfs_create_file(kobj, &br->br_attr); -+ if (unlikely(err)) -+ pr_warning("failed %s under sysfs(%d)\n", -+ br->br_name, err); -+ } -+} -diff --git a/fs/aufs/sysrq.c b/fs/aufs/sysrq.c -new file mode 100644 -index 0000000..3db9d84 ---- /dev/null -+++ b/fs/aufs/sysrq.c -@@ -0,0 +1,116 @@ -+/* -+ * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * -+ * This program, aufs is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ */ -+ -+/* -+ * magic sysrq hanlder -+ */ -+ -+#include -+#include -+#include -+/* #include */ -+#include "aufs.h" -+ -+/* ---------------------------------------------------------------------- */ -+ -+static void sysrq_sb(struct super_block *sb) -+{ -+ char *plevel; -+ struct au_sbinfo *sbinfo; -+ struct file *file; -+ -+ plevel = au_plevel; -+ au_plevel = KERN_WARNING; -+ au_debug(1); -+ -+ sbinfo = au_sbi(sb); -+ /* since we define pr_fmt, call printk directly */ -+ printk(KERN_WARNING "si=%lx\n", sysaufs_si_id(sbinfo)); -+ printk(KERN_WARNING AUFS_NAME ": superblock\n"); -+ au_dpri_sb(sb); -+ printk(KERN_WARNING AUFS_NAME ": root dentry\n"); -+ au_dpri_dentry(sb->s_root); -+ printk(KERN_WARNING AUFS_NAME ": root inode\n"); -+ au_dpri_inode(sb->s_root->d_inode); -+#if 0 -+ struct inode *i; -+ printk(KERN_WARNING AUFS_NAME ": isolated inode\n"); -+ list_for_each_entry(i, &sb->s_inodes, i_sb_list) -+ if (list_empty(&i->i_dentry)) -+ au_dpri_inode(i); -+#endif -+ printk(KERN_WARNING AUFS_NAME ": files\n"); -+ list_for_each_entry(file, &sb->s_files, f_u.fu_list) -+ if (!special_file(file->f_dentry->d_inode->i_mode)) -+ au_dpri_file(file); -+ -+ au_plevel = plevel; -+ au_debug(0); -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+/* module parameter */ -+static char *aufs_sysrq_key = "a"; -+module_param_named(sysrq, aufs_sysrq_key, charp, S_IRUGO); -+MODULE_PARM_DESC(sysrq, "MagicSysRq key for " AUFS_NAME); -+ -+static void au_sysrq(int key __maybe_unused, -+ struct tty_struct *tty __maybe_unused) -+{ -+ struct kobject *kobj; -+ struct au_sbinfo *sbinfo; -+ -+ /* spin_lock(&sysaufs_ket->list_lock); */ -+ list_for_each_entry(kobj, &sysaufs_ket->list, entry) { -+ sbinfo = container_of(kobj, struct au_sbinfo, si_kobj); -+ sysrq_sb(sbinfo->si_sb); -+ } -+ /* spin_unlock(&sysaufs_ket->list_lock); */ -+} -+ -+static struct sysrq_key_op au_sysrq_op = { -+ .handler = au_sysrq, -+ .help_msg = "Aufs", -+ .action_msg = "Aufs", -+ .enable_mask = SYSRQ_ENABLE_DUMP -+}; -+ -+/* ---------------------------------------------------------------------- */ -+ -+int __init au_sysrq_init(void) -+{ -+ int err; -+ char key; -+ -+ err = -1; -+ key = *aufs_sysrq_key; -+ if ('a' <= key && key <= 'z') -+ err = register_sysrq_key(key, &au_sysrq_op); -+ if (unlikely(err)) -+ pr_err("err %d, sysrq=%c\n", err, key); -+ return err; -+} -+ -+void au_sysrq_fin(void) -+{ -+ int err; -+ err = unregister_sysrq_key(*aufs_sysrq_key, &au_sysrq_op); -+ if (unlikely(err)) -+ pr_err("err %d (ignored)\n", err); -+} -diff --git a/fs/aufs/vdir.c b/fs/aufs/vdir.c -new file mode 100644 -index 0000000..50a3caf ---- /dev/null -+++ b/fs/aufs/vdir.c -@@ -0,0 +1,878 @@ -+/* -+ * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * -+ * This program, aufs is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ */ -+ -+/* -+ * virtual or vertical directory -+ */ -+ -+#include -+#include "aufs.h" -+ -+static unsigned int calc_size(int nlen) -+{ -+ return ALIGN(sizeof(struct au_vdir_de) + nlen, sizeof(ino_t)); -+} -+ -+static int set_deblk_end(union au_vdir_deblk_p *p, -+ union au_vdir_deblk_p *deblk_end) -+{ -+ if (calc_size(0) <= deblk_end->deblk - p->deblk) { -+ p->de->de_str.len = 0; -+ /* smp_mb(); */ -+ return 0; -+ } -+ return -1; /* error */ -+} -+ -+/* returns true or false */ -+static int is_deblk_end(union au_vdir_deblk_p *p, -+ union au_vdir_deblk_p *deblk_end) -+{ -+ if (calc_size(0) <= deblk_end->deblk - p->deblk) -+ return !p->de->de_str.len; -+ return 1; -+} -+ -+static unsigned char *last_deblk(struct au_vdir *vdir) -+{ -+ return vdir->vd_deblk[vdir->vd_nblk - 1]; -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+/* estimate the apropriate size for name hash table */ -+unsigned int au_rdhash_est(loff_t sz) -+{ -+ unsigned int n; -+ -+ n = UINT_MAX; -+ sz >>= 10; -+ if (sz < n) -+ n = sz; -+ if (sz < AUFS_RDHASH_DEF) -+ n = AUFS_RDHASH_DEF; -+ /* pr_info("n %u\n", n); */ -+ return n; -+} -+ -+/* -+ * the allocated memory has to be freed by -+ * au_nhash_wh_free() or au_nhash_de_free(). -+ */ -+int au_nhash_alloc(struct au_nhash *nhash, unsigned int num_hash, gfp_t gfp) -+{ -+ struct hlist_head *head; -+ unsigned int u; -+ -+ head = kmalloc(sizeof(*nhash->nh_head) * num_hash, gfp); -+ if (head) { -+ nhash->nh_num = num_hash; -+ nhash->nh_head = head; -+ for (u = 0; u < num_hash; u++) -+ INIT_HLIST_HEAD(head++); -+ return 0; /* success */ -+ } -+ -+ return -ENOMEM; -+} -+ -+static void nhash_count(struct hlist_head *head) -+{ -+#if 0 -+ unsigned long n; -+ struct hlist_node *pos; -+ -+ n = 0; -+ hlist_for_each(pos, head) -+ n++; -+ pr_info("%lu\n", n); -+#endif -+} -+ -+static void au_nhash_wh_do_free(struct hlist_head *head) -+{ -+ struct au_vdir_wh *tpos; -+ struct hlist_node *pos, *node; -+ -+ hlist_for_each_entry_safe(tpos, pos, node, head, wh_hash) { -+ /* hlist_del(pos); */ -+ kfree(tpos); -+ } -+} -+ -+static void au_nhash_de_do_free(struct hlist_head *head) -+{ -+ struct au_vdir_dehstr *tpos; -+ struct hlist_node *pos, *node; -+ -+ hlist_for_each_entry_safe(tpos, pos, node, head, hash) { -+ /* hlist_del(pos); */ -+ au_cache_free_dehstr(tpos); -+ } -+} -+ -+static void au_nhash_do_free(struct au_nhash *nhash, -+ void (*free)(struct hlist_head *head)) -+{ -+ unsigned int n; -+ struct hlist_head *head; -+ -+ n = nhash->nh_num; -+ if (!n) -+ return; -+ -+ head = nhash->nh_head; -+ while (n-- > 0) { -+ nhash_count(head); -+ free(head++); -+ } -+ kfree(nhash->nh_head); -+} -+ -+void au_nhash_wh_free(struct au_nhash *whlist) -+{ -+ au_nhash_do_free(whlist, au_nhash_wh_do_free); -+} -+ -+static void au_nhash_de_free(struct au_nhash *delist) -+{ -+ au_nhash_do_free(delist, au_nhash_de_do_free); -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+int au_nhash_test_longer_wh(struct au_nhash *whlist, aufs_bindex_t btgt, -+ int limit) -+{ -+ int num; -+ unsigned int u, n; -+ struct hlist_head *head; -+ struct au_vdir_wh *tpos; -+ struct hlist_node *pos; -+ -+ num = 0; -+ n = whlist->nh_num; -+ head = whlist->nh_head; -+ for (u = 0; u < n; u++, head++) -+ hlist_for_each_entry(tpos, pos, head, wh_hash) -+ if (tpos->wh_bindex == btgt && ++num > limit) -+ return 1; -+ return 0; -+} -+ -+static struct hlist_head *au_name_hash(struct au_nhash *nhash, -+ unsigned char *name, -+ unsigned int len) -+{ -+ unsigned int v; -+ /* const unsigned int magic_bit = 12; */ -+ -+ AuDebugOn(!nhash->nh_num || !nhash->nh_head); -+ -+ v = 0; -+ while (len--) -+ v += *name++; -+ /* v = hash_long(v, magic_bit); */ -+ v %= nhash->nh_num; -+ return nhash->nh_head + v; -+} -+ -+static int au_nhash_test_name(struct au_vdir_destr *str, const char *name, -+ int nlen) -+{ -+ return str->len == nlen && !memcmp(str->name, name, nlen); -+} -+ -+/* returns found or not */ -+int au_nhash_test_known_wh(struct au_nhash *whlist, char *name, int nlen) -+{ -+ struct hlist_head *head; -+ struct au_vdir_wh *tpos; -+ struct hlist_node *pos; -+ struct au_vdir_destr *str; -+ -+ head = au_name_hash(whlist, name, nlen); -+ hlist_for_each_entry(tpos, pos, head, wh_hash) { -+ str = &tpos->wh_str; -+ AuDbg("%.*s\n", str->len, str->name); -+ if (au_nhash_test_name(str, name, nlen)) -+ return 1; -+ } -+ return 0; -+} -+ -+/* returns found(true) or not */ -+static int test_known(struct au_nhash *delist, char *name, int nlen) -+{ -+ struct hlist_head *head; -+ struct au_vdir_dehstr *tpos; -+ struct hlist_node *pos; -+ struct au_vdir_destr *str; -+ -+ head = au_name_hash(delist, name, nlen); -+ hlist_for_each_entry(tpos, pos, head, hash) { -+ str = tpos->str; -+ AuDbg("%.*s\n", str->len, str->name); -+ if (au_nhash_test_name(str, name, nlen)) -+ return 1; -+ } -+ return 0; -+} -+ -+static void au_shwh_init_wh(struct au_vdir_wh *wh, ino_t ino, -+ unsigned char d_type) -+{ -+#ifdef CONFIG_AUFS_SHWH -+ wh->wh_ino = ino; -+ wh->wh_type = d_type; -+#endif -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+int au_nhash_append_wh(struct au_nhash *whlist, char *name, int nlen, ino_t ino, -+ unsigned int d_type, aufs_bindex_t bindex, -+ unsigned char shwh) -+{ -+ int err; -+ struct au_vdir_destr *str; -+ struct au_vdir_wh *wh; -+ -+ AuDbg("%.*s\n", nlen, name); -+ AuDebugOn(!whlist->nh_num || !whlist->nh_head); -+ -+ err = -ENOMEM; -+ wh = kmalloc(sizeof(*wh) + nlen, GFP_NOFS); -+ if (unlikely(!wh)) -+ goto out; -+ -+ err = 0; -+ wh->wh_bindex = bindex; -+ if (shwh) -+ au_shwh_init_wh(wh, ino, d_type); -+ str = &wh->wh_str; -+ str->len = nlen; -+ memcpy(str->name, name, nlen); -+ hlist_add_head(&wh->wh_hash, au_name_hash(whlist, name, nlen)); -+ /* smp_mb(); */ -+ -+ out: -+ return err; -+} -+ -+static int append_deblk(struct au_vdir *vdir) -+{ -+ int err; -+ unsigned long ul; -+ const unsigned int deblk_sz = vdir->vd_deblk_sz; -+ union au_vdir_deblk_p p, deblk_end; -+ unsigned char **o; -+ -+ err = -ENOMEM; -+ o = krealloc(vdir->vd_deblk, sizeof(*o) * (vdir->vd_nblk + 1), -+ GFP_NOFS); -+ if (unlikely(!o)) -+ goto out; -+ -+ vdir->vd_deblk = o; -+ p.deblk = kmalloc(deblk_sz, GFP_NOFS); -+ if (p.deblk) { -+ ul = vdir->vd_nblk++; -+ vdir->vd_deblk[ul] = p.deblk; -+ vdir->vd_last.ul = ul; -+ vdir->vd_last.p.deblk = p.deblk; -+ deblk_end.deblk = p.deblk + deblk_sz; -+ err = set_deblk_end(&p, &deblk_end); -+ } -+ -+ out: -+ return err; -+} -+ -+static int append_de(struct au_vdir *vdir, char *name, int nlen, ino_t ino, -+ unsigned int d_type, struct au_nhash *delist) -+{ -+ int err; -+ unsigned int sz; -+ const unsigned int deblk_sz = vdir->vd_deblk_sz; -+ union au_vdir_deblk_p p, *room, deblk_end; -+ struct au_vdir_dehstr *dehstr; -+ -+ p.deblk = last_deblk(vdir); -+ deblk_end.deblk = p.deblk + deblk_sz; -+ room = &vdir->vd_last.p; -+ AuDebugOn(room->deblk < p.deblk || deblk_end.deblk <= room->deblk -+ || !is_deblk_end(room, &deblk_end)); -+ -+ sz = calc_size(nlen); -+ if (unlikely(sz > deblk_end.deblk - room->deblk)) { -+ err = append_deblk(vdir); -+ if (unlikely(err)) -+ goto out; -+ -+ p.deblk = last_deblk(vdir); -+ deblk_end.deblk = p.deblk + deblk_sz; -+ /* smp_mb(); */ -+ AuDebugOn(room->deblk != p.deblk); -+ } -+ -+ err = -ENOMEM; -+ dehstr = au_cache_alloc_dehstr(); -+ if (unlikely(!dehstr)) -+ goto out; -+ -+ dehstr->str = &room->de->de_str; -+ hlist_add_head(&dehstr->hash, au_name_hash(delist, name, nlen)); -+ room->de->de_ino = ino; -+ room->de->de_type = d_type; -+ room->de->de_str.len = nlen; -+ memcpy(room->de->de_str.name, name, nlen); -+ -+ err = 0; -+ room->deblk += sz; -+ if (unlikely(set_deblk_end(room, &deblk_end))) -+ err = append_deblk(vdir); -+ /* smp_mb(); */ -+ -+ out: -+ return err; -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+void au_vdir_free(struct au_vdir *vdir) -+{ -+ unsigned char **deblk; -+ -+ deblk = vdir->vd_deblk; -+ while (vdir->vd_nblk--) -+ kfree(*deblk++); -+ kfree(vdir->vd_deblk); -+ au_cache_free_vdir(vdir); -+} -+ -+static struct au_vdir *alloc_vdir(struct file *file) -+{ -+ struct au_vdir *vdir; -+ struct super_block *sb; -+ int err; -+ -+ sb = file->f_dentry->d_sb; -+ SiMustAnyLock(sb); -+ -+ err = -ENOMEM; -+ vdir = au_cache_alloc_vdir(); -+ if (unlikely(!vdir)) -+ goto out; -+ -+ vdir->vd_deblk = kzalloc(sizeof(*vdir->vd_deblk), GFP_NOFS); -+ if (unlikely(!vdir->vd_deblk)) -+ goto out_free; -+ -+ vdir->vd_deblk_sz = au_sbi(sb)->si_rdblk; -+ if (!vdir->vd_deblk_sz) { -+ /* estimate the apropriate size for deblk */ -+ vdir->vd_deblk_sz = au_dir_size(file, /*dentry*/NULL); -+ /* pr_info("vd_deblk_sz %u\n", vdir->vd_deblk_sz); */ -+ } -+ vdir->vd_nblk = 0; -+ vdir->vd_version = 0; -+ vdir->vd_jiffy = 0; -+ err = append_deblk(vdir); -+ if (!err) -+ return vdir; /* success */ -+ -+ kfree(vdir->vd_deblk); -+ -+ out_free: -+ au_cache_free_vdir(vdir); -+ out: -+ vdir = ERR_PTR(err); -+ return vdir; -+} -+ -+static int reinit_vdir(struct au_vdir *vdir) -+{ -+ int err; -+ union au_vdir_deblk_p p, deblk_end; -+ -+ while (vdir->vd_nblk > 1) { -+ kfree(vdir->vd_deblk[vdir->vd_nblk - 1]); -+ /* vdir->vd_deblk[vdir->vd_nblk - 1] = NULL; */ -+ vdir->vd_nblk--; -+ } -+ p.deblk = vdir->vd_deblk[0]; -+ deblk_end.deblk = p.deblk + vdir->vd_deblk_sz; -+ err = set_deblk_end(&p, &deblk_end); -+ /* keep vd_dblk_sz */ -+ vdir->vd_last.ul = 0; -+ vdir->vd_last.p.deblk = vdir->vd_deblk[0]; -+ vdir->vd_version = 0; -+ vdir->vd_jiffy = 0; -+ /* smp_mb(); */ -+ return err; -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+#define AuFillVdir_CALLED 1 -+#define AuFillVdir_WHABLE (1 << 1) -+#define AuFillVdir_SHWH (1 << 2) -+#define au_ftest_fillvdir(flags, name) ((flags) & AuFillVdir_##name) -+#define au_fset_fillvdir(flags, name) { (flags) |= AuFillVdir_##name; } -+#define au_fclr_fillvdir(flags, name) { (flags) &= ~AuFillVdir_##name; } -+ -+#ifndef CONFIG_AUFS_SHWH -+#undef AuFillVdir_SHWH -+#define AuFillVdir_SHWH 0 -+#endif -+ -+struct fillvdir_arg { -+ struct file *file; -+ struct au_vdir *vdir; -+ struct au_nhash delist; -+ struct au_nhash whlist; -+ aufs_bindex_t bindex; -+ unsigned int flags; -+ int err; -+}; -+ -+static int fillvdir(void *__arg, const char *__name, int nlen, -+ loff_t offset __maybe_unused, u64 h_ino, -+ unsigned int d_type) -+{ -+ struct fillvdir_arg *arg = __arg; -+ char *name = (void *)__name; -+ struct super_block *sb; -+ ino_t ino; -+ const unsigned char shwh = !!au_ftest_fillvdir(arg->flags, SHWH); -+ -+ arg->err = 0; -+ sb = arg->file->f_dentry->d_sb; -+ au_fset_fillvdir(arg->flags, CALLED); -+ /* smp_mb(); */ -+ if (nlen <= AUFS_WH_PFX_LEN -+ || memcmp(name, AUFS_WH_PFX, AUFS_WH_PFX_LEN)) { -+ if (test_known(&arg->delist, name, nlen) -+ || au_nhash_test_known_wh(&arg->whlist, name, nlen)) -+ goto out; /* already exists or whiteouted */ -+ -+ sb = arg->file->f_dentry->d_sb; -+ arg->err = au_ino(sb, arg->bindex, h_ino, d_type, &ino); -+ if (!arg->err) -+ arg->err = append_de(arg->vdir, name, nlen, ino, -+ d_type, &arg->delist); -+ } else if (au_ftest_fillvdir(arg->flags, WHABLE)) { -+ name += AUFS_WH_PFX_LEN; -+ nlen -= AUFS_WH_PFX_LEN; -+ if (au_nhash_test_known_wh(&arg->whlist, name, nlen)) -+ goto out; /* already whiteouted */ -+ -+ if (shwh) -+ arg->err = au_wh_ino(sb, arg->bindex, h_ino, d_type, -+ &ino); -+ if (!arg->err) -+ arg->err = au_nhash_append_wh -+ (&arg->whlist, name, nlen, ino, d_type, -+ arg->bindex, shwh); -+ } -+ -+ out: -+ if (!arg->err) -+ arg->vdir->vd_jiffy = jiffies; -+ /* smp_mb(); */ -+ AuTraceErr(arg->err); -+ return arg->err; -+} -+ -+static int au_handle_shwh(struct super_block *sb, struct au_vdir *vdir, -+ struct au_nhash *whlist, struct au_nhash *delist) -+{ -+#ifdef CONFIG_AUFS_SHWH -+ int err; -+ unsigned int nh, u; -+ struct hlist_head *head; -+ struct au_vdir_wh *tpos; -+ struct hlist_node *pos, *n; -+ char *p, *o; -+ struct au_vdir_destr *destr; -+ -+ AuDebugOn(!au_opt_test(au_mntflags(sb), SHWH)); -+ -+ err = -ENOMEM; -+ o = p = __getname(); -+ if (unlikely(!p)) -+ goto out; -+ -+ err = 0; -+ nh = whlist->nh_num; -+ memcpy(p, AUFS_WH_PFX, AUFS_WH_PFX_LEN); -+ p += AUFS_WH_PFX_LEN; -+ for (u = 0; u < nh; u++) { -+ head = whlist->nh_head + u; -+ hlist_for_each_entry_safe(tpos, pos, n, head, wh_hash) { -+ destr = &tpos->wh_str; -+ memcpy(p, destr->name, destr->len); -+ err = append_de(vdir, o, destr->len + AUFS_WH_PFX_LEN, -+ tpos->wh_ino, tpos->wh_type, delist); -+ if (unlikely(err)) -+ break; -+ } -+ } -+ -+ __putname(o); -+ -+ out: -+ AuTraceErr(err); -+ return err; -+#else -+ return 0; -+#endif -+} -+ -+static int au_do_read_vdir(struct fillvdir_arg *arg) -+{ -+ int err; -+ unsigned int rdhash; -+ loff_t offset; -+ aufs_bindex_t bend, bindex, bstart; -+ unsigned char shwh; -+ struct file *hf, *file; -+ struct super_block *sb; -+ -+ file = arg->file; -+ sb = file->f_dentry->d_sb; -+ SiMustAnyLock(sb); -+ -+ rdhash = au_sbi(sb)->si_rdhash; -+ if (!rdhash) -+ rdhash = au_rdhash_est(au_dir_size(file, /*dentry*/NULL)); -+ err = au_nhash_alloc(&arg->delist, rdhash, GFP_NOFS); -+ if (unlikely(err)) -+ goto out; -+ err = au_nhash_alloc(&arg->whlist, rdhash, GFP_NOFS); -+ if (unlikely(err)) -+ goto out_delist; -+ -+ err = 0; -+ arg->flags = 0; -+ shwh = 0; -+ if (au_opt_test(au_mntflags(sb), SHWH)) { -+ shwh = 1; -+ au_fset_fillvdir(arg->flags, SHWH); -+ } -+ bstart = au_fbstart(file); -+ bend = au_fbend(file); -+ for (bindex = bstart; !err && bindex <= bend; bindex++) { -+ hf = au_h_fptr(file, bindex); -+ if (!hf) -+ continue; -+ -+ offset = vfsub_llseek(hf, 0, SEEK_SET); -+ err = offset; -+ if (unlikely(offset)) -+ break; -+ -+ arg->bindex = bindex; -+ au_fclr_fillvdir(arg->flags, WHABLE); -+ if (shwh -+ || (bindex != bend -+ && au_br_whable(au_sbr_perm(sb, bindex)))) -+ au_fset_fillvdir(arg->flags, WHABLE); -+ do { -+ arg->err = 0; -+ au_fclr_fillvdir(arg->flags, CALLED); -+ /* smp_mb(); */ -+ err = vfsub_readdir(hf, fillvdir, arg); -+ if (err >= 0) -+ err = arg->err; -+ } while (!err && au_ftest_fillvdir(arg->flags, CALLED)); -+ } -+ -+ if (!err && shwh) -+ err = au_handle_shwh(sb, arg->vdir, &arg->whlist, &arg->delist); -+ -+ au_nhash_wh_free(&arg->whlist); -+ -+ out_delist: -+ au_nhash_de_free(&arg->delist); -+ out: -+ return err; -+} -+ -+static int read_vdir(struct file *file, int may_read) -+{ -+ int err; -+ unsigned long expire; -+ unsigned char do_read; -+ struct fillvdir_arg arg; -+ struct inode *inode; -+ struct au_vdir *vdir, *allocated; -+ -+ err = 0; -+ inode = file->f_dentry->d_inode; -+ IMustLock(inode); -+ SiMustAnyLock(inode->i_sb); -+ -+ allocated = NULL; -+ do_read = 0; -+ expire = au_sbi(inode->i_sb)->si_rdcache; -+ vdir = au_ivdir(inode); -+ if (!vdir) { -+ do_read = 1; -+ vdir = alloc_vdir(file); -+ err = PTR_ERR(vdir); -+ if (IS_ERR(vdir)) -+ goto out; -+ err = 0; -+ allocated = vdir; -+ } else if (may_read -+ && (inode->i_version != vdir->vd_version -+ || time_after(jiffies, vdir->vd_jiffy + expire))) { -+ do_read = 1; -+ err = reinit_vdir(vdir); -+ if (unlikely(err)) -+ goto out; -+ } -+ -+ if (!do_read) -+ return 0; /* success */ -+ -+ arg.file = file; -+ arg.vdir = vdir; -+ err = au_do_read_vdir(&arg); -+ if (!err) { -+ /* file->f_pos = 0; */ -+ vdir->vd_version = inode->i_version; -+ vdir->vd_last.ul = 0; -+ vdir->vd_last.p.deblk = vdir->vd_deblk[0]; -+ if (allocated) -+ au_set_ivdir(inode, allocated); -+ } else if (allocated) -+ au_vdir_free(allocated); -+ -+ out: -+ return err; -+} -+ -+static int copy_vdir(struct au_vdir *tgt, struct au_vdir *src) -+{ -+ int err, rerr; -+ unsigned long ul, n; -+ const unsigned int deblk_sz = src->vd_deblk_sz; -+ -+ AuDebugOn(tgt->vd_nblk != 1); -+ -+ err = -ENOMEM; -+ if (tgt->vd_nblk < src->vd_nblk) { -+ unsigned char **p; -+ -+ p = krealloc(tgt->vd_deblk, sizeof(*p) * src->vd_nblk, -+ GFP_NOFS); -+ if (unlikely(!p)) -+ goto out; -+ tgt->vd_deblk = p; -+ } -+ -+ if (tgt->vd_deblk_sz != deblk_sz) { -+ unsigned char *p; -+ -+ tgt->vd_deblk_sz = deblk_sz; -+ p = krealloc(tgt->vd_deblk[0], deblk_sz, GFP_NOFS); -+ if (unlikely(!p)) -+ goto out; -+ tgt->vd_deblk[0] = p; -+ } -+ memcpy(tgt->vd_deblk[0], src->vd_deblk[0], deblk_sz); -+ tgt->vd_version = src->vd_version; -+ tgt->vd_jiffy = src->vd_jiffy; -+ -+ n = src->vd_nblk; -+ for (ul = 1; ul < n; ul++) { -+ tgt->vd_deblk[ul] = kmemdup(src->vd_deblk[ul], deblk_sz, -+ GFP_NOFS); -+ if (unlikely(!tgt->vd_deblk[ul])) -+ goto out; -+ tgt->vd_nblk++; -+ } -+ tgt->vd_nblk = n; -+ tgt->vd_last.ul = tgt->vd_last.ul; -+ tgt->vd_last.p.deblk = tgt->vd_deblk[tgt->vd_last.ul]; -+ tgt->vd_last.p.deblk += src->vd_last.p.deblk -+ - src->vd_deblk[src->vd_last.ul]; -+ /* smp_mb(); */ -+ return 0; /* success */ -+ -+ out: -+ rerr = reinit_vdir(tgt); -+ BUG_ON(rerr); -+ return err; -+} -+ -+int au_vdir_init(struct file *file) -+{ -+ int err; -+ struct inode *inode; -+ struct au_vdir *vdir_cache, *allocated; -+ -+ err = read_vdir(file, !file->f_pos); -+ if (unlikely(err)) -+ goto out; -+ -+ allocated = NULL; -+ vdir_cache = au_fvdir_cache(file); -+ if (!vdir_cache) { -+ vdir_cache = alloc_vdir(file); -+ err = PTR_ERR(vdir_cache); -+ if (IS_ERR(vdir_cache)) -+ goto out; -+ allocated = vdir_cache; -+ } else if (!file->f_pos && vdir_cache->vd_version != file->f_version) { -+ err = reinit_vdir(vdir_cache); -+ if (unlikely(err)) -+ goto out; -+ } else -+ return 0; /* success */ -+ -+ inode = file->f_dentry->d_inode; -+ err = copy_vdir(vdir_cache, au_ivdir(inode)); -+ if (!err) { -+ file->f_version = inode->i_version; -+ if (allocated) -+ au_set_fvdir_cache(file, allocated); -+ } else if (allocated) -+ au_vdir_free(allocated); -+ -+ out: -+ return err; -+} -+ -+static loff_t calc_offset(struct au_vdir *vdir) -+{ -+ loff_t offset; -+ union au_vdir_deblk_p p; -+ -+ p.deblk = vdir->vd_deblk[vdir->vd_last.ul]; -+ offset = vdir->vd_last.p.deblk - p.deblk; -+ offset += vdir->vd_deblk_sz * vdir->vd_last.ul; -+ return offset; -+} -+ -+/* returns true or false */ -+static int seek_vdir(struct file *file) -+{ -+ int valid; -+ unsigned int deblk_sz; -+ unsigned long ul, n; -+ loff_t offset; -+ union au_vdir_deblk_p p, deblk_end; -+ struct au_vdir *vdir_cache; -+ -+ valid = 1; -+ vdir_cache = au_fvdir_cache(file); -+ offset = calc_offset(vdir_cache); -+ AuDbg("offset %lld\n", offset); -+ if (file->f_pos == offset) -+ goto out; -+ -+ vdir_cache->vd_last.ul = 0; -+ vdir_cache->vd_last.p.deblk = vdir_cache->vd_deblk[0]; -+ if (!file->f_pos) -+ goto out; -+ -+ valid = 0; -+ deblk_sz = vdir_cache->vd_deblk_sz; -+ ul = div64_u64(file->f_pos, deblk_sz); -+ AuDbg("ul %lu\n", ul); -+ if (ul >= vdir_cache->vd_nblk) -+ goto out; -+ -+ n = vdir_cache->vd_nblk; -+ for (; ul < n; ul++) { -+ p.deblk = vdir_cache->vd_deblk[ul]; -+ deblk_end.deblk = p.deblk + deblk_sz; -+ offset = ul; -+ offset *= deblk_sz; -+ while (!is_deblk_end(&p, &deblk_end) && offset < file->f_pos) { -+ unsigned int l; -+ -+ l = calc_size(p.de->de_str.len); -+ offset += l; -+ p.deblk += l; -+ } -+ if (!is_deblk_end(&p, &deblk_end)) { -+ valid = 1; -+ vdir_cache->vd_last.ul = ul; -+ vdir_cache->vd_last.p = p; -+ break; -+ } -+ } -+ -+ out: -+ /* smp_mb(); */ -+ AuTraceErr(!valid); -+ return valid; -+} -+ -+int au_vdir_fill_de(struct file *file, void *dirent, filldir_t filldir) -+{ -+ int err; -+ unsigned int l, deblk_sz; -+ union au_vdir_deblk_p deblk_end; -+ struct au_vdir *vdir_cache; -+ struct au_vdir_de *de; -+ -+ vdir_cache = au_fvdir_cache(file); -+ if (!seek_vdir(file)) -+ return 0; -+ -+ deblk_sz = vdir_cache->vd_deblk_sz; -+ while (1) { -+ deblk_end.deblk = vdir_cache->vd_deblk[vdir_cache->vd_last.ul]; -+ deblk_end.deblk += deblk_sz; -+ while (!is_deblk_end(&vdir_cache->vd_last.p, &deblk_end)) { -+ de = vdir_cache->vd_last.p.de; -+ AuDbg("%.*s, off%lld, i%lu, dt%d\n", -+ de->de_str.len, de->de_str.name, file->f_pos, -+ (unsigned long)de->de_ino, de->de_type); -+ err = filldir(dirent, de->de_str.name, de->de_str.len, -+ file->f_pos, de->de_ino, de->de_type); -+ if (unlikely(err)) { -+ AuTraceErr(err); -+ /* todo: ignore the error caused by udba? */ -+ /* return err; */ -+ return 0; -+ } -+ -+ l = calc_size(de->de_str.len); -+ vdir_cache->vd_last.p.deblk += l; -+ file->f_pos += l; -+ } -+ if (vdir_cache->vd_last.ul < vdir_cache->vd_nblk - 1) { -+ vdir_cache->vd_last.ul++; -+ vdir_cache->vd_last.p.deblk -+ = vdir_cache->vd_deblk[vdir_cache->vd_last.ul]; -+ file->f_pos = deblk_sz * vdir_cache->vd_last.ul; -+ continue; -+ } -+ break; -+ } -+ -+ /* smp_mb(); */ -+ return 0; -+} -diff --git a/fs/aufs/vfsub.c b/fs/aufs/vfsub.c -new file mode 100644 -index 0000000..34c0d95 ---- /dev/null -+++ b/fs/aufs/vfsub.c -@@ -0,0 +1,753 @@ -+/* -+ * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * -+ * This program, aufs is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ */ -+ -+/* -+ * sub-routines for VFS -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include "aufs.h" -+ -+int vfsub_update_h_iattr(struct path *h_path, int *did) -+{ -+ int err; -+ struct kstat st; -+ struct super_block *h_sb; -+ -+ /* for remote fs, leave work for its getattr or d_revalidate */ -+ /* for bad i_attr fs, handle them in aufs_getattr() */ -+ /* still some fs may acquire i_mutex. we need to skip them */ -+ err = 0; -+ if (!did) -+ did = &err; -+ h_sb = h_path->dentry->d_sb; -+ *did = (!au_test_fs_remote(h_sb) && au_test_fs_refresh_iattr(h_sb)); -+ if (*did) -+ err = vfs_getattr(h_path->mnt, h_path->dentry, &st); -+ -+ return err; -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+struct file *vfsub_dentry_open(struct path *path, int flags, -+ const struct cred *cred) -+{ -+ struct file *file; -+ -+ file = dentry_open(path->dentry, path->mnt, flags, cred); -+ if (IS_ERR(file)) -+ return file; -+ /* as NFSD does, just call ima_..._get() simply after dentry_open */ -+ ima_counts_get(file); -+ return file; -+} -+ -+struct file *vfsub_filp_open(const char *path, int oflags, int mode) -+{ -+ struct file *file; -+ -+ /* lockdep_off(); */ -+ file = filp_open(path, oflags, mode); -+ /* lockdep_on(); */ -+ if (IS_ERR(file)) -+ goto out; -+ vfsub_update_h_iattr(&file->f_path, /*did*/NULL); /*ignore*/ -+ -+ out: -+ return file; -+} -+ -+int vfsub_kern_path(const char *name, unsigned int flags, struct path *path) -+{ -+ int err; -+ -+ /* lockdep_off(); */ -+ err = kern_path(name, flags, path); -+ /* lockdep_on(); */ -+ if (!err && path->dentry->d_inode) -+ vfsub_update_h_iattr(path, /*did*/NULL); /*ignore*/ -+ return err; -+} -+ -+struct dentry *vfsub_lookup_one_len(const char *name, struct dentry *parent, -+ int len) -+{ -+ struct path path = { -+ .mnt = NULL -+ }; -+ -+ /* VFS checks it too, but by WARN_ON_ONCE() */ -+ IMustLock(parent->d_inode); -+ -+ path.dentry = lookup_one_len(name, parent, len); -+ if (IS_ERR(path.dentry)) -+ goto out; -+ if (path.dentry->d_inode) -+ vfsub_update_h_iattr(&path, /*did*/NULL); /*ignore*/ -+ -+ out: -+ AuTraceErrPtr(path.dentry); -+ return path.dentry; -+} -+ -+struct dentry *vfsub_lookup_hash(struct nameidata *nd) -+{ -+ struct path path = { -+ .mnt = nd->path.mnt -+ }; -+ -+ IMustLock(nd->path.dentry->d_inode); -+ -+ path.dentry = lookup_hash(nd); -+ if (!IS_ERR(path.dentry) && path.dentry->d_inode) -+ vfsub_update_h_iattr(&path, /*did*/NULL); /*ignore*/ -+ -+ AuTraceErrPtr(path.dentry); -+ return path.dentry; -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+struct dentry *vfsub_lock_rename(struct dentry *d1, struct au_hinode *hdir1, -+ struct dentry *d2, struct au_hinode *hdir2) -+{ -+ struct dentry *d; -+ -+ lockdep_off(); -+ d = lock_rename(d1, d2); -+ lockdep_on(); -+ au_hin_suspend(hdir1); -+ if (hdir1 != hdir2) -+ au_hin_suspend(hdir2); -+ -+ return d; -+} -+ -+void vfsub_unlock_rename(struct dentry *d1, struct au_hinode *hdir1, -+ struct dentry *d2, struct au_hinode *hdir2) -+{ -+ au_hin_resume(hdir1); -+ if (hdir1 != hdir2) -+ au_hin_resume(hdir2); -+ lockdep_off(); -+ unlock_rename(d1, d2); -+ lockdep_on(); -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+int vfsub_create(struct inode *dir, struct path *path, int mode) -+{ -+ int err; -+ struct dentry *d; -+ -+ IMustLock(dir); -+ -+ d = path->dentry; -+ path->dentry = d->d_parent; -+ err = security_path_mknod(path, path->dentry, mode, 0); -+ path->dentry = d; -+ if (unlikely(err)) -+ goto out; -+ -+ if (au_test_fs_null_nd(dir->i_sb)) -+ err = vfs_create(dir, path->dentry, mode, NULL); -+ else { -+ struct nameidata h_nd; -+ -+ memset(&h_nd, 0, sizeof(h_nd)); -+ h_nd.flags = LOOKUP_CREATE; -+ h_nd.intent.open.flags = O_CREAT -+ | vfsub_fmode_to_uint(FMODE_READ); -+ h_nd.intent.open.create_mode = mode; -+ h_nd.path.dentry = path->dentry->d_parent; -+ h_nd.path.mnt = path->mnt; -+ path_get(&h_nd.path); -+ err = vfs_create(dir, path->dentry, mode, &h_nd); -+ path_put(&h_nd.path); -+ } -+ -+ if (!err) { -+ struct path tmp = *path; -+ int did; -+ -+ vfsub_update_h_iattr(&tmp, &did); -+ if (did) { -+ tmp.dentry = path->dentry->d_parent; -+ vfsub_update_h_iattr(&tmp, /*did*/NULL); -+ } -+ /*ignore*/ -+ } -+ -+ out: -+ return err; -+} -+ -+int vfsub_symlink(struct inode *dir, struct path *path, const char *symname) -+{ -+ int err; -+ struct dentry *d; -+ -+ IMustLock(dir); -+ -+ d = path->dentry; -+ path->dentry = d->d_parent; -+ err = security_path_symlink(path, path->dentry, symname); -+ path->dentry = d; -+ if (unlikely(err)) -+ goto out; -+ -+ err = vfs_symlink(dir, path->dentry, symname); -+ if (!err) { -+ struct path tmp = *path; -+ int did; -+ -+ vfsub_update_h_iattr(&tmp, &did); -+ if (did) { -+ tmp.dentry = path->dentry->d_parent; -+ vfsub_update_h_iattr(&tmp, /*did*/NULL); -+ } -+ /*ignore*/ -+ } -+ -+ out: -+ return err; -+} -+ -+int vfsub_mknod(struct inode *dir, struct path *path, int mode, dev_t dev) -+{ -+ int err; -+ struct dentry *d; -+ -+ IMustLock(dir); -+ -+ d = path->dentry; -+ path->dentry = d->d_parent; -+ err = security_path_mknod(path, path->dentry, mode, dev); -+ path->dentry = d; -+ if (unlikely(err)) -+ goto out; -+ -+ err = vfs_mknod(dir, path->dentry, mode, dev); -+ if (!err) { -+ struct path tmp = *path; -+ int did; -+ -+ vfsub_update_h_iattr(&tmp, &did); -+ if (did) { -+ tmp.dentry = path->dentry->d_parent; -+ vfsub_update_h_iattr(&tmp, /*did*/NULL); -+ } -+ /*ignore*/ -+ } -+ -+ out: -+ return err; -+} -+ -+static int au_test_nlink(struct inode *inode) -+{ -+ const unsigned int link_max = UINT_MAX >> 1; /* rough margin */ -+ -+ if (!au_test_fs_no_limit_nlink(inode->i_sb) -+ || inode->i_nlink < link_max) -+ return 0; -+ return -EMLINK; -+} -+ -+int vfsub_link(struct dentry *src_dentry, struct inode *dir, struct path *path) -+{ -+ int err; -+ struct dentry *d; -+ -+ IMustLock(dir); -+ -+ err = au_test_nlink(src_dentry->d_inode); -+ if (unlikely(err)) -+ return err; -+ -+ d = path->dentry; -+ path->dentry = d->d_parent; -+ err = security_path_link(src_dentry, path, path->dentry); -+ path->dentry = d; -+ if (unlikely(err)) -+ goto out; -+ -+ /* lockdep_off(); */ -+ err = vfs_link(src_dentry, dir, path->dentry); -+ /* lockdep_on(); */ -+ if (!err) { -+ struct path tmp = *path; -+ int did; -+ -+ /* fuse has different memory inode for the same inumber */ -+ vfsub_update_h_iattr(&tmp, &did); -+ if (did) { -+ tmp.dentry = path->dentry->d_parent; -+ vfsub_update_h_iattr(&tmp, /*did*/NULL); -+ tmp.dentry = src_dentry; -+ vfsub_update_h_iattr(&tmp, /*did*/NULL); -+ } -+ /*ignore*/ -+ } -+ -+ out: -+ return err; -+} -+ -+int vfsub_rename(struct inode *src_dir, struct dentry *src_dentry, -+ struct inode *dir, struct path *path) -+{ -+ int err; -+ struct path tmp = { -+ .mnt = path->mnt -+ }; -+ struct dentry *d; -+ -+ IMustLock(dir); -+ IMustLock(src_dir); -+ -+ d = path->dentry; -+ path->dentry = d->d_parent; -+ tmp.dentry = src_dentry->d_parent; -+ err = security_path_rename(&tmp, src_dentry, path, path->dentry); -+ path->dentry = d; -+ if (unlikely(err)) -+ goto out; -+ -+ /* lockdep_off(); */ -+ err = vfs_rename(src_dir, src_dentry, dir, path->dentry); -+ /* lockdep_on(); */ -+ if (!err) { -+ int did; -+ -+ tmp.dentry = d->d_parent; -+ vfsub_update_h_iattr(&tmp, &did); -+ if (did) { -+ tmp.dentry = src_dentry; -+ vfsub_update_h_iattr(&tmp, /*did*/NULL); -+ tmp.dentry = src_dentry->d_parent; -+ vfsub_update_h_iattr(&tmp, /*did*/NULL); -+ } -+ /*ignore*/ -+ } -+ -+ out: -+ return err; -+} -+ -+int vfsub_mkdir(struct inode *dir, struct path *path, int mode) -+{ -+ int err; -+ struct dentry *d; -+ -+ IMustLock(dir); -+ -+ d = path->dentry; -+ path->dentry = d->d_parent; -+ err = security_path_mkdir(path, path->dentry, mode); -+ path->dentry = d; -+ if (unlikely(err)) -+ goto out; -+ -+ err = vfs_mkdir(dir, path->dentry, mode); -+ if (!err) { -+ struct path tmp = *path; -+ int did; -+ -+ vfsub_update_h_iattr(&tmp, &did); -+ if (did) { -+ tmp.dentry = path->dentry->d_parent; -+ vfsub_update_h_iattr(&tmp, /*did*/NULL); -+ } -+ /*ignore*/ -+ } -+ -+ out: -+ return err; -+} -+ -+int vfsub_rmdir(struct inode *dir, struct path *path) -+{ -+ int err; -+ struct dentry *d; -+ -+ IMustLock(dir); -+ -+ d = path->dentry; -+ path->dentry = d->d_parent; -+ err = security_path_rmdir(path, path->dentry); -+ path->dentry = d; -+ if (unlikely(err)) -+ goto out; -+ -+ /* lockdep_off(); */ -+ err = vfs_rmdir(dir, path->dentry); -+ /* lockdep_on(); */ -+ if (!err) { -+ struct path tmp = { -+ .dentry = path->dentry->d_parent, -+ .mnt = path->mnt -+ }; -+ -+ vfsub_update_h_iattr(&tmp, /*did*/NULL); /*ignore*/ -+ } -+ -+ out: -+ return err; -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+ssize_t vfsub_read_u(struct file *file, char __user *ubuf, size_t count, -+ loff_t *ppos) -+{ -+ ssize_t err; -+ -+ err = vfs_read(file, ubuf, count, ppos); -+ if (err >= 0) -+ vfsub_update_h_iattr(&file->f_path, /*did*/NULL); /*ignore*/ -+ return err; -+} -+ -+/* todo: kernel_read()? */ -+ssize_t vfsub_read_k(struct file *file, void *kbuf, size_t count, -+ loff_t *ppos) -+{ -+ ssize_t err; -+ mm_segment_t oldfs; -+ -+ oldfs = get_fs(); -+ set_fs(KERNEL_DS); -+ err = vfsub_read_u(file, (char __user *)kbuf, count, ppos); -+ set_fs(oldfs); -+ return err; -+} -+ -+ssize_t vfsub_write_u(struct file *file, const char __user *ubuf, size_t count, -+ loff_t *ppos) -+{ -+ ssize_t err; -+ -+ /* lockdep_off(); */ -+ err = vfs_write(file, ubuf, count, ppos); -+ /* lockdep_on(); */ -+ if (err >= 0) -+ vfsub_update_h_iattr(&file->f_path, /*did*/NULL); /*ignore*/ -+ return err; -+} -+ -+ssize_t vfsub_write_k(struct file *file, void *kbuf, size_t count, loff_t *ppos) -+{ -+ ssize_t err; -+ mm_segment_t oldfs; -+ -+ oldfs = get_fs(); -+ set_fs(KERNEL_DS); -+ err = vfsub_write_u(file, (const char __user *)kbuf, count, ppos); -+ set_fs(oldfs); -+ return err; -+} -+ -+int vfsub_readdir(struct file *file, filldir_t filldir, void *arg) -+{ -+ int err; -+ -+ /* lockdep_off(); */ -+ err = vfs_readdir(file, filldir, arg); -+ /* lockdep_on(); */ -+ if (err >= 0) -+ vfsub_update_h_iattr(&file->f_path, /*did*/NULL); /*ignore*/ -+ return err; -+} -+ -+long vfsub_splice_to(struct file *in, loff_t *ppos, -+ struct pipe_inode_info *pipe, size_t len, -+ unsigned int flags) -+{ -+ long err; -+ -+ /* lockdep_off(); */ -+ err = do_splice_to(in, ppos, pipe, len, flags); -+ /* lockdep_on(); */ -+ if (err >= 0) -+ vfsub_update_h_iattr(&in->f_path, /*did*/NULL); /*ignore*/ -+ return err; -+} -+ -+long vfsub_splice_from(struct pipe_inode_info *pipe, struct file *out, -+ loff_t *ppos, size_t len, unsigned int flags) -+{ -+ long err; -+ -+ /* lockdep_off(); */ -+ err = do_splice_from(pipe, out, ppos, len, flags); -+ /* lockdep_on(); */ -+ if (err >= 0) -+ vfsub_update_h_iattr(&out->f_path, /*did*/NULL); /*ignore*/ -+ return err; -+} -+ -+/* cf. open.c:do_sys_truncate() and do_sys_ftruncate() */ -+int vfsub_trunc(struct path *h_path, loff_t length, unsigned int attr, -+ struct file *h_file) -+{ -+ int err; -+ struct inode *h_inode; -+ -+ h_inode = h_path->dentry->d_inode; -+ if (!h_file) { -+ err = mnt_want_write(h_path->mnt); -+ if (err) -+ goto out; -+ err = inode_permission(h_inode, MAY_WRITE); -+ if (err) -+ goto out_mnt; -+ err = get_write_access(h_inode); -+ if (err) -+ goto out_mnt; -+ err = break_lease(h_inode, vfsub_fmode_to_uint(FMODE_WRITE)); -+ if (err) -+ goto out_inode; -+ } -+ -+ err = locks_verify_truncate(h_inode, h_file, length); -+ if (!err) -+ err = security_path_truncate(h_path, length, attr); -+ if (!err) { -+ /* lockdep_off(); */ -+ err = do_truncate(h_path->dentry, length, attr, h_file); -+ /* lockdep_on(); */ -+ } -+ -+ out_inode: -+ if (!h_file) -+ put_write_access(h_inode); -+ out_mnt: -+ if (!h_file) -+ mnt_drop_write(h_path->mnt); -+ out: -+ return err; -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+struct au_vfsub_mkdir_args { -+ int *errp; -+ struct inode *dir; -+ struct path *path; -+ int mode; -+}; -+ -+static void au_call_vfsub_mkdir(void *args) -+{ -+ struct au_vfsub_mkdir_args *a = args; -+ *a->errp = vfsub_mkdir(a->dir, a->path, a->mode); -+} -+ -+int vfsub_sio_mkdir(struct inode *dir, struct path *path, int mode) -+{ -+ int err, do_sio, wkq_err; -+ -+ do_sio = au_test_h_perm_sio(dir, MAY_EXEC | MAY_WRITE); -+ if (!do_sio) -+ err = vfsub_mkdir(dir, path, mode); -+ else { -+ struct au_vfsub_mkdir_args args = { -+ .errp = &err, -+ .dir = dir, -+ .path = path, -+ .mode = mode -+ }; -+ wkq_err = au_wkq_wait(au_call_vfsub_mkdir, &args); -+ if (unlikely(wkq_err)) -+ err = wkq_err; -+ } -+ -+ return err; -+} -+ -+struct au_vfsub_rmdir_args { -+ int *errp; -+ struct inode *dir; -+ struct path *path; -+}; -+ -+static void au_call_vfsub_rmdir(void *args) -+{ -+ struct au_vfsub_rmdir_args *a = args; -+ *a->errp = vfsub_rmdir(a->dir, a->path); -+} -+ -+int vfsub_sio_rmdir(struct inode *dir, struct path *path) -+{ -+ int err, do_sio, wkq_err; -+ -+ do_sio = au_test_h_perm_sio(dir, MAY_EXEC | MAY_WRITE); -+ if (!do_sio) -+ err = vfsub_rmdir(dir, path); -+ else { -+ struct au_vfsub_rmdir_args args = { -+ .errp = &err, -+ .dir = dir, -+ .path = path -+ }; -+ wkq_err = au_wkq_wait(au_call_vfsub_rmdir, &args); -+ if (unlikely(wkq_err)) -+ err = wkq_err; -+ } -+ -+ return err; -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+struct notify_change_args { -+ int *errp; -+ struct path *path; -+ struct iattr *ia; -+}; -+ -+static void call_notify_change(void *args) -+{ -+ struct notify_change_args *a = args; -+ struct inode *h_inode; -+ -+ h_inode = a->path->dentry->d_inode; -+ IMustLock(h_inode); -+ -+ *a->errp = -EPERM; -+ if (!IS_IMMUTABLE(h_inode) && !IS_APPEND(h_inode)) { -+ /* lockdep_off(); */ -+ *a->errp = notify_change(a->path->dentry, a->ia); -+ /* lockdep_on(); */ -+ if (!*a->errp) -+ vfsub_update_h_iattr(a->path, /*did*/NULL); /*ignore*/ -+ } -+ AuTraceErr(*a->errp); -+} -+ -+int vfsub_notify_change(struct path *path, struct iattr *ia) -+{ -+ int err; -+ struct notify_change_args args = { -+ .errp = &err, -+ .path = path, -+ .ia = ia -+ }; -+ -+ call_notify_change(&args); -+ -+ return err; -+} -+ -+int vfsub_sio_notify_change(struct path *path, struct iattr *ia) -+{ -+ int err, wkq_err; -+ struct notify_change_args args = { -+ .errp = &err, -+ .path = path, -+ .ia = ia -+ }; -+ -+ wkq_err = au_wkq_wait(call_notify_change, &args); -+ if (unlikely(wkq_err)) -+ err = wkq_err; -+ -+ return err; -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+struct unlink_args { -+ int *errp; -+ struct inode *dir; -+ struct path *path; -+}; -+ -+static void call_unlink(void *args) -+{ -+ struct unlink_args *a = args; -+ struct dentry *d = a->path->dentry; -+ struct inode *h_inode; -+ const int stop_sillyrename = (au_test_nfs(d->d_sb) -+ && atomic_read(&d->d_count) == 1); -+ -+ IMustLock(a->dir); -+ -+ a->path->dentry = d->d_parent; -+ *a->errp = security_path_unlink(a->path, d); -+ a->path->dentry = d; -+ if (unlikely(*a->errp)) -+ return; -+ -+ if (!stop_sillyrename) -+ dget(d); -+ h_inode = d->d_inode; -+ if (h_inode) -+ atomic_inc(&h_inode->i_count); -+ -+ /* lockdep_off(); */ -+ *a->errp = vfs_unlink(a->dir, d); -+ /* lockdep_on(); */ -+ if (!*a->errp) { -+ struct path tmp = { -+ .dentry = d->d_parent, -+ .mnt = a->path->mnt -+ }; -+ vfsub_update_h_iattr(&tmp, /*did*/NULL); /*ignore*/ -+ } -+ -+ if (!stop_sillyrename) -+ dput(d); -+ if (h_inode) -+ iput(h_inode); -+ -+ AuTraceErr(*a->errp); -+} -+ -+/* -+ * @dir: must be locked. -+ * @dentry: target dentry. -+ */ -+int vfsub_unlink(struct inode *dir, struct path *path, int force) -+{ -+ int err; -+ struct unlink_args args = { -+ .errp = &err, -+ .dir = dir, -+ .path = path -+ }; -+ -+ if (!force) -+ call_unlink(&args); -+ else { -+ int wkq_err; -+ -+ wkq_err = au_wkq_wait(call_unlink, &args); -+ if (unlikely(wkq_err)) -+ err = wkq_err; -+ } -+ -+ return err; -+} -diff --git a/fs/aufs/vfsub.h b/fs/aufs/vfsub.h -new file mode 100644 -index 0000000..63d21d3 ---- /dev/null -+++ b/fs/aufs/vfsub.h -@@ -0,0 +1,172 @@ -+/* -+ * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * -+ * This program, aufs is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ */ -+ -+/* -+ * sub-routines for VFS -+ */ -+ -+#ifndef __AUFS_VFSUB_H__ -+#define __AUFS_VFSUB_H__ -+ -+#ifdef __KERNEL__ -+ -+#include -+#include -+ -+/* ---------------------------------------------------------------------- */ -+ -+/* lock subclass for lower inode */ -+/* default MAX_LOCKDEP_SUBCLASSES(8) is not enough */ -+/* reduce? gave up. */ -+enum { -+ AuLsc_I_Begin = I_MUTEX_QUOTA, /* 4 */ -+ AuLsc_I_PARENT, /* lower inode, parent first */ -+ AuLsc_I_PARENT2, /* copyup dirs */ -+ AuLsc_I_PARENT3, /* copyup wh */ -+ AuLsc_I_CHILD, -+ AuLsc_I_CHILD2, -+ AuLsc_I_End -+}; -+ -+/* to debug easier, do not make them inlined functions */ -+#define MtxMustLock(mtx) AuDebugOn(!mutex_is_locked(mtx)) -+#define IMustLock(i) MtxMustLock(&(i)->i_mutex) -+ -+/* ---------------------------------------------------------------------- */ -+ -+static inline void vfsub_copy_inode_size(struct inode *inode, -+ struct inode *h_inode) -+{ -+ spin_lock(&inode->i_lock); -+ fsstack_copy_inode_size(inode, h_inode); -+ spin_unlock(&inode->i_lock); -+} -+ -+int vfsub_update_h_iattr(struct path *h_path, int *did); -+struct file *vfsub_filp_open(const char *path, int oflags, int mode); -+struct file *vfsub_dentry_open(struct path *path, int flags, -+ const struct cred *cred); -+int vfsub_kern_path(const char *name, unsigned int flags, struct path *path); -+struct dentry *vfsub_lookup_one_len(const char *name, struct dentry *parent, -+ int len); -+struct dentry *vfsub_lookup_hash(struct nameidata *nd); -+ -+/* ---------------------------------------------------------------------- */ -+ -+struct au_hinode; -+struct dentry *vfsub_lock_rename(struct dentry *d1, struct au_hinode *hdir1, -+ struct dentry *d2, struct au_hinode *hdir2); -+void vfsub_unlock_rename(struct dentry *d1, struct au_hinode *hdir1, -+ struct dentry *d2, struct au_hinode *hdir2); -+ -+int vfsub_create(struct inode *dir, struct path *path, int mode); -+int vfsub_symlink(struct inode *dir, struct path *path, -+ const char *symname); -+int vfsub_mknod(struct inode *dir, struct path *path, int mode, dev_t dev); -+int vfsub_link(struct dentry *src_dentry, struct inode *dir, -+ struct path *path); -+int vfsub_rename(struct inode *src_hdir, struct dentry *src_dentry, -+ struct inode *hdir, struct path *path); -+int vfsub_mkdir(struct inode *dir, struct path *path, int mode); -+int vfsub_rmdir(struct inode *dir, struct path *path); -+ -+int vfsub_sio_mkdir(struct inode *dir, struct path *path, int mode); -+int vfsub_sio_rmdir(struct inode *dir, struct path *path); -+int vfsub_sio_notify_change(struct path *path, struct iattr *ia); -+int vfsub_notify_change(struct path *path, struct iattr *ia); -+int vfsub_unlink(struct inode *dir, struct path *path, int force); -+ -+/* ---------------------------------------------------------------------- */ -+ -+ssize_t vfsub_read_u(struct file *file, char __user *ubuf, size_t count, -+ loff_t *ppos); -+ssize_t vfsub_read_k(struct file *file, void *kbuf, size_t count, -+ loff_t *ppos); -+ssize_t vfsub_write_u(struct file *file, const char __user *ubuf, size_t count, -+ loff_t *ppos); -+ssize_t vfsub_write_k(struct file *file, void *kbuf, size_t count, -+ loff_t *ppos); -+int vfsub_readdir(struct file *file, filldir_t filldir, void *arg); -+ -+long vfsub_splice_to(struct file *in, loff_t *ppos, -+ struct pipe_inode_info *pipe, size_t len, -+ unsigned int flags); -+long vfsub_splice_from(struct pipe_inode_info *pipe, struct file *out, -+ loff_t *ppos, size_t len, unsigned int flags); -+int vfsub_trunc(struct path *h_path, loff_t length, unsigned int attr, -+ struct file *h_file); -+ -+static inline void vfsub_file_accessed(struct file *h_file) -+{ -+ file_accessed(h_file); -+ vfsub_update_h_iattr(&h_file->f_path, /*did*/NULL); /*ignore*/ -+} -+ -+static inline void vfsub_touch_atime(struct vfsmount *h_mnt, -+ struct dentry *h_dentry) -+{ -+ struct path h_path = { -+ .dentry = h_dentry, -+ .mnt = h_mnt -+ }; -+ touch_atime(h_mnt, h_dentry); -+ vfsub_update_h_iattr(&h_path, /*did*/NULL); /*ignore*/ -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+static inline loff_t vfsub_llseek(struct file *file, loff_t offset, int origin) -+{ -+ loff_t err; -+ -+ /* lockdep_off(); */ -+ err = vfs_llseek(file, offset, origin); -+ /* lockdep_on(); */ -+ return err; -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+/* dirty workaround for strict type of fmode_t */ -+union vfsub_fmu { -+ fmode_t fm; -+ unsigned int ui; -+}; -+ -+static inline unsigned int vfsub_fmode_to_uint(fmode_t fm) -+{ -+ union vfsub_fmu u = { -+ .fm = fm -+ }; -+ -+ BUILD_BUG_ON(sizeof(u.fm) != sizeof(u.ui)); -+ -+ return u.ui; -+} -+ -+static inline fmode_t vfsub_uint_to_fmode(unsigned int ui) -+{ -+ union vfsub_fmu u = { -+ .ui = ui -+ }; -+ -+ return u.fm; -+} -+ -+#endif /* __KERNEL__ */ -+#endif /* __AUFS_VFSUB_H__ */ -diff --git a/fs/aufs/wbr_policy.c b/fs/aufs/wbr_policy.c -new file mode 100644 -index 0000000..05a8c1e ---- /dev/null -+++ b/fs/aufs/wbr_policy.c -@@ -0,0 +1,641 @@ -+/* -+ * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * -+ * This program, aufs is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ */ -+ -+/* -+ * policies for selecting one among multiple writable branches -+ */ -+ -+#include -+#include "aufs.h" -+ -+/* subset of cpup_attr() */ -+static noinline_for_stack -+int au_cpdown_attr(struct path *h_path, struct dentry *h_src) -+{ -+ int err, sbits; -+ struct iattr ia; -+ struct inode *h_isrc; -+ -+ h_isrc = h_src->d_inode; -+ ia.ia_valid = ATTR_FORCE | ATTR_MODE | ATTR_UID | ATTR_GID; -+ ia.ia_mode = h_isrc->i_mode; -+ ia.ia_uid = h_isrc->i_uid; -+ ia.ia_gid = h_isrc->i_gid; -+ sbits = !!(ia.ia_mode & (S_ISUID | S_ISGID)); -+ au_cpup_attr_flags(h_path->dentry->d_inode, h_isrc); -+ err = vfsub_sio_notify_change(h_path, &ia); -+ -+ /* is this nfs only? */ -+ if (!err && sbits && au_test_nfs(h_path->dentry->d_sb)) { -+ ia.ia_valid = ATTR_FORCE | ATTR_MODE; -+ ia.ia_mode = h_isrc->i_mode; -+ err = vfsub_sio_notify_change(h_path, &ia); -+ } -+ -+ return err; -+} -+ -+#define AuCpdown_PARENT_OPQ 1 -+#define AuCpdown_WHED (1 << 1) -+#define AuCpdown_MADE_DIR (1 << 2) -+#define AuCpdown_DIROPQ (1 << 3) -+#define au_ftest_cpdown(flags, name) ((flags) & AuCpdown_##name) -+#define au_fset_cpdown(flags, name) { (flags) |= AuCpdown_##name; } -+#define au_fclr_cpdown(flags, name) { (flags) &= ~AuCpdown_##name; } -+ -+struct au_cpdown_dir_args { -+ struct dentry *parent; -+ unsigned int flags; -+}; -+ -+static int au_cpdown_dir_opq(struct dentry *dentry, aufs_bindex_t bdst, -+ struct au_cpdown_dir_args *a) -+{ -+ int err; -+ struct dentry *opq_dentry; -+ -+ opq_dentry = au_diropq_create(dentry, bdst); -+ err = PTR_ERR(opq_dentry); -+ if (IS_ERR(opq_dentry)) -+ goto out; -+ dput(opq_dentry); -+ au_fset_cpdown(a->flags, DIROPQ); -+ -+ out: -+ return err; -+} -+ -+static int au_cpdown_dir_wh(struct dentry *dentry, struct dentry *h_parent, -+ struct inode *dir, aufs_bindex_t bdst) -+{ -+ int err; -+ struct path h_path; -+ struct au_branch *br; -+ -+ br = au_sbr(dentry->d_sb, bdst); -+ h_path.dentry = au_wh_lkup(h_parent, &dentry->d_name, br); -+ err = PTR_ERR(h_path.dentry); -+ if (IS_ERR(h_path.dentry)) -+ goto out; -+ -+ err = 0; -+ if (h_path.dentry->d_inode) { -+ h_path.mnt = br->br_mnt; -+ err = au_wh_unlink_dentry(au_h_iptr(dir, bdst), &h_path, -+ dentry); -+ } -+ dput(h_path.dentry); -+ -+ out: -+ return err; -+} -+ -+static int au_cpdown_dir(struct dentry *dentry, aufs_bindex_t bdst, -+ struct dentry *h_parent, void *arg) -+{ -+ int err, rerr; -+ aufs_bindex_t bend, bopq, bstart; -+ unsigned char parent_opq; -+ struct path h_path; -+ struct dentry *parent; -+ struct inode *h_dir, *h_inode, *inode, *dir; -+ struct au_cpdown_dir_args *args = arg; -+ -+ bstart = au_dbstart(dentry); -+ /* dentry is di-locked */ -+ parent = dget_parent(dentry); -+ dir = parent->d_inode; -+ h_dir = h_parent->d_inode; -+ AuDebugOn(h_dir != au_h_iptr(dir, bdst)); -+ IMustLock(h_dir); -+ -+ err = au_lkup_neg(dentry, bdst); -+ if (unlikely(err < 0)) -+ goto out; -+ h_path.dentry = au_h_dptr(dentry, bdst); -+ h_path.mnt = au_sbr_mnt(dentry->d_sb, bdst); -+ err = vfsub_sio_mkdir(au_h_iptr(dir, bdst), &h_path, -+ S_IRWXU | S_IRUGO | S_IXUGO); -+ if (unlikely(err)) -+ goto out_put; -+ au_fset_cpdown(args->flags, MADE_DIR); -+ -+ bend = au_dbend(dentry); -+ bopq = au_dbdiropq(dentry); -+ au_fclr_cpdown(args->flags, WHED); -+ au_fclr_cpdown(args->flags, DIROPQ); -+ if (au_dbwh(dentry) == bdst) -+ au_fset_cpdown(args->flags, WHED); -+ if (!au_ftest_cpdown(args->flags, PARENT_OPQ) && bopq <= bdst) -+ au_fset_cpdown(args->flags, PARENT_OPQ); -+ parent_opq = (au_ftest_cpdown(args->flags, PARENT_OPQ) -+ && args->parent == dentry); -+ h_inode = h_path.dentry->d_inode; -+ mutex_lock_nested(&h_inode->i_mutex, AuLsc_I_CHILD); -+ if (au_ftest_cpdown(args->flags, WHED)) { -+ err = au_cpdown_dir_opq(dentry, bdst, args); -+ if (unlikely(err)) { -+ mutex_unlock(&h_inode->i_mutex); -+ goto out_dir; -+ } -+ } -+ -+ err = au_cpdown_attr(&h_path, au_h_dptr(dentry, bstart)); -+ mutex_unlock(&h_inode->i_mutex); -+ if (unlikely(err)) -+ goto out_opq; -+ -+ if (au_ftest_cpdown(args->flags, WHED)) { -+ err = au_cpdown_dir_wh(dentry, h_parent, dir, bdst); -+ if (unlikely(err)) -+ goto out_opq; -+ } -+ -+ inode = dentry->d_inode; -+ if (au_ibend(inode) < bdst) -+ au_set_ibend(inode, bdst); -+ au_set_h_iptr(inode, bdst, au_igrab(h_inode), -+ au_hi_flags(inode, /*isdir*/1)); -+ goto out; /* success */ -+ -+ /* revert */ -+ out_opq: -+ if (au_ftest_cpdown(args->flags, DIROPQ)) { -+ mutex_lock_nested(&h_inode->i_mutex, AuLsc_I_CHILD); -+ rerr = au_diropq_remove(dentry, bdst); -+ mutex_unlock(&h_inode->i_mutex); -+ if (unlikely(rerr)) { -+ AuIOErr("failed removing diropq for %.*s b%d (%d)\n", -+ AuDLNPair(dentry), bdst, rerr); -+ err = -EIO; -+ goto out; -+ } -+ } -+ out_dir: -+ if (au_ftest_cpdown(args->flags, MADE_DIR)) { -+ rerr = vfsub_sio_rmdir(au_h_iptr(dir, bdst), &h_path); -+ if (unlikely(rerr)) { -+ AuIOErr("failed removing %.*s b%d (%d)\n", -+ AuDLNPair(dentry), bdst, rerr); -+ err = -EIO; -+ } -+ } -+ out_put: -+ au_set_h_dptr(dentry, bdst, NULL); -+ if (au_dbend(dentry) == bdst) -+ au_update_dbend(dentry); -+ out: -+ dput(parent); -+ return err; -+} -+ -+int au_cpdown_dirs(struct dentry *dentry, aufs_bindex_t bdst) -+{ -+ int err; -+ struct au_cpdown_dir_args args = { -+ .parent = dget_parent(dentry), -+ .flags = 0 -+ }; -+ -+ err = au_cp_dirs(dentry, bdst, au_cpdown_dir, &args); -+ dput(args.parent); -+ -+ return err; -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+/* policies for create */ -+ -+static int au_wbr_bu(struct super_block *sb, aufs_bindex_t bindex) -+{ -+ for (; bindex >= 0; bindex--) -+ if (!au_br_rdonly(au_sbr(sb, bindex))) -+ return bindex; -+ return -EROFS; -+} -+ -+/* top down parent */ -+static int au_wbr_create_tdp(struct dentry *dentry, int isdir __maybe_unused) -+{ -+ int err; -+ aufs_bindex_t bstart, bindex; -+ struct super_block *sb; -+ struct dentry *parent, *h_parent; -+ -+ sb = dentry->d_sb; -+ bstart = au_dbstart(dentry); -+ err = bstart; -+ if (!au_br_rdonly(au_sbr(sb, bstart))) -+ goto out; -+ -+ err = -EROFS; -+ parent = dget_parent(dentry); -+ for (bindex = au_dbstart(parent); bindex < bstart; bindex++) { -+ h_parent = au_h_dptr(parent, bindex); -+ if (!h_parent || !h_parent->d_inode) -+ continue; -+ -+ if (!au_br_rdonly(au_sbr(sb, bindex))) { -+ err = bindex; -+ break; -+ } -+ } -+ dput(parent); -+ -+ /* bottom up here */ -+ if (unlikely(err < 0)) -+ err = au_wbr_bu(sb, bstart - 1); -+ -+ out: -+ AuDbg("b%d\n", err); -+ return err; -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+/* an exception for the policy other than tdp */ -+static int au_wbr_create_exp(struct dentry *dentry) -+{ -+ int err; -+ aufs_bindex_t bwh, bdiropq; -+ struct dentry *parent; -+ -+ err = -1; -+ bwh = au_dbwh(dentry); -+ parent = dget_parent(dentry); -+ bdiropq = au_dbdiropq(parent); -+ if (bwh >= 0) { -+ if (bdiropq >= 0) -+ err = min(bdiropq, bwh); -+ else -+ err = bwh; -+ AuDbg("%d\n", err); -+ } else if (bdiropq >= 0) { -+ err = bdiropq; -+ AuDbg("%d\n", err); -+ } -+ dput(parent); -+ -+ if (err >= 0 && au_br_rdonly(au_sbr(dentry->d_sb, err))) -+ err = -1; -+ -+ AuDbg("%d\n", err); -+ return err; -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+/* round robin */ -+static int au_wbr_create_init_rr(struct super_block *sb) -+{ -+ int err; -+ -+ err = au_wbr_bu(sb, au_sbend(sb)); -+ atomic_set(&au_sbi(sb)->si_wbr_rr_next, -err); /* less important */ -+ /* smp_mb(); */ -+ -+ AuDbg("b%d\n", err); -+ return err; -+} -+ -+static int au_wbr_create_rr(struct dentry *dentry, int isdir) -+{ -+ int err, nbr; -+ unsigned int u; -+ aufs_bindex_t bindex, bend; -+ struct super_block *sb; -+ atomic_t *next; -+ -+ err = au_wbr_create_exp(dentry); -+ if (err >= 0) -+ goto out; -+ -+ sb = dentry->d_sb; -+ next = &au_sbi(sb)->si_wbr_rr_next; -+ bend = au_sbend(sb); -+ nbr = bend + 1; -+ for (bindex = 0; bindex <= bend; bindex++) { -+ if (!isdir) { -+ err = atomic_dec_return(next) + 1; -+ /* modulo for 0 is meaningless */ -+ if (unlikely(!err)) -+ err = atomic_dec_return(next) + 1; -+ } else -+ err = atomic_read(next); -+ AuDbg("%d\n", err); -+ u = err; -+ err = u % nbr; -+ AuDbg("%d\n", err); -+ if (!au_br_rdonly(au_sbr(sb, err))) -+ break; -+ err = -EROFS; -+ } -+ -+ out: -+ AuDbg("%d\n", err); -+ return err; -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+/* most free space */ -+static void au_mfs(struct dentry *dentry) -+{ -+ struct super_block *sb; -+ struct au_branch *br; -+ struct au_wbr_mfs *mfs; -+ aufs_bindex_t bindex, bend; -+ int err; -+ unsigned long long b, bavail; -+ /* reduce the stack usage */ -+ struct kstatfs *st; -+ -+ st = kmalloc(sizeof(*st), GFP_NOFS); -+ if (unlikely(!st)) { -+ AuWarn1("failed updating mfs(%d), ignored\n", -ENOMEM); -+ return; -+ } -+ -+ bavail = 0; -+ sb = dentry->d_sb; -+ mfs = &au_sbi(sb)->si_wbr_mfs; -+ MtxMustLock(&mfs->mfs_lock); -+ mfs->mfs_bindex = -EROFS; -+ mfs->mfsrr_bytes = 0; -+ bend = au_sbend(sb); -+ for (bindex = 0; bindex <= bend; bindex++) { -+ br = au_sbr(sb, bindex); -+ if (au_br_rdonly(br)) -+ continue; -+ -+ /* sb->s_root for NFS is unreliable */ -+ err = vfs_statfs(br->br_mnt->mnt_root, st); -+ if (unlikely(err)) { -+ AuWarn1("failed statfs, b%d, %d\n", bindex, err); -+ continue; -+ } -+ -+ /* when the available size is equal, select the lower one */ -+ BUILD_BUG_ON(sizeof(b) < sizeof(st->f_bavail) -+ || sizeof(b) < sizeof(st->f_bsize)); -+ b = st->f_bavail * st->f_bsize; -+ br->br_wbr->wbr_bytes = b; -+ if (b >= bavail) { -+ bavail = b; -+ mfs->mfs_bindex = bindex; -+ mfs->mfs_jiffy = jiffies; -+ } -+ } -+ -+ mfs->mfsrr_bytes = bavail; -+ AuDbg("b%d\n", mfs->mfs_bindex); -+ kfree(st); -+} -+ -+static int au_wbr_create_mfs(struct dentry *dentry, int isdir __maybe_unused) -+{ -+ int err; -+ struct super_block *sb; -+ struct au_wbr_mfs *mfs; -+ -+ err = au_wbr_create_exp(dentry); -+ if (err >= 0) -+ goto out; -+ -+ sb = dentry->d_sb; -+ mfs = &au_sbi(sb)->si_wbr_mfs; -+ mutex_lock(&mfs->mfs_lock); -+ if (time_after(jiffies, mfs->mfs_jiffy + mfs->mfs_expire) -+ || mfs->mfs_bindex < 0 -+ || au_br_rdonly(au_sbr(sb, mfs->mfs_bindex))) -+ au_mfs(dentry); -+ mutex_unlock(&mfs->mfs_lock); -+ err = mfs->mfs_bindex; -+ -+ out: -+ AuDbg("b%d\n", err); -+ return err; -+} -+ -+static int au_wbr_create_init_mfs(struct super_block *sb) -+{ -+ struct au_wbr_mfs *mfs; -+ -+ mfs = &au_sbi(sb)->si_wbr_mfs; -+ mutex_init(&mfs->mfs_lock); -+ mfs->mfs_jiffy = 0; -+ mfs->mfs_bindex = -EROFS; -+ -+ return 0; -+} -+ -+static int au_wbr_create_fin_mfs(struct super_block *sb __maybe_unused) -+{ -+ mutex_destroy(&au_sbi(sb)->si_wbr_mfs.mfs_lock); -+ return 0; -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+/* most free space and then round robin */ -+static int au_wbr_create_mfsrr(struct dentry *dentry, int isdir) -+{ -+ int err; -+ struct au_wbr_mfs *mfs; -+ -+ err = au_wbr_create_mfs(dentry, isdir); -+ if (err >= 0) { -+ mfs = &au_sbi(dentry->d_sb)->si_wbr_mfs; -+ mutex_lock(&mfs->mfs_lock); -+ if (mfs->mfsrr_bytes < mfs->mfsrr_watermark) -+ err = au_wbr_create_rr(dentry, isdir); -+ mutex_unlock(&mfs->mfs_lock); -+ } -+ -+ AuDbg("b%d\n", err); -+ return err; -+} -+ -+static int au_wbr_create_init_mfsrr(struct super_block *sb) -+{ -+ int err; -+ -+ au_wbr_create_init_mfs(sb); /* ignore */ -+ err = au_wbr_create_init_rr(sb); -+ -+ return err; -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+/* top down parent and most free space */ -+static int au_wbr_create_pmfs(struct dentry *dentry, int isdir) -+{ -+ int err, e2; -+ unsigned long long b; -+ aufs_bindex_t bindex, bstart, bend; -+ struct super_block *sb; -+ struct dentry *parent, *h_parent; -+ struct au_branch *br; -+ -+ err = au_wbr_create_tdp(dentry, isdir); -+ if (unlikely(err < 0)) -+ goto out; -+ parent = dget_parent(dentry); -+ bstart = au_dbstart(parent); -+ bend = au_dbtaildir(parent); -+ if (bstart == bend) -+ goto out_parent; /* success */ -+ -+ e2 = au_wbr_create_mfs(dentry, isdir); -+ if (e2 < 0) -+ goto out_parent; /* success */ -+ -+ /* when the available size is equal, select upper one */ -+ sb = dentry->d_sb; -+ br = au_sbr(sb, err); -+ b = br->br_wbr->wbr_bytes; -+ AuDbg("b%d, %llu\n", err, b); -+ -+ for (bindex = bstart; bindex <= bend; bindex++) { -+ h_parent = au_h_dptr(parent, bindex); -+ if (!h_parent || !h_parent->d_inode) -+ continue; -+ -+ br = au_sbr(sb, bindex); -+ if (!au_br_rdonly(br) && br->br_wbr->wbr_bytes > b) { -+ b = br->br_wbr->wbr_bytes; -+ err = bindex; -+ AuDbg("b%d, %llu\n", err, b); -+ } -+ } -+ -+ out_parent: -+ dput(parent); -+ out: -+ AuDbg("b%d\n", err); -+ return err; -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+/* policies for copyup */ -+ -+/* top down parent */ -+static int au_wbr_copyup_tdp(struct dentry *dentry) -+{ -+ return au_wbr_create_tdp(dentry, /*isdir, anything is ok*/0); -+} -+ -+/* bottom up parent */ -+static int au_wbr_copyup_bup(struct dentry *dentry) -+{ -+ int err; -+ aufs_bindex_t bindex, bstart; -+ struct dentry *parent, *h_parent; -+ struct super_block *sb; -+ -+ err = -EROFS; -+ sb = dentry->d_sb; -+ parent = dget_parent(dentry); -+ bstart = au_dbstart(parent); -+ for (bindex = au_dbstart(dentry); bindex >= bstart; bindex--) { -+ h_parent = au_h_dptr(parent, bindex); -+ if (!h_parent || !h_parent->d_inode) -+ continue; -+ -+ if (!au_br_rdonly(au_sbr(sb, bindex))) { -+ err = bindex; -+ break; -+ } -+ } -+ dput(parent); -+ -+ /* bottom up here */ -+ if (unlikely(err < 0)) -+ err = au_wbr_bu(sb, bstart - 1); -+ -+ AuDbg("b%d\n", err); -+ return err; -+} -+ -+/* bottom up */ -+static int au_wbr_copyup_bu(struct dentry *dentry) -+{ -+ int err; -+ -+ err = au_wbr_bu(dentry->d_sb, au_dbstart(dentry)); -+ -+ AuDbg("b%d\n", err); -+ return err; -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+struct au_wbr_copyup_operations au_wbr_copyup_ops[] = { -+ [AuWbrCopyup_TDP] = { -+ .copyup = au_wbr_copyup_tdp -+ }, -+ [AuWbrCopyup_BUP] = { -+ .copyup = au_wbr_copyup_bup -+ }, -+ [AuWbrCopyup_BU] = { -+ .copyup = au_wbr_copyup_bu -+ } -+}; -+ -+struct au_wbr_create_operations au_wbr_create_ops[] = { -+ [AuWbrCreate_TDP] = { -+ .create = au_wbr_create_tdp -+ }, -+ [AuWbrCreate_RR] = { -+ .create = au_wbr_create_rr, -+ .init = au_wbr_create_init_rr -+ }, -+ [AuWbrCreate_MFS] = { -+ .create = au_wbr_create_mfs, -+ .init = au_wbr_create_init_mfs, -+ .fin = au_wbr_create_fin_mfs -+ }, -+ [AuWbrCreate_MFSV] = { -+ .create = au_wbr_create_mfs, -+ .init = au_wbr_create_init_mfs, -+ .fin = au_wbr_create_fin_mfs -+ }, -+ [AuWbrCreate_MFSRR] = { -+ .create = au_wbr_create_mfsrr, -+ .init = au_wbr_create_init_mfsrr, -+ .fin = au_wbr_create_fin_mfs -+ }, -+ [AuWbrCreate_MFSRRV] = { -+ .create = au_wbr_create_mfsrr, -+ .init = au_wbr_create_init_mfsrr, -+ .fin = au_wbr_create_fin_mfs -+ }, -+ [AuWbrCreate_PMFS] = { -+ .create = au_wbr_create_pmfs, -+ .init = au_wbr_create_init_mfs, -+ .fin = au_wbr_create_fin_mfs -+ }, -+ [AuWbrCreate_PMFSV] = { -+ .create = au_wbr_create_pmfs, -+ .init = au_wbr_create_init_mfs, -+ .fin = au_wbr_create_fin_mfs -+ } -+}; -diff --git a/fs/aufs/whout.c b/fs/aufs/whout.c -new file mode 100644 -index 0000000..b0ee925 ---- /dev/null -+++ b/fs/aufs/whout.c -@@ -0,0 +1,1056 @@ -+/* -+ * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * -+ * This program, aufs is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ */ -+ -+/* -+ * whiteout for logical deletion and opaque directory -+ */ -+ -+#include -+#include "aufs.h" -+ -+#define WH_MASK S_IRUGO -+ -+/* -+ * If a directory contains this file, then it is opaque. We start with the -+ * .wh. flag so that it is blocked by lookup. -+ */ -+static struct qstr diropq_name = { -+ .name = AUFS_WH_DIROPQ, -+ .len = sizeof(AUFS_WH_DIROPQ) - 1 -+}; -+ -+/* -+ * generate whiteout name, which is NOT terminated by NULL. -+ * @name: original d_name.name -+ * @len: original d_name.len -+ * @wh: whiteout qstr -+ * returns zero when succeeds, otherwise error. -+ * succeeded value as wh->name should be freed by kfree(). -+ */ -+int au_wh_name_alloc(struct qstr *wh, const struct qstr *name) -+{ -+ char *p; -+ -+ if (unlikely(name->len > PATH_MAX - AUFS_WH_PFX_LEN)) -+ return -ENAMETOOLONG; -+ -+ wh->len = name->len + AUFS_WH_PFX_LEN; -+ p = kmalloc(wh->len, GFP_NOFS); -+ wh->name = p; -+ if (p) { -+ memcpy(p, AUFS_WH_PFX, AUFS_WH_PFX_LEN); -+ memcpy(p + AUFS_WH_PFX_LEN, name->name, name->len); -+ /* smp_mb(); */ -+ return 0; -+ } -+ return -ENOMEM; -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+/* -+ * test if the @wh_name exists under @h_parent. -+ * @try_sio specifies the necessary of super-io. -+ */ -+int au_wh_test(struct dentry *h_parent, struct qstr *wh_name, -+ struct au_branch *br, int try_sio) -+{ -+ int err; -+ struct dentry *wh_dentry; -+ struct inode *h_dir; -+ -+ h_dir = h_parent->d_inode; -+ if (!try_sio) -+ wh_dentry = au_lkup_one(wh_name, h_parent, br, /*nd*/NULL); -+ else -+ wh_dentry = au_sio_lkup_one(wh_name, h_parent, br); -+ err = PTR_ERR(wh_dentry); -+ if (IS_ERR(wh_dentry)) -+ goto out; -+ -+ err = 0; -+ if (!wh_dentry->d_inode) -+ goto out_wh; /* success */ -+ -+ err = 1; -+ if (S_ISREG(wh_dentry->d_inode->i_mode)) -+ goto out_wh; /* success */ -+ -+ err = -EIO; -+ AuIOErr("%.*s Invalid whiteout entry type 0%o.\n", -+ AuDLNPair(wh_dentry), wh_dentry->d_inode->i_mode); -+ -+ out_wh: -+ dput(wh_dentry); -+ out: -+ return err; -+} -+ -+/* -+ * test if the @h_dentry sets opaque or not. -+ */ -+int au_diropq_test(struct dentry *h_dentry, struct au_branch *br) -+{ -+ int err; -+ struct inode *h_dir; -+ -+ h_dir = h_dentry->d_inode; -+ err = au_wh_test(h_dentry, &diropq_name, br, -+ au_test_h_perm_sio(h_dir, MAY_EXEC)); -+ return err; -+} -+ -+/* -+ * returns a negative dentry whose name is unique and temporary. -+ */ -+struct dentry *au_whtmp_lkup(struct dentry *h_parent, struct au_branch *br, -+ struct qstr *prefix) -+{ -+ struct dentry *dentry; -+ int i; -+ /* cf. AUFS_MAX_NAMELEN in include/linux/aufs_type.h */ -+ char defname[AUFS_WH_PFX_LEN * 2 + DNAME_INLINE_LEN_MIN + 1 -+ + AUFS_WH_TMP_LEN + 1], *name, *p; -+ static unsigned short cnt; -+ struct qstr qs; -+ -+ BUILD_BUG_ON(sizeof(cnt) * 2 > AUFS_WH_TMP_LEN); -+ -+ name = defname; -+ qs.len = sizeof(defname) - DNAME_INLINE_LEN_MIN + prefix->len - 1; -+ if (unlikely(prefix->len > DNAME_INLINE_LEN_MIN)) { -+ dentry = ERR_PTR(-ENAMETOOLONG); -+ if (unlikely(qs.len > NAME_MAX)) -+ goto out; -+ dentry = ERR_PTR(-ENOMEM); -+ name = kmalloc(qs.len + 1, GFP_NOFS); -+ if (unlikely(!name)) -+ goto out; -+ } -+ -+ /* doubly whiteout-ed */ -+ memcpy(name, AUFS_WH_PFX AUFS_WH_PFX, AUFS_WH_PFX_LEN * 2); -+ p = name + AUFS_WH_PFX_LEN * 2; -+ memcpy(p, prefix->name, prefix->len); -+ p += prefix->len; -+ *p++ = '.'; -+ AuDebugOn(name + qs.len + 1 - p <= AUFS_WH_TMP_LEN); -+ -+ qs.name = name; -+ for (i = 0; i < 3; i++) { -+ sprintf(p, "%.*d", AUFS_WH_TMP_LEN, cnt++); -+ dentry = au_sio_lkup_one(&qs, h_parent, br); -+ if (IS_ERR(dentry) || !dentry->d_inode) -+ goto out_name; -+ dput(dentry); -+ } -+ /* pr_warning("could not get random name\n"); */ -+ dentry = ERR_PTR(-EEXIST); -+ AuDbg("%.*s\n", AuLNPair(&qs)); -+ BUG(); -+ -+ out_name: -+ if (name != defname) -+ kfree(name); -+ out: -+ AuTraceErrPtr(dentry); -+ return dentry; -+} -+ -+/* -+ * rename the @h_dentry on @br to the whiteouted temporary name. -+ */ -+int au_whtmp_ren(struct dentry *h_dentry, struct au_branch *br) -+{ -+ int err; -+ struct path h_path = { -+ .mnt = br->br_mnt -+ }; -+ struct inode *h_dir; -+ struct dentry *h_parent; -+ -+ h_parent = h_dentry->d_parent; /* dir inode is locked */ -+ h_dir = h_parent->d_inode; -+ IMustLock(h_dir); -+ -+ h_path.dentry = au_whtmp_lkup(h_parent, br, &h_dentry->d_name); -+ err = PTR_ERR(h_path.dentry); -+ if (IS_ERR(h_path.dentry)) -+ goto out; -+ -+ /* under the same dir, no need to lock_rename() */ -+ err = vfsub_rename(h_dir, h_dentry, h_dir, &h_path); -+ AuTraceErr(err); -+ dput(h_path.dentry); -+ -+ out: -+ AuTraceErr(err); -+ return err; -+} -+ -+/* ---------------------------------------------------------------------- */ -+/* -+ * functions for removing a whiteout -+ */ -+ -+static int do_unlink_wh(struct inode *h_dir, struct path *h_path) -+{ -+ int force; -+ -+ /* -+ * forces superio when the dir has a sticky bit. -+ * this may be a violation of unix fs semantics. -+ */ -+ force = (h_dir->i_mode & S_ISVTX) -+ && h_path->dentry->d_inode->i_uid != current_fsuid(); -+ return vfsub_unlink(h_dir, h_path, force); -+} -+ -+int au_wh_unlink_dentry(struct inode *h_dir, struct path *h_path, -+ struct dentry *dentry) -+{ -+ int err; -+ -+ err = do_unlink_wh(h_dir, h_path); -+ if (!err && dentry) -+ au_set_dbwh(dentry, -1); -+ -+ return err; -+} -+ -+static int unlink_wh_name(struct dentry *h_parent, struct qstr *wh, -+ struct au_branch *br) -+{ -+ int err; -+ struct path h_path = { -+ .mnt = br->br_mnt -+ }; -+ -+ err = 0; -+ h_path.dentry = au_lkup_one(wh, h_parent, br, /*nd*/NULL); -+ if (IS_ERR(h_path.dentry)) -+ err = PTR_ERR(h_path.dentry); -+ else { -+ if (h_path.dentry->d_inode -+ && S_ISREG(h_path.dentry->d_inode->i_mode)) -+ err = do_unlink_wh(h_parent->d_inode, &h_path); -+ dput(h_path.dentry); -+ } -+ -+ return err; -+} -+ -+/* ---------------------------------------------------------------------- */ -+/* -+ * initialize/clean whiteout for a branch -+ */ -+ -+static void au_wh_clean(struct inode *h_dir, struct path *whpath, -+ const int isdir) -+{ -+ int err; -+ -+ if (!whpath->dentry->d_inode) -+ return; -+ -+ err = mnt_want_write(whpath->mnt); -+ if (!err) { -+ if (isdir) -+ err = vfsub_rmdir(h_dir, whpath); -+ else -+ err = vfsub_unlink(h_dir, whpath, /*force*/0); -+ mnt_drop_write(whpath->mnt); -+ } -+ if (unlikely(err)) -+ pr_warning("failed removing %.*s (%d), ignored.\n", -+ AuDLNPair(whpath->dentry), err); -+} -+ -+static int test_linkable(struct dentry *h_root) -+{ -+ struct inode *h_dir = h_root->d_inode; -+ -+ if (h_dir->i_op->link) -+ return 0; -+ -+ pr_err("%.*s (%s) doesn't support link(2), use noplink and rw+nolwh\n", -+ AuDLNPair(h_root), au_sbtype(h_root->d_sb)); -+ return -ENOSYS; -+} -+ -+/* todo: should this mkdir be done in /sbin/mount.aufs helper? */ -+static int au_whdir(struct inode *h_dir, struct path *path) -+{ -+ int err; -+ -+ err = -EEXIST; -+ if (!path->dentry->d_inode) { -+ int mode = S_IRWXU; -+ -+ if (au_test_nfs(path->dentry->d_sb)) -+ mode |= S_IXUGO; -+ err = mnt_want_write(path->mnt); -+ if (!err) { -+ err = vfsub_mkdir(h_dir, path, mode); -+ mnt_drop_write(path->mnt); -+ } -+ } else if (S_ISDIR(path->dentry->d_inode->i_mode)) -+ err = 0; -+ else -+ pr_err("unknown %.*s exists\n", AuDLNPair(path->dentry)); -+ -+ return err; -+} -+ -+struct au_wh_base { -+ const struct qstr *name; -+ struct dentry *dentry; -+}; -+ -+static void au_wh_init_ro(struct inode *h_dir, struct au_wh_base base[], -+ struct path *h_path) -+{ -+ h_path->dentry = base[AuBrWh_BASE].dentry; -+ au_wh_clean(h_dir, h_path, /*isdir*/0); -+ h_path->dentry = base[AuBrWh_PLINK].dentry; -+ au_wh_clean(h_dir, h_path, /*isdir*/1); -+ h_path->dentry = base[AuBrWh_ORPH].dentry; -+ au_wh_clean(h_dir, h_path, /*isdir*/1); -+} -+ -+/* -+ * returns tri-state, -+ * minus: error, caller should print the mesage -+ * zero: succuess -+ * plus: error, caller should NOT print the mesage -+ */ -+static int au_wh_init_rw_nolink(struct dentry *h_root, struct au_wbr *wbr, -+ int do_plink, struct au_wh_base base[], -+ struct path *h_path) -+{ -+ int err; -+ struct inode *h_dir; -+ -+ h_dir = h_root->d_inode; -+ h_path->dentry = base[AuBrWh_BASE].dentry; -+ au_wh_clean(h_dir, h_path, /*isdir*/0); -+ h_path->dentry = base[AuBrWh_PLINK].dentry; -+ if (do_plink) { -+ err = test_linkable(h_root); -+ if (unlikely(err)) { -+ err = 1; -+ goto out; -+ } -+ -+ err = au_whdir(h_dir, h_path); -+ if (unlikely(err)) -+ goto out; -+ wbr->wbr_plink = dget(base[AuBrWh_PLINK].dentry); -+ } else -+ au_wh_clean(h_dir, h_path, /*isdir*/1); -+ h_path->dentry = base[AuBrWh_ORPH].dentry; -+ err = au_whdir(h_dir, h_path); -+ if (unlikely(err)) -+ goto out; -+ wbr->wbr_orph = dget(base[AuBrWh_ORPH].dentry); -+ -+ out: -+ return err; -+} -+ -+/* -+ * for the moment, aufs supports the branch filesystem which does not support -+ * link(2). testing on FAT which does not support i_op->setattr() fully either, -+ * copyup failed. finally, such filesystem will not be used as the writable -+ * branch. -+ * -+ * returns tri-state, see above. -+ */ -+static int au_wh_init_rw(struct dentry *h_root, struct au_wbr *wbr, -+ int do_plink, struct au_wh_base base[], -+ struct path *h_path) -+{ -+ int err; -+ struct inode *h_dir; -+ -+ WbrWhMustWriteLock(wbr); -+ -+ err = test_linkable(h_root); -+ if (unlikely(err)) { -+ err = 1; -+ goto out; -+ } -+ -+ /* -+ * todo: should this create be done in /sbin/mount.aufs helper? -+ */ -+ err = -EEXIST; -+ h_dir = h_root->d_inode; -+ if (!base[AuBrWh_BASE].dentry->d_inode) { -+ err = mnt_want_write(h_path->mnt); -+ if (!err) { -+ h_path->dentry = base[AuBrWh_BASE].dentry; -+ err = vfsub_create(h_dir, h_path, WH_MASK); -+ mnt_drop_write(h_path->mnt); -+ } -+ } else if (S_ISREG(base[AuBrWh_BASE].dentry->d_inode->i_mode)) -+ err = 0; -+ else -+ pr_err("unknown %.*s/%.*s exists\n", -+ AuDLNPair(h_root), AuDLNPair(base[AuBrWh_BASE].dentry)); -+ if (unlikely(err)) -+ goto out; -+ -+ h_path->dentry = base[AuBrWh_PLINK].dentry; -+ if (do_plink) { -+ err = au_whdir(h_dir, h_path); -+ if (unlikely(err)) -+ goto out; -+ wbr->wbr_plink = dget(base[AuBrWh_PLINK].dentry); -+ } else -+ au_wh_clean(h_dir, h_path, /*isdir*/1); -+ wbr->wbr_whbase = dget(base[AuBrWh_BASE].dentry); -+ -+ h_path->dentry = base[AuBrWh_ORPH].dentry; -+ err = au_whdir(h_dir, h_path); -+ if (unlikely(err)) -+ goto out; -+ wbr->wbr_orph = dget(base[AuBrWh_ORPH].dentry); -+ -+ out: -+ return err; -+} -+ -+/* -+ * initialize the whiteout base file/dir for @br. -+ */ -+int au_wh_init(struct dentry *h_root, struct au_branch *br, -+ struct super_block *sb) -+{ -+ int err, i; -+ const unsigned char do_plink -+ = !!au_opt_test(au_mntflags(sb), PLINK); -+ struct path path = { -+ .mnt = br->br_mnt -+ }; -+ struct inode *h_dir; -+ struct au_wbr *wbr = br->br_wbr; -+ static const struct qstr base_name[] = { -+ [AuBrWh_BASE] = { -+ .name = AUFS_BASE_NAME, -+ .len = sizeof(AUFS_BASE_NAME) - 1 -+ }, -+ [AuBrWh_PLINK] = { -+ .name = AUFS_PLINKDIR_NAME, -+ .len = sizeof(AUFS_PLINKDIR_NAME) - 1 -+ }, -+ [AuBrWh_ORPH] = { -+ .name = AUFS_ORPHDIR_NAME, -+ .len = sizeof(AUFS_ORPHDIR_NAME) - 1 -+ } -+ }; -+ struct au_wh_base base[] = { -+ [AuBrWh_BASE] = { -+ .name = base_name + AuBrWh_BASE, -+ .dentry = NULL -+ }, -+ [AuBrWh_PLINK] = { -+ .name = base_name + AuBrWh_PLINK, -+ .dentry = NULL -+ }, -+ [AuBrWh_ORPH] = { -+ .name = base_name + AuBrWh_ORPH, -+ .dentry = NULL -+ } -+ }; -+ -+ if (wbr) -+ WbrWhMustWriteLock(wbr); -+ -+ h_dir = h_root->d_inode; -+ for (i = 0; i < AuBrWh_Last; i++) { -+ /* doubly whiteouted */ -+ struct dentry *d; -+ -+ d = au_wh_lkup(h_root, (void *)base[i].name, br); -+ err = PTR_ERR(d); -+ if (IS_ERR(d)) -+ goto out; -+ -+ base[i].dentry = d; -+ AuDebugOn(wbr -+ && wbr->wbr_wh[i] -+ && wbr->wbr_wh[i] != base[i].dentry); -+ } -+ -+ if (wbr) -+ for (i = 0; i < AuBrWh_Last; i++) { -+ dput(wbr->wbr_wh[i]); -+ wbr->wbr_wh[i] = NULL; -+ } -+ -+ err = 0; -+ -+ switch (br->br_perm) { -+ case AuBrPerm_RO: -+ case AuBrPerm_ROWH: -+ case AuBrPerm_RR: -+ case AuBrPerm_RRWH: -+ au_wh_init_ro(h_dir, base, &path); -+ break; -+ -+ case AuBrPerm_RWNoLinkWH: -+ err = au_wh_init_rw_nolink(h_root, wbr, do_plink, base, &path); -+ if (err > 0) -+ goto out; -+ else if (err) -+ goto out_err; -+ break; -+ -+ case AuBrPerm_RW: -+ err = au_wh_init_rw(h_root, wbr, do_plink, base, &path); -+ if (err > 0) -+ goto out; -+ else if (err) -+ goto out_err; -+ break; -+ -+ default: -+ BUG(); -+ } -+ goto out; /* success */ -+ -+ out_err: -+ pr_err("an error(%d) on the writable branch %.*s(%s)\n", -+ err, AuDLNPair(h_root), au_sbtype(h_root->d_sb)); -+ out: -+ for (i = 0; i < AuBrWh_Last; i++) -+ dput(base[i].dentry); -+ return err; -+} -+ -+/* ---------------------------------------------------------------------- */ -+/* -+ * whiteouts are all hard-linked usually. -+ * when its link count reaches a ceiling, we create a new whiteout base -+ * asynchronously. -+ */ -+ -+struct reinit_br_wh { -+ struct super_block *sb; -+ struct au_branch *br; -+}; -+ -+static void reinit_br_wh(void *arg) -+{ -+ int err; -+ aufs_bindex_t bindex; -+ struct path h_path; -+ struct reinit_br_wh *a = arg; -+ struct au_wbr *wbr; -+ struct inode *dir; -+ struct dentry *h_root; -+ struct au_hinode *hdir; -+ -+ err = 0; -+ wbr = a->br->br_wbr; -+ /* big aufs lock */ -+ si_noflush_write_lock(a->sb); -+ if (!au_br_writable(a->br->br_perm)) -+ goto out; -+ bindex = au_br_index(a->sb, a->br->br_id); -+ if (unlikely(bindex < 0)) -+ goto out; -+ -+ di_read_lock_parent(a->sb->s_root, AuLock_IR); -+ dir = a->sb->s_root->d_inode; -+ hdir = au_hi(dir, bindex); -+ h_root = au_h_dptr(a->sb->s_root, bindex); -+ -+ au_hin_imtx_lock_nested(hdir, AuLsc_I_PARENT); -+ wbr_wh_write_lock(wbr); -+ err = au_h_verify(wbr->wbr_whbase, au_opt_udba(a->sb), hdir->hi_inode, -+ h_root, a->br); -+ if (!err) { -+ err = mnt_want_write(a->br->br_mnt); -+ if (!err) { -+ h_path.dentry = wbr->wbr_whbase; -+ h_path.mnt = a->br->br_mnt; -+ err = vfsub_unlink(hdir->hi_inode, &h_path, /*force*/0); -+ mnt_drop_write(a->br->br_mnt); -+ } -+ } else { -+ pr_warning("%.*s is moved, ignored\n", -+ AuDLNPair(wbr->wbr_whbase)); -+ err = 0; -+ } -+ dput(wbr->wbr_whbase); -+ wbr->wbr_whbase = NULL; -+ if (!err) -+ err = au_wh_init(h_root, a->br, a->sb); -+ wbr_wh_write_unlock(wbr); -+ au_hin_imtx_unlock(hdir); -+ di_read_unlock(a->sb->s_root, AuLock_IR); -+ -+ out: -+ if (wbr) -+ atomic_dec(&wbr->wbr_wh_running); -+ atomic_dec(&a->br->br_count); -+ au_nwt_done(&au_sbi(a->sb)->si_nowait); -+ si_write_unlock(a->sb); -+ kfree(arg); -+ if (unlikely(err)) -+ AuIOErr("err %d\n", err); -+} -+ -+static void kick_reinit_br_wh(struct super_block *sb, struct au_branch *br) -+{ -+ int do_dec, wkq_err; -+ struct reinit_br_wh *arg; -+ -+ do_dec = 1; -+ if (atomic_inc_return(&br->br_wbr->wbr_wh_running) != 1) -+ goto out; -+ -+ /* ignore ENOMEM */ -+ arg = kmalloc(sizeof(*arg), GFP_NOFS); -+ if (arg) { -+ /* -+ * dec(wh_running), kfree(arg) and dec(br_count) -+ * in reinit function -+ */ -+ arg->sb = sb; -+ arg->br = br; -+ atomic_inc(&br->br_count); -+ wkq_err = au_wkq_nowait(reinit_br_wh, arg, sb); -+ if (unlikely(wkq_err)) { -+ atomic_dec(&br->br_wbr->wbr_wh_running); -+ atomic_dec(&br->br_count); -+ kfree(arg); -+ } -+ do_dec = 0; -+ } -+ -+ out: -+ if (do_dec) -+ atomic_dec(&br->br_wbr->wbr_wh_running); -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+/* -+ * create the whiteout @wh. -+ */ -+static int link_or_create_wh(struct super_block *sb, aufs_bindex_t bindex, -+ struct dentry *wh) -+{ -+ int err; -+ struct path h_path = { -+ .dentry = wh -+ }; -+ struct au_branch *br; -+ struct au_wbr *wbr; -+ struct dentry *h_parent; -+ struct inode *h_dir; -+ -+ h_parent = wh->d_parent; /* dir inode is locked */ -+ h_dir = h_parent->d_inode; -+ IMustLock(h_dir); -+ -+ br = au_sbr(sb, bindex); -+ h_path.mnt = br->br_mnt; -+ wbr = br->br_wbr; -+ wbr_wh_read_lock(wbr); -+ if (wbr->wbr_whbase) { -+ err = vfsub_link(wbr->wbr_whbase, h_dir, &h_path); -+ if (!err || err != -EMLINK) -+ goto out; -+ -+ /* link count full. re-initialize br_whbase. */ -+ kick_reinit_br_wh(sb, br); -+ } -+ -+ /* return this error in this context */ -+ err = vfsub_create(h_dir, &h_path, WH_MASK); -+ -+ out: -+ wbr_wh_read_unlock(wbr); -+ return err; -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+/* -+ * create or remove the diropq. -+ */ -+static struct dentry *do_diropq(struct dentry *dentry, aufs_bindex_t bindex, -+ unsigned int flags) -+{ -+ struct dentry *opq_dentry, *h_dentry; -+ struct super_block *sb; -+ struct au_branch *br; -+ int err; -+ -+ sb = dentry->d_sb; -+ br = au_sbr(sb, bindex); -+ h_dentry = au_h_dptr(dentry, bindex); -+ opq_dentry = au_lkup_one(&diropq_name, h_dentry, br, /*nd*/NULL); -+ if (IS_ERR(opq_dentry)) -+ goto out; -+ -+ if (au_ftest_diropq(flags, CREATE)) { -+ err = link_or_create_wh(sb, bindex, opq_dentry); -+ if (!err) { -+ au_set_dbdiropq(dentry, bindex); -+ goto out; /* success */ -+ } -+ } else { -+ struct path tmp = { -+ .dentry = opq_dentry, -+ .mnt = br->br_mnt -+ }; -+ err = do_unlink_wh(au_h_iptr(dentry->d_inode, bindex), &tmp); -+ if (!err) -+ au_set_dbdiropq(dentry, -1); -+ } -+ dput(opq_dentry); -+ opq_dentry = ERR_PTR(err); -+ -+ out: -+ return opq_dentry; -+} -+ -+struct do_diropq_args { -+ struct dentry **errp; -+ struct dentry *dentry; -+ aufs_bindex_t bindex; -+ unsigned int flags; -+}; -+ -+static void call_do_diropq(void *args) -+{ -+ struct do_diropq_args *a = args; -+ *a->errp = do_diropq(a->dentry, a->bindex, a->flags); -+} -+ -+struct dentry *au_diropq_sio(struct dentry *dentry, aufs_bindex_t bindex, -+ unsigned int flags) -+{ -+ struct dentry *diropq, *h_dentry; -+ -+ h_dentry = au_h_dptr(dentry, bindex); -+ if (!au_test_h_perm_sio(h_dentry->d_inode, MAY_EXEC | MAY_WRITE)) -+ diropq = do_diropq(dentry, bindex, flags); -+ else { -+ int wkq_err; -+ struct do_diropq_args args = { -+ .errp = &diropq, -+ .dentry = dentry, -+ .bindex = bindex, -+ .flags = flags -+ }; -+ -+ wkq_err = au_wkq_wait(call_do_diropq, &args); -+ if (unlikely(wkq_err)) -+ diropq = ERR_PTR(wkq_err); -+ } -+ -+ return diropq; -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+/* -+ * lookup whiteout dentry. -+ * @h_parent: lower parent dentry which must exist and be locked -+ * @base_name: name of dentry which will be whiteouted -+ * returns dentry for whiteout. -+ */ -+struct dentry *au_wh_lkup(struct dentry *h_parent, struct qstr *base_name, -+ struct au_branch *br) -+{ -+ int err; -+ struct qstr wh_name; -+ struct dentry *wh_dentry; -+ -+ err = au_wh_name_alloc(&wh_name, base_name); -+ wh_dentry = ERR_PTR(err); -+ if (!err) { -+ wh_dentry = au_lkup_one(&wh_name, h_parent, br, /*nd*/NULL); -+ kfree(wh_name.name); -+ } -+ return wh_dentry; -+} -+ -+/* -+ * link/create a whiteout for @dentry on @bindex. -+ */ -+struct dentry *au_wh_create(struct dentry *dentry, aufs_bindex_t bindex, -+ struct dentry *h_parent) -+{ -+ struct dentry *wh_dentry; -+ struct super_block *sb; -+ int err; -+ -+ sb = dentry->d_sb; -+ wh_dentry = au_wh_lkup(h_parent, &dentry->d_name, au_sbr(sb, bindex)); -+ if (!IS_ERR(wh_dentry) && !wh_dentry->d_inode) { -+ err = link_or_create_wh(sb, bindex, wh_dentry); -+ if (!err) -+ au_set_dbwh(dentry, bindex); -+ else { -+ dput(wh_dentry); -+ wh_dentry = ERR_PTR(err); -+ } -+ } -+ -+ return wh_dentry; -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+/* Delete all whiteouts in this directory on branch bindex. */ -+static int del_wh_children(struct dentry *h_dentry, struct au_nhash *whlist, -+ aufs_bindex_t bindex, struct au_branch *br) -+{ -+ int err; -+ unsigned long ul, n; -+ struct qstr wh_name; -+ char *p; -+ struct hlist_head *head; -+ struct au_vdir_wh *tpos; -+ struct hlist_node *pos; -+ struct au_vdir_destr *str; -+ -+ err = -ENOMEM; -+ p = __getname(); -+ wh_name.name = p; -+ if (unlikely(!wh_name.name)) -+ goto out; -+ -+ err = 0; -+ memcpy(p, AUFS_WH_PFX, AUFS_WH_PFX_LEN); -+ p += AUFS_WH_PFX_LEN; -+ n = whlist->nh_num; -+ head = whlist->nh_head; -+ for (ul = 0; !err && ul < n; ul++, head++) { -+ hlist_for_each_entry(tpos, pos, head, wh_hash) { -+ if (tpos->wh_bindex != bindex) -+ continue; -+ -+ str = &tpos->wh_str; -+ if (str->len + AUFS_WH_PFX_LEN <= PATH_MAX) { -+ memcpy(p, str->name, str->len); -+ wh_name.len = AUFS_WH_PFX_LEN + str->len; -+ err = unlink_wh_name(h_dentry, &wh_name, br); -+ if (!err) -+ continue; -+ break; -+ } -+ AuIOErr("whiteout name too long %.*s\n", -+ str->len, str->name); -+ err = -EIO; -+ break; -+ } -+ } -+ __putname(wh_name.name); -+ -+ out: -+ return err; -+} -+ -+struct del_wh_children_args { -+ int *errp; -+ struct dentry *h_dentry; -+ struct au_nhash *whlist; -+ aufs_bindex_t bindex; -+ struct au_branch *br; -+}; -+ -+static void call_del_wh_children(void *args) -+{ -+ struct del_wh_children_args *a = args; -+ *a->errp = del_wh_children(a->h_dentry, a->whlist, a->bindex, a->br); -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+struct au_whtmp_rmdir *au_whtmp_rmdir_alloc(struct super_block *sb, gfp_t gfp) -+{ -+ struct au_whtmp_rmdir *whtmp; -+ int err; -+ unsigned int rdhash; -+ -+ SiMustAnyLock(sb); -+ -+ whtmp = kmalloc(sizeof(*whtmp), gfp); -+ if (unlikely(!whtmp)) { -+ whtmp = ERR_PTR(-ENOMEM); -+ goto out; -+ } -+ -+ whtmp->dir = NULL; -+ whtmp->wh_dentry = NULL; -+ /* no estimation for dir size */ -+ rdhash = au_sbi(sb)->si_rdhash; -+ if (!rdhash) -+ rdhash = AUFS_RDHASH_DEF; -+ err = au_nhash_alloc(&whtmp->whlist, rdhash, gfp); -+ if (unlikely(err)) { -+ kfree(whtmp); -+ whtmp = ERR_PTR(err); -+ } -+ -+ out: -+ return whtmp; -+} -+ -+void au_whtmp_rmdir_free(struct au_whtmp_rmdir *whtmp) -+{ -+ dput(whtmp->wh_dentry); -+ iput(whtmp->dir); -+ au_nhash_wh_free(&whtmp->whlist); -+ kfree(whtmp); -+} -+ -+/* -+ * rmdir the whiteouted temporary named dir @h_dentry. -+ * @whlist: whiteouted children. -+ */ -+int au_whtmp_rmdir(struct inode *dir, aufs_bindex_t bindex, -+ struct dentry *wh_dentry, struct au_nhash *whlist) -+{ -+ int err; -+ struct path h_tmp; -+ struct inode *wh_inode, *h_dir; -+ struct au_branch *br; -+ -+ h_dir = wh_dentry->d_parent->d_inode; /* dir inode is locked */ -+ IMustLock(h_dir); -+ -+ br = au_sbr(dir->i_sb, bindex); -+ wh_inode = wh_dentry->d_inode; -+ mutex_lock_nested(&wh_inode->i_mutex, AuLsc_I_CHILD); -+ -+ /* -+ * someone else might change some whiteouts while we were sleeping. -+ * it means this whlist may have an obsoleted entry. -+ */ -+ if (!au_test_h_perm_sio(wh_inode, MAY_EXEC | MAY_WRITE)) -+ err = del_wh_children(wh_dentry, whlist, bindex, br); -+ else { -+ int wkq_err; -+ struct del_wh_children_args args = { -+ .errp = &err, -+ .h_dentry = wh_dentry, -+ .whlist = whlist, -+ .bindex = bindex, -+ .br = br -+ }; -+ -+ wkq_err = au_wkq_wait(call_del_wh_children, &args); -+ if (unlikely(wkq_err)) -+ err = wkq_err; -+ } -+ mutex_unlock(&wh_inode->i_mutex); -+ -+ if (!err) { -+ h_tmp.dentry = wh_dentry; -+ h_tmp.mnt = br->br_mnt; -+ err = vfsub_rmdir(h_dir, &h_tmp); -+ /* d_drop(h_dentry); */ -+ } -+ -+ if (!err) { -+ if (au_ibstart(dir) == bindex) { -+ au_cpup_attr_timesizes(dir); -+ drop_nlink(dir); -+ } -+ return 0; /* success */ -+ } -+ -+ pr_warning("failed removing %.*s(%d), ignored\n", -+ AuDLNPair(wh_dentry), err); -+ return err; -+} -+ -+static void call_rmdir_whtmp(void *args) -+{ -+ int err; -+ struct au_whtmp_rmdir *a = args; -+ struct super_block *sb; -+ struct dentry *h_parent; -+ struct inode *h_dir; -+ struct au_branch *br; -+ struct au_hinode *hdir; -+ -+ /* rmdir by nfsd may cause deadlock with this i_mutex */ -+ /* mutex_lock(&a->dir->i_mutex); */ -+ sb = a->dir->i_sb; -+ si_noflush_read_lock(sb); -+ err = au_test_ro(sb, a->bindex, NULL); -+ if (unlikely(err)) -+ goto out; -+ -+ err = -EIO; -+ br = au_sbr(sb, a->bindex); -+ ii_write_lock_parent(a->dir); -+ h_parent = dget_parent(a->wh_dentry); -+ h_dir = h_parent->d_inode; -+ hdir = au_hi(a->dir, a->bindex); -+ au_hin_imtx_lock_nested(hdir, AuLsc_I_PARENT); -+ err = au_h_verify(a->wh_dentry, au_opt_udba(sb), h_dir, h_parent, br); -+ if (!err) { -+ err = mnt_want_write(br->br_mnt); -+ if (!err) { -+ err = au_whtmp_rmdir(a->dir, a->bindex, a->wh_dentry, -+ &a->whlist); -+ mnt_drop_write(br->br_mnt); -+ } -+ } -+ au_hin_imtx_unlock(hdir); -+ dput(h_parent); -+ ii_write_unlock(a->dir); -+ -+ out: -+ /* mutex_unlock(&a->dir->i_mutex); */ -+ au_nwt_done(&au_sbi(sb)->si_nowait); -+ si_read_unlock(sb); -+ au_whtmp_rmdir_free(a); -+ if (unlikely(err)) -+ AuIOErr("err %d\n", err); -+} -+ -+void au_whtmp_kick_rmdir(struct inode *dir, aufs_bindex_t bindex, -+ struct dentry *wh_dentry, struct au_whtmp_rmdir *args) -+{ -+ int wkq_err; -+ -+ IMustLock(dir); -+ -+ /* all post-process will be done in do_rmdir_whtmp(). */ -+ args->dir = au_igrab(dir); -+ args->bindex = bindex; -+ args->wh_dentry = dget(wh_dentry); -+ wkq_err = au_wkq_nowait(call_rmdir_whtmp, args, dir->i_sb); -+ if (unlikely(wkq_err)) { -+ pr_warning("rmdir error %.*s (%d), ignored\n", -+ AuDLNPair(wh_dentry), wkq_err); -+ au_whtmp_rmdir_free(args); -+ } -+} -diff --git a/fs/aufs/whout.h b/fs/aufs/whout.h -new file mode 100644 -index 0000000..40c6926 ---- /dev/null -+++ b/fs/aufs/whout.h -@@ -0,0 +1,87 @@ -+/* -+ * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * -+ * This program, aufs is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ */ -+ -+/* -+ * whiteout for logical deletion and opaque directory -+ */ -+ -+#ifndef __AUFS_WHOUT_H__ -+#define __AUFS_WHOUT_H__ -+ -+#ifdef __KERNEL__ -+ -+#include -+#include "dir.h" -+ -+/* whout.c */ -+int au_wh_name_alloc(struct qstr *wh, const struct qstr *name); -+struct au_branch; -+int au_wh_test(struct dentry *h_parent, struct qstr *wh_name, -+ struct au_branch *br, int try_sio); -+int au_diropq_test(struct dentry *h_dentry, struct au_branch *br); -+struct dentry *au_whtmp_lkup(struct dentry *h_parent, struct au_branch *br, -+ struct qstr *prefix); -+int au_whtmp_ren(struct dentry *h_dentry, struct au_branch *br); -+int au_wh_unlink_dentry(struct inode *h_dir, struct path *h_path, -+ struct dentry *dentry); -+int au_wh_init(struct dentry *h_parent, struct au_branch *br, -+ struct super_block *sb); -+ -+/* diropq flags */ -+#define AuDiropq_CREATE 1 -+#define au_ftest_diropq(flags, name) ((flags) & AuDiropq_##name) -+#define au_fset_diropq(flags, name) { (flags) |= AuDiropq_##name; } -+#define au_fclr_diropq(flags, name) { (flags) &= ~AuDiropq_##name; } -+ -+struct dentry *au_diropq_sio(struct dentry *dentry, aufs_bindex_t bindex, -+ unsigned int flags); -+struct dentry *au_wh_lkup(struct dentry *h_parent, struct qstr *base_name, -+ struct au_branch *br); -+struct dentry *au_wh_create(struct dentry *dentry, aufs_bindex_t bindex, -+ struct dentry *h_parent); -+ -+/* real rmdir for the whiteout-ed dir */ -+struct au_whtmp_rmdir { -+ struct inode *dir; -+ aufs_bindex_t bindex; -+ struct dentry *wh_dentry; -+ struct au_nhash whlist; -+}; -+ -+struct au_whtmp_rmdir *au_whtmp_rmdir_alloc(struct super_block *sb, gfp_t gfp); -+void au_whtmp_rmdir_free(struct au_whtmp_rmdir *whtmp); -+int au_whtmp_rmdir(struct inode *dir, aufs_bindex_t bindex, -+ struct dentry *wh_dentry, struct au_nhash *whlist); -+void au_whtmp_kick_rmdir(struct inode *dir, aufs_bindex_t bindex, -+ struct dentry *wh_dentry, struct au_whtmp_rmdir *args); -+ -+/* ---------------------------------------------------------------------- */ -+ -+static inline struct dentry *au_diropq_create(struct dentry *dentry, -+ aufs_bindex_t bindex) -+{ -+ return au_diropq_sio(dentry, bindex, AuDiropq_CREATE); -+} -+ -+static inline int au_diropq_remove(struct dentry *dentry, aufs_bindex_t bindex) -+{ -+ return PTR_ERR(au_diropq_sio(dentry, bindex, !AuDiropq_CREATE)); -+} -+ -+#endif /* __KERNEL__ */ -+#endif /* __AUFS_WHOUT_H__ */ -diff --git a/fs/aufs/wkq.c b/fs/aufs/wkq.c -new file mode 100644 -index 0000000..89656e9 ---- /dev/null -+++ b/fs/aufs/wkq.c -@@ -0,0 +1,259 @@ -+/* -+ * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * -+ * This program, aufs is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ */ -+ -+/* -+ * workqueue for asynchronous/super-io operations -+ * todo: try new dredential scheme -+ */ -+ -+#include -+#include "aufs.h" -+ -+/* internal workqueue named AUFS_WKQ_NAME */ -+static struct au_wkq { -+ struct workqueue_struct *q; -+ -+ /* balancing */ -+ atomic_t busy; -+} *au_wkq; -+ -+struct au_wkinfo { -+ struct work_struct wk; -+ struct super_block *sb; -+ -+ unsigned int flags; /* see wkq.h */ -+ -+ au_wkq_func_t func; -+ void *args; -+ -+ atomic_t *busyp; -+ struct completion *comp; -+}; -+ -+/* ---------------------------------------------------------------------- */ -+ -+static int enqueue(struct au_wkq *wkq, struct au_wkinfo *wkinfo) -+{ -+ wkinfo->busyp = &wkq->busy; -+ if (au_ftest_wkq(wkinfo->flags, WAIT)) -+ return !queue_work(wkq->q, &wkinfo->wk); -+ else -+ return !schedule_work(&wkinfo->wk); -+} -+ -+static void do_wkq(struct au_wkinfo *wkinfo) -+{ -+ unsigned int idle, n; -+ int i, idle_idx; -+ -+ while (1) { -+ if (au_ftest_wkq(wkinfo->flags, WAIT)) { -+ idle_idx = 0; -+ idle = UINT_MAX; -+ for (i = 0; i < aufs_nwkq; i++) { -+ n = atomic_inc_return(&au_wkq[i].busy); -+ if (n == 1 && !enqueue(au_wkq + i, wkinfo)) -+ return; /* success */ -+ -+ if (n < idle) { -+ idle_idx = i; -+ idle = n; -+ } -+ atomic_dec(&au_wkq[i].busy); -+ } -+ } else -+ idle_idx = aufs_nwkq; -+ -+ atomic_inc(&au_wkq[idle_idx].busy); -+ if (!enqueue(au_wkq + idle_idx, wkinfo)) -+ return; /* success */ -+ -+ /* impossible? */ -+ AuWarn1("failed to queue_work()\n"); -+ yield(); -+ } -+} -+ -+static void wkq_func(struct work_struct *wk) -+{ -+ struct au_wkinfo *wkinfo = container_of(wk, struct au_wkinfo, wk); -+ -+ wkinfo->func(wkinfo->args); -+ atomic_dec_return(wkinfo->busyp); -+ if (au_ftest_wkq(wkinfo->flags, WAIT)) -+ complete(wkinfo->comp); -+ else { -+ kobject_put(&au_sbi(wkinfo->sb)->si_kobj); -+ module_put(THIS_MODULE); -+ kfree(wkinfo); -+ } -+} -+ -+/* -+ * Since struct completion is large, try allocating it dynamically. -+ */ -+#if defined(CONFIG_4KSTACKS) || defined(AuTest4KSTACKS) -+#define AuWkqCompDeclare(name) struct completion *comp = NULL -+ -+static int au_wkq_comp_alloc(struct au_wkinfo *wkinfo, struct completion **comp) -+{ -+ *comp = kmalloc(sizeof(**comp), GFP_NOFS); -+ if (*comp) { -+ init_completion(*comp); -+ wkinfo->comp = *comp; -+ return 0; -+ } -+ return -ENOMEM; -+} -+ -+static void au_wkq_comp_free(struct completion *comp) -+{ -+ kfree(comp); -+} -+ -+#else -+ -+/* no braces */ -+#define AuWkqCompDeclare(name) \ -+ DECLARE_COMPLETION_ONSTACK(_ ## name); \ -+ struct completion *comp = &_ ## name -+ -+static int au_wkq_comp_alloc(struct au_wkinfo *wkinfo, struct completion **comp) -+{ -+ wkinfo->comp = *comp; -+ return 0; -+} -+ -+static void au_wkq_comp_free(struct completion *comp __maybe_unused) -+{ -+ /* empty */ -+} -+#endif /* 4KSTACKS */ -+ -+static void au_wkq_run(struct au_wkinfo *wkinfo) -+{ -+ au_dbg_verify_kthread(); -+ INIT_WORK(&wkinfo->wk, wkq_func); -+ do_wkq(wkinfo); -+} -+ -+int au_wkq_wait(au_wkq_func_t func, void *args) -+{ -+ int err; -+ AuWkqCompDeclare(comp); -+ struct au_wkinfo wkinfo = { -+ .flags = AuWkq_WAIT, -+ .func = func, -+ .args = args -+ }; -+ -+ err = au_wkq_comp_alloc(&wkinfo, &comp); -+ if (!err) { -+ au_wkq_run(&wkinfo); -+ /* no timeout, no interrupt */ -+ wait_for_completion(wkinfo.comp); -+ au_wkq_comp_free(comp); -+ } -+ -+ return err; -+ -+} -+ -+int au_wkq_nowait(au_wkq_func_t func, void *args, struct super_block *sb) -+{ -+ int err; -+ struct au_wkinfo *wkinfo; -+ -+ atomic_inc(&au_sbi(sb)->si_nowait.nw_len); -+ -+ /* -+ * wkq_func() must free this wkinfo. -+ * it highly depends upon the implementation of workqueue. -+ */ -+ err = 0; -+ wkinfo = kmalloc(sizeof(*wkinfo), GFP_NOFS); -+ if (wkinfo) { -+ wkinfo->sb = sb; -+ wkinfo->flags = !AuWkq_WAIT; -+ wkinfo->func = func; -+ wkinfo->args = args; -+ wkinfo->comp = NULL; -+ kobject_get(&au_sbi(sb)->si_kobj); -+ __module_get(THIS_MODULE); -+ -+ au_wkq_run(wkinfo); -+ } else { -+ err = -ENOMEM; -+ atomic_dec(&au_sbi(sb)->si_nowait.nw_len); -+ } -+ -+ return err; -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+void au_nwt_init(struct au_nowait_tasks *nwt) -+{ -+ atomic_set(&nwt->nw_len, 0); -+ /* smp_mb();*/ /* atomic_set */ -+ init_waitqueue_head(&nwt->nw_wq); -+} -+ -+void au_wkq_fin(void) -+{ -+ int i; -+ -+ for (i = 0; i < aufs_nwkq; i++) -+ if (au_wkq[i].q && !IS_ERR(au_wkq[i].q)) -+ destroy_workqueue(au_wkq[i].q); -+ kfree(au_wkq); -+} -+ -+int __init au_wkq_init(void) -+{ -+ int err, i; -+ struct au_wkq *nowaitq; -+ -+ /* '+1' is for accounting of nowait queue */ -+ err = -ENOMEM; -+ au_wkq = kcalloc(aufs_nwkq + 1, sizeof(*au_wkq), GFP_NOFS); -+ if (unlikely(!au_wkq)) -+ goto out; -+ -+ err = 0; -+ for (i = 0; i < aufs_nwkq; i++) { -+ au_wkq[i].q = create_singlethread_workqueue(AUFS_WKQ_NAME); -+ if (au_wkq[i].q && !IS_ERR(au_wkq[i].q)) { -+ atomic_set(&au_wkq[i].busy, 0); -+ continue; -+ } -+ -+ err = PTR_ERR(au_wkq[i].q); -+ au_wkq_fin(); -+ goto out; -+ } -+ -+ /* nowait accounting */ -+ nowaitq = au_wkq + aufs_nwkq; -+ atomic_set(&nowaitq->busy, 0); -+ nowaitq->q = NULL; -+ /* smp_mb(); */ /* atomic_set */ -+ -+ out: -+ return err; -+} -diff --git a/fs/aufs/wkq.h b/fs/aufs/wkq.h -new file mode 100644 -index 0000000..b5b6a61 ---- /dev/null -+++ b/fs/aufs/wkq.h -@@ -0,0 +1,82 @@ -+/* -+ * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * -+ * This program, aufs is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ */ -+ -+/* -+ * workqueue for asynchronous/super-io operations -+ * todo: try new credentials management scheme -+ */ -+ -+#ifndef __AUFS_WKQ_H__ -+#define __AUFS_WKQ_H__ -+ -+#ifdef __KERNEL__ -+ -+#include -+#include -+#include -+ -+struct super_block; -+ -+/* ---------------------------------------------------------------------- */ -+ -+/* -+ * in the next operation, wait for the 'nowait' tasks in system-wide workqueue -+ */ -+struct au_nowait_tasks { -+ atomic_t nw_len; -+ wait_queue_head_t nw_wq; -+}; -+ -+/* ---------------------------------------------------------------------- */ -+ -+typedef void (*au_wkq_func_t)(void *args); -+ -+/* wkq flags */ -+#define AuWkq_WAIT 1 -+#define au_ftest_wkq(flags, name) ((flags) & AuWkq_##name) -+#define au_fset_wkq(flags, name) { (flags) |= AuWkq_##name; } -+#define au_fclr_wkq(flags, name) { (flags) &= ~AuWkq_##name; } -+ -+/* wkq.c */ -+int au_wkq_wait(au_wkq_func_t func, void *args); -+int au_wkq_nowait(au_wkq_func_t func, void *args, struct super_block *sb); -+void au_nwt_init(struct au_nowait_tasks *nwt); -+int __init au_wkq_init(void); -+void au_wkq_fin(void); -+ -+/* ---------------------------------------------------------------------- */ -+ -+static inline int au_test_wkq(struct task_struct *tsk) -+{ -+ return !tsk->mm && !strcmp(tsk->comm, AUFS_WKQ_NAME); -+} -+ -+static inline void au_nwt_done(struct au_nowait_tasks *nwt) -+{ -+ if (!atomic_dec_return(&nwt->nw_len)) -+ wake_up_all(&nwt->nw_wq); -+} -+ -+static inline int au_nwt_flush(struct au_nowait_tasks *nwt) -+{ -+ wait_event(nwt->nw_wq, !atomic_read(&nwt->nw_len)); -+ return 0; -+} -+ -+#endif /* __KERNEL__ */ -+#endif /* __AUFS_WKQ_H__ */ -diff --git a/fs/aufs/xino.c b/fs/aufs/xino.c -new file mode 100644 -index 0000000..b401aa9 ---- /dev/null -+++ b/fs/aufs/xino.c -@@ -0,0 +1,1204 @@ -+/* -+ * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * -+ * This program, aufs is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ */ -+ -+/* -+ * external inode number translation table and bitmap -+ */ -+ -+#include -+#include -+#include -+#include "aufs.h" -+ -+ssize_t xino_fread(au_readf_t func, struct file *file, void *buf, size_t size, -+ loff_t *pos) -+{ -+ ssize_t err; -+ mm_segment_t oldfs; -+ -+ oldfs = get_fs(); -+ set_fs(KERNEL_DS); -+ do { -+ /* todo: signal_pending? */ -+ err = func(file, (char __user *)buf, size, pos); -+ } while (err == -EAGAIN || err == -EINTR); -+ set_fs(oldfs); -+ -+#if 0 /* reserved for future use */ -+ if (err > 0) -+ fsnotify_access(file->f_dentry); -+#endif -+ -+ return err; -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+static ssize_t do_xino_fwrite(au_writef_t func, struct file *file, void *buf, -+ size_t size, loff_t *pos) -+{ -+ ssize_t err; -+ mm_segment_t oldfs; -+ -+ oldfs = get_fs(); -+ set_fs(KERNEL_DS); -+ /* lockdep_off(); */ -+ do { -+ /* todo: signal_pending? */ -+ err = func(file, (const char __user *)buf, size, pos); -+ } while (err == -EAGAIN || err == -EINTR); -+ /* lockdep_on(); */ -+ set_fs(oldfs); -+ -+#if 0 /* reserved for future use */ -+ if (err > 0) -+ fsnotify_modify(file->f_dentry); -+#endif -+ -+ return err; -+} -+ -+struct do_xino_fwrite_args { -+ ssize_t *errp; -+ au_writef_t func; -+ struct file *file; -+ void *buf; -+ size_t size; -+ loff_t *pos; -+}; -+ -+static void call_do_xino_fwrite(void *args) -+{ -+ struct do_xino_fwrite_args *a = args; -+ *a->errp = do_xino_fwrite(a->func, a->file, a->buf, a->size, a->pos); -+} -+ -+ssize_t xino_fwrite(au_writef_t func, struct file *file, void *buf, size_t size, -+ loff_t *pos) -+{ -+ ssize_t err; -+ -+ /* todo: signal block and no wkq? */ -+ /* todo: new credential scheme */ -+ /* -+ * it breaks RLIMIT_FSIZE and normal user's limit, -+ * users should care about quota and real 'filesystem full.' -+ */ -+ if (!au_test_wkq(current)) { -+ int wkq_err; -+ struct do_xino_fwrite_args args = { -+ .errp = &err, -+ .func = func, -+ .file = file, -+ .buf = buf, -+ .size = size, -+ .pos = pos -+ }; -+ -+ wkq_err = au_wkq_wait(call_do_xino_fwrite, &args); -+ if (unlikely(wkq_err)) -+ err = wkq_err; -+ } else -+ err = do_xino_fwrite(func, file, buf, size, pos); -+ -+ return err; -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+/* -+ * create a new xinofile at the same place/path as @base_file. -+ */ -+struct file *au_xino_create2(struct file *base_file, struct file *copy_src) -+{ -+ struct file *file; -+ struct dentry *base, *dentry, *parent; -+ struct inode *dir; -+ struct qstr *name; -+ int err; -+ struct path path; -+ -+ base = base_file->f_dentry; -+ parent = base->d_parent; /* dir inode is locked */ -+ dir = parent->d_inode; -+ IMustLock(dir); -+ -+ file = ERR_PTR(-EINVAL); -+ name = &base->d_name; -+ dentry = vfsub_lookup_one_len(name->name, parent, name->len); -+ if (IS_ERR(dentry)) { -+ file = (void *)dentry; -+ pr_err("%.*s lookup err %ld\n", -+ AuLNPair(name), PTR_ERR(dentry)); -+ goto out; -+ } -+ -+ /* no need to mnt_want_write() since we call dentry_open() later */ -+ err = vfs_create(dir, dentry, S_IRUGO | S_IWUGO, NULL); -+ if (unlikely(err)) { -+ file = ERR_PTR(err); -+ pr_err("%.*s create err %d\n", AuLNPair(name), err); -+ goto out_dput; -+ } -+ -+ path.dentry = dentry; -+ path.mnt = base_file->f_vfsmnt; -+ path_get(&path); -+ file = vfsub_dentry_open(&path, O_RDWR | O_CREAT | O_EXCL | O_LARGEFILE, -+ current_cred()); -+ if (IS_ERR(file)) { -+ pr_err("%.*s open err %ld\n", AuLNPair(name), PTR_ERR(file)); -+ goto out_dput; -+ } -+ -+ err = vfsub_unlink(dir, &file->f_path, /*force*/0); -+ if (unlikely(err)) { -+ pr_err("%.*s unlink err %d\n", AuLNPair(name), err); -+ goto out_fput; -+ } -+ -+ if (copy_src) { -+ /* no one can touch copy_src xino */ -+ err = au_copy_file(file, copy_src, -+ i_size_read(copy_src->f_dentry->d_inode)); -+ if (unlikely(err)) { -+ pr_err("%.*s copy err %d\n", AuLNPair(name), err); -+ goto out_fput; -+ } -+ } -+ goto out_dput; /* success */ -+ -+ out_fput: -+ fput(file); -+ file = ERR_PTR(err); -+ out_dput: -+ dput(dentry); -+ out: -+ return file; -+} -+ -+struct au_xino_lock_dir { -+ struct au_hinode *hdir; -+ struct dentry *parent; -+ struct mutex *mtx; -+}; -+ -+static void au_xino_lock_dir(struct super_block *sb, struct file *xino, -+ struct au_xino_lock_dir *ldir) -+{ -+ aufs_bindex_t brid, bindex; -+ -+ ldir->hdir = NULL; -+ bindex = -1; -+ brid = au_xino_brid(sb); -+ if (brid >= 0) -+ bindex = au_br_index(sb, brid); -+ if (bindex >= 0) { -+ ldir->hdir = au_hi(sb->s_root->d_inode, bindex); -+ au_hin_imtx_lock_nested(ldir->hdir, AuLsc_I_PARENT); -+ } else { -+ ldir->parent = dget_parent(xino->f_dentry); -+ ldir->mtx = &ldir->parent->d_inode->i_mutex; -+ mutex_lock_nested(ldir->mtx, AuLsc_I_PARENT); -+ } -+} -+ -+static void au_xino_unlock_dir(struct au_xino_lock_dir *ldir) -+{ -+ if (ldir->hdir) -+ au_hin_imtx_unlock(ldir->hdir); -+ else { -+ mutex_unlock(ldir->mtx); -+ dput(ldir->parent); -+ } -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+/* trucate xino files asynchronously */ -+ -+int au_xino_trunc(struct super_block *sb, aufs_bindex_t bindex) -+{ -+ int err; -+ aufs_bindex_t bi, bend; -+ struct au_branch *br; -+ struct file *new_xino, *file; -+ struct super_block *h_sb; -+ struct au_xino_lock_dir ldir; -+ -+ err = -EINVAL; -+ bend = au_sbend(sb); -+ if (unlikely(bindex < 0 || bend < bindex)) -+ goto out; -+ br = au_sbr(sb, bindex); -+ file = br->br_xino.xi_file; -+ if (!file) -+ goto out; -+ -+ au_xino_lock_dir(sb, file, &ldir); -+ /* mnt_want_write() is unnecessary here */ -+ new_xino = au_xino_create2(file, file); -+ au_xino_unlock_dir(&ldir); -+ err = PTR_ERR(new_xino); -+ if (IS_ERR(new_xino)) -+ goto out; -+ err = 0; -+ fput(file); -+ br->br_xino.xi_file = new_xino; -+ -+ h_sb = br->br_mnt->mnt_sb; -+ for (bi = 0; bi <= bend; bi++) { -+ if (unlikely(bi == bindex)) -+ continue; -+ br = au_sbr(sb, bi); -+ if (br->br_mnt->mnt_sb != h_sb) -+ continue; -+ -+ fput(br->br_xino.xi_file); -+ br->br_xino.xi_file = new_xino; -+ get_file(new_xino); -+ } -+ -+ out: -+ return err; -+} -+ -+struct xino_do_trunc_args { -+ struct super_block *sb; -+ struct au_branch *br; -+}; -+ -+static void xino_do_trunc(void *_args) -+{ -+ struct xino_do_trunc_args *args = _args; -+ struct super_block *sb; -+ struct au_branch *br; -+ struct inode *dir; -+ int err; -+ aufs_bindex_t bindex; -+ -+ err = 0; -+ sb = args->sb; -+ dir = sb->s_root->d_inode; -+ br = args->br; -+ -+ si_noflush_write_lock(sb); -+ ii_read_lock_parent(dir); -+ bindex = au_br_index(sb, br->br_id); -+ err = au_xino_trunc(sb, bindex); -+ if (!err -+ && br->br_xino.xi_file->f_dentry->d_inode->i_blocks -+ >= br->br_xino_upper) -+ br->br_xino_upper += AUFS_XINO_TRUNC_STEP; -+ -+ ii_read_unlock(dir); -+ if (unlikely(err)) -+ pr_warning("err b%d, (%d)\n", bindex, err); -+ atomic_dec(&br->br_xino_running); -+ atomic_dec(&br->br_count); -+ au_nwt_done(&au_sbi(sb)->si_nowait); -+ si_write_unlock(sb); -+ kfree(args); -+} -+ -+static void xino_try_trunc(struct super_block *sb, struct au_branch *br) -+{ -+ struct xino_do_trunc_args *args; -+ int wkq_err; -+ -+ if (br->br_xino.xi_file->f_dentry->d_inode->i_blocks -+ < br->br_xino_upper) -+ return; -+ -+ if (atomic_inc_return(&br->br_xino_running) > 1) -+ goto out; -+ -+ /* lock and kfree() will be called in trunc_xino() */ -+ args = kmalloc(sizeof(*args), GFP_NOFS); -+ if (unlikely(!args)) { -+ AuErr1("no memory\n"); -+ goto out_args; -+ } -+ -+ atomic_inc_return(&br->br_count); -+ args->sb = sb; -+ args->br = br; -+ wkq_err = au_wkq_nowait(xino_do_trunc, args, sb); -+ if (!wkq_err) -+ return; /* success */ -+ -+ pr_err("wkq %d\n", wkq_err); -+ atomic_dec_return(&br->br_count); -+ -+ out_args: -+ kfree(args); -+ out: -+ atomic_dec_return(&br->br_xino_running); -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+static int au_xino_do_write(au_writef_t write, struct file *file, -+ ino_t h_ino, ino_t ino) -+{ -+ loff_t pos; -+ ssize_t sz; -+ -+ pos = h_ino; -+ if (unlikely(au_loff_max / sizeof(ino) - 1 < pos)) { -+ AuIOErr1("too large hi%lu\n", (unsigned long)h_ino); -+ return -EFBIG; -+ } -+ pos *= sizeof(ino); -+ sz = xino_fwrite(write, file, &ino, sizeof(ino), &pos); -+ if (sz == sizeof(ino)) -+ return 0; /* success */ -+ -+ AuIOErr("write failed (%zd)\n", sz); -+ return -EIO; -+} -+ -+/* -+ * write @ino to the xinofile for the specified branch{@sb, @bindex} -+ * at the position of @h_ino. -+ * even if @ino is zero, it is written to the xinofile and means no entry. -+ * if the size of the xino file on a specific filesystem exceeds the watermark, -+ * try truncating it. -+ */ -+int au_xino_write(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, -+ ino_t ino) -+{ -+ int err; -+ unsigned int mnt_flags; -+ struct au_branch *br; -+ -+ BUILD_BUG_ON(sizeof(long long) != sizeof(au_loff_max) -+ || ((loff_t)-1) > 0); -+ SiMustAnyLock(sb); -+ -+ mnt_flags = au_mntflags(sb); -+ if (!au_opt_test(mnt_flags, XINO)) -+ return 0; -+ -+ br = au_sbr(sb, bindex); -+ err = au_xino_do_write(au_sbi(sb)->si_xwrite, br->br_xino.xi_file, -+ h_ino, ino); -+ if (!err) { -+ if (au_opt_test(mnt_flags, TRUNC_XINO) -+ && au_test_fs_trunc_xino(br->br_mnt->mnt_sb)) -+ xino_try_trunc(sb, br); -+ return 0; /* success */ -+ } -+ -+ AuIOErr("write failed (%d)\n", err); -+ return -EIO; -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+/* aufs inode number bitmap */ -+ -+static const int page_bits = (int)PAGE_SIZE * BITS_PER_BYTE; -+static ino_t xib_calc_ino(unsigned long pindex, int bit) -+{ -+ ino_t ino; -+ -+ AuDebugOn(bit < 0 || page_bits <= bit); -+ ino = AUFS_FIRST_INO + pindex * page_bits + bit; -+ return ino; -+} -+ -+static void xib_calc_bit(ino_t ino, unsigned long *pindex, int *bit) -+{ -+ AuDebugOn(ino < AUFS_FIRST_INO); -+ ino -= AUFS_FIRST_INO; -+ *pindex = ino / page_bits; -+ *bit = ino % page_bits; -+} -+ -+static int xib_pindex(struct super_block *sb, unsigned long pindex) -+{ -+ int err; -+ loff_t pos; -+ ssize_t sz; -+ struct au_sbinfo *sbinfo; -+ struct file *xib; -+ unsigned long *p; -+ -+ sbinfo = au_sbi(sb); -+ MtxMustLock(&sbinfo->si_xib_mtx); -+ AuDebugOn(pindex > ULONG_MAX / PAGE_SIZE -+ || !au_opt_test(sbinfo->si_mntflags, XINO)); -+ -+ if (pindex == sbinfo->si_xib_last_pindex) -+ return 0; -+ -+ xib = sbinfo->si_xib; -+ p = sbinfo->si_xib_buf; -+ pos = sbinfo->si_xib_last_pindex; -+ pos *= PAGE_SIZE; -+ sz = xino_fwrite(sbinfo->si_xwrite, xib, p, PAGE_SIZE, &pos); -+ if (unlikely(sz != PAGE_SIZE)) -+ goto out; -+ -+ pos = pindex; -+ pos *= PAGE_SIZE; -+ if (i_size_read(xib->f_dentry->d_inode) >= pos + PAGE_SIZE) -+ sz = xino_fread(sbinfo->si_xread, xib, p, PAGE_SIZE, &pos); -+ else { -+ memset(p, 0, PAGE_SIZE); -+ sz = xino_fwrite(sbinfo->si_xwrite, xib, p, PAGE_SIZE, &pos); -+ } -+ if (sz == PAGE_SIZE) { -+ sbinfo->si_xib_last_pindex = pindex; -+ return 0; /* success */ -+ } -+ -+ out: -+ AuIOErr1("write failed (%zd)\n", sz); -+ err = sz; -+ if (sz >= 0) -+ err = -EIO; -+ return err; -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+int au_xino_write0(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, -+ ino_t ino) -+{ -+ int err, bit; -+ unsigned long pindex; -+ struct au_sbinfo *sbinfo; -+ -+ if (!au_opt_test(au_mntflags(sb), XINO)) -+ return 0; -+ -+ err = 0; -+ if (ino) { -+ sbinfo = au_sbi(sb); -+ xib_calc_bit(ino, &pindex, &bit); -+ AuDebugOn(page_bits <= bit); -+ mutex_lock(&sbinfo->si_xib_mtx); -+ err = xib_pindex(sb, pindex); -+ if (!err) { -+ clear_bit(bit, sbinfo->si_xib_buf); -+ sbinfo->si_xib_next_bit = bit; -+ } -+ mutex_unlock(&sbinfo->si_xib_mtx); -+ } -+ -+ if (!err) -+ err = au_xino_write(sb, bindex, h_ino, 0); -+ return err; -+} -+ -+/* get an unused inode number from bitmap */ -+ino_t au_xino_new_ino(struct super_block *sb) -+{ -+ ino_t ino; -+ unsigned long *p, pindex, ul, pend; -+ struct au_sbinfo *sbinfo; -+ struct file *file; -+ int free_bit, err; -+ -+ if (!au_opt_test(au_mntflags(sb), XINO)) -+ return iunique(sb, AUFS_FIRST_INO); -+ -+ sbinfo = au_sbi(sb); -+ mutex_lock(&sbinfo->si_xib_mtx); -+ p = sbinfo->si_xib_buf; -+ free_bit = sbinfo->si_xib_next_bit; -+ if (free_bit < page_bits && !test_bit(free_bit, p)) -+ goto out; /* success */ -+ free_bit = find_first_zero_bit(p, page_bits); -+ if (free_bit < page_bits) -+ goto out; /* success */ -+ -+ pindex = sbinfo->si_xib_last_pindex; -+ for (ul = pindex - 1; ul < ULONG_MAX; ul--) { -+ err = xib_pindex(sb, ul); -+ if (unlikely(err)) -+ goto out_err; -+ free_bit = find_first_zero_bit(p, page_bits); -+ if (free_bit < page_bits) -+ goto out; /* success */ -+ } -+ -+ file = sbinfo->si_xib; -+ pend = i_size_read(file->f_dentry->d_inode) / PAGE_SIZE; -+ for (ul = pindex + 1; ul <= pend; ul++) { -+ err = xib_pindex(sb, ul); -+ if (unlikely(err)) -+ goto out_err; -+ free_bit = find_first_zero_bit(p, page_bits); -+ if (free_bit < page_bits) -+ goto out; /* success */ -+ } -+ BUG(); -+ -+ out: -+ set_bit(free_bit, p); -+ sbinfo->si_xib_next_bit++; -+ pindex = sbinfo->si_xib_last_pindex; -+ mutex_unlock(&sbinfo->si_xib_mtx); -+ ino = xib_calc_ino(pindex, free_bit); -+ AuDbg("i%lu\n", (unsigned long)ino); -+ return ino; -+ out_err: -+ mutex_unlock(&sbinfo->si_xib_mtx); -+ AuDbg("i0\n"); -+ return 0; -+} -+ -+/* -+ * read @ino from xinofile for the specified branch{@sb, @bindex} -+ * at the position of @h_ino. -+ * if @ino does not exist and @do_new is true, get new one. -+ */ -+int au_xino_read(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, -+ ino_t *ino) -+{ -+ int err; -+ ssize_t sz; -+ loff_t pos; -+ struct file *file; -+ struct au_sbinfo *sbinfo; -+ -+ *ino = 0; -+ if (!au_opt_test(au_mntflags(sb), XINO)) -+ return 0; /* no xino */ -+ -+ err = 0; -+ sbinfo = au_sbi(sb); -+ pos = h_ino; -+ if (unlikely(au_loff_max / sizeof(*ino) - 1 < pos)) { -+ AuIOErr1("too large hi%lu\n", (unsigned long)h_ino); -+ return -EFBIG; -+ } -+ pos *= sizeof(*ino); -+ -+ file = au_sbr(sb, bindex)->br_xino.xi_file; -+ if (i_size_read(file->f_dentry->d_inode) < pos + sizeof(*ino)) -+ return 0; /* no ino */ -+ -+ sz = xino_fread(sbinfo->si_xread, file, ino, sizeof(*ino), &pos); -+ if (sz == sizeof(*ino)) -+ return 0; /* success */ -+ -+ err = sz; -+ if (unlikely(sz >= 0)) { -+ err = -EIO; -+ AuIOErr("xino read error (%zd)\n", sz); -+ } -+ -+ return err; -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+/* create and set a new xino file */ -+ -+struct file *au_xino_create(struct super_block *sb, char *fname, int silent) -+{ -+ struct file *file; -+ struct dentry *h_parent, *d; -+ struct inode *h_dir; -+ int err; -+ -+ /* -+ * at mount-time, and the xino file is the default path, -+ * hinotify is disabled so we have no inotify events to ignore. -+ * when a user specified the xino, we cannot get au_hdir to be ignored. -+ */ -+ file = vfsub_filp_open(fname, O_RDWR | O_CREAT | O_EXCL | O_LARGEFILE, -+ S_IRUGO | S_IWUGO); -+ if (IS_ERR(file)) { -+ if (!silent) -+ pr_err("open %s(%ld)\n", fname, PTR_ERR(file)); -+ return file; -+ } -+ -+ /* keep file count */ -+ h_parent = dget_parent(file->f_dentry); -+ h_dir = h_parent->d_inode; -+ mutex_lock_nested(&h_dir->i_mutex, AuLsc_I_PARENT); -+ /* mnt_want_write() is unnecessary here */ -+ err = vfsub_unlink(h_dir, &file->f_path, /*force*/0); -+ mutex_unlock(&h_dir->i_mutex); -+ dput(h_parent); -+ if (unlikely(err)) { -+ if (!silent) -+ pr_err("unlink %s(%d)\n", fname, err); -+ goto out; -+ } -+ -+ err = -EINVAL; -+ d = file->f_dentry; -+ if (unlikely(sb == d->d_sb)) { -+ if (!silent) -+ pr_err("%s must be outside\n", fname); -+ goto out; -+ } -+ if (unlikely(au_test_fs_bad_xino(d->d_sb))) { -+ if (!silent) -+ pr_err("xino doesn't support %s(%s)\n", -+ fname, au_sbtype(d->d_sb)); -+ goto out; -+ } -+ return file; /* success */ -+ -+ out: -+ fput(file); -+ file = ERR_PTR(err); -+ return file; -+} -+ -+/* -+ * find another branch who is on the same filesystem of the specified -+ * branch{@btgt}. search until @bend. -+ */ -+static int is_sb_shared(struct super_block *sb, aufs_bindex_t btgt, -+ aufs_bindex_t bend) -+{ -+ aufs_bindex_t bindex; -+ struct super_block *tgt_sb = au_sbr_sb(sb, btgt); -+ -+ for (bindex = 0; bindex < btgt; bindex++) -+ if (unlikely(tgt_sb == au_sbr_sb(sb, bindex))) -+ return bindex; -+ for (bindex++; bindex <= bend; bindex++) -+ if (unlikely(tgt_sb == au_sbr_sb(sb, bindex))) -+ return bindex; -+ return -1; -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+/* -+ * initialize the xinofile for the specified branch @br -+ * at the place/path where @base_file indicates. -+ * test whether another branch is on the same filesystem or not, -+ * if @do_test is true. -+ */ -+int au_xino_br(struct super_block *sb, struct au_branch *br, ino_t h_ino, -+ struct file *base_file, int do_test) -+{ -+ int err; -+ ino_t ino; -+ aufs_bindex_t bend, bindex; -+ struct au_branch *shared_br, *b; -+ struct file *file; -+ struct super_block *tgt_sb; -+ -+ shared_br = NULL; -+ bend = au_sbend(sb); -+ if (do_test) { -+ tgt_sb = br->br_mnt->mnt_sb; -+ for (bindex = 0; bindex <= bend; bindex++) { -+ b = au_sbr(sb, bindex); -+ if (tgt_sb == b->br_mnt->mnt_sb) { -+ shared_br = b; -+ break; -+ } -+ } -+ } -+ -+ if (!shared_br || !shared_br->br_xino.xi_file) { -+ struct au_xino_lock_dir ldir; -+ -+ au_xino_lock_dir(sb, base_file, &ldir); -+ /* mnt_want_write() is unnecessary here */ -+ file = au_xino_create2(base_file, NULL); -+ au_xino_unlock_dir(&ldir); -+ err = PTR_ERR(file); -+ if (IS_ERR(file)) -+ goto out; -+ br->br_xino.xi_file = file; -+ } else { -+ br->br_xino.xi_file = shared_br->br_xino.xi_file; -+ get_file(br->br_xino.xi_file); -+ } -+ -+ ino = AUFS_ROOT_INO; -+ err = au_xino_do_write(au_sbi(sb)->si_xwrite, br->br_xino.xi_file, -+ h_ino, ino); -+ if (!err) -+ return 0; /* success */ -+ -+ -+ out: -+ return err; -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+/* trucate a xino bitmap file */ -+ -+/* todo: slow */ -+static int do_xib_restore(struct super_block *sb, struct file *file, void *page) -+{ -+ int err, bit; -+ ssize_t sz; -+ unsigned long pindex; -+ loff_t pos, pend; -+ struct au_sbinfo *sbinfo; -+ au_readf_t func; -+ ino_t *ino; -+ unsigned long *p; -+ -+ err = 0; -+ sbinfo = au_sbi(sb); -+ MtxMustLock(&sbinfo->si_xib_mtx); -+ p = sbinfo->si_xib_buf; -+ func = sbinfo->si_xread; -+ pend = i_size_read(file->f_dentry->d_inode); -+ pos = 0; -+ while (pos < pend) { -+ sz = xino_fread(func, file, page, PAGE_SIZE, &pos); -+ err = sz; -+ if (unlikely(sz <= 0)) -+ goto out; -+ -+ err = 0; -+ for (ino = page; sz > 0; ino++, sz -= sizeof(ino)) { -+ if (unlikely(*ino < AUFS_FIRST_INO)) -+ continue; -+ -+ xib_calc_bit(*ino, &pindex, &bit); -+ AuDebugOn(page_bits <= bit); -+ err = xib_pindex(sb, pindex); -+ if (!err) -+ set_bit(bit, p); -+ else -+ goto out; -+ } -+ } -+ -+ out: -+ return err; -+} -+ -+static int xib_restore(struct super_block *sb) -+{ -+ int err; -+ aufs_bindex_t bindex, bend; -+ void *page; -+ -+ err = -ENOMEM; -+ page = (void *)__get_free_page(GFP_NOFS); -+ if (unlikely(!page)) -+ goto out; -+ -+ err = 0; -+ bend = au_sbend(sb); -+ for (bindex = 0; !err && bindex <= bend; bindex++) -+ if (!bindex || is_sb_shared(sb, bindex, bindex - 1) < 0) -+ err = do_xib_restore -+ (sb, au_sbr(sb, bindex)->br_xino.xi_file, page); -+ else -+ AuDbg("b%d\n", bindex); -+ free_page((unsigned long)page); -+ -+ out: -+ return err; -+} -+ -+int au_xib_trunc(struct super_block *sb) -+{ -+ int err; -+ ssize_t sz; -+ loff_t pos; -+ struct au_xino_lock_dir ldir; -+ struct au_sbinfo *sbinfo; -+ unsigned long *p; -+ struct file *file; -+ -+ SiMustWriteLock(sb); -+ -+ err = 0; -+ sbinfo = au_sbi(sb); -+ if (!au_opt_test(sbinfo->si_mntflags, XINO)) -+ goto out; -+ -+ file = sbinfo->si_xib; -+ if (i_size_read(file->f_dentry->d_inode) <= PAGE_SIZE) -+ goto out; -+ -+ au_xino_lock_dir(sb, file, &ldir); -+ /* mnt_want_write() is unnecessary here */ -+ file = au_xino_create2(sbinfo->si_xib, NULL); -+ au_xino_unlock_dir(&ldir); -+ err = PTR_ERR(file); -+ if (IS_ERR(file)) -+ goto out; -+ fput(sbinfo->si_xib); -+ sbinfo->si_xib = file; -+ -+ p = sbinfo->si_xib_buf; -+ memset(p, 0, PAGE_SIZE); -+ pos = 0; -+ sz = xino_fwrite(sbinfo->si_xwrite, sbinfo->si_xib, p, PAGE_SIZE, &pos); -+ if (unlikely(sz != PAGE_SIZE)) { -+ err = sz; -+ AuIOErr("err %d\n", err); -+ if (sz >= 0) -+ err = -EIO; -+ goto out; -+ } -+ -+ mutex_lock(&sbinfo->si_xib_mtx); -+ /* mnt_want_write() is unnecessary here */ -+ err = xib_restore(sb); -+ mutex_unlock(&sbinfo->si_xib_mtx); -+ -+out: -+ return err; -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+/* -+ * xino mount option handlers -+ */ -+static au_readf_t find_readf(struct file *h_file) -+{ -+ const struct file_operations *fop = h_file->f_op; -+ -+ if (fop) { -+ if (fop->read) -+ return fop->read; -+ if (fop->aio_read) -+ return do_sync_read; -+ } -+ return ERR_PTR(-ENOSYS); -+} -+ -+static au_writef_t find_writef(struct file *h_file) -+{ -+ const struct file_operations *fop = h_file->f_op; -+ -+ if (fop) { -+ if (fop->write) -+ return fop->write; -+ if (fop->aio_write) -+ return do_sync_write; -+ } -+ return ERR_PTR(-ENOSYS); -+} -+ -+/* xino bitmap */ -+static void xino_clear_xib(struct super_block *sb) -+{ -+ struct au_sbinfo *sbinfo; -+ -+ SiMustWriteLock(sb); -+ -+ sbinfo = au_sbi(sb); -+ sbinfo->si_xread = NULL; -+ sbinfo->si_xwrite = NULL; -+ if (sbinfo->si_xib) -+ fput(sbinfo->si_xib); -+ sbinfo->si_xib = NULL; -+ free_page((unsigned long)sbinfo->si_xib_buf); -+ sbinfo->si_xib_buf = NULL; -+} -+ -+static int au_xino_set_xib(struct super_block *sb, struct file *base) -+{ -+ int err; -+ loff_t pos; -+ struct au_sbinfo *sbinfo; -+ struct file *file; -+ -+ SiMustWriteLock(sb); -+ -+ sbinfo = au_sbi(sb); -+ file = au_xino_create2(base, sbinfo->si_xib); -+ err = PTR_ERR(file); -+ if (IS_ERR(file)) -+ goto out; -+ if (sbinfo->si_xib) -+ fput(sbinfo->si_xib); -+ sbinfo->si_xib = file; -+ sbinfo->si_xread = find_readf(file); -+ sbinfo->si_xwrite = find_writef(file); -+ -+ err = -ENOMEM; -+ if (!sbinfo->si_xib_buf) -+ sbinfo->si_xib_buf = (void *)get_zeroed_page(GFP_NOFS); -+ if (unlikely(!sbinfo->si_xib_buf)) -+ goto out_unset; -+ -+ sbinfo->si_xib_last_pindex = 0; -+ sbinfo->si_xib_next_bit = 0; -+ if (i_size_read(file->f_dentry->d_inode) < PAGE_SIZE) { -+ pos = 0; -+ err = xino_fwrite(sbinfo->si_xwrite, file, sbinfo->si_xib_buf, -+ PAGE_SIZE, &pos); -+ if (unlikely(err != PAGE_SIZE)) -+ goto out_free; -+ } -+ err = 0; -+ goto out; /* success */ -+ -+ out_free: -+ free_page((unsigned long)sbinfo->si_xib_buf); -+ sbinfo->si_xib_buf = NULL; -+ if (err >= 0) -+ err = -EIO; -+ out_unset: -+ fput(sbinfo->si_xib); -+ sbinfo->si_xib = NULL; -+ sbinfo->si_xread = NULL; -+ sbinfo->si_xwrite = NULL; -+ out: -+ return err; -+} -+ -+/* xino for each branch */ -+static void xino_clear_br(struct super_block *sb) -+{ -+ aufs_bindex_t bindex, bend; -+ struct au_branch *br; -+ -+ bend = au_sbend(sb); -+ for (bindex = 0; bindex <= bend; bindex++) { -+ br = au_sbr(sb, bindex); -+ if (!br || !br->br_xino.xi_file) -+ continue; -+ -+ fput(br->br_xino.xi_file); -+ br->br_xino.xi_file = NULL; -+ } -+} -+ -+static int au_xino_set_br(struct super_block *sb, struct file *base) -+{ -+ int err; -+ ino_t ino; -+ aufs_bindex_t bindex, bend, bshared; -+ struct { -+ struct file *old, *new; -+ } *fpair, *p; -+ struct au_branch *br; -+ struct inode *inode; -+ au_writef_t writef; -+ -+ SiMustWriteLock(sb); -+ -+ err = -ENOMEM; -+ bend = au_sbend(sb); -+ fpair = kcalloc(bend + 1, sizeof(*fpair), GFP_NOFS); -+ if (unlikely(!fpair)) -+ goto out; -+ -+ inode = sb->s_root->d_inode; -+ ino = AUFS_ROOT_INO; -+ writef = au_sbi(sb)->si_xwrite; -+ for (bindex = 0, p = fpair; bindex <= bend; bindex++, p++) { -+ br = au_sbr(sb, bindex); -+ bshared = is_sb_shared(sb, bindex, bindex - 1); -+ if (bshared >= 0) { -+ /* shared xino */ -+ *p = fpair[bshared]; -+ get_file(p->new); -+ } -+ -+ if (!p->new) { -+ /* new xino */ -+ p->old = br->br_xino.xi_file; -+ p->new = au_xino_create2(base, br->br_xino.xi_file); -+ err = PTR_ERR(p->new); -+ if (IS_ERR(p->new)) { -+ p->new = NULL; -+ goto out_pair; -+ } -+ } -+ -+ err = au_xino_do_write(writef, p->new, -+ au_h_iptr(inode, bindex)->i_ino, ino); -+ if (unlikely(err)) -+ goto out_pair; -+ } -+ -+ for (bindex = 0, p = fpair; bindex <= bend; bindex++, p++) { -+ br = au_sbr(sb, bindex); -+ if (br->br_xino.xi_file) -+ fput(br->br_xino.xi_file); -+ get_file(p->new); -+ br->br_xino.xi_file = p->new; -+ } -+ -+ out_pair: -+ for (bindex = 0, p = fpair; bindex <= bend; bindex++, p++) -+ if (p->new) -+ fput(p->new); -+ else -+ break; -+ kfree(fpair); -+ out: -+ return err; -+} -+ -+void au_xino_clr(struct super_block *sb) -+{ -+ struct au_sbinfo *sbinfo; -+ -+ au_xigen_clr(sb); -+ xino_clear_xib(sb); -+ xino_clear_br(sb); -+ sbinfo = au_sbi(sb); -+ /* lvalue, do not call au_mntflags() */ -+ au_opt_clr(sbinfo->si_mntflags, XINO); -+} -+ -+int au_xino_set(struct super_block *sb, struct au_opt_xino *xino, int remount) -+{ -+ int err, skip; -+ struct dentry *parent, *cur_parent; -+ struct qstr *dname, *cur_name; -+ struct file *cur_xino; -+ struct inode *dir; -+ struct au_sbinfo *sbinfo; -+ -+ SiMustWriteLock(sb); -+ -+ err = 0; -+ sbinfo = au_sbi(sb); -+ parent = dget_parent(xino->file->f_dentry); -+ if (remount) { -+ skip = 0; -+ dname = &xino->file->f_dentry->d_name; -+ cur_xino = sbinfo->si_xib; -+ if (cur_xino) { -+ cur_parent = dget_parent(cur_xino->f_dentry); -+ cur_name = &cur_xino->f_dentry->d_name; -+ skip = (cur_parent == parent -+ && dname->len == cur_name->len -+ && !memcmp(dname->name, cur_name->name, -+ dname->len)); -+ dput(cur_parent); -+ } -+ if (skip) -+ goto out; -+ } -+ -+ au_opt_set(sbinfo->si_mntflags, XINO); -+ dir = parent->d_inode; -+ mutex_lock_nested(&dir->i_mutex, AuLsc_I_PARENT); -+ /* mnt_want_write() is unnecessary here */ -+ err = au_xino_set_xib(sb, xino->file); -+ if (!err) -+ err = au_xigen_set(sb, xino->file); -+ if (!err) -+ err = au_xino_set_br(sb, xino->file); -+ mutex_unlock(&dir->i_mutex); -+ if (!err) -+ goto out; /* success */ -+ -+ /* reset all */ -+ AuIOErr("failed creating xino(%d).\n", err); -+ -+ out: -+ dput(parent); -+ return err; -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+/* -+ * create a xinofile at the default place/path. -+ */ -+struct file *au_xino_def(struct super_block *sb) -+{ -+ struct file *file; -+ char *page, *p; -+ struct au_branch *br; -+ struct super_block *h_sb; -+ struct path path; -+ aufs_bindex_t bend, bindex, bwr; -+ -+ br = NULL; -+ bend = au_sbend(sb); -+ bwr = -1; -+ for (bindex = 0; bindex <= bend; bindex++) { -+ br = au_sbr(sb, bindex); -+ if (au_br_writable(br->br_perm) -+ && !au_test_fs_bad_xino(br->br_mnt->mnt_sb)) { -+ bwr = bindex; -+ break; -+ } -+ } -+ -+ if (bwr >= 0) { -+ file = ERR_PTR(-ENOMEM); -+ page = __getname(); -+ if (unlikely(!page)) -+ goto out; -+ path.mnt = br->br_mnt; -+ path.dentry = au_h_dptr(sb->s_root, bwr); -+ p = d_path(&path, page, PATH_MAX - sizeof(AUFS_XINO_FNAME)); -+ file = (void *)p; -+ if (!IS_ERR(p)) { -+ strcat(p, "/" AUFS_XINO_FNAME); -+ AuDbg("%s\n", p); -+ file = au_xino_create(sb, p, /*silent*/0); -+ if (!IS_ERR(file)) -+ au_xino_brid_set(sb, br->br_id); -+ } -+ __putname(page); -+ } else { -+ file = au_xino_create(sb, AUFS_XINO_DEFPATH, /*silent*/0); -+ if (IS_ERR(file)) -+ goto out; -+ h_sb = file->f_dentry->d_sb; -+ if (unlikely(au_test_fs_bad_xino(h_sb))) { -+ pr_err("xino doesn't support %s(%s)\n", -+ AUFS_XINO_DEFPATH, au_sbtype(h_sb)); -+ fput(file); -+ file = ERR_PTR(-EINVAL); -+ } -+ if (!IS_ERR(file)) -+ au_xino_brid_set(sb, -1); -+ } -+ -+ out: -+ return file; -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+int au_xino_path(struct seq_file *seq, struct file *file) -+{ -+ int err; -+ -+ err = au_seq_path(seq, &file->f_path); -+ if (unlikely(err < 0)) -+ goto out; -+ -+ err = 0; -+#define Deleted "\\040(deleted)" -+ seq->count -= sizeof(Deleted) - 1; -+ AuDebugOn(memcmp(seq->buf + seq->count, Deleted, -+ sizeof(Deleted) - 1)); -+#undef Deleted -+ -+ out: -+ return err; -+} -diff --git a/include/linux/aufs_type.h b/include/linux/aufs_type.h -new file mode 100644 -index 0000000..b4fee85 ---- /dev/null -+++ b/include/linux/aufs_type.h -@@ -0,0 +1,191 @@ -+/* -+ * Copyright (C) 2005-2009 Junjiro R. Okajima -+ * -+ * This program, aufs is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ */ -+ -+#ifndef __AUFS_TYPE_H__ -+#define __AUFS_TYPE_H__ -+ -+#include -+#include -+#include -+ -+#define AUFS_VERSION "2-standalone.tree-20091130" -+ -+/* todo? move this to linux-2.6.19/include/magic.h */ -+#define AUFS_SUPER_MAGIC ('a' << 24 | 'u' << 16 | 'f' << 8 | 's') -+ -+/* ---------------------------------------------------------------------- */ -+ -+#ifdef CONFIG_AUFS_BRANCH_MAX_127 -+typedef __s8 aufs_bindex_t; -+#define AUFS_BRANCH_MAX 127 -+#else -+typedef __s16 aufs_bindex_t; -+#ifdef CONFIG_AUFS_BRANCH_MAX_511 -+#define AUFS_BRANCH_MAX 511 -+#elif defined(CONFIG_AUFS_BRANCH_MAX_1023) -+#define AUFS_BRANCH_MAX 1023 -+#elif defined(CONFIG_AUFS_BRANCH_MAX_32767) -+#define AUFS_BRANCH_MAX 32767 -+#endif -+#endif -+ -+#ifdef __KERNEL__ -+#ifndef AUFS_BRANCH_MAX -+#error unknown CONFIG_AUFS_BRANCH_MAX value -+#endif -+#endif /* __KERNEL__ */ -+ -+/* ---------------------------------------------------------------------- */ -+ -+#define AUFS_NAME "aufs" -+#define AUFS_FSTYPE AUFS_NAME -+ -+#define AUFS_ROOT_INO 2 -+#define AUFS_FIRST_INO 11 -+ -+#define AUFS_WH_PFX ".wh." -+#define AUFS_WH_PFX_LEN ((int)sizeof(AUFS_WH_PFX) - 1) -+#define AUFS_WH_TMP_LEN 4 -+/* a limit for rmdir/rename a dir */ -+#define AUFS_MAX_NAMELEN (NAME_MAX \ -+ - AUFS_WH_PFX_LEN * 2 /* doubly whiteouted */\ -+ - 1 /* dot */\ -+ - AUFS_WH_TMP_LEN) /* hex */ -+#define AUFS_XINO_FNAME "." AUFS_NAME ".xino" -+#define AUFS_XINO_DEFPATH "/tmp/" AUFS_XINO_FNAME -+#define AUFS_XINO_TRUNC_INIT 64 /* blocks */ -+#define AUFS_XINO_TRUNC_STEP 4 /* blocks */ -+#define AUFS_DIRWH_DEF 3 -+#define AUFS_RDCACHE_DEF 10 /* seconds */ -+#define AUFS_RDBLK_DEF 512 /* bytes */ -+#define AUFS_RDHASH_DEF 32 -+#define AUFS_WKQ_NAME AUFS_NAME "d" -+#define AUFS_NWKQ_DEF 4 -+#define AUFS_MFS_SECOND_DEF 30 /* seconds */ -+#define AUFS_PLINK_WARN 100 /* number of plinks */ -+ -+#define AUFS_DIROPQ_NAME AUFS_WH_PFX ".opq" /* whiteouted doubly */ -+#define AUFS_WH_DIROPQ AUFS_WH_PFX AUFS_DIROPQ_NAME -+ -+#define AUFS_BASE_NAME AUFS_WH_PFX AUFS_NAME -+#define AUFS_PLINKDIR_NAME AUFS_WH_PFX "plnk" -+#define AUFS_ORPHDIR_NAME AUFS_WH_PFX "orph" -+ -+/* doubly whiteouted */ -+#define AUFS_WH_BASE AUFS_WH_PFX AUFS_BASE_NAME -+#define AUFS_WH_PLINKDIR AUFS_WH_PFX AUFS_PLINKDIR_NAME -+#define AUFS_WH_ORPHDIR AUFS_WH_PFX AUFS_ORPHDIR_NAME -+ -+/* branch permission */ -+#define AUFS_BRPERM_RW "rw" -+#define AUFS_BRPERM_RO "ro" -+#define AUFS_BRPERM_RR "rr" -+#define AUFS_BRPERM_WH "wh" -+#define AUFS_BRPERM_NLWH "nolwh" -+#define AUFS_BRPERM_ROWH AUFS_BRPERM_RO "+" AUFS_BRPERM_WH -+#define AUFS_BRPERM_RRWH AUFS_BRPERM_RR "+" AUFS_BRPERM_WH -+#define AUFS_BRPERM_RWNLWH AUFS_BRPERM_RW "+" AUFS_BRPERM_NLWH -+ -+/* ---------------------------------------------------------------------- */ -+ -+/* ioctl */ -+enum { -+ AuCtl_PLINK_MAINT, -+ AuCtl_PLINK_CLEAN, -+ -+ /* readdir in userspace */ -+ AuCtl_RDU, -+ AuCtl_RDU_INO -+}; -+ -+/* borrowed from linux/include/linux/kernel.h */ -+#ifndef ALIGN -+#define ALIGN(x, a) __ALIGN_MASK(x, (typeof(x))(a)-1) -+#define __ALIGN_MASK(x, mask) (((x)+(mask))&~(mask)) -+#endif -+ -+/* borrowed from linux/include/linux/compiler-gcc3.h */ -+#ifndef __aligned -+#define __aligned(x) __attribute__((aligned(x))) -+#define __packed __attribute__((packed)) -+#endif -+ -+struct au_rdu_cookie { -+ __u64 h_pos; -+ __s16 bindex; -+ __u8 flags; -+ __u8 pad; -+ __u32 generation; -+} __aligned(8); -+ -+struct au_rdu_ent { -+ __u64 ino; -+ __s16 bindex; -+ __u8 type; -+ __u8 nlen; -+ __u8 wh; -+ char name[0]; -+} __aligned(8); -+ -+static inline int au_rdu_len(int nlen) -+{ -+ /* include the terminating NULL */ -+ return ALIGN(sizeof(struct au_rdu_ent) + nlen + 1, -+ sizeof(__u64)); -+} -+ -+union au_rdu_ent_ul { -+ struct au_rdu_ent __user *e; -+ unsigned long ul; -+}; -+ -+enum { -+ AufsCtlRduV_SZ, -+ AufsCtlRduV_SZ_PTR, -+ AufsCtlRduV_End -+}; -+ -+struct aufs_rdu { -+ /* input */ -+ union { -+ __u64 sz; /* AuCtl_RDU */ -+ __u64 nent; /* AuCtl_RDU_INO */ -+ }; -+ union au_rdu_ent_ul ent; -+ __u16 verify[AufsCtlRduV_End]; -+ -+ /* input/output */ -+ __u32 blk; -+ -+ /* output */ -+ union au_rdu_ent_ul tail; -+ /* number of entries which were added in a single call */ -+ __u64 rent; -+ __u8 full; -+ __u8 shwh; -+ -+ struct au_rdu_cookie cookie; -+} __aligned(8); -+ -+#define AuCtlType 'A' -+#define AUFS_CTL_PLINK_MAINT _IO(AuCtlType, AuCtl_PLINK_MAINT) -+#define AUFS_CTL_PLINK_CLEAN _IO(AuCtlType, AuCtl_PLINK_CLEAN) -+#define AUFS_CTL_RDU _IOWR(AuCtlType, AuCtl_RDU, struct aufs_rdu) -+#define AUFS_CTL_RDU_INO _IOWR(AuCtlType, AuCtl_RDU_INO, struct aufs_rdu) -+ -+#endif /* __AUFS_TYPE_H__ */ diff --git a/debian/patches/features/all/aufs2/aufs2-base.patch b/debian/patches/features/all/aufs2/aufs2-base.patch deleted file mode 100644 index d07fb86ba..000000000 --- a/debian/patches/features/all/aufs2/aufs2-base.patch +++ /dev/null @@ -1,81 +0,0 @@ -aufs2 base patch for linux-2.6.32 - -diff --git a/fs/namei.c b/fs/namei.c -index d11f404..7d28f56 100644 ---- a/fs/namei.c -+++ b/fs/namei.c -@@ -1219,7 +1219,7 @@ out: - * needs parent already locked. Doesn't follow mounts. - * SMP-safe. - */ --static struct dentry *lookup_hash(struct nameidata *nd) -+struct dentry *lookup_hash(struct nameidata *nd) - { - int err; - -@@ -1229,7 +1229,7 @@ static struct dentry *lookup_hash(struct nameidata *nd) - return __lookup_hash(&nd->last, nd->path.dentry, nd); - } - --static int __lookup_one_len(const char *name, struct qstr *this, -+int __lookup_one_len(const char *name, struct qstr *this, - struct dentry *base, int len) - { - unsigned long hash; -diff --git a/fs/splice.c b/fs/splice.c -index 7394e9e..77184f0 100644 ---- a/fs/splice.c -+++ b/fs/splice.c -@@ -1051,8 +1051,8 @@ EXPORT_SYMBOL_GPL(generic_splice_sendpage); - /* - * Attempt to initiate a splice from pipe to file. - */ --static long do_splice_from(struct pipe_inode_info *pipe, struct file *out, -- loff_t *ppos, size_t len, unsigned int flags) -+long do_splice_from(struct pipe_inode_info *pipe, struct file *out, -+ loff_t *ppos, size_t len, unsigned int flags) - { - ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, - loff_t *, size_t, unsigned int); -@@ -1078,9 +1078,9 @@ static long do_splice_from(struct pipe_inode_info *pipe, struct file *out, - /* - * Attempt to initiate a splice from a file to a pipe. - */ --static long do_splice_to(struct file *in, loff_t *ppos, -- struct pipe_inode_info *pipe, size_t len, -- unsigned int flags) -+long do_splice_to(struct file *in, loff_t *ppos, -+ struct pipe_inode_info *pipe, size_t len, -+ unsigned int flags) - { - ssize_t (*splice_read)(struct file *, loff_t *, - struct pipe_inode_info *, size_t, unsigned int); -diff --git a/include/linux/namei.h b/include/linux/namei.h -index ec0f607..1438153 100644 ---- a/include/linux/namei.h -+++ b/include/linux/namei.h -@@ -75,6 +75,9 @@ extern struct file *lookup_instantiate_filp(struct nameidata *nd, struct dentry - extern struct file *nameidata_to_filp(struct nameidata *nd, int flags); - extern void release_open_intent(struct nameidata *); - -+extern struct dentry *lookup_hash(struct nameidata *nd); -+extern int __lookup_one_len(const char *name, struct qstr *this, -+ struct dentry *base, int len); - extern struct dentry *lookup_one_len(const char *, struct dentry *, int); - extern struct dentry *lookup_one_noperm(const char *, struct dentry *); - -diff --git a/include/linux/splice.h b/include/linux/splice.h -index 18e7c7c..8393b5c 100644 ---- a/include/linux/splice.h -+++ b/include/linux/splice.h -@@ -82,4 +82,10 @@ extern ssize_t splice_to_pipe(struct pipe_inode_info *, - extern ssize_t splice_direct_to_actor(struct file *, struct splice_desc *, - splice_direct_actor *); - -+extern long do_splice_from(struct pipe_inode_info *pipe, struct file *out, -+ loff_t *ppos, size_t len, unsigned int flags); -+extern long do_splice_to(struct file *in, loff_t *ppos, -+ struct pipe_inode_info *pipe, size_t len, -+ unsigned int flags); -+ - #endif diff --git a/debian/patches/features/all/aufs2/aufs2-kbuild.patch b/debian/patches/features/all/aufs2/aufs2-kbuild.patch deleted file mode 100644 index 10168c089..000000000 --- a/debian/patches/features/all/aufs2/aufs2-kbuild.patch +++ /dev/null @@ -1,35 +0,0 @@ -aufs2 kbuild patch for linux-2.6.32 - -diff --git a/fs/Kconfig b/fs/Kconfig -index 64d44ef..3e1f2f0 100644 ---- a/fs/Kconfig -+++ b/fs/Kconfig -@@ -188,6 +188,7 @@ source "fs/romfs/Kconfig" - source "fs/sysv/Kconfig" - source "fs/ufs/Kconfig" - source "fs/exofs/Kconfig" -+source "fs/aufs/Kconfig" - - endif # MISC_FILESYSTEMS - -diff --git a/fs/Makefile b/fs/Makefile -index af6d047..dba1ce1 100644 ---- a/fs/Makefile -+++ b/fs/Makefile -@@ -124,3 +124,4 @@ obj-$(CONFIG_OCFS2_FS) += ocfs2/ - obj-$(CONFIG_BTRFS_FS) += btrfs/ - obj-$(CONFIG_GFS2_FS) += gfs2/ - obj-$(CONFIG_EXOFS_FS) += exofs/ -+obj-$(CONFIG_AUFS_FS) += aufs/ -diff --git a/include/linux/Kbuild b/include/linux/Kbuild -index 1feed71..4ceebc7 100644 ---- a/include/linux/Kbuild -+++ b/include/linux/Kbuild -@@ -34,6 +34,7 @@ header-y += atmppp.h - header-y += atmsap.h - header-y += atmsvc.h - header-y += atm_zatm.h -+header-y += aufs_type.h - header-y += auto_fs4.h - header-y += ax25.h - header-y += b1lli.h diff --git a/debian/patches/features/all/aufs2/aufs2-standalone.patch b/debian/patches/features/all/aufs2/aufs2-standalone.patch deleted file mode 100644 index 587480736..000000000 --- a/debian/patches/features/all/aufs2/aufs2-standalone.patch +++ /dev/null @@ -1,182 +0,0 @@ -aufs2 standalone patch for linux-2.6. - -diff --git a/fs/namei.c b/fs/namei.c -index 7d28f56..0f6117c 100644 ---- a/fs/namei.c -+++ b/fs/namei.c -@@ -350,6 +350,7 @@ int deny_write_access(struct file * file) - - return 0; - } -+EXPORT_SYMBOL_GPL(deny_write_access); - - /** - * path_get - get a reference to a path -@@ -1228,6 +1229,7 @@ struct dentry *lookup_hash(struct nameidata *nd) - return ERR_PTR(err); - return __lookup_hash(&nd->last, nd->path.dentry, nd); - } -+EXPORT_SYMBOL_GPL(lookup_hash); - - int __lookup_one_len(const char *name, struct qstr *this, - struct dentry *base, int len) -@@ -1250,6 +1252,7 @@ int __lookup_one_len(const char *name, struct qstr *this, - this->hash = end_name_hash(hash); - return 0; - } -+EXPORT_SYMBOL_GPL(__lookup_one_len); - - /** - * lookup_one_len - filesystem helper to lookup single pathname component -diff --git a/fs/namespace.c b/fs/namespace.c -index bdc3cb4..a2cadcf 100644 ---- a/fs/namespace.c -+++ b/fs/namespace.c -@@ -39,6 +39,7 @@ - - /* spinlock for vfsmount related operations, inplace of dcache_lock */ - __cacheline_aligned_in_smp DEFINE_SPINLOCK(vfsmount_lock); -+EXPORT_SYMBOL_GPL(vfsmount_lock); - - static int event; - static DEFINE_IDA(mnt_id_ida); -diff --git a/fs/open.c b/fs/open.c -index 4f01e06..ef09031 100644 ---- a/fs/open.c -+++ b/fs/open.c -@@ -223,6 +223,7 @@ int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs, - mutex_unlock(&dentry->d_inode->i_mutex); - return ret; - } -+EXPORT_SYMBOL_GPL(do_truncate); - - static long do_sys_truncate(const char __user *pathname, loff_t length) - { -diff --git a/fs/splice.c b/fs/splice.c -index 77184f0..8479d95 100644 ---- a/fs/splice.c -+++ b/fs/splice.c -@@ -1074,6 +1074,7 @@ long do_splice_from(struct pipe_inode_info *pipe, struct file *out, - - return splice_write(pipe, out, ppos, len, flags); - } -+EXPORT_SYMBOL_GPL(do_splice_from); - - /* - * Attempt to initiate a splice from a file to a pipe. -@@ -1099,6 +1100,7 @@ long do_splice_to(struct file *in, loff_t *ppos, - - return splice_read(in, ppos, pipe, len, flags); - } -+EXPORT_SYMBOL_GPL(do_splice_to); - - /** - * splice_direct_to_actor - splices data directly between two non-pipes -diff --git a/security/device_cgroup.c b/security/device_cgroup.c -index 6cf8fd2..008e0d8 100644 ---- a/security/device_cgroup.c -+++ b/security/device_cgroup.c -@@ -514,6 +514,7 @@ found: - - return -EPERM; - } -+EXPORT_SYMBOL_GPL(devcgroup_inode_permission); - - int devcgroup_inode_mknod(int mode, dev_t dev) - { -diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c -index b85e61b..a23fad4 100644 ---- a/security/integrity/ima/ima_main.c -+++ b/security/integrity/ima/ima_main.c -@@ -324,6 +324,7 @@ int ima_file_mmap(struct file *file, unsigned long prot) - MAY_EXEC, FILE_MMAP); - return 0; - } -+EXPORT_SYMBOL_GPL(ima_file_mmap); - - /** - * ima_bprm_check - based on policy, collect/store measurement. -diff --git a/security/security.c b/security/security.c -index c4c6732..854d15c 100644 ---- a/security/security.c -+++ b/security/security.c -@@ -386,6 +386,7 @@ int security_path_mkdir(struct path *path, struct dentry *dentry, int mode) - return 0; - return security_ops->path_mkdir(path, dentry, mode); - } -+EXPORT_SYMBOL_GPL(security_path_mkdir); - - int security_path_rmdir(struct path *path, struct dentry *dentry) - { -@@ -393,6 +394,7 @@ int security_path_rmdir(struct path *path, struct dentry *dentry) - return 0; - return security_ops->path_rmdir(path, dentry); - } -+EXPORT_SYMBOL_GPL(security_path_rmdir); - - int security_path_unlink(struct path *path, struct dentry *dentry) - { -@@ -400,6 +402,7 @@ int security_path_unlink(struct path *path, struct dentry *dentry) - return 0; - return security_ops->path_unlink(path, dentry); - } -+EXPORT_SYMBOL_GPL(security_path_unlink); - - int security_path_symlink(struct path *path, struct dentry *dentry, - const char *old_name) -@@ -408,6 +411,7 @@ int security_path_symlink(struct path *path, struct dentry *dentry, - return 0; - return security_ops->path_symlink(path, dentry, old_name); - } -+EXPORT_SYMBOL_GPL(security_path_symlink); - - int security_path_link(struct dentry *old_dentry, struct path *new_dir, - struct dentry *new_dentry) -@@ -416,6 +420,7 @@ int security_path_link(struct dentry *old_dentry, struct path *new_dir, - return 0; - return security_ops->path_link(old_dentry, new_dir, new_dentry); - } -+EXPORT_SYMBOL_GPL(security_path_link); - - int security_path_rename(struct path *old_dir, struct dentry *old_dentry, - struct path *new_dir, struct dentry *new_dentry) -@@ -426,6 +431,7 @@ int security_path_rename(struct path *old_dir, struct dentry *old_dentry, - return security_ops->path_rename(old_dir, old_dentry, new_dir, - new_dentry); - } -+EXPORT_SYMBOL_GPL(security_path_rename); - - int security_path_truncate(struct path *path, loff_t length, - unsigned int time_attrs) -@@ -434,6 +440,7 @@ int security_path_truncate(struct path *path, loff_t length, - return 0; - return security_ops->path_truncate(path, length, time_attrs); - } -+EXPORT_SYMBOL_GPL(security_path_truncate); - #endif - - int security_inode_create(struct inode *dir, struct dentry *dentry, int mode) -@@ -505,6 +512,7 @@ int security_inode_readlink(struct dentry *dentry) - return 0; - return security_ops->inode_readlink(dentry); - } -+EXPORT_SYMBOL_GPL(security_inode_readlink); - - int security_inode_follow_link(struct dentry *dentry, struct nameidata *nd) - { -@@ -519,6 +527,7 @@ int security_inode_permission(struct inode *inode, int mask) - return 0; - return security_ops->inode_permission(inode, mask); - } -+EXPORT_SYMBOL_GPL(security_inode_permission); - - int security_inode_setattr(struct dentry *dentry, struct iattr *attr) - { -@@ -619,6 +628,7 @@ int security_file_permission(struct file *file, int mask) - { - return security_ops->file_permission(file, mask); - } -+EXPORT_SYMBOL_GPL(security_file_permission); - - int security_file_alloc(struct file *file) - { diff --git a/debian/patches/features/all/aufs2/mark-as-staging.patch b/debian/patches/features/all/aufs2/mark-as-staging.patch deleted file mode 100644 index 7b92e919d..000000000 --- a/debian/patches/features/all/aufs2/mark-as-staging.patch +++ /dev/null @@ -1,15 +0,0 @@ -From: Ben Hutchings -Subject: [PATCH] aufs: mark as staging - -I really don't want to support this. - ---- a/fs/aufs/module.c -+++ b/fs/aufs/module.c -@@ -81,6 +81,7 @@ - MODULE_DESCRIPTION(AUFS_NAME - " -- Advanced multi layered unification filesystem"); - MODULE_VERSION(AUFS_VERSION); -+MODULE_INFO(staging, "Y"); - - /* it should be 'byte', but param_set_byte() prints it by "%c" */ - short aufs_nwkq = AUFS_NWKQ_DEF; diff --git a/debian/patches/features/all/ethtool-Add-reset-operation.patch b/debian/patches/features/all/ethtool-Add-reset-operation.patch deleted file mode 100644 index c886a6c4f..000000000 --- a/debian/patches/features/all/ethtool-Add-reset-operation.patch +++ /dev/null @@ -1,122 +0,0 @@ -From d73d3a8cb4723e161589864741d8528d70b350eb Mon Sep 17 00:00:00 2001 -From: Ben Hutchings -Date: Mon, 5 Oct 2009 10:59:58 +0000 -Subject: [PATCH] ethtool: Add reset operation - -After updating firmware stored in flash, users may wish to reset the -relevant hardware and start the new firmware immediately. This should -not be completely automatic as it may be disruptive. - -A selective reset may also be useful for debugging or diagnostics. - -This adds a separate reset operation which takes flags indicating the -components to be reset. Drivers are allowed to reset only a subset of -those requested, and must indicate the actual subset. This allows the -use of generic component masks and some future expansion. - -Signed-off-by: Ben Hutchings -Signed-off-by: David S. Miller ---- - include/linux/ethtool.h | 32 ++++++++++++++++++++++++++++++++ - net/core/ethtool.c | 23 +++++++++++++++++++++++ - 2 files changed, 55 insertions(+), 0 deletions(-) - -diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h -index aa0dcb3..eb1a48d 100644 ---- a/include/linux/ethtool.h -+++ b/include/linux/ethtool.h -@@ -498,6 +498,7 @@ struct ethtool_ops { - int (*get_rxnfc)(struct net_device *, struct ethtool_rxnfc *, void *); - int (*set_rxnfc)(struct net_device *, struct ethtool_rxnfc *); - int (*flash_device)(struct net_device *, struct ethtool_flash *); -+ int (*reset)(struct net_device *, u32 *); - }; - #endif /* __KERNEL__ */ - -@@ -555,6 +556,7 @@ struct ethtool_ops { - #define ETHTOOL_SRXCLSRLDEL 0x00000031 /* Delete RX classification rule */ - #define ETHTOOL_SRXCLSRLINS 0x00000032 /* Insert RX classification rule */ - #define ETHTOOL_FLASHDEV 0x00000033 /* Flash firmware to device */ -+#define ETHTOOL_RESET 0x00000034 /* Reset hardware */ - - /* compatibility with older code */ - #define SPARC_ETH_GSET ETHTOOL_GSET -@@ -685,4 +687,34 @@ struct ethtool_ops { - - #define RX_CLS_FLOW_DISC 0xffffffffffffffffULL - -+/* Reset flags */ -+/* The reset() operation must clear the flags for the components which -+ * were actually reset. On successful return, the flags indicate the -+ * components which were not reset, either because they do not exist -+ * in the hardware or because they cannot be reset independently. The -+ * driver must never reset any components that were not requested. -+ */ -+enum ethtool_reset_flags { -+ /* These flags represent components dedicated to the interface -+ * the command is addressed to. Shift any flag left by -+ * ETH_RESET_SHARED_SHIFT to reset a shared component of the -+ * same type. -+ */ -+ ETH_RESET_MGMT = 1 << 0, /* Management processor */ -+ ETH_RESET_IRQ = 1 << 1, /* Interrupt requester */ -+ ETH_RESET_DMA = 1 << 2, /* DMA engine */ -+ ETH_RESET_FILTER = 1 << 3, /* Filtering/flow direction */ -+ ETH_RESET_OFFLOAD = 1 << 4, /* Protocol offload */ -+ ETH_RESET_MAC = 1 << 5, /* Media access controller */ -+ ETH_RESET_PHY = 1 << 6, /* Transceiver/PHY */ -+ ETH_RESET_RAM = 1 << 7, /* RAM shared between -+ * multiple components */ -+ -+ ETH_RESET_DEDICATED = 0x0000ffff, /* All components dedicated to -+ * this interface */ -+ ETH_RESET_ALL = 0xffffffff, /* All components used by this -+ * interface, even if shared */ -+}; -+#define ETH_RESET_SHARED_SHIFT 16 -+ - #endif /* _LINUX_ETHTOOL_H */ -diff --git a/net/core/ethtool.c b/net/core/ethtool.c -index e195108..d8aee58 100644 ---- a/net/core/ethtool.c -+++ b/net/core/ethtool.c -@@ -302,6 +302,26 @@ static int ethtool_get_regs(struct net_device *dev, char __user *useraddr) - return ret; - } - -+static int ethtool_reset(struct net_device *dev, char __user *useraddr) -+{ -+ struct ethtool_value reset; -+ int ret; -+ -+ if (!dev->ethtool_ops->reset) -+ return -EOPNOTSUPP; -+ -+ if (copy_from_user(&reset, useraddr, sizeof(reset))) -+ return -EFAULT; -+ -+ ret = dev->ethtool_ops->reset(dev, &reset.data); -+ if (ret) -+ return ret; -+ -+ if (copy_to_user(useraddr, &reset, sizeof(reset))) -+ return -EFAULT; -+ return 0; -+} -+ - static int ethtool_get_wol(struct net_device *dev, char __user *useraddr) - { - struct ethtool_wolinfo wol = { ETHTOOL_GWOL }; -@@ -1089,6 +1109,9 @@ int dev_ethtool(struct net *net, struct ifreq *ifr) - case ETHTOOL_FLASHDEV: - rc = ethtool_flash_device(dev, useraddr); - break; -+ case ETHTOOL_RESET: -+ rc = ethtool_reset(dev, useraddr); -+ break; - default: - rc = -EOPNOTSUPP; - } --- -1.6.5.4 - diff --git a/debian/patches/features/all/gro-Change-all-receive-functions-to-return-GRO-result.patch b/debian/patches/features/all/gro-Change-all-receive-functions-to-return-GRO-result.patch deleted file mode 100644 index d140457dc..000000000 --- a/debian/patches/features/all/gro-Change-all-receive-functions-to-return-GRO-result.patch +++ /dev/null @@ -1,242 +0,0 @@ -From c7c4b3b6e976b95facbb723951bdcd554a3530a4 Mon Sep 17 00:00:00 2001 -From: Ben Hutchings -Date: Thu, 29 Oct 2009 21:36:53 -0700 -Subject: [PATCH 2/2] gro: Change all receive functions to return GRO result codes - -This will allow drivers to adjust their receive path dynamically -based on whether GRO is being applied successfully. - -Currently all in-tree callers ignore the return values of these -functions and do not need to be changed. - -Signed-off-by: Ben Hutchings -Acked-by: Herbert Xu -Signed-off-by: David S. Miller ---- - include/linux/if_vlan.h | 25 ++++++++++++++----------- - include/linux/netdevice.h | 8 ++++---- - net/8021q/vlan_core.c | 16 +++++++++------- - net/core/dev.c | 38 +++++++++++++++----------------------- - 4 files changed, 42 insertions(+), 45 deletions(-) - -diff --git a/include/linux/if_vlan.h b/include/linux/if_vlan.h -index 71a4870..153f6b9 100644 ---- a/include/linux/if_vlan.h -+++ b/include/linux/if_vlan.h -@@ -120,10 +120,12 @@ extern u16 vlan_dev_vlan_id(const struct net_device *dev); - extern int __vlan_hwaccel_rx(struct sk_buff *skb, struct vlan_group *grp, - u16 vlan_tci, int polling); - extern int vlan_hwaccel_do_receive(struct sk_buff *skb); --extern int vlan_gro_receive(struct napi_struct *napi, struct vlan_group *grp, -- unsigned int vlan_tci, struct sk_buff *skb); --extern int vlan_gro_frags(struct napi_struct *napi, struct vlan_group *grp, -- unsigned int vlan_tci); -+extern gro_result_t -+vlan_gro_receive(struct napi_struct *napi, struct vlan_group *grp, -+ unsigned int vlan_tci, struct sk_buff *skb); -+extern gro_result_t -+vlan_gro_frags(struct napi_struct *napi, struct vlan_group *grp, -+ unsigned int vlan_tci); - - #else - static inline struct net_device *vlan_dev_real_dev(const struct net_device *dev) -@@ -150,17 +152,18 @@ static inline int vlan_hwaccel_do_receive(struct sk_buff *skb) - return 0; - } - --static inline int vlan_gro_receive(struct napi_struct *napi, -- struct vlan_group *grp, -- unsigned int vlan_tci, struct sk_buff *skb) -+static inline gro_result_t -+vlan_gro_receive(struct napi_struct *napi, struct vlan_group *grp, -+ unsigned int vlan_tci, struct sk_buff *skb) - { -- return NET_RX_DROP; -+ return GRO_DROP; - } - --static inline int vlan_gro_frags(struct napi_struct *napi, -- struct vlan_group *grp, unsigned int vlan_tci) -+static inline gro_result_t -+vlan_gro_frags(struct napi_struct *napi, struct vlan_group *grp, -+ unsigned int vlan_tci) - { -- return NET_RX_DROP; -+ return GRO_DROP; - } - #endif - -diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h -index 6e777ef..193b637 100644 ---- a/include/linux/netdevice.h -+++ b/include/linux/netdevice.h -@@ -1483,17 +1483,17 @@ extern int netif_receive_skb(struct sk_buff *skb); - extern void napi_gro_flush(struct napi_struct *napi); - extern gro_result_t dev_gro_receive(struct napi_struct *napi, - struct sk_buff *skb); --extern int napi_skb_finish(gro_result_t ret, struct sk_buff *skb); --extern int napi_gro_receive(struct napi_struct *napi, -+extern gro_result_t napi_skb_finish(gro_result_t ret, struct sk_buff *skb); -+extern gro_result_t napi_gro_receive(struct napi_struct *napi, - struct sk_buff *skb); - extern void napi_reuse_skb(struct napi_struct *napi, - struct sk_buff *skb); - extern struct sk_buff * napi_get_frags(struct napi_struct *napi); --extern int napi_frags_finish(struct napi_struct *napi, -+extern gro_result_t napi_frags_finish(struct napi_struct *napi, - struct sk_buff *skb, - gro_result_t ret); - extern struct sk_buff * napi_frags_skb(struct napi_struct *napi); --extern int napi_gro_frags(struct napi_struct *napi); -+extern gro_result_t napi_gro_frags(struct napi_struct *napi); - - static inline void napi_free_frags(struct napi_struct *napi) - { -diff --git a/net/8021q/vlan_core.c b/net/8021q/vlan_core.c -index 47a80d6..8d5ca2a 100644 ---- a/net/8021q/vlan_core.c -+++ b/net/8021q/vlan_core.c -@@ -102,11 +102,12 @@ drop: - return GRO_DROP; - } - --int vlan_gro_receive(struct napi_struct *napi, struct vlan_group *grp, -- unsigned int vlan_tci, struct sk_buff *skb) -+gro_result_t vlan_gro_receive(struct napi_struct *napi, struct vlan_group *grp, -+ unsigned int vlan_tci, struct sk_buff *skb) - { - if (netpoll_rx_on(skb)) -- return vlan_hwaccel_receive_skb(skb, grp, vlan_tci); -+ return vlan_hwaccel_receive_skb(skb, grp, vlan_tci) -+ ? GRO_DROP : GRO_NORMAL; - - skb_gro_reset_offset(skb); - -@@ -114,17 +115,18 @@ int vlan_gro_receive(struct napi_struct *napi, struct vlan_group *grp, - } - EXPORT_SYMBOL(vlan_gro_receive); - --int vlan_gro_frags(struct napi_struct *napi, struct vlan_group *grp, -- unsigned int vlan_tci) -+gro_result_t vlan_gro_frags(struct napi_struct *napi, struct vlan_group *grp, -+ unsigned int vlan_tci) - { - struct sk_buff *skb = napi_frags_skb(napi); - - if (!skb) -- return NET_RX_DROP; -+ return GRO_DROP; - - if (netpoll_rx_on(skb)) { - skb->protocol = eth_type_trans(skb, skb->dev); -- return vlan_hwaccel_receive_skb(skb, grp, vlan_tci); -+ return vlan_hwaccel_receive_skb(skb, grp, vlan_tci) -+ ? GRO_DROP : GRO_NORMAL; - } - - return napi_frags_finish(napi, skb, -diff --git a/net/core/dev.c b/net/core/dev.c -index 1dc1374..631cc40 100644 ---- a/net/core/dev.c -+++ b/net/core/dev.c -@@ -2586,18 +2586,15 @@ __napi_gro_receive(struct napi_struct *napi, struct sk_buff *skb) - return dev_gro_receive(napi, skb); - } - --int napi_skb_finish(gro_result_t ret, struct sk_buff *skb) -+gro_result_t napi_skb_finish(gro_result_t ret, struct sk_buff *skb) - { -- int err = NET_RX_SUCCESS; -- - switch (ret) { - case GRO_NORMAL: -- return netif_receive_skb(skb); -+ if (netif_receive_skb(skb)) -+ ret = GRO_DROP; -+ break; - - case GRO_DROP: -- err = NET_RX_DROP; -- /* fall through */ -- - case GRO_MERGED_FREE: - kfree_skb(skb); - break; -@@ -2607,7 +2604,7 @@ int napi_skb_finish(gro_result_t ret, struct sk_buff *skb) - break; - } - -- return err; -+ return ret; - } - EXPORT_SYMBOL(napi_skb_finish); - -@@ -2627,7 +2624,7 @@ void skb_gro_reset_offset(struct sk_buff *skb) - } - EXPORT_SYMBOL(skb_gro_reset_offset); - --int napi_gro_receive(struct napi_struct *napi, struct sk_buff *skb) -+gro_result_t napi_gro_receive(struct napi_struct *napi, struct sk_buff *skb) - { - skb_gro_reset_offset(skb); - -@@ -2657,26 +2654,21 @@ struct sk_buff *napi_get_frags(struct napi_struct *napi) - } - EXPORT_SYMBOL(napi_get_frags); - --int napi_frags_finish(struct napi_struct *napi, struct sk_buff *skb, -- gro_result_t ret) -+gro_result_t napi_frags_finish(struct napi_struct *napi, struct sk_buff *skb, -+ gro_result_t ret) - { -- int err = NET_RX_SUCCESS; -- - switch (ret) { - case GRO_NORMAL: - case GRO_HELD: - skb->protocol = eth_type_trans(skb, napi->dev); - -- if (ret == GRO_NORMAL) -- return netif_receive_skb(skb); -- -- skb_gro_pull(skb, -ETH_HLEN); -+ if (ret == GRO_HELD) -+ skb_gro_pull(skb, -ETH_HLEN); -+ else if (netif_receive_skb(skb)) -+ ret = GRO_DROP; - break; - - case GRO_DROP: -- err = NET_RX_DROP; -- /* fall through */ -- - case GRO_MERGED_FREE: - napi_reuse_skb(napi, skb); - break; -@@ -2685,7 +2677,7 @@ int napi_frags_finish(struct napi_struct *napi, struct sk_buff *skb, - break; - } - -- return err; -+ return ret; - } - EXPORT_SYMBOL(napi_frags_finish); - -@@ -2726,12 +2718,12 @@ out: - } - EXPORT_SYMBOL(napi_frags_skb); - --int napi_gro_frags(struct napi_struct *napi) -+gro_result_t napi_gro_frags(struct napi_struct *napi) - { - struct sk_buff *skb = napi_frags_skb(napi); - - if (!skb) -- return NET_RX_DROP; -+ return GRO_DROP; - - return napi_frags_finish(napi, skb, __napi_gro_receive(napi, skb)); - } --- -1.6.5.4 - diff --git a/debian/patches/features/all/gro-Name-the-GRO-result-enumeration-type.patch b/debian/patches/features/all/gro-Name-the-GRO-result-enumeration-type.patch deleted file mode 100644 index 1f7d65b04..000000000 --- a/debian/patches/features/all/gro-Name-the-GRO-result-enumeration-type.patch +++ /dev/null @@ -1,149 +0,0 @@ -From 5b252f0c2f98df21fadf0f6cf189b87a0b938228 Mon Sep 17 00:00:00 2001 -From: Ben Hutchings -Date: Thu, 29 Oct 2009 07:17:09 +0000 -Subject: [PATCH 1/2] gro: Name the GRO result enumeration type - -This clarifies which return and parameter types are GRO result codes -and not RX result codes. - -Signed-off-by: Ben Hutchings -Acked-by: Herbert Xu -Signed-off-by: David S. Miller ---- - include/linux/netdevice.h | 10 ++++++---- - net/8021q/vlan_core.c | 5 +++-- - net/core/dev.c | 19 ++++++++++++++----- - 3 files changed, 23 insertions(+), 11 deletions(-) - -diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h -index ffc3106..6e777ef 100644 ---- a/include/linux/netdevice.h -+++ b/include/linux/netdevice.h -@@ -348,13 +348,14 @@ enum - NAPI_STATE_NPSVC, /* Netpoll - don't dequeue from poll_list */ - }; - --enum { -+enum gro_result { - GRO_MERGED, - GRO_MERGED_FREE, - GRO_HELD, - GRO_NORMAL, - GRO_DROP, - }; -+typedef enum gro_result gro_result_t; - - extern void __napi_schedule(struct napi_struct *n); - -@@ -1480,16 +1481,17 @@ extern int netif_rx_ni(struct sk_buff *skb); - #define HAVE_NETIF_RECEIVE_SKB 1 - extern int netif_receive_skb(struct sk_buff *skb); - extern void napi_gro_flush(struct napi_struct *napi); --extern int dev_gro_receive(struct napi_struct *napi, -+extern gro_result_t dev_gro_receive(struct napi_struct *napi, - struct sk_buff *skb); --extern int napi_skb_finish(int ret, struct sk_buff *skb); -+extern int napi_skb_finish(gro_result_t ret, struct sk_buff *skb); - extern int napi_gro_receive(struct napi_struct *napi, - struct sk_buff *skb); - extern void napi_reuse_skb(struct napi_struct *napi, - struct sk_buff *skb); - extern struct sk_buff * napi_get_frags(struct napi_struct *napi); - extern int napi_frags_finish(struct napi_struct *napi, -- struct sk_buff *skb, int ret); -+ struct sk_buff *skb, -+ gro_result_t ret); - extern struct sk_buff * napi_frags_skb(struct napi_struct *napi); - extern int napi_gro_frags(struct napi_struct *napi); - -diff --git a/net/8021q/vlan_core.c b/net/8021q/vlan_core.c -index 7f7de1a..47a80d6 100644 ---- a/net/8021q/vlan_core.c -+++ b/net/8021q/vlan_core.c -@@ -74,8 +74,9 @@ u16 vlan_dev_vlan_id(const struct net_device *dev) - } - EXPORT_SYMBOL(vlan_dev_vlan_id); - --static int vlan_gro_common(struct napi_struct *napi, struct vlan_group *grp, -- unsigned int vlan_tci, struct sk_buff *skb) -+static gro_result_t -+vlan_gro_common(struct napi_struct *napi, struct vlan_group *grp, -+ unsigned int vlan_tci, struct sk_buff *skb) - { - struct sk_buff *p; - -diff --git a/net/core/dev.c b/net/core/dev.c -index 68a1bb6..1dc1374 100644 ---- a/net/core/dev.c -+++ b/net/core/dev.c -@@ -2476,7 +2476,7 @@ void napi_gro_flush(struct napi_struct *napi) - } - EXPORT_SYMBOL(napi_gro_flush); - --int dev_gro_receive(struct napi_struct *napi, struct sk_buff *skb) -+enum gro_result dev_gro_receive(struct napi_struct *napi, struct sk_buff *skb) - { - struct sk_buff **pp = NULL; - struct packet_type *ptype; -@@ -2484,7 +2484,7 @@ int dev_gro_receive(struct napi_struct *napi, struct sk_buff *skb) - struct list_head *head = &ptype_base[ntohs(type) & PTYPE_HASH_MASK]; - int same_flow; - int mac_len; -- int ret; -+ enum gro_result ret; - - if (!(skb->dev->features & NETIF_F_GRO)) - goto normal; -@@ -2568,7 +2568,8 @@ normal: - } - EXPORT_SYMBOL(dev_gro_receive); - --static int __napi_gro_receive(struct napi_struct *napi, struct sk_buff *skb) -+static gro_result_t -+__napi_gro_receive(struct napi_struct *napi, struct sk_buff *skb) - { - struct sk_buff *p; - -@@ -2585,7 +2586,7 @@ static int __napi_gro_receive(struct napi_struct *napi, struct sk_buff *skb) - return dev_gro_receive(napi, skb); - } - --int napi_skb_finish(int ret, struct sk_buff *skb) -+int napi_skb_finish(gro_result_t ret, struct sk_buff *skb) - { - int err = NET_RX_SUCCESS; - -@@ -2600,6 +2601,10 @@ int napi_skb_finish(int ret, struct sk_buff *skb) - case GRO_MERGED_FREE: - kfree_skb(skb); - break; -+ -+ case GRO_HELD: -+ case GRO_MERGED: -+ break; - } - - return err; -@@ -2652,7 +2657,8 @@ struct sk_buff *napi_get_frags(struct napi_struct *napi) - } - EXPORT_SYMBOL(napi_get_frags); - --int napi_frags_finish(struct napi_struct *napi, struct sk_buff *skb, int ret) -+int napi_frags_finish(struct napi_struct *napi, struct sk_buff *skb, -+ gro_result_t ret) - { - int err = NET_RX_SUCCESS; - -@@ -2674,6 +2680,9 @@ int napi_frags_finish(struct napi_struct *napi, struct sk_buff *skb, int ret) - case GRO_MERGED_FREE: - napi_reuse_skb(napi, skb); - break; -+ -+ case GRO_MERGED: -+ break; - } - - return err; --- -1.6.5.4 - diff --git a/debian/patches/features/all/input-alps-add-support-for-touchpads-with-4-directional-button.patch b/debian/patches/features/all/input-alps-add-support-for-touchpads-with-4-directional-button.patch deleted file mode 100644 index 31f357b21..000000000 --- a/debian/patches/features/all/input-alps-add-support-for-touchpads-with-4-directional-button.patch +++ /dev/null @@ -1,263 +0,0 @@ -commit 71bb21b677e89a2b438b804231f92b779beda5d7 -Author: Maxim Levitsky -Date: Mon Nov 16 22:12:22 2009 -0800 - - Input: ALPS - add support for touchpads with 4-directional button - - The touchpad on Acer Aspire 5720, 5520 and some other Aspire models - (signature 0x73, 0x02, 0x50) has a button that can be rocked in 4 - different directions. Make the driver to generate BTN_0..BTN_3 events - in response. The Synaptics driver by default maps BTN_0 and BTN_1 to - up and down, so there should be no visible changes with the old setup - that generated BTN_FORWARD and BTN_BACK (also mapped to up and down). - - Signed-off-by: Maxim Levitsky - Signed-off-by: Dmitry Torokhov - -diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c -index f361106..a3f492a 100644 ---- a/drivers/input/mouse/alps.c -+++ b/drivers/input/mouse/alps.c -@@ -28,13 +28,16 @@ - #define dbg(format, arg...) do {} while (0) - #endif - --#define ALPS_DUALPOINT 0x01 --#define ALPS_WHEEL 0x02 --#define ALPS_FW_BK_1 0x04 --#define ALPS_4BTN 0x08 --#define ALPS_OLDPROTO 0x10 --#define ALPS_PASS 0x20 --#define ALPS_FW_BK_2 0x40 -+ -+#define ALPS_OLDPROTO 0x01 /* old style input */ -+#define ALPS_DUALPOINT 0x02 /* touchpad has trackstick */ -+#define ALPS_PASS 0x04 /* device has a pass-through port */ -+ -+#define ALPS_WHEEL 0x08 /* hardware wheel present */ -+#define ALPS_FW_BK_1 0x10 /* front & back buttons present */ -+#define ALPS_FW_BK_2 0x20 /* front & back buttons present */ -+#define ALPS_FOUR_BUTTONS 0x40 /* 4 direction button present */ -+ - - static const struct alps_model_info alps_model_data[] = { - { { 0x32, 0x02, 0x14 }, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* Toshiba Salellite Pro M10 */ -@@ -56,7 +59,7 @@ static const struct alps_model_info alps_model_data[] = { - { { 0x22, 0x02, 0x0a }, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, - { { 0x22, 0x02, 0x14 }, 0xff, 0xff, ALPS_PASS | ALPS_DUALPOINT }, /* Dell Latitude D600 */ - { { 0x62, 0x02, 0x14 }, 0xcf, 0xcf, ALPS_PASS | ALPS_DUALPOINT }, /* Dell Latitude E6500 */ -- { { 0x73, 0x02, 0x50 }, 0xcf, 0xcf, ALPS_FW_BK_1 }, /* Dell Vostro 1400 */ -+ { { 0x73, 0x02, 0x50 }, 0xcf, 0xcf, ALPS_FOUR_BUTTONS }, /* Dell Vostro 1400 */ - }; - - /* -@@ -83,6 +86,7 @@ static const struct alps_model_info alps_model_data[] = { - static void alps_process_packet(struct psmouse *psmouse) - { - struct alps_data *priv = psmouse->private; -+ const struct alps_model_info *model = priv->i; - unsigned char *packet = psmouse->packet; - struct input_dev *dev = psmouse->dev; - struct input_dev *dev2 = priv->dev2; -@@ -101,7 +105,7 @@ static void alps_process_packet(struct psmouse *psmouse) - return; - } - -- if (priv->i->flags & ALPS_OLDPROTO) { -+ if (model->flags & ALPS_OLDPROTO) { - left = packet[2] & 0x10; - right = packet[2] & 0x08; - middle = 0; -@@ -117,12 +121,12 @@ static void alps_process_packet(struct psmouse *psmouse) - z = packet[5]; - } - -- if (priv->i->flags & ALPS_FW_BK_1) { -+ if (model->flags & ALPS_FW_BK_1) { - back = packet[0] & 0x10; - forward = packet[2] & 4; - } - -- if (priv->i->flags & ALPS_FW_BK_2) { -+ if (model->flags & ALPS_FW_BK_2) { - back = packet[3] & 4; - forward = packet[2] & 4; - if ((middle = forward && back)) -@@ -132,7 +136,7 @@ static void alps_process_packet(struct psmouse *psmouse) - ges = packet[2] & 1; - fin = packet[2] & 2; - -- if ((priv->i->flags & ALPS_DUALPOINT) && z == 127) { -+ if ((model->flags & ALPS_DUALPOINT) && z == 127) { - input_report_rel(dev2, REL_X, (x > 383 ? (x - 768) : x)); - input_report_rel(dev2, REL_Y, -(y > 255 ? (y - 512) : y)); - -@@ -150,7 +154,8 @@ static void alps_process_packet(struct psmouse *psmouse) - input_report_key(dev, BTN_MIDDLE, middle); - - /* Convert hardware tap to a reasonable Z value */ -- if (ges && !fin) z = 40; -+ if (ges && !fin) -+ z = 40; - - /* - * A "tap and drag" operation is reported by the hardware as a transition -@@ -166,8 +171,10 @@ static void alps_process_packet(struct psmouse *psmouse) - } - priv->prev_fin = fin; - -- if (z > 30) input_report_key(dev, BTN_TOUCH, 1); -- if (z < 25) input_report_key(dev, BTN_TOUCH, 0); -+ if (z > 30) -+ input_report_key(dev, BTN_TOUCH, 1); -+ if (z < 25) -+ input_report_key(dev, BTN_TOUCH, 0); - - if (z > 0) { - input_report_abs(dev, ABS_X, x); -@@ -177,14 +184,21 @@ static void alps_process_packet(struct psmouse *psmouse) - input_report_abs(dev, ABS_PRESSURE, z); - input_report_key(dev, BTN_TOOL_FINGER, z > 0); - -- if (priv->i->flags & ALPS_WHEEL) -+ if (model->flags & ALPS_WHEEL) - input_report_rel(dev, REL_WHEEL, ((packet[2] << 1) & 0x08) - ((packet[0] >> 4) & 0x07)); - -- if (priv->i->flags & (ALPS_FW_BK_1 | ALPS_FW_BK_2)) { -+ if (model->flags & (ALPS_FW_BK_1 | ALPS_FW_BK_2)) { - input_report_key(dev, BTN_FORWARD, forward); - input_report_key(dev, BTN_BACK, back); - } - -+ if (model->flags & ALPS_FOUR_BUTTONS) { -+ input_report_key(dev, BTN_0, packet[2] & 4); -+ input_report_key(dev, BTN_1, packet[0] & 0x10); -+ input_report_key(dev, BTN_2, packet[3] & 4); -+ input_report_key(dev, BTN_3, packet[0] & 0x20); -+ } -+ - input_sync(dev); - } - -@@ -393,15 +407,12 @@ static int alps_poll(struct psmouse *psmouse) - return 0; - } - --static int alps_hw_init(struct psmouse *psmouse, int *version) -+static int alps_hw_init(struct psmouse *psmouse) - { - struct alps_data *priv = psmouse->private; -+ const struct alps_model_info *model = priv->i; - -- priv->i = alps_get_model(psmouse, version); -- if (!priv->i) -- return -1; -- -- if ((priv->i->flags & ALPS_PASS) && -+ if ((model->flags & ALPS_PASS) && - alps_passthrough_mode(psmouse, true)) { - return -1; - } -@@ -416,7 +427,7 @@ static int alps_hw_init(struct psmouse *psmouse, int *version) - return -1; - } - -- if ((priv->i->flags & ALPS_PASS) && -+ if ((model->flags & ALPS_PASS) && - alps_passthrough_mode(psmouse, false)) { - return -1; - } -@@ -432,12 +443,15 @@ static int alps_hw_init(struct psmouse *psmouse, int *version) - - static int alps_reconnect(struct psmouse *psmouse) - { -+ const struct alps_model_info *model; -+ - psmouse_reset(psmouse); - -- if (alps_hw_init(psmouse, NULL)) -+ model = alps_get_model(psmouse, NULL); -+ if (!model) - return -1; - -- return 0; -+ return alps_hw_init(psmouse); - } - - static void alps_disconnect(struct psmouse *psmouse) -@@ -452,6 +466,7 @@ static void alps_disconnect(struct psmouse *psmouse) - int alps_init(struct psmouse *psmouse) - { - struct alps_data *priv; -+ const struct alps_model_info *model; - struct input_dev *dev1 = psmouse->dev, *dev2; - int version; - -@@ -463,33 +478,48 @@ int alps_init(struct psmouse *psmouse) - priv->dev2 = dev2; - psmouse->private = priv; - -- if (alps_hw_init(psmouse, &version)) -+ model = alps_get_model(psmouse, &version); -+ if (!model) -+ goto init_fail; -+ -+ priv->i = model; -+ -+ if (alps_hw_init(psmouse)) - goto init_fail; - - dev1->evbit[BIT_WORD(EV_KEY)] |= BIT_MASK(EV_KEY); - dev1->keybit[BIT_WORD(BTN_TOUCH)] |= BIT_MASK(BTN_TOUCH); - dev1->keybit[BIT_WORD(BTN_TOOL_FINGER)] |= BIT_MASK(BTN_TOOL_FINGER); -- dev1->keybit[BIT_WORD(BTN_LEFT)] |= BIT_MASK(BTN_LEFT) | -- BIT_MASK(BTN_MIDDLE) | BIT_MASK(BTN_RIGHT); -+ dev1->keybit[BIT_WORD(BTN_LEFT)] |= -+ BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_RIGHT); - - dev1->evbit[BIT_WORD(EV_ABS)] |= BIT_MASK(EV_ABS); - input_set_abs_params(dev1, ABS_X, 0, 1023, 0, 0); - input_set_abs_params(dev1, ABS_Y, 0, 767, 0, 0); - input_set_abs_params(dev1, ABS_PRESSURE, 0, 127, 0, 0); - -- if (priv->i->flags & ALPS_WHEEL) { -+ if (model->flags & ALPS_WHEEL) { - dev1->evbit[BIT_WORD(EV_REL)] |= BIT_MASK(EV_REL); - dev1->relbit[BIT_WORD(REL_WHEEL)] |= BIT_MASK(REL_WHEEL); - } - -- if (priv->i->flags & (ALPS_FW_BK_1 | ALPS_FW_BK_2)) { -+ if (model->flags & (ALPS_FW_BK_1 | ALPS_FW_BK_2)) { - dev1->keybit[BIT_WORD(BTN_FORWARD)] |= BIT_MASK(BTN_FORWARD); - dev1->keybit[BIT_WORD(BTN_BACK)] |= BIT_MASK(BTN_BACK); - } - -+ if (model->flags & ALPS_FOUR_BUTTONS) { -+ dev1->keybit[BIT_WORD(BTN_0)] |= BIT_MASK(BTN_0); -+ dev1->keybit[BIT_WORD(BTN_1)] |= BIT_MASK(BTN_1); -+ dev1->keybit[BIT_WORD(BTN_2)] |= BIT_MASK(BTN_2); -+ dev1->keybit[BIT_WORD(BTN_3)] |= BIT_MASK(BTN_3); -+ } else { -+ dev1->keybit[BIT_WORD(BTN_MIDDLE)] |= BIT_MASK(BTN_MIDDLE); -+ } -+ - snprintf(priv->phys, sizeof(priv->phys), "%s/input1", psmouse->ps2dev.serio->phys); - dev2->phys = priv->phys; -- dev2->name = (priv->i->flags & ALPS_DUALPOINT) ? "DualPoint Stick" : "PS/2 Mouse"; -+ dev2->name = (model->flags & ALPS_DUALPOINT) ? "DualPoint Stick" : "PS/2 Mouse"; - dev2->id.bustype = BUS_I8042; - dev2->id.vendor = 0x0002; - dev2->id.product = PSMOUSE_ALPS; -@@ -497,9 +527,9 @@ int alps_init(struct psmouse *psmouse) - dev2->dev.parent = &psmouse->ps2dev.serio->dev; - - dev2->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL); -- dev2->relbit[BIT_WORD(REL_X)] |= BIT_MASK(REL_X) | BIT_MASK(REL_Y); -- dev2->keybit[BIT_WORD(BTN_LEFT)] |= BIT_MASK(BTN_LEFT) | -- BIT_MASK(BTN_MIDDLE) | BIT_MASK(BTN_RIGHT); -+ dev2->relbit[BIT_WORD(REL_X)] = BIT_MASK(REL_X) | BIT_MASK(REL_Y); -+ dev2->keybit[BIT_WORD(BTN_LEFT)] = -+ BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_MIDDLE) | BIT_MASK(BTN_RIGHT); - - if (input_register_device(priv->dev2)) - goto init_fail; diff --git a/debian/patches/features/all/macvlan-Copy-functions-from-2.6.33-net-core-dev-c.patch b/debian/patches/features/all/macvlan-Copy-functions-from-2.6.33-net-core-dev-c.patch deleted file mode 100644 index 69c901984..000000000 --- a/debian/patches/features/all/macvlan-Copy-functions-from-2.6.33-net-core-dev-c.patch +++ /dev/null @@ -1,64 +0,0 @@ -From 2b071e9effc16db91cd17577a35b0e61e9fcee9d Mon Sep 17 00:00:00 2001 -From: Ben Hutchings -Date: Tue, 16 Feb 2010 03:06:44 +0000 -Subject: [PATCH] macvlan: Copy necessary helper functions from 2.6.33 net/core/dev.c - ---- - drivers/net/macvlan.c | 41 +++++++++++++++++++++++++++++++++++++++++ - 1 files changed, 41 insertions(+), 0 deletions(-) - -diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c -index 2490aa3..cb4a16e 100644 ---- a/drivers/net/macvlan.c -+++ b/drivers/net/macvlan.c -@@ -46,6 +46,47 @@ struct macvlan_dev { - struct net_device *lowerdev; - }; - -+/* From 2.6.33 net/core/dev.c */ -+static int dev_forward_skb(struct net_device *dev, struct sk_buff *skb) -+{ -+ skb_orphan(skb); -+ -+ if (!(dev->flags & IFF_UP)) -+ return NET_RX_DROP; -+ -+ if (skb->len > (dev->mtu + dev->hard_header_len)) -+ return NET_RX_DROP; -+ -+ skb_dst_drop(skb); -+ skb->tstamp.tv64 = 0; -+ skb->pkt_type = PACKET_HOST; -+ skb->protocol = eth_type_trans(skb, dev); -+ skb->mark = 0; -+ secpath_reset(skb); -+ nf_reset(skb); -+ return netif_rx(skb); -+} -+ -+/* From 2.6.33 net/core/dev.c */ -+static void dev_txq_stats_fold(const struct net_device *dev, -+ struct net_device_stats *stats) -+{ -+ unsigned long tx_bytes = 0, tx_packets = 0, tx_dropped = 0; -+ unsigned int i; -+ struct netdev_queue *txq; -+ -+ for (i = 0; i < dev->num_tx_queues; i++) { -+ txq = netdev_get_tx_queue(dev, i); -+ tx_bytes += txq->tx_bytes; -+ tx_packets += txq->tx_packets; -+ tx_dropped += txq->tx_dropped; -+ } -+ if (tx_bytes || tx_packets || tx_dropped) { -+ stats->tx_bytes = tx_bytes; -+ stats->tx_packets = tx_packets; -+ stats->tx_dropped = tx_dropped; -+ } -+} - - static struct macvlan_dev *macvlan_hash_lookup(const struct macvlan_port *port, - const unsigned char *addr) --- -1.6.6.2 - diff --git a/debian/patches/features/all/macvlan-Precise-RX-stats-accounting.patch b/debian/patches/features/all/macvlan-Precise-RX-stats-accounting.patch deleted file mode 100644 index 7f8a50318..000000000 --- a/debian/patches/features/all/macvlan-Precise-RX-stats-accounting.patch +++ /dev/null @@ -1,183 +0,0 @@ -From fccaf71011b171883efee5bae321eac4760584d1 Mon Sep 17 00:00:00 2001 -From: Eric Dumazet -Date: Tue, 17 Nov 2009 08:53:49 +0000 -Subject: [PATCH 1/4] macvlan: Precise RX stats accounting - -With multi queue devices, its possible that several cpus call -macvlan RX routines simultaneously for the same macvlan device. - -We update RX stats counter without any locking, so we can -get slightly wrong counters. - -One possible fix is to use percpu counters, to get precise -accounting and also get guarantee of no cache line ping pongs -between cpus. - -Note: this adds 16 bytes (32 bytes on 64bit arches) of percpu -data per macvlan device. - -Signed-off-by: Eric Dumazet -Signed-off-by: David S. Miller ---- - drivers/net/macvlan.c | 76 ++++++++++++++++++++++++++++++++++++++++++------ - 1 files changed, 66 insertions(+), 10 deletions(-) - -diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c -index 271aa7e..ae2b5c7 100644 ---- a/drivers/net/macvlan.c -+++ b/drivers/net/macvlan.c -@@ -38,12 +38,27 @@ struct macvlan_port { - struct list_head vlans; - }; - -+/** -+ * struct macvlan_rx_stats - MACVLAN percpu rx stats -+ * @rx_packets: number of received packets -+ * @rx_bytes: number of received bytes -+ * @multicast: number of received multicast packets -+ * @rx_errors: number of errors -+ */ -+struct macvlan_rx_stats { -+ unsigned long rx_packets; -+ unsigned long rx_bytes; -+ unsigned long multicast; -+ unsigned long rx_errors; -+}; -+ - struct macvlan_dev { - struct net_device *dev; - struct list_head list; - struct hlist_node hlist; - struct macvlan_port *port; - struct net_device *lowerdev; -+ struct macvlan_rx_stats *rx_stats; - }; - - -@@ -110,6 +125,7 @@ static void macvlan_broadcast(struct sk_buff *skb, - struct net_device *dev; - struct sk_buff *nskb; - unsigned int i; -+ struct macvlan_rx_stats *rx_stats; - - if (skb->protocol == htons(ETH_P_PAUSE)) - return; -@@ -117,17 +133,17 @@ static void macvlan_broadcast(struct sk_buff *skb, - for (i = 0; i < MACVLAN_HASH_SIZE; i++) { - hlist_for_each_entry_rcu(vlan, n, &port->vlan_hash[i], hlist) { - dev = vlan->dev; -+ rx_stats = per_cpu_ptr(vlan->rx_stats, smp_processor_id()); - - nskb = skb_clone(skb, GFP_ATOMIC); - if (nskb == NULL) { -- dev->stats.rx_errors++; -- dev->stats.rx_dropped++; -+ rx_stats->rx_errors++; - continue; - } - -- dev->stats.rx_bytes += skb->len + ETH_HLEN; -- dev->stats.rx_packets++; -- dev->stats.multicast++; -+ rx_stats->rx_bytes += skb->len + ETH_HLEN; -+ rx_stats->rx_packets++; -+ rx_stats->multicast++; - - nskb->dev = dev; - if (!compare_ether_addr_64bits(eth->h_dest, dev->broadcast)) -@@ -147,6 +163,7 @@ static struct sk_buff *macvlan_handle_frame(struct sk_buff *skb) - const struct macvlan_port *port; - const struct macvlan_dev *vlan; - struct net_device *dev; -+ struct macvlan_rx_stats *rx_stats; - - port = rcu_dereference(skb->dev->macvlan_port); - if (port == NULL) -@@ -166,16 +183,15 @@ static struct sk_buff *macvlan_handle_frame(struct sk_buff *skb) - kfree_skb(skb); - return NULL; - } -- -+ rx_stats = per_cpu_ptr(vlan->rx_stats, smp_processor_id()); - skb = skb_share_check(skb, GFP_ATOMIC); - if (skb == NULL) { -- dev->stats.rx_errors++; -- dev->stats.rx_dropped++; -+ rx_stats->rx_errors++; - return NULL; - } - -- dev->stats.rx_bytes += skb->len + ETH_HLEN; -- dev->stats.rx_packets++; -+ rx_stats->rx_bytes += skb->len + ETH_HLEN; -+ rx_stats->rx_packets++; - - skb->dev = dev; - skb->pkt_type = PACKET_HOST; -@@ -365,9 +381,47 @@ static int macvlan_init(struct net_device *dev) - - macvlan_set_lockdep_class(dev); - -+ vlan->rx_stats = alloc_percpu(struct macvlan_rx_stats); -+ if (!vlan->rx_stats) -+ return -ENOMEM; -+ - return 0; - } - -+static void macvlan_uninit(struct net_device *dev) -+{ -+ struct macvlan_dev *vlan = netdev_priv(dev); -+ -+ free_percpu(vlan->rx_stats); -+} -+ -+static struct net_device_stats *macvlan_dev_get_stats(struct net_device *dev) -+{ -+ struct net_device_stats *stats = &dev->stats; -+ struct macvlan_dev *vlan = netdev_priv(dev); -+ -+ dev_txq_stats_fold(dev, stats); -+ -+ if (vlan->rx_stats) { -+ struct macvlan_rx_stats *p, rx = {0}; -+ int i; -+ -+ for_each_possible_cpu(i) { -+ p = per_cpu_ptr(vlan->rx_stats, i); -+ rx.rx_packets += p->rx_packets; -+ rx.rx_bytes += p->rx_bytes; -+ rx.rx_errors += p->rx_errors; -+ rx.multicast += p->multicast; -+ } -+ stats->rx_packets = rx.rx_packets; -+ stats->rx_bytes = rx.rx_bytes; -+ stats->rx_errors = rx.rx_errors; -+ stats->rx_dropped = rx.rx_errors; -+ stats->multicast = rx.multicast; -+ } -+ return stats; -+} -+ - static void macvlan_ethtool_get_drvinfo(struct net_device *dev, - struct ethtool_drvinfo *drvinfo) - { -@@ -404,6 +458,7 @@ static const struct ethtool_ops macvlan_ethtool_ops = { - - static const struct net_device_ops macvlan_netdev_ops = { - .ndo_init = macvlan_init, -+ .ndo_uninit = macvlan_uninit, - .ndo_open = macvlan_open, - .ndo_stop = macvlan_stop, - .ndo_start_xmit = macvlan_start_xmit, -@@ -411,6 +466,7 @@ static const struct net_device_ops macvlan_netdev_ops = { - .ndo_change_rx_flags = macvlan_change_rx_flags, - .ndo_set_mac_address = macvlan_set_mac_address, - .ndo_set_multicast_list = macvlan_set_multicast_list, -+ .ndo_get_stats = macvlan_dev_get_stats, - .ndo_validate_addr = eth_validate_addr, - }; - --- -1.6.6.2 - diff --git a/debian/patches/features/all/macvlan-cleanup-rx-statistics.patch b/debian/patches/features/all/macvlan-cleanup-rx-statistics.patch deleted file mode 100644 index bd5b8b4f9..000000000 --- a/debian/patches/features/all/macvlan-cleanup-rx-statistics.patch +++ /dev/null @@ -1,134 +0,0 @@ -From a1e514c5d0397b5581721aad9b303f7df83b103d Mon Sep 17 00:00:00 2001 -From: Arnd Bergmann -Date: Thu, 26 Nov 2009 06:07:09 +0000 -Subject: [PATCH 2/4] macvlan: cleanup rx statistics - -We have very similar code for rx statistics in -two places in the macvlan driver, with a third -one being added in the next patch. - -Consolidate them into one function to improve -overall readability of the driver. - -Signed-off-by: Arnd Bergmann -Acked-by: Patrick McHardy -Signed-off-by: David S. Miller ---- - drivers/net/macvlan.c | 70 ++++++++++++++++++++++++++++-------------------- - 1 files changed, 41 insertions(+), 29 deletions(-) - -diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c -index ae2b5c7..1e7faf9 100644 ---- a/drivers/net/macvlan.c -+++ b/drivers/net/macvlan.c -@@ -116,42 +116,58 @@ static int macvlan_addr_busy(const struct macvlan_port *port, - return 0; - } - -+static inline void macvlan_count_rx(const struct macvlan_dev *vlan, -+ unsigned int len, bool success, -+ bool multicast) -+{ -+ struct macvlan_rx_stats *rx_stats; -+ -+ rx_stats = per_cpu_ptr(vlan->rx_stats, smp_processor_id()); -+ if (likely(success)) { -+ rx_stats->rx_packets++;; -+ rx_stats->rx_bytes += len; -+ if (multicast) -+ rx_stats->multicast++; -+ } else { -+ rx_stats->rx_errors++; -+ } -+} -+ -+static int macvlan_broadcast_one(struct sk_buff *skb, struct net_device *dev, -+ const struct ethhdr *eth) -+{ -+ if (!skb) -+ return NET_RX_DROP; -+ -+ skb->dev = dev; -+ if (!compare_ether_addr_64bits(eth->h_dest, -+ dev->broadcast)) -+ skb->pkt_type = PACKET_BROADCAST; -+ else -+ skb->pkt_type = PACKET_MULTICAST; -+ -+ return netif_rx(skb); -+} -+ - static void macvlan_broadcast(struct sk_buff *skb, - const struct macvlan_port *port) - { - const struct ethhdr *eth = eth_hdr(skb); - const struct macvlan_dev *vlan; - struct hlist_node *n; -- struct net_device *dev; - struct sk_buff *nskb; - unsigned int i; -- struct macvlan_rx_stats *rx_stats; -+ int err; - - if (skb->protocol == htons(ETH_P_PAUSE)) - return; - - for (i = 0; i < MACVLAN_HASH_SIZE; i++) { - hlist_for_each_entry_rcu(vlan, n, &port->vlan_hash[i], hlist) { -- dev = vlan->dev; -- rx_stats = per_cpu_ptr(vlan->rx_stats, smp_processor_id()); -- - nskb = skb_clone(skb, GFP_ATOMIC); -- if (nskb == NULL) { -- rx_stats->rx_errors++; -- continue; -- } -- -- rx_stats->rx_bytes += skb->len + ETH_HLEN; -- rx_stats->rx_packets++; -- rx_stats->multicast++; -- -- nskb->dev = dev; -- if (!compare_ether_addr_64bits(eth->h_dest, dev->broadcast)) -- nskb->pkt_type = PACKET_BROADCAST; -- else -- nskb->pkt_type = PACKET_MULTICAST; -- -- netif_rx(nskb); -+ err = macvlan_broadcast_one(nskb, vlan->dev, eth); -+ macvlan_count_rx(vlan, skb->len + ETH_HLEN, -+ err == NET_RX_SUCCESS, 1); - } - } - } -@@ -163,7 +179,7 @@ static struct sk_buff *macvlan_handle_frame(struct sk_buff *skb) - const struct macvlan_port *port; - const struct macvlan_dev *vlan; - struct net_device *dev; -- struct macvlan_rx_stats *rx_stats; -+ unsigned int len; - - port = rcu_dereference(skb->dev->macvlan_port); - if (port == NULL) -@@ -183,15 +199,11 @@ static struct sk_buff *macvlan_handle_frame(struct sk_buff *skb) - kfree_skb(skb); - return NULL; - } -- rx_stats = per_cpu_ptr(vlan->rx_stats, smp_processor_id()); -+ len = skb->len + ETH_HLEN; - skb = skb_share_check(skb, GFP_ATOMIC); -- if (skb == NULL) { -- rx_stats->rx_errors++; -+ macvlan_count_rx(vlan, len, skb != NULL, 0); -+ if (!skb) - return NULL; -- } -- -- rx_stats->rx_bytes += skb->len + ETH_HLEN; -- rx_stats->rx_packets++; - - skb->dev = dev; - skb->pkt_type = PACKET_HOST; --- -1.6.6.2 - diff --git a/debian/patches/features/all/macvlan-export-macvlan-mode-through-netlink.patch b/debian/patches/features/all/macvlan-export-macvlan-mode-through-netlink.patch deleted file mode 100644 index ba7d60cf1..000000000 --- a/debian/patches/features/all/macvlan-export-macvlan-mode-through-netlink.patch +++ /dev/null @@ -1,143 +0,0 @@ -From 27c0b1a850cdea6298f573d835782f3337be913c Mon Sep 17 00:00:00 2001 -From: Arnd Bergmann -Date: Thu, 26 Nov 2009 06:07:11 +0000 -Subject: [PATCH 4/4] macvlan: export macvlan mode through netlink - -In order to support all three modes of macvlan at -runtime, extend the existing netlink protocol -to allow choosing the mode per macvlan slave -interface. - -This depends on a matching patch to iproute2 -in order to become accessible in user land. - -Signed-off-by: Arnd Bergmann -Acked-by: Patrick McHardy -Signed-off-by: David S. Miller ---- - drivers/net/macvlan.c | 56 +++++++++++++++++++++++++++++++++++++++++----- - include/linux/if_link.h | 15 ++++++++++++ - 2 files changed, 65 insertions(+), 6 deletions(-) - -diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c -index d6bd843..322112c 100644 ---- a/drivers/net/macvlan.c -+++ b/drivers/net/macvlan.c -@@ -33,12 +33,6 @@ - - #define MACVLAN_HASH_SIZE (1 << BITS_PER_BYTE) - --enum macvlan_mode { -- MACVLAN_MODE_PRIVATE = 1, -- MACVLAN_MODE_VEPA = 2, -- MACVLAN_MODE_BRIDGE = 4, --}; -- - struct macvlan_port { - struct net_device *dev; - struct hlist_head vlan_hash[MACVLAN_HASH_SIZE]; -@@ -614,6 +608,17 @@ static int macvlan_validate(struct nlattr *tb[], struct nlattr *data[]) - if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS]))) - return -EADDRNOTAVAIL; - } -+ -+ if (data && data[IFLA_MACVLAN_MODE]) { -+ switch (nla_get_u32(data[IFLA_MACVLAN_MODE])) { -+ case MACVLAN_MODE_PRIVATE: -+ case MACVLAN_MODE_VEPA: -+ case MACVLAN_MODE_BRIDGE: -+ break; -+ default: -+ return -EINVAL; -+ } -+ } - return 0; - } - -@@ -678,6 +683,10 @@ static int macvlan_newlink(struct net *src_net, struct net_device *dev, - vlan->dev = dev; - vlan->port = port; - -+ vlan->mode = MACVLAN_MODE_VEPA; -+ if (data && data[IFLA_MACVLAN_MODE]) -+ vlan->mode = nla_get_u32(data[IFLA_MACVLAN_MODE]); -+ - err = register_netdevice(dev); - if (err < 0) - return err; -@@ -699,6 +708,36 @@ static void macvlan_dellink(struct net_device *dev, struct list_head *head) - macvlan_port_destroy(port->dev); - } - -+static int macvlan_changelink(struct net_device *dev, -+ struct nlattr *tb[], struct nlattr *data[]) -+{ -+ struct macvlan_dev *vlan = netdev_priv(dev); -+ if (data && data[IFLA_MACVLAN_MODE]) -+ vlan->mode = nla_get_u32(data[IFLA_MACVLAN_MODE]); -+ return 0; -+} -+ -+static size_t macvlan_get_size(const struct net_device *dev) -+{ -+ return nla_total_size(4); -+} -+ -+static int macvlan_fill_info(struct sk_buff *skb, -+ const struct net_device *dev) -+{ -+ struct macvlan_dev *vlan = netdev_priv(dev); -+ -+ NLA_PUT_U32(skb, IFLA_MACVLAN_MODE, vlan->mode); -+ return 0; -+ -+nla_put_failure: -+ return -EMSGSIZE; -+} -+ -+static const struct nla_policy macvlan_policy[IFLA_MACVLAN_MAX + 1] = { -+ [IFLA_MACVLAN_MODE] = { .type = NLA_U32 }, -+}; -+ - static struct rtnl_link_ops macvlan_link_ops __read_mostly = { - .kind = "macvlan", - .priv_size = sizeof(struct macvlan_dev), -@@ -707,6 +746,11 @@ static struct rtnl_link_ops macvlan_link_ops __read_mostly = { - .validate = macvlan_validate, - .newlink = macvlan_newlink, - .dellink = macvlan_dellink, -+ .maxtype = IFLA_MACVLAN_MAX, -+ .policy = macvlan_policy, -+ .changelink = macvlan_changelink, -+ .get_size = macvlan_get_size, -+ .fill_info = macvlan_fill_info, - }; - - static int macvlan_device_event(struct notifier_block *unused, -diff --git a/include/linux/if_link.h b/include/linux/if_link.h -index 1d3b242..6674791 100644 ---- a/include/linux/if_link.h -+++ b/include/linux/if_link.h -@@ -181,4 +181,19 @@ struct ifla_vlan_qos_mapping { - __u32 to; - }; - -+/* MACVLAN section */ -+enum { -+ IFLA_MACVLAN_UNSPEC, -+ IFLA_MACVLAN_MODE, -+ __IFLA_MACVLAN_MAX, -+}; -+ -+#define IFLA_MACVLAN_MAX (__IFLA_MACVLAN_MAX - 1) -+ -+enum macvlan_mode { -+ MACVLAN_MODE_PRIVATE = 1, /* don't talk to other macvlans */ -+ MACVLAN_MODE_VEPA = 2, /* talk to other ports through ext bridge */ -+ MACVLAN_MODE_BRIDGE = 4, /* talk to bridge ports directly */ -+}; -+ - #endif /* _LINUX_IF_LINK_H */ --- -1.6.6.2 - diff --git a/debian/patches/features/all/macvlan-implement-bridge-VEPA-and-private-mode.patch b/debian/patches/features/all/macvlan-implement-bridge-VEPA-and-private-mode.patch deleted file mode 100644 index 4dcdec0b8..000000000 --- a/debian/patches/features/all/macvlan-implement-bridge-VEPA-and-private-mode.patch +++ /dev/null @@ -1,206 +0,0 @@ -From 618e1b7482f7a8a4c6c6e8ccbe140e4c331df4e9 Mon Sep 17 00:00:00 2001 -From: Arnd Bergmann -Date: Thu, 26 Nov 2009 06:07:10 +0000 -Subject: [PATCH 3/4] macvlan: implement bridge, VEPA and private mode - -This allows each macvlan slave device to be in one -of three modes, depending on the use case: - -MACVLAN_PRIVATE: - The device never communicates with any other device - on the same upper_dev. This even includes frames - coming back from a reflective relay, where supported - by the adjacent bridge. - -MACVLAN_VEPA: - The new Virtual Ethernet Port Aggregator (VEPA) mode, - we assume that the adjacent bridge returns all frames - where both source and destination are local to the - macvlan port, i.e. the bridge is set up as a reflective - relay. - Broadcast frames coming in from the upper_dev get - flooded to all macvlan interfaces in VEPA mode. - We never deliver any frames locally. - -MACVLAN_BRIDGE: - We provide the behavior of a simple bridge between - different macvlan interfaces on the same port. Frames - from one interface to another one get delivered directly - and are not sent out externally. Broadcast frames get - flooded to all other bridge ports and to the external - interface, but when they come back from a reflective - relay, we don't deliver them again. - Since we know all the MAC addresses, the macvlan bridge - mode does not require learning or STP like the bridge - module does. - -Based on an earlier patch "macvlan: Reflect macvlan packets -meant for other macvlan devices" by Eric Biederman. - -Signed-off-by: Arnd Bergmann -Acked-by: Patrick McHardy -Cc: Eric Biederman -Signed-off-by: David S. Miller ---- - drivers/net/macvlan.c | 80 ++++++++++++++++++++++++++++++++++++++++++++----- - 1 files changed, 72 insertions(+), 8 deletions(-) - -diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c -index 1e7faf9..d6bd843 100644 ---- a/drivers/net/macvlan.c -+++ b/drivers/net/macvlan.c -@@ -29,9 +29,16 @@ - #include - #include - #include -+#include - - #define MACVLAN_HASH_SIZE (1 << BITS_PER_BYTE) - -+enum macvlan_mode { -+ MACVLAN_MODE_PRIVATE = 1, -+ MACVLAN_MODE_VEPA = 2, -+ MACVLAN_MODE_BRIDGE = 4, -+}; -+ - struct macvlan_port { - struct net_device *dev; - struct hlist_head vlan_hash[MACVLAN_HASH_SIZE]; -@@ -59,6 +66,7 @@ struct macvlan_dev { - struct macvlan_port *port; - struct net_device *lowerdev; - struct macvlan_rx_stats *rx_stats; -+ enum macvlan_mode mode; - }; - - -@@ -134,11 +142,14 @@ static inline void macvlan_count_rx(const struct macvlan_dev *vlan, - } - - static int macvlan_broadcast_one(struct sk_buff *skb, struct net_device *dev, -- const struct ethhdr *eth) -+ const struct ethhdr *eth, bool local) - { - if (!skb) - return NET_RX_DROP; - -+ if (local) -+ return dev_forward_skb(dev, skb); -+ - skb->dev = dev; - if (!compare_ether_addr_64bits(eth->h_dest, - dev->broadcast)) -@@ -150,7 +161,9 @@ static int macvlan_broadcast_one(struct sk_buff *skb, struct net_device *dev, - } - - static void macvlan_broadcast(struct sk_buff *skb, -- const struct macvlan_port *port) -+ const struct macvlan_port *port, -+ struct net_device *src, -+ enum macvlan_mode mode) - { - const struct ethhdr *eth = eth_hdr(skb); - const struct macvlan_dev *vlan; -@@ -164,8 +177,12 @@ static void macvlan_broadcast(struct sk_buff *skb, - - for (i = 0; i < MACVLAN_HASH_SIZE; i++) { - hlist_for_each_entry_rcu(vlan, n, &port->vlan_hash[i], hlist) { -+ if (vlan->dev == src || !(vlan->mode & mode)) -+ continue; -+ - nskb = skb_clone(skb, GFP_ATOMIC); -- err = macvlan_broadcast_one(nskb, vlan->dev, eth); -+ err = macvlan_broadcast_one(nskb, vlan->dev, eth, -+ mode == MACVLAN_MODE_BRIDGE); - macvlan_count_rx(vlan, skb->len + ETH_HLEN, - err == NET_RX_SUCCESS, 1); - } -@@ -178,6 +195,7 @@ static struct sk_buff *macvlan_handle_frame(struct sk_buff *skb) - const struct ethhdr *eth = eth_hdr(skb); - const struct macvlan_port *port; - const struct macvlan_dev *vlan; -+ const struct macvlan_dev *src; - struct net_device *dev; - unsigned int len; - -@@ -186,7 +204,25 @@ static struct sk_buff *macvlan_handle_frame(struct sk_buff *skb) - return skb; - - if (is_multicast_ether_addr(eth->h_dest)) { -- macvlan_broadcast(skb, port); -+ src = macvlan_hash_lookup(port, eth->h_source); -+ if (!src) -+ /* frame comes from an external address */ -+ macvlan_broadcast(skb, port, NULL, -+ MACVLAN_MODE_PRIVATE | -+ MACVLAN_MODE_VEPA | -+ MACVLAN_MODE_BRIDGE); -+ else if (src->mode == MACVLAN_MODE_VEPA) -+ /* flood to everyone except source */ -+ macvlan_broadcast(skb, port, src->dev, -+ MACVLAN_MODE_VEPA | -+ MACVLAN_MODE_BRIDGE); -+ else if (src->mode == MACVLAN_MODE_BRIDGE) -+ /* -+ * flood only to VEPA ports, bridge ports -+ * already saw the frame on the way out. -+ */ -+ macvlan_broadcast(skb, port, src->dev, -+ MACVLAN_MODE_VEPA); - return skb; - } - -@@ -212,18 +248,46 @@ static struct sk_buff *macvlan_handle_frame(struct sk_buff *skb) - return NULL; - } - -+static int macvlan_queue_xmit(struct sk_buff *skb, struct net_device *dev) -+{ -+ const struct macvlan_dev *vlan = netdev_priv(dev); -+ const struct macvlan_port *port = vlan->port; -+ const struct macvlan_dev *dest; -+ -+ if (vlan->mode == MACVLAN_MODE_BRIDGE) { -+ const struct ethhdr *eth = (void *)skb->data; -+ -+ /* send to other bridge ports directly */ -+ if (is_multicast_ether_addr(eth->h_dest)) { -+ macvlan_broadcast(skb, port, dev, MACVLAN_MODE_BRIDGE); -+ goto xmit_world; -+ } -+ -+ dest = macvlan_hash_lookup(port, eth->h_dest); -+ if (dest && dest->mode == MACVLAN_MODE_BRIDGE) { -+ unsigned int length = skb->len + ETH_HLEN; -+ int ret = dev_forward_skb(dest->dev, skb); -+ macvlan_count_rx(dest, length, -+ ret == NET_RX_SUCCESS, 0); -+ -+ return NET_XMIT_SUCCESS; -+ } -+ } -+ -+xmit_world: -+ skb->dev = vlan->lowerdev; -+ return dev_queue_xmit(skb); -+} -+ - static netdev_tx_t macvlan_start_xmit(struct sk_buff *skb, - struct net_device *dev) - { - int i = skb_get_queue_mapping(skb); - struct netdev_queue *txq = netdev_get_tx_queue(dev, i); -- const struct macvlan_dev *vlan = netdev_priv(dev); - unsigned int len = skb->len; - int ret; - -- skb->dev = vlan->lowerdev; -- ret = dev_queue_xmit(skb); -- -+ ret = macvlan_queue_xmit(skb, dev); - if (likely(ret == NET_XMIT_SUCCESS)) { - txq->tx_packets++; - txq->tx_bytes += len; --- -1.6.6.2 - diff --git a/debian/patches/features/all/module-firmware/0001-netxen-module-firmware-hints.patch b/debian/patches/features/all/module-firmware/0001-netxen-module-firmware-hints.patch deleted file mode 100644 index 0c0dd20f2..000000000 --- a/debian/patches/features/all/module-firmware/0001-netxen-module-firmware-hints.patch +++ /dev/null @@ -1,48 +0,0 @@ -Based on: - -From: Dhananjay Phadke -Subject: [PATCH 01/24] netxen: module firmware hints - -Add MODULE_FIRMWARE hints for various firmware file types, -required by different chip revisions. - ---- a/drivers/net/netxen/netxen_nic.h -+++ b/drivers/net/netxen/netxen_nic.h -@@ -517,6 +517,11 @@ struct uni_data_desc{ - #define NX_P3_MN_ROMIMAGE 2 - #define NX_FLASH_ROMIMAGE 3 - -+#define NX_P2_MN_ROMIMAGE_NAME "nxromimg.bin" -+#define NX_P3_CT_ROMIMAGE_NAME "nx3fwct.bin" -+#define NX_P3_MN_ROMIMAGE_NAME "nx3fwmn.bin" -+#define NX_FLASH_ROMIMAGE_NAME "flash" -+ - extern char netxen_nic_driver_name[]; - - /* Number of status descriptors to handle per interrupt */ ---- a/drivers/net/netxen/netxen_nic_init.c -+++ b/drivers/net/netxen/netxen_nic_init.c -@@ -822,7 +822,10 @@ netxen_need_fw_reset(struct netxen_adapter *adapter) - } - - static char *fw_name[] = { -- "nxromimg.bin", "nx3fwct.bin", "nx3fwmn.bin", "flash", -+ NX_P2_MN_ROMIMAGE_NAME, -+ NX_P3_CT_ROMIMAGE_NAME, -+ NX_P3_MN_ROMIMAGE_NAME, -+ NX_FLASH_ROMIMAGE_NAME, - }; - - int ---- a/drivers/net/netxen/netxen_nic_main.c -+++ b/drivers/net/netxen/netxen_nic_main.c -@@ -39,6 +39,9 @@ - MODULE_DESCRIPTION("QLogic/NetXen (1/10) GbE Converged Ethernet Driver"); - MODULE_LICENSE("GPL"); - MODULE_VERSION(NETXEN_NIC_LINUX_VERSIONID); -+MODULE_FIRMWARE(NX_P2_MN_ROMIMAGE_NAME); -+MODULE_FIRMWARE(NX_P3_CT_ROMIMAGE_NAME); -+MODULE_FIRMWARE(NX_P3_MN_ROMIMAGE_NAME); - - char netxen_nic_driver_name[] = "netxen_nic"; - static char netxen_nic_driver_string[] = "QLogic/NetXen Network Driver v" diff --git a/debian/patches/features/all/module-firmware/0002-netx-declare-MODULE_FIRMWARE.patch b/debian/patches/features/all/module-firmware/0002-netx-declare-MODULE_FIRMWARE.patch deleted file mode 100644 index c2626fd3c..000000000 --- a/debian/patches/features/all/module-firmware/0002-netx-declare-MODULE_FIRMWARE.patch +++ /dev/null @@ -1,26 +0,0 @@ -From 36c04a61f516742dad6f9bad8c6c1a7137a260f5 Mon Sep 17 00:00:00 2001 -From: Ben Hutchings -Date: Sat, 7 Nov 2009 11:37:36 +0000 -Subject: [PATCH 02/24] netx: declare MODULE_FIRMWARE - -Signed-off-by: Ben Hutchings -Acked-by: Sascha Hauer -Signed-off-by: David S. Miller ---- - drivers/net/netx-eth.c | 3 +++ - 1 files changed, 3 insertions(+), 0 deletions(-) - -diff --git a/drivers/net/netx-eth.c b/drivers/net/netx-eth.c -index 9f42354..a0d65f5 100644 ---- a/drivers/net/netx-eth.c -+++ b/drivers/net/netx-eth.c -@@ -510,3 +510,6 @@ module_exit(netx_eth_cleanup); - MODULE_AUTHOR("Sascha Hauer, Pengutronix"); - MODULE_LICENSE("GPL"); - MODULE_ALIAS("platform:" CARDNAME); -+MODULE_FIRMWARE("xc0.bin"); -+MODULE_FIRMWARE("xc1.bin"); -+MODULE_FIRMWARE("xc2.bin"); --- -1.6.5.3 - diff --git a/debian/patches/features/all/module-firmware/0003-solos-pci-declare-MODULE_FIRMWARE.patch b/debian/patches/features/all/module-firmware/0003-solos-pci-declare-MODULE_FIRMWARE.patch deleted file mode 100644 index 9b02e6fe6..000000000 --- a/debian/patches/features/all/module-firmware/0003-solos-pci-declare-MODULE_FIRMWARE.patch +++ /dev/null @@ -1,28 +0,0 @@ -From 9fca79d67031203ab1c3b59807aec261d7bb5539 Mon Sep 17 00:00:00 2001 -From: Ben Hutchings -Date: Sat, 7 Nov 2009 11:40:32 +0000 -Subject: [PATCH 03/24] solos-pci: declare MODULE_FIRMWARE - -Signed-off-by: Ben Hutchings -Signed-off-by: David S. Miller ---- - drivers/atm/solos-pci.c | 3 +++ - 1 files changed, 3 insertions(+), 0 deletions(-) - -diff --git a/drivers/atm/solos-pci.c b/drivers/atm/solos-pci.c -index c5f5186..d7ad19d 100644 ---- a/drivers/atm/solos-pci.c -+++ b/drivers/atm/solos-pci.c -@@ -142,6 +142,9 @@ MODULE_AUTHOR("Traverse Technologies "); - MODULE_DESCRIPTION("Solos PCI driver"); - MODULE_VERSION(VERSION); - MODULE_LICENSE("GPL"); -+MODULE_FIRMWARE("solos-FPGA.bin"); -+MODULE_FIRMWARE("solos-Firmware.bin"); -+MODULE_FIRMWARE("solos-db-FPGA.bin"); - MODULE_PARM_DESC(reset, "Reset Solos chips on startup"); - MODULE_PARM_DESC(atmdebug, "Print ATM data"); - MODULE_PARM_DESC(firmware_upgrade, "Initiate Solos firmware upgrade"); --- -1.6.5.3 - diff --git a/debian/patches/features/all/module-firmware/0004-ambassador-declare-MODULE_FIRMWARE.patch b/debian/patches/features/all/module-firmware/0004-ambassador-declare-MODULE_FIRMWARE.patch deleted file mode 100644 index a0f47d8d9..000000000 --- a/debian/patches/features/all/module-firmware/0004-ambassador-declare-MODULE_FIRMWARE.patch +++ /dev/null @@ -1,26 +0,0 @@ -From e8c0ae2c04372248f2f6940a5984f5748aae9664 Mon Sep 17 00:00:00 2001 -From: Ben Hutchings -Date: Sat, 7 Nov 2009 11:46:07 +0000 -Subject: [PATCH 04/24] ambassador: declare MODULE_FIRMWARE - -Signed-off-by: Ben Hutchings -Signed-off-by: David S. Miller ---- - drivers/atm/ambassador.c | 1 + - 1 files changed, 1 insertions(+), 0 deletions(-) - -diff --git a/drivers/atm/ambassador.c b/drivers/atm/ambassador.c -index 66e1813..8af2341 100644 ---- a/drivers/atm/ambassador.c -+++ b/drivers/atm/ambassador.c -@@ -2351,6 +2351,7 @@ static void __init amb_check_args (void) { - MODULE_AUTHOR(maintainer_string); - MODULE_DESCRIPTION(description_string); - MODULE_LICENSE("GPL"); -+MODULE_FIRMWARE("atmsar11.fw"); - module_param(debug, ushort, 0644); - module_param(cmds, uint, 0); - module_param(txs, uint, 0); --- -1.6.5.3 - diff --git a/debian/patches/features/all/module-firmware/0005-bnx2x-declare-MODULE_FIRMWARE.patch b/debian/patches/features/all/module-firmware/0005-bnx2x-declare-MODULE_FIRMWARE.patch deleted file mode 100644 index 08bf08a92..000000000 --- a/debian/patches/features/all/module-firmware/0005-bnx2x-declare-MODULE_FIRMWARE.patch +++ /dev/null @@ -1,81 +0,0 @@ -From 45229b420f90bb6736dfeb7e491eb46cb02a3e9c Mon Sep 17 00:00:00 2001 -From: Ben Hutchings -Date: Sat, 7 Nov 2009 11:53:39 +0000 -Subject: [PATCH 05/24] bnx2x: declare MODULE_FIRMWARE - -Replace run-time string formatting with preprocessor string -manipulation. - -Signed-off-by: Ben Hutchings -Acked-by: Eilon Greenstein -Signed-off-by: David S. Miller ---- - drivers/net/bnx2x_main.c | 27 ++++++++++++++------------- - 1 files changed, 14 insertions(+), 13 deletions(-) - -diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c -index 61974b7..5b6c68a 100644 ---- a/drivers/net/bnx2x_main.c -+++ b/drivers/net/bnx2x_main.c -@@ -49,6 +49,7 @@ - #include - #include - #include -+#include - - - #include "bnx2x.h" -@@ -63,8 +64,13 @@ - #include - #include "bnx2x_fw_file_hdr.h" - /* FW files */ --#define FW_FILE_PREFIX_E1 "bnx2x-e1-" --#define FW_FILE_PREFIX_E1H "bnx2x-e1h-" -+#define FW_FILE_VERSION \ -+ __stringify(BCM_5710_FW_MAJOR_VERSION) "." \ -+ __stringify(BCM_5710_FW_MINOR_VERSION) "." \ -+ __stringify(BCM_5710_FW_REVISION_VERSION) "." \ -+ __stringify(BCM_5710_FW_ENGINEERING_VERSION) -+#define FW_FILE_NAME_E1 "bnx2x-e1-" FW_FILE_VERSION ".fw" -+#define FW_FILE_NAME_E1H "bnx2x-e1h-" FW_FILE_VERSION ".fw" - - /* Time in jiffies before concluding the transmitter is hung */ - #define TX_TIMEOUT (5*HZ) -@@ -77,6 +83,8 @@ MODULE_AUTHOR("Eliezer Tamir"); - MODULE_DESCRIPTION("Broadcom NetXtreme II BCM57710/57711/57711E Driver"); - MODULE_LICENSE("GPL"); - MODULE_VERSION(DRV_MODULE_VERSION); -+MODULE_FIRMWARE(FW_FILE_NAME_E1); -+MODULE_FIRMWARE(FW_FILE_NAME_E1H); - - static int multi_mode = 1; - module_param(multi_mode, int, 0); -@@ -12111,21 +12119,14 @@ static inline void be16_to_cpu_n(const u8 *_source, u8 *_target, u32 n) - - static int __devinit bnx2x_init_firmware(struct bnx2x *bp, struct device *dev) - { -- char fw_file_name[40] = {0}; -+ const char *fw_file_name; - struct bnx2x_fw_file_hdr *fw_hdr; -- int rc, offset; -+ int rc; - -- /* Create a FW file name */ - if (CHIP_IS_E1(bp)) -- offset = sprintf(fw_file_name, FW_FILE_PREFIX_E1); -+ fw_file_name = FW_FILE_NAME_E1; - else -- offset = sprintf(fw_file_name, FW_FILE_PREFIX_E1H); -- -- sprintf(fw_file_name + offset, "%d.%d.%d.%d.fw", -- BCM_5710_FW_MAJOR_VERSION, -- BCM_5710_FW_MINOR_VERSION, -- BCM_5710_FW_REVISION_VERSION, -- BCM_5710_FW_ENGINEERING_VERSION); -+ fw_file_name = FW_FILE_NAME_E1H; - - printk(KERN_INFO PFX "Loading %s\n", fw_file_name); - --- -1.6.5.3 - diff --git a/debian/patches/features/all/module-firmware/0006-cxgb3-declare-MODULE_FIRMWARE.patch b/debian/patches/features/all/module-firmware/0006-cxgb3-declare-MODULE_FIRMWARE.patch deleted file mode 100644 index 190d9f352..000000000 --- a/debian/patches/features/all/module-firmware/0006-cxgb3-declare-MODULE_FIRMWARE.patch +++ /dev/null @@ -1,103 +0,0 @@ -From 34336ec032878d1a32e7df881f16ce2145e53f83 Mon Sep 17 00:00:00 2001 -From: Ben Hutchings -Date: Sat, 7 Nov 2009 11:53:52 +0000 -Subject: [PATCH 06/24] cxgb3: declare MODULE_FIRMWARE - -Replace run-time string formatting with preprocessor string -manipulation. - -Signed-off-by: Ben Hutchings -Acked-by: Divy Le Ray -Signed-off-by: David S. Miller ---- - drivers/net/cxgb3/common.h | 8 +++----- - drivers/net/cxgb3/cxgb3_main.c | 25 ++++++++++++++++--------- - 2 files changed, 19 insertions(+), 14 deletions(-) - -diff --git a/drivers/net/cxgb3/common.h b/drivers/net/cxgb3/common.h -index 1b2c305..6ff356d 100644 ---- a/drivers/net/cxgb3/common.h -+++ b/drivers/net/cxgb3/common.h -@@ -125,11 +125,9 @@ enum { /* adapter interrupt-maintained statistics */ - IRQ_NUM_STATS /* keep last */ - }; - --enum { -- TP_VERSION_MAJOR = 1, -- TP_VERSION_MINOR = 1, -- TP_VERSION_MICRO = 0 --}; -+#define TP_VERSION_MAJOR 1 -+#define TP_VERSION_MINOR 1 -+#define TP_VERSION_MICRO 0 - - #define S_TP_VERSION_MAJOR 16 - #define M_TP_VERSION_MAJOR 0xFF -diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c -index c9113d3..b1a5a00 100644 ---- a/drivers/net/cxgb3/cxgb3_main.c -+++ b/drivers/net/cxgb3/cxgb3_main.c -@@ -44,6 +44,7 @@ - #include - #include - #include -+#include - #include - - #include "common.h" -@@ -992,11 +993,21 @@ static int bind_qsets(struct adapter *adap) - return err; - } - --#define FW_FNAME "cxgb3/t3fw-%d.%d.%d.bin" --#define TPSRAM_NAME "cxgb3/t3%c_psram-%d.%d.%d.bin" -+#define FW_VERSION __stringify(FW_VERSION_MAJOR) "." \ -+ __stringify(FW_VERSION_MINOR) "." __stringify(FW_VERSION_MICRO) -+#define FW_FNAME "cxgb3/t3fw-" FW_VERSION ".bin" -+#define TPSRAM_VERSION __stringify(TP_VERSION_MAJOR) "." \ -+ __stringify(TP_VERSION_MINOR) "." __stringify(TP_VERSION_MICRO) -+#define TPSRAM_NAME "cxgb3/t3%c_psram-" TPSRAM_VERSION ".bin" - #define AEL2005_OPT_EDC_NAME "cxgb3/ael2005_opt_edc.bin" - #define AEL2005_TWX_EDC_NAME "cxgb3/ael2005_twx_edc.bin" - #define AEL2020_TWX_EDC_NAME "cxgb3/ael2020_twx_edc.bin" -+MODULE_FIRMWARE(FW_FNAME); -+MODULE_FIRMWARE("cxgb3/t3b_psram-" TPSRAM_VERSION ".bin"); -+MODULE_FIRMWARE("cxgb3/t3c_psram-" TPSRAM_VERSION ".bin"); -+MODULE_FIRMWARE(AEL2005_OPT_EDC_NAME); -+MODULE_FIRMWARE(AEL2005_TWX_EDC_NAME); -+MODULE_FIRMWARE(AEL2020_TWX_EDC_NAME); - - static inline const char *get_edc_fw_name(int edc_idx) - { -@@ -1067,16 +1078,13 @@ int t3_get_edc_fw(struct cphy *phy, int edc_idx, int size) - static int upgrade_fw(struct adapter *adap) - { - int ret; -- char buf[64]; - const struct firmware *fw; - struct device *dev = &adap->pdev->dev; - -- snprintf(buf, sizeof(buf), FW_FNAME, FW_VERSION_MAJOR, -- FW_VERSION_MINOR, FW_VERSION_MICRO); -- ret = request_firmware(&fw, buf, dev); -+ ret = request_firmware(&fw, FW_FNAME, dev); - if (ret < 0) { - dev_err(dev, "could not upgrade firmware: unable to load %s\n", -- buf); -+ FW_FNAME); - return ret; - } - ret = t3_load_fw(adap, fw->data, fw->size); -@@ -1120,8 +1128,7 @@ static int update_tpsram(struct adapter *adap) - if (!rev) - return 0; - -- snprintf(buf, sizeof(buf), TPSRAM_NAME, rev, -- TP_VERSION_MAJOR, TP_VERSION_MINOR, TP_VERSION_MICRO); -+ snprintf(buf, sizeof(buf), TPSRAM_NAME, rev); - - ret = request_firmware(&tpsram, buf, dev); - if (ret < 0) { --- -1.6.5.3 - diff --git a/debian/patches/features/all/module-firmware/0007-myri10ge-declare-MODULE_FIRMWARE.patch b/debian/patches/features/all/module-firmware/0007-myri10ge-declare-MODULE_FIRMWARE.patch deleted file mode 100644 index ca6f77ae6..000000000 --- a/debian/patches/features/all/module-firmware/0007-myri10ge-declare-MODULE_FIRMWARE.patch +++ /dev/null @@ -1,29 +0,0 @@ -From b9721d5a2fa00ad979c19a9511d43d2664d5381c Mon Sep 17 00:00:00 2001 -From: Ben Hutchings -Date: Sat, 7 Nov 2009 11:54:44 +0000 -Subject: [PATCH 07/24] myri10ge: declare MODULE_FIRMWARE - -Signed-off-by: Ben Hutchings -Signed-off-by: David S. Miller ---- - drivers/net/myri10ge/myri10ge.c | 4 ++++ - 1 files changed, 4 insertions(+), 0 deletions(-) - -diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c -index 5319db9..85e1b6a 100644 ---- a/drivers/net/myri10ge/myri10ge.c -+++ b/drivers/net/myri10ge/myri10ge.c -@@ -263,6 +263,10 @@ static char *myri10ge_fw_unaligned = "myri10ge_ethp_z8e.dat"; - static char *myri10ge_fw_aligned = "myri10ge_eth_z8e.dat"; - static char *myri10ge_fw_rss_unaligned = "myri10ge_rss_ethp_z8e.dat"; - static char *myri10ge_fw_rss_aligned = "myri10ge_rss_eth_z8e.dat"; -+MODULE_FIRMWARE("myri10ge_ethp_z8e.dat"); -+MODULE_FIRMWARE("myri10ge_eth_z8e.dat"); -+MODULE_FIRMWARE("myri10ge_rss_ethp_z8e.dat"); -+MODULE_FIRMWARE("myri10ge_rss_eth_z8e.dat"); - - static char *myri10ge_fw_name = NULL; - module_param(myri10ge_fw_name, charp, S_IRUGO | S_IWUSR); --- -1.6.5.3 - diff --git a/debian/patches/features/all/module-firmware/0008-spider-net-declare-MODULE_FIRMWARE.patch b/debian/patches/features/all/module-firmware/0008-spider-net-declare-MODULE_FIRMWARE.patch deleted file mode 100644 index 28f6a0983..000000000 --- a/debian/patches/features/all/module-firmware/0008-spider-net-declare-MODULE_FIRMWARE.patch +++ /dev/null @@ -1,26 +0,0 @@ -From 866691a21e8c9dfc58c5ab1ed77d5c41e779755b Mon Sep 17 00:00:00 2001 -From: Ben Hutchings -Date: Sat, 7 Nov 2009 11:55:07 +0000 -Subject: [PATCH 08/24] spider-net: declare MODULE_FIRMWARE - -Signed-off-by: Ben Hutchings -Signed-off-by: David S. Miller ---- - drivers/net/spider_net.c | 1 + - 1 files changed, 1 insertions(+), 0 deletions(-) - -diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c -index 90e663f..782910c 100644 ---- a/drivers/net/spider_net.c -+++ b/drivers/net/spider_net.c -@@ -57,6 +57,7 @@ MODULE_AUTHOR("Utz Bacher and Jens Osterkamp " \ - MODULE_DESCRIPTION("Spider Southbridge Gigabit Ethernet driver"); - MODULE_LICENSE("GPL"); - MODULE_VERSION(VERSION); -+MODULE_FIRMWARE(SPIDER_NET_FIRMWARE_NAME); - - static int rx_descriptors = SPIDER_NET_RX_DESCRIPTORS_DEFAULT; - static int tx_descriptors = SPIDER_NET_TX_DESCRIPTORS_DEFAULT; --- -1.6.5.3 - diff --git a/debian/patches/features/all/module-firmware/0009-tms380tr-declare-MODULE_FIRMWARE.patch b/debian/patches/features/all/module-firmware/0009-tms380tr-declare-MODULE_FIRMWARE.patch deleted file mode 100644 index aa37a4dcb..000000000 --- a/debian/patches/features/all/module-firmware/0009-tms380tr-declare-MODULE_FIRMWARE.patch +++ /dev/null @@ -1,27 +0,0 @@ -From b3ccbb24e8914973be0d2ee7b66e44cecaed9bf5 Mon Sep 17 00:00:00 2001 -From: Ben Hutchings -Date: Sat, 7 Nov 2009 11:55:20 +0000 -Subject: [PATCH 09/24] tms380tr: declare MODULE_FIRMWARE - -Signed-off-by: Ben Hutchings -Signed-off-by: David S. Miller ---- - drivers/net/tokenring/tms380tr.c | 2 ++ - 1 files changed, 2 insertions(+), 0 deletions(-) - -diff --git a/drivers/net/tokenring/tms380tr.c b/drivers/net/tokenring/tms380tr.c -index a7b6888..fa15214 100644 ---- a/drivers/net/tokenring/tms380tr.c -+++ b/drivers/net/tokenring/tms380tr.c -@@ -1364,6 +1364,8 @@ static int tms380tr_reset_adapter(struct net_device *dev) - return (-1); - } - -+MODULE_FIRMWARE("tms380tr.bin"); -+ - /* - * Starts bring up diagnostics of token ring adapter and evaluates - * diagnostic results. --- -1.6.5.3 - diff --git a/debian/patches/features/all/module-firmware/0010-pcnet-cs-declare-MODULE_FIRMWARE.patch b/debian/patches/features/all/module-firmware/0010-pcnet-cs-declare-MODULE_FIRMWARE.patch deleted file mode 100644 index 2c57d3e37..000000000 --- a/debian/patches/features/all/module-firmware/0010-pcnet-cs-declare-MODULE_FIRMWARE.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 8489992e723b5def1a807e615854f51b75d10600 Mon Sep 17 00:00:00 2001 -From: Ben Hutchings -Date: Sat, 7 Nov 2009 12:04:09 +0000 -Subject: [PATCH 10/24] pcnet-cs: declare MODULE_FIRMWARE - -Signed-off-by: Ben Hutchings -Signed-off-by: David S. Miller ---- - drivers/net/pcmcia/pcnet_cs.c | 7 +++++++ - 1 files changed, 7 insertions(+), 0 deletions(-) - -diff --git a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c -index 94c9ad2..4696844 100644 ---- a/drivers/net/pcmcia/pcnet_cs.c -+++ b/drivers/net/pcmcia/pcnet_cs.c -@@ -1768,6 +1768,13 @@ static struct pcmcia_device_id pcnet_ids[] = { - PCMCIA_DEVICE_NULL - }; - MODULE_DEVICE_TABLE(pcmcia, pcnet_ids); -+MODULE_FIRMWARE("cis/PCMLM28.cis"); -+MODULE_FIRMWARE("cis/DP83903.cis"); -+MODULE_FIRMWARE("cis/LA-PCM.cis"); -+MODULE_FIRMWARE("PE520.cis"); -+MODULE_FIRMWARE("cis/NE2K.cis"); -+MODULE_FIRMWARE("cis/PE-200.cis"); -+MODULE_FIRMWARE("cis/tamarack.cis"); - - static struct pcmcia_driver pcnet_driver = { - .drv = { --- -1.6.5.3 - diff --git a/debian/patches/features/all/module-firmware/0011-speedfax-declare-MODULE_FIRMWARE.patch b/debian/patches/features/all/module-firmware/0011-speedfax-declare-MODULE_FIRMWARE.patch deleted file mode 100644 index d42c5bbf7..000000000 --- a/debian/patches/features/all/module-firmware/0011-speedfax-declare-MODULE_FIRMWARE.patch +++ /dev/null @@ -1,26 +0,0 @@ -From 4a9b5e5053a184ada2e9b19aee12b6200bb8980f Mon Sep 17 00:00:00 2001 -From: Ben Hutchings -Date: Tue, 10 Nov 2009 20:30:37 -0800 -Subject: [PATCH 11/24] speedfax: declare MODULE_FIRMWARE - -Signed-off-by: Ben Hutchings -Signed-off-by: David S. Miller ---- - drivers/isdn/hardware/mISDN/speedfax.c | 1 + - 1 files changed, 1 insertions(+), 0 deletions(-) - -diff --git a/drivers/isdn/hardware/mISDN/speedfax.c b/drivers/isdn/hardware/mISDN/speedfax.c -index ff3a4e2..7726afd 100644 ---- a/drivers/isdn/hardware/mISDN/speedfax.c -+++ b/drivers/isdn/hardware/mISDN/speedfax.c -@@ -110,6 +110,7 @@ set_debug(const char *val, struct kernel_param *kp) - MODULE_AUTHOR("Karsten Keil"); - MODULE_LICENSE("GPL v2"); - MODULE_VERSION(SPEEDFAX_REV); -+MODULE_FIRMWARE("isdn/ISAR.BIN"); - module_param_call(debug, set_debug, param_get_uint, &debug, S_IRUGO | S_IWUSR); - MODULE_PARM_DESC(debug, "Speedfax debug mask"); - module_param(irqloops, uint, S_IRUGO | S_IWUSR); --- -1.6.5.3 - diff --git a/debian/patches/features/all/module-firmware/0012-at76c50x-usb-declare-MODULE_FIRMWARE.patch b/debian/patches/features/all/module-firmware/0012-at76c50x-usb-declare-MODULE_FIRMWARE.patch deleted file mode 100644 index fc785dbe0..000000000 --- a/debian/patches/features/all/module-firmware/0012-at76c50x-usb-declare-MODULE_FIRMWARE.patch +++ /dev/null @@ -1,33 +0,0 @@ -From 202982dbf51ece7c2b49dc8b6066ff60cb02bcce Mon Sep 17 00:00:00 2001 -From: Ben Hutchings -Date: Sat, 7 Nov 2009 21:56:08 +0000 -Subject: [PATCH 12/24] at76c50x-usb: declare MODULE_FIRMWARE - -Signed-off-by: Ben Hutchings -Signed-off-by: John W. Linville ---- - drivers/net/wireless/at76c50x-usb.c | 8 ++++++++ - 1 files changed, 8 insertions(+), 0 deletions(-) - -diff --git a/drivers/net/wireless/at76c50x-usb.c b/drivers/net/wireless/at76c50x-usb.c -index e559dc9..0a917e4 100644 ---- a/drivers/net/wireless/at76c50x-usb.c -+++ b/drivers/net/wireless/at76c50x-usb.c -@@ -121,6 +121,14 @@ static struct fwentry firmwares[] = { - [BOARD_505A] = { "atmel_at76c505a-rfmd2958.bin" }, - [BOARD_505AMX] = { "atmel_at76c505amx-rfmd.bin" }, - }; -+MODULE_FIRMWARE("atmel_at76c503-i3861.bin"); -+MODULE_FIRMWARE("atmel_at76c503-i3863.bin"); -+MODULE_FIRMWARE("atmel_at76c503-rfmd.bin"); -+MODULE_FIRMWARE("atmel_at76c503-rfmd-acc.bin"); -+MODULE_FIRMWARE("atmel_at76c505-rfmd.bin"); -+MODULE_FIRMWARE("atmel_at76c505-rfmd2958.bin"); -+MODULE_FIRMWARE("atmel_at76c505a-rfmd2958.bin"); -+MODULE_FIRMWARE("atmel_at76c505amx-rfmd.bin"); - - #define USB_DEVICE_DATA(__ops) .driver_info = (kernel_ulong_t)(__ops) - --- -1.6.5.3 - diff --git a/debian/patches/features/all/module-firmware/0013-atmel-declare-MODULE_FIRMWARE.patch b/debian/patches/features/all/module-firmware/0013-atmel-declare-MODULE_FIRMWARE.patch deleted file mode 100644 index 1fad44cdc..000000000 --- a/debian/patches/features/all/module-firmware/0013-atmel-declare-MODULE_FIRMWARE.patch +++ /dev/null @@ -1,41 +0,0 @@ -From b98a032f6d9d4a5bc17490f67b13e5ca77c8410f Mon Sep 17 00:00:00 2001 -From: Ben Hutchings -Date: Sat, 7 Nov 2009 21:58:05 +0000 -Subject: [PATCH 13/24] atmel: declare MODULE_FIRMWARE - -Signed-off-by: Ben Hutchings -Signed-off-by: John W. Linville ---- - drivers/net/wireless/atmel.c | 16 ++++++++++++++++ - 1 files changed, 16 insertions(+), 0 deletions(-) - -diff --git a/drivers/net/wireless/atmel.c b/drivers/net/wireless/atmel.c -index cce1888..3edbbcf 100644 ---- a/drivers/net/wireless/atmel.c -+++ b/drivers/net/wireless/atmel.c -@@ -99,6 +99,22 @@ static struct { - { ATMEL_FW_TYPE_506, "atmel_at76c506", "bin" }, - { ATMEL_FW_TYPE_NONE, NULL, NULL } - }; -+MODULE_FIRMWARE("atmel_at76c502-wpa.bin"); -+MODULE_FIRMWARE("atmel_at76c502.bin"); -+MODULE_FIRMWARE("atmel_at76c502d-wpa.bin"); -+MODULE_FIRMWARE("atmel_at76c502d.bin"); -+MODULE_FIRMWARE("atmel_at76c502e-wpa.bin"); -+MODULE_FIRMWARE("atmel_at76c502e.bin"); -+MODULE_FIRMWARE("atmel_at76c502_3com-wpa.bin"); -+MODULE_FIRMWARE("atmel_at76c502_3com.bin"); -+MODULE_FIRMWARE("atmel_at76c504-wpa.bin"); -+MODULE_FIRMWARE("atmel_at76c504.bin"); -+MODULE_FIRMWARE("atmel_at76c504_2958-wpa.bin"); -+MODULE_FIRMWARE("atmel_at76c504_2958.bin"); -+MODULE_FIRMWARE("atmel_at76c504a_2958-wpa.bin"); -+MODULE_FIRMWARE("atmel_at76c504a_2958.bin"); -+MODULE_FIRMWARE("atmel_at76c506-wpa.bin"); -+MODULE_FIRMWARE("atmel_at76c506.bin"); - - #define MAX_SSID_LENGTH 32 - #define MGMT_JIFFIES (256 * HZ / 100) --- -1.6.5.3 - diff --git a/debian/patches/features/all/module-firmware/0014-ipw2100-declare-MODULE_FIRMWARE.patch b/debian/patches/features/all/module-firmware/0014-ipw2100-declare-MODULE_FIRMWARE.patch deleted file mode 100644 index 5aeac8591..000000000 --- a/debian/patches/features/all/module-firmware/0014-ipw2100-declare-MODULE_FIRMWARE.patch +++ /dev/null @@ -1,32 +0,0 @@ -From a278ea3e423f7231934ba06a29592cddad8a6663 Mon Sep 17 00:00:00 2001 -From: Ben Hutchings -Date: Sat, 7 Nov 2009 21:58:47 +0000 -Subject: [PATCH 14/24] ipw2100: declare MODULE_FIRMWARE - -Signed-off-by: Ben Hutchings -Acked-by: Zhu Yi -Signed-off-by: John W. Linville ---- - drivers/net/wireless/ipw2x00/ipw2100.c | 6 ++++++ - 1 files changed, 6 insertions(+), 0 deletions(-) - -diff --git a/drivers/net/wireless/ipw2x00/ipw2100.c b/drivers/net/wireless/ipw2x00/ipw2100.c -index 240cff1..a9bc8a9 100644 ---- a/drivers/net/wireless/ipw2x00/ipw2100.c -+++ b/drivers/net/wireless/ipw2x00/ipw2100.c -@@ -8462,6 +8462,12 @@ static int ipw2100_get_firmware(struct ipw2100_priv *priv, - return 0; - } - -+MODULE_FIRMWARE(IPW2100_FW_NAME("-i")); -+#ifdef CONFIG_IPW2100_MONITOR -+MODULE_FIRMWARE(IPW2100_FW_NAME("-p")); -+#endif -+MODULE_FIRMWARE(IPW2100_FW_NAME("")); -+ - static void ipw2100_release_firmware(struct ipw2100_priv *priv, - struct ipw2100_fw *fw) - { --- -1.6.5.3 - diff --git a/debian/patches/features/all/module-firmware/0015-ipw2200-declare-MODULE_FIRMWARE.patch b/debian/patches/features/all/module-firmware/0015-ipw2200-declare-MODULE_FIRMWARE.patch deleted file mode 100644 index f3e4d2a46..000000000 --- a/debian/patches/features/all/module-firmware/0015-ipw2200-declare-MODULE_FIRMWARE.patch +++ /dev/null @@ -1,31 +0,0 @@ -From 873395a9fe15e5c42004e341b7d3632e6a273f73 Mon Sep 17 00:00:00 2001 -From: Ben Hutchings -Date: Sat, 7 Nov 2009 21:59:10 +0000 -Subject: [PATCH 15/24] ipw2200: declare MODULE_FIRMWARE - -Signed-off-by: Ben Hutchings -Acked-by: Zhu Yi -Signed-off-by: John W. Linville ---- - drivers/net/wireless/ipw2x00/ipw2200.c | 5 +++++ - 1 files changed, 5 insertions(+), 0 deletions(-) - -diff --git a/drivers/net/wireless/ipw2x00/ipw2200.c b/drivers/net/wireless/ipw2x00/ipw2200.c -index 61ef890..39808e9 100644 ---- a/drivers/net/wireless/ipw2x00/ipw2200.c -+++ b/drivers/net/wireless/ipw2x00/ipw2200.c -@@ -80,6 +80,11 @@ MODULE_DESCRIPTION(DRV_DESCRIPTION); - MODULE_VERSION(DRV_VERSION); - MODULE_AUTHOR(DRV_COPYRIGHT); - MODULE_LICENSE("GPL"); -+MODULE_FIRMWARE("ipw2200-ibss.fw"); -+#ifdef CONFIG_IPW2200_MONITOR -+MODULE_FIRMWARE("ipw2200-sniffer.fw"); -+#endif -+MODULE_FIRMWARE("ipw2200-bss.fw"); - - static int cmdlog = 0; - static int debug = 0; --- -1.6.5.3 - diff --git a/debian/patches/features/all/module-firmware/0016-iwmc3200wifi-declare-MODULE_FIRMWARE.patch b/debian/patches/features/all/module-firmware/0016-iwmc3200wifi-declare-MODULE_FIRMWARE.patch deleted file mode 100644 index 6b8599a52..000000000 --- a/debian/patches/features/all/module-firmware/0016-iwmc3200wifi-declare-MODULE_FIRMWARE.patch +++ /dev/null @@ -1,28 +0,0 @@ -From 328aca32783cc98088151ce905977c8e899e5fc9 Mon Sep 17 00:00:00 2001 -From: Ben Hutchings -Date: Sat, 7 Nov 2009 21:59:38 +0000 -Subject: [PATCH 16/24] iwmc3200wifi: declare MODULE_FIRMWARE - -Signed-off-by: Ben Hutchings -Signed-off-by: John W. Linville ---- - drivers/net/wireless/iwmc3200wifi/sdio.c | 3 +++ - 1 files changed, 3 insertions(+), 0 deletions(-) - -diff --git a/drivers/net/wireless/iwmc3200wifi/sdio.c b/drivers/net/wireless/iwmc3200wifi/sdio.c -index cf86294..a7ec7ea 100644 ---- a/drivers/net/wireless/iwmc3200wifi/sdio.c -+++ b/drivers/net/wireless/iwmc3200wifi/sdio.c -@@ -399,6 +399,9 @@ static struct iwm_if_ops if_sdio_ops = { - .calib_lmac_name = "iwmc3200wifi-calib-sdio.bin", - .lmac_name = "iwmc3200wifi-lmac-sdio.bin", - }; -+MODULE_FIRMWARE("iwmc3200wifi-umac-sdio.bin"); -+MODULE_FIRMWARE("iwmc3200wifi-calib-sdio.bin"); -+MODULE_FIRMWARE("iwmc3200wifi-lmac-sdio.bin"); - - static int iwm_sdio_probe(struct sdio_func *func, - const struct sdio_device_id *id) --- -1.6.5.3 - diff --git a/debian/patches/features/all/module-firmware/0017-libertas-declare-MODULE_FIRMWARE.patch b/debian/patches/features/all/module-firmware/0017-libertas-declare-MODULE_FIRMWARE.patch deleted file mode 100644 index db260fd25..000000000 --- a/debian/patches/features/all/module-firmware/0017-libertas-declare-MODULE_FIRMWARE.patch +++ /dev/null @@ -1,74 +0,0 @@ -From a974a4bbcb1ceddc9c89defd7dab4da4b2b53d77 Mon Sep 17 00:00:00 2001 -From: Ben Hutchings -Date: Sat, 7 Nov 2009 22:00:03 +0000 -Subject: [PATCH 17/24] libertas: declare MODULE_FIRMWARE - -Signed-off-by: Ben Hutchings -Signed-off-by: John W. Linville ---- - drivers/net/wireless/libertas/if_cs.c | 1 + - drivers/net/wireless/libertas/if_sdio.c | 6 ++++++ - drivers/net/wireless/libertas/if_spi.c | 4 ++++ - drivers/net/wireless/libertas/if_usb.c | 2 ++ - 4 files changed, 13 insertions(+), 0 deletions(-) - -diff --git a/drivers/net/wireless/libertas/if_cs.c b/drivers/net/wireless/libertas/if_cs.c -index 465742f..875516d 100644 ---- a/drivers/net/wireless/libertas/if_cs.c -+++ b/drivers/net/wireless/libertas/if_cs.c -@@ -48,6 +48,7 @@ - MODULE_AUTHOR("Holger Schurig "); - MODULE_DESCRIPTION("Driver for Marvell 83xx compact flash WLAN cards"); - MODULE_LICENSE("GPL"); -+MODULE_FIRMWARE("libertas_cs_helper.fw"); - - - -diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c -index 9716728..09fcfad 100644 ---- a/drivers/net/wireless/libertas/if_sdio.c -+++ b/drivers/net/wireless/libertas/if_sdio.c -@@ -99,6 +99,12 @@ static struct if_sdio_model if_sdio_models[] = { - .firmware = "sd8688.bin", - }, - }; -+MODULE_FIRMWARE("sd8385_helper.bin"); -+MODULE_FIRMWARE("sd8385.bin"); -+MODULE_FIRMWARE("sd8686_helper.bin"); -+MODULE_FIRMWARE("sd8686.bin"); -+MODULE_FIRMWARE("sd8688_helper.bin"); -+MODULE_FIRMWARE("sd8688.bin"); - - struct if_sdio_packet { - struct if_sdio_packet *next; -diff --git a/drivers/net/wireless/libertas/if_spi.c b/drivers/net/wireless/libertas/if_spi.c -index d6a48dd..bf4bfba 100644 ---- a/drivers/net/wireless/libertas/if_spi.c -+++ b/drivers/net/wireless/libertas/if_spi.c -@@ -902,6 +902,10 @@ static int if_spi_calculate_fw_names(u16 card_id, - chip_id_to_device_name[i].name); - return 0; - } -+MODULE_FIRMWARE("libertas/gspi8385_hlp.bin"); -+MODULE_FIRMWARE("libertas/gspi8385.bin"); -+MODULE_FIRMWARE("libertas/gspi8686_hlp.bin"); -+MODULE_FIRMWARE("libertas/gspi8686.bin"); - - static int __devinit if_spi_probe(struct spi_device *spi) - { -diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c -index f12d667..65e1745 100644 ---- a/drivers/net/wireless/libertas/if_usb.c -+++ b/drivers/net/wireless/libertas/if_usb.c -@@ -28,6 +28,8 @@ - static char *lbs_fw_name = "usb8388.bin"; - module_param_named(fw_name, lbs_fw_name, charp, 0644); - -+MODULE_FIRMWARE("usb8388.bin"); -+ - static struct usb_device_id if_usb_table[] = { - /* Enter the device signature inside */ - { USB_DEVICE(0x1286, 0x2001) }, --- -1.6.5.3 - diff --git a/debian/patches/features/all/module-firmware/0018-libertas_tf_usb-declare-MODULE_FIRMWARE.patch b/debian/patches/features/all/module-firmware/0018-libertas_tf_usb-declare-MODULE_FIRMWARE.patch deleted file mode 100644 index 601f6a00d..000000000 --- a/debian/patches/features/all/module-firmware/0018-libertas_tf_usb-declare-MODULE_FIRMWARE.patch +++ /dev/null @@ -1,27 +0,0 @@ -From 790e7560c09a0184afcc00ac0f8df95de7468acc Mon Sep 17 00:00:00 2001 -From: Ben Hutchings -Date: Sat, 7 Nov 2009 22:00:38 +0000 -Subject: [PATCH 18/24] libertas_tf_usb: declare MODULE_FIRMWARE - -Signed-off-by: Ben Hutchings -Signed-off-by: John W. Linville ---- - drivers/net/wireless/libertas_tf/if_usb.c | 2 ++ - 1 files changed, 2 insertions(+), 0 deletions(-) - -diff --git a/drivers/net/wireless/libertas_tf/if_usb.c b/drivers/net/wireless/libertas_tf/if_usb.c -index 392337b..3691c30 100644 ---- a/drivers/net/wireless/libertas_tf/if_usb.c -+++ b/drivers/net/wireless/libertas_tf/if_usb.c -@@ -23,6 +23,8 @@ - static char *lbtf_fw_name = "lbtf_usb.bin"; - module_param_named(fw_name, lbtf_fw_name, charp, 0644); - -+MODULE_FIRMWARE("lbtf_usb.bin"); -+ - static struct usb_device_id if_usb_table[] = { - /* Enter the device signature inside */ - { USB_DEVICE(0x1286, 0x2001) }, --- -1.6.5.3 - diff --git a/debian/patches/features/all/module-firmware/0019-mwl8k-declare-MODULE_FIRMWARE.patch b/debian/patches/features/all/module-firmware/0019-mwl8k-declare-MODULE_FIRMWARE.patch deleted file mode 100644 index 6d7aeebf2..000000000 --- a/debian/patches/features/all/module-firmware/0019-mwl8k-declare-MODULE_FIRMWARE.patch +++ /dev/null @@ -1,28 +0,0 @@ -From 7e75b942f67a13a9980c5e2b4fa1993b20426284 Mon Sep 17 00:00:00 2001 -From: Ben Hutchings -Date: Sat, 7 Nov 2009 22:00:57 +0000 -Subject: [PATCH 19/24] mwl8k: declare MODULE_FIRMWARE - -Signed-off-by: Ben Hutchings -Signed-off-by: John W. Linville ---- - drivers/net/wireless/mwl8k.c | 3 +++ - 1 files changed, 3 insertions(+), 0 deletions(-) - -diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c -index 2ebfee4..9e64dd4 100644 ---- a/drivers/net/wireless/mwl8k.c -+++ b/drivers/net/wireless/mwl8k.c -@@ -400,6 +400,9 @@ static int mwl8k_request_firmware(struct mwl8k_priv *priv) - return 0; - } - -+MODULE_FIRMWARE("mwl8k/helper_8687.fw"); -+MODULE_FIRMWARE("mwl8k/fmimage_8687.fw"); -+ - struct mwl8k_cmd_pkt { - __le16 code; - __le16 length; --- -1.6.5.3 - diff --git a/debian/patches/features/all/module-firmware/0020-orinoco-declare-MODULE_FIRMWARE.patch b/debian/patches/features/all/module-firmware/0020-orinoco-declare-MODULE_FIRMWARE.patch deleted file mode 100644 index f2069e5f8..000000000 --- a/debian/patches/features/all/module-firmware/0020-orinoco-declare-MODULE_FIRMWARE.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 6f48d0e981c026572eac643ed43ebfb883048c14 Mon Sep 17 00:00:00 2001 -From: Ben Hutchings -Date: Sat, 7 Nov 2009 22:01:29 +0000 -Subject: [PATCH 20/24] orinoco: declare MODULE_FIRMWARE - -Signed-off-by: Ben Hutchings -Signed-off-by: Pavel Roskin -Signed-off-by: John W. Linville ---- - drivers/net/wireless/orinoco/fw.c | 6 ++++++ - 1 files changed, 6 insertions(+), 0 deletions(-) - -diff --git a/drivers/net/wireless/orinoco/fw.c b/drivers/net/wireless/orinoco/fw.c -index 1257250..cfa7296 100644 ---- a/drivers/net/wireless/orinoco/fw.c -+++ b/drivers/net/wireless/orinoco/fw.c -@@ -28,6 +28,12 @@ static const struct fw_info orinoco_fw[] = { - { NULL, "prism_sta_fw.bin", "prism_ap_fw.bin", 0, 1024 }, - { "symbol_sp24t_prim_fw", "symbol_sp24t_sec_fw", NULL, 0x00003100, 512 } - }; -+MODULE_FIRMWARE("agere_sta_fw.bin"); -+MODULE_FIRMWARE("agere_ap_fw.bin"); -+MODULE_FIRMWARE("prism_sta_fw.bin"); -+MODULE_FIRMWARE("prism_ap_fw.bin"); -+MODULE_FIRMWARE("symbol_sp24t_prim_fw"); -+MODULE_FIRMWARE("symbol_sp24t_sec_fw"); - - /* Structure used to access fields in FW - * Make sure LE decoding macros are used --- -1.6.5.3 - diff --git a/debian/patches/features/all/module-firmware/0021-prism54-declare-MODULE_FIRMWARE.patch b/debian/patches/features/all/module-firmware/0021-prism54-declare-MODULE_FIRMWARE.patch deleted file mode 100644 index 29da1c9de..000000000 --- a/debian/patches/features/all/module-firmware/0021-prism54-declare-MODULE_FIRMWARE.patch +++ /dev/null @@ -1,28 +0,0 @@ -From a830e6599263aa535e298f5f834f3a119050757f Mon Sep 17 00:00:00 2001 -From: Ben Hutchings -Date: Sat, 7 Nov 2009 22:01:55 +0000 -Subject: [PATCH 21/24] prism54: declare MODULE_FIRMWARE - -Signed-off-by: Ben Hutchings -Signed-off-by: John W. Linville ---- - drivers/net/wireless/prism54/islpci_dev.c | 3 +++ - 1 files changed, 3 insertions(+), 0 deletions(-) - -diff --git a/drivers/net/wireless/prism54/islpci_dev.c b/drivers/net/wireless/prism54/islpci_dev.c -index e26d7b3..3e6a71c 100644 ---- a/drivers/net/wireless/prism54/islpci_dev.c -+++ b/drivers/net/wireless/prism54/islpci_dev.c -@@ -40,6 +40,9 @@ - #define ISL3877_IMAGE_FILE "isl3877" - #define ISL3886_IMAGE_FILE "isl3886" - #define ISL3890_IMAGE_FILE "isl3890" -+MODULE_FIRMWARE(ISL3877_IMAGE_FILE); -+MODULE_FIRMWARE(ISL3886_IMAGE_FILE); -+MODULE_FIRMWARE(ISL3890_IMAGE_FILE); - - static int prism54_bring_down(islpci_private *); - static int islpci_alloc_memory(islpci_private *); --- -1.6.5.3 - diff --git a/debian/patches/features/all/module-firmware/0022-wl12xx-declare-MODULE_FIRMWARE.patch b/debian/patches/features/all/module-firmware/0022-wl12xx-declare-MODULE_FIRMWARE.patch deleted file mode 100644 index 1d092372e..000000000 --- a/debian/patches/features/all/module-firmware/0022-wl12xx-declare-MODULE_FIRMWARE.patch +++ /dev/null @@ -1,17 +0,0 @@ -From: Ben Hutchings -Subject: [PATCH 22/24] wl12xx: declare MODULE_FIRMWARE - ---- a/drivers/net/wireless/wl12xx/wl1251_main.c -+++ b/drivers/net/wireless/wl12xx/wl1251_main.c -@@ -1431,3 +1431,4 @@ MODULE_DESCRIPTION("TI wl1251 Wireles LAN Driver Core"); - MODULE_LICENSE("GPL"); - MODULE_AUTHOR("Kalle Valo "); - MODULE_ALIAS("spi:wl12xx"); -+MODULE_FIRMWARE(WL1251_FW_NAME); ---- a/drivers/net/wireless/wl12xx/wl1271_main.c -+++ b/drivers/net/wireless/wl12xx/wl1271_main.c -@@ -1979,3 +1979,4 @@ module_exit(wl1271_exit); - - MODULE_LICENSE("GPL"); - MODULE_AUTHOR("Luciano Coelho "); -+MODULE_FIRMWARE(WL1271_FW_NAME); diff --git a/debian/patches/features/all/module-firmware/0023-zd1201-declare-MODULE_FIRMWARE.patch b/debian/patches/features/all/module-firmware/0023-zd1201-declare-MODULE_FIRMWARE.patch deleted file mode 100644 index b9dbb2443..000000000 --- a/debian/patches/features/all/module-firmware/0023-zd1201-declare-MODULE_FIRMWARE.patch +++ /dev/null @@ -1,28 +0,0 @@ -From e01b0e0f90681072d29fe1ba6a29298683f42c15 Mon Sep 17 00:00:00 2001 -From: Ben Hutchings -Date: Sat, 7 Nov 2009 22:02:39 +0000 -Subject: [PATCH 23/24] zd1201: declare MODULE_FIRMWARE - -Signed-off-by: Ben Hutchings -Signed-off-by: John W. Linville ---- - drivers/net/wireless/zd1201.c | 3 +++ - 1 files changed, 3 insertions(+), 0 deletions(-) - -diff --git a/drivers/net/wireless/zd1201.c b/drivers/net/wireless/zd1201.c -index bc81974..33c8be7 100644 ---- a/drivers/net/wireless/zd1201.c -+++ b/drivers/net/wireless/zd1201.c -@@ -112,6 +112,9 @@ exit: - return err; - } - -+MODULE_FIRMWARE("zd1201-ap.fw"); -+MODULE_FIRMWARE("zd1201.fw"); -+ - static void zd1201_usbfree(struct urb *urb) - { - struct zd1201 *zd = urb->context; --- -1.6.5.3 - diff --git a/debian/patches/features/all/module-firmware/0024-zd1211rw-declare-MODULE_FIRMWARE.patch b/debian/patches/features/all/module-firmware/0024-zd1211rw-declare-MODULE_FIRMWARE.patch deleted file mode 100644 index c53de8477..000000000 --- a/debian/patches/features/all/module-firmware/0024-zd1211rw-declare-MODULE_FIRMWARE.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 3e8b4d006ed04b1ddb7450faee7fa429e2a00e48 Mon Sep 17 00:00:00 2001 -From: Ben Hutchings -Date: Sat, 7 Nov 2009 22:03:22 +0000 -Subject: [PATCH 24/24] zd1211rw: declare MODULE_FIRMWARE - -Signed-off-by: Ben Hutchings -Signed-off-by: John W. Linville ---- - drivers/net/wireless/zd1211rw/zd_usb.c | 7 +++++++ - 1 files changed, 7 insertions(+), 0 deletions(-) - -diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c -index d46f20a..ac19ecd 100644 ---- a/drivers/net/wireless/zd1211rw/zd_usb.c -+++ b/drivers/net/wireless/zd1211rw/zd_usb.c -@@ -318,6 +318,13 @@ error: - return r; - } - -+MODULE_FIRMWARE(FW_ZD1211B_PREFIX "ur"); -+MODULE_FIRMWARE(FW_ZD1211_PREFIX "ur"); -+MODULE_FIRMWARE(FW_ZD1211B_PREFIX "ub"); -+MODULE_FIRMWARE(FW_ZD1211_PREFIX "ub"); -+MODULE_FIRMWARE(FW_ZD1211B_PREFIX "uphr"); -+MODULE_FIRMWARE(FW_ZD1211_PREFIX "uphr"); -+ - /* Read data from device address space using "firmware interface" which does - * not require firmware to be loaded. */ - int zd_usb_read_fw(struct zd_usb *usb, zd_addr_t addr, u8 *data, u16 len) --- -1.6.5.3 - diff --git a/debian/patches/features/all/module-firmware/0025-tty-declare-MODULE_FIRMWARE-in-various-drivers.patch b/debian/patches/features/all/module-firmware/0025-tty-declare-MODULE_FIRMWARE-in-various-drivers.patch deleted file mode 100644 index 682aaa799..000000000 --- a/debian/patches/features/all/module-firmware/0025-tty-declare-MODULE_FIRMWARE-in-various-drivers.patch +++ /dev/null @@ -1,69 +0,0 @@ -Based on: - -From: Ben Hutchings -Subject: [PATCH] tty: declare MODULE_FIRMWARE in various drivers - ---- a/drivers/char/cyclades.c -+++ b/drivers/char/cyclades.c -@@ -4195,3 +4195,4 @@ module_exit(cy_cleanup_module); - MODULE_LICENSE("GPL"); - MODULE_VERSION(CY_VERSION); - MODULE_ALIAS_CHARDEV_MAJOR(CYCLADES_MAJOR); -+MODULE_FIRMWARE("cyzfirm.bin"); ---- a/drivers/char/ip2/ip2main.c -+++ b/drivers/char/ip2/ip2main.c -@@ -3196,3 +3196,5 @@ static struct pci_device_id ip2main_pci_tbl[] __devinitdata = { - }; - - MODULE_DEVICE_TABLE(pci, ip2main_pci_tbl); -+ -+MODULE_FIRMWARE("intelliport2.bin"); ---- a/drivers/char/isicom.c -+++ b/drivers/char/isicom.c -@@ -1720,3 +1720,8 @@ module_exit(isicom_exit); - MODULE_AUTHOR("MultiTech"); - MODULE_DESCRIPTION("Driver for the ISI series of cards by MultiTech"); - MODULE_LICENSE("GPL"); -+MODULE_FIRMWARE("isi608.bin"); -+MODULE_FIRMWARE("isi608em.bin"); -+MODULE_FIRMWARE("isi616em.bin"); -+MODULE_FIRMWARE("isi4608.bin"); -+MODULE_FIRMWARE("isi4616.bin"); ---- a/drivers/char/moxa.c -+++ b/drivers/char/moxa.c -@@ -172,6 +172,9 @@ static unsigned int numports[MAX_BOARDS]; - MODULE_AUTHOR("William Chen"); - MODULE_DESCRIPTION("MOXA Intellio Family Multiport Board Device Driver"); - MODULE_LICENSE("GPL"); -+MODULE_FIRMWARE("c218tunx.cod"); -+MODULE_FIRMWARE("cp204unx.cod"); -+MODULE_FIRMWARE("c320tunx.cod"); - #ifdef MODULE - module_param_array(type, uint, NULL, 0); - MODULE_PARM_DESC(type, "card type: C218=2, C320=4"); ---- a/drivers/serial/icom.c -+++ b/drivers/serial/icom.c -@@ -1654,4 +1654,6 @@ MODULE_DESCRIPTION("IBM iSeries Serial IOA driver"); - MODULE_SUPPORTED_DEVICE - ("IBM iSeries 2745, 2771, 2772, 2742, 2793 and 2805 Communications adapters"); - MODULE_LICENSE("GPL"); -- -+MODULE_FIRMWARE("icom_call_setup.bin"); -+MODULE_FIRMWARE("icom_res_dce.bin"); -+MODULE_FIRMWARE("icom_asc.bin"); ---- a/drivers/usb/serial/keyspan_pda.c -+++ b/drivers/usb/serial/keyspan_pda.c -@@ -789,6 +789,13 @@ static int keyspan_pda_fake_startup(struct usb_serial *serial) - return 1; - } - -+#ifdef KEYSPAN -+MODULE_FIRMWARE("keyspan_pda/keyspan_pda.fw"); -+#endif -+#ifdef XIRCOM -+MODULE_FIRMWARE("keyspan_pda/xircom_pgs.fw"); -+#endif -+ - static int keyspan_pda_startup(struct usb_serial *serial) - { - diff --git a/debian/patches/features/all/module-firmware/0026-staging-declare-MODULE_FIRMWARE-in-various-drivers.patch b/debian/patches/features/all/module-firmware/0026-staging-declare-MODULE_FIRMWARE-in-various-drivers.patch deleted file mode 100644 index 4f423034f..000000000 --- a/debian/patches/features/all/module-firmware/0026-staging-declare-MODULE_FIRMWARE-in-various-drivers.patch +++ /dev/null @@ -1,97 +0,0 @@ -Based on: - -From: Ben Hutchings -Subject: [PATCH] staging: declare MODULE_FIRMWARE in various drivers - ---- a/drivers/staging/comedi/drivers/jr3_pci.c -+++ b/drivers/staging/comedi/drivers/jr3_pci.c -@@ -954,6 +954,8 @@ out: - return result; - } - -+MODULE_FIRMWARE("comedi/jr3pci.idm"); -+ - static int jr3_pci_detach(struct comedi_device *dev) - { - int i; ---- a/drivers/staging/go7007/go7007-driver.c -+++ b/drivers/staging/go7007/go7007-driver.c -@@ -128,6 +128,8 @@ static int go7007_load_encoder(struct go7007 *go) - return rv; - } - -+MODULE_FIRMWARE("go7007fw.bin"); -+ - /* - * Boot the encoder and register the I2C adapter if requested. Do the - * minimum initialization necessary, since the board-specific code may ---- a/drivers/staging/go7007/go7007-usb.c -+++ b/drivers/staging/go7007/go7007-usb.c -@@ -444,6 +444,8 @@ static struct go7007_usb_board board_sensoray_2250 = { - }, - }; - -+MODULE_FIRMWARE("go7007tv.bin"); -+ - static struct usb_device_id go7007_usb_id_table[] = { - { - .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION | ---- a/drivers/staging/go7007/saa7134-go7007.c -+++ b/drivers/staging/go7007/saa7134-go7007.c -@@ -84,6 +84,7 @@ static struct go7007_board_info board_voyager = { - }, - }, - }; -+MODULE_FIRMWARE("go7007tv.bin"); - - /********************* Driver for GPIO HPI interface *********************/ - ---- a/drivers/staging/rtl8192e/r819xE_firmware.c -+++ b/drivers/staging/rtl8192e/r819xE_firmware.c -@@ -365,3 +365,7 @@ download_firmware_fail: - return rt_status; - - } -+ -+MODULE_FIRMWARE("RTL8192E/boot.img"); -+MODULE_FIRMWARE("RTL8192E/main.img"); -+MODULE_FIRMWARE("RTL8192E/data.img"); ---- a/drivers/staging/rtl8192su/r8192S_firmware.c -+++ b/drivers/staging/rtl8192su/r8192S_firmware.c -@@ -538,3 +538,4 @@ bool FirmwareDownload92S(struct net_device *dev) - return rtStatus; - } - -+MODULE_FIRMWARE("RTL8192SU/rtl8192sfw.bin"); ---- a/drivers/staging/slicoss/slicoss.c -+++ b/drivers/staging/slicoss/slicoss.c -@@ -1866,6 +1866,9 @@ static int slic_card_download_gbrcv(struct adapter *adapter) - return 0; - } - -+MODULE_FIRMWARE("slicoss/oasisrcvucode.sys"); -+MODULE_FIRMWARE("slicoss/gbrcvucode.sys"); -+ - static int slic_card_download(struct adapter *adapter) - { - const struct firmware *fw; -@@ -1977,6 +1980,9 @@ static int slic_card_download(struct adapter *adapter) - return STATUS_SUCCESS; - } - -+MODULE_FIRMWARE("slicoss/oasisdownload.sys"); -+MODULE_FIRMWARE("slicoss/gbdownload.sys"); -+ - static void slic_adapter_set_hwaddr(struct adapter *adapter) - { - struct sliccard *card = adapter->card; ---- a/drivers/staging/wlan-ng/prism2fw.c -+++ b/drivers/staging/wlan-ng/prism2fw.c -@@ -53,6 +53,7 @@ - /* Local Constants */ - - #define PRISM2_USB_FWFILE "prism2_ru.fw" -+MODULE_FIRMWARE(PRISM2_USB_FWFILE); - - #define S3DATA_MAX 5000 - #define S3PLUG_MAX 200 diff --git a/debian/patches/features/all/module-firmware/0027-sep-include-driver-name-in-firmware-filenames.patch b/debian/patches/features/all/module-firmware/0027-sep-include-driver-name-in-firmware-filenames.patch deleted file mode 100644 index 789841e23..000000000 --- a/debian/patches/features/all/module-firmware/0027-sep-include-driver-name-in-firmware-filenames.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 9210aeb3bd3ad862f2063b7128ba4b33799b4092 Mon Sep 17 00:00:00 2001 -From: Ben Hutchings -Date: Sat, 7 Nov 2009 20:09:26 +0000 -Subject: [PATCH] sep: include driver name in firmware filenames - -The current names "cache.image.bin" and "resident.image.bin" are far -too generic. ---- - drivers/staging/sep/sep_driver.c | 4 ++-- - 1 files changed, 2 insertions(+), 2 deletions(-) - -diff --git a/drivers/staging/sep/sep_driver.c b/drivers/staging/sep/sep_driver.c -index e7bc9ec..6b763b7 100644 ---- a/drivers/staging/sep/sep_driver.c -+++ b/drivers/staging/sep/sep_driver.c -@@ -182,8 +182,8 @@ static DECLARE_WAIT_QUEUE_HEAD(sep_event); - static int sep_load_firmware(struct sep_device *sep) - { - const struct firmware *fw; -- char *cache_name = "cache.image.bin"; -- char *res_name = "resident.image.bin"; -+ char *cache_name = "sep/cache.image.bin"; -+ char *res_name = "sep/resident.image.bin"; - int error; - - edbg("SEP Driver:rar_virtual is %p\n", sep->rar_addr); --- -1.6.6 - diff --git a/debian/patches/features/all/module-firmware/0028-sep-declare-MODULE_FIRMWARE.patch b/debian/patches/features/all/module-firmware/0028-sep-declare-MODULE_FIRMWARE.patch deleted file mode 100644 index 4c06ba3de..000000000 --- a/debian/patches/features/all/module-firmware/0028-sep-declare-MODULE_FIRMWARE.patch +++ /dev/null @@ -1,26 +0,0 @@ -From 94820c94108bf46801939d3e342e9a07a81da64e Mon Sep 17 00:00:00 2001 -From: Ben Hutchings -Date: Sat, 7 Nov 2009 20:10:23 +0000 -Subject: [PATCH] sep: declare MODULE_FIRMWARE - ---- - drivers/staging/sep/sep_driver.c | 3 +++ - 1 files changed, 3 insertions(+), 0 deletions(-) - -diff --git a/drivers/staging/sep/sep_driver.c b/drivers/staging/sep/sep_driver.c -index 6b763b7..916a9c1 100644 ---- a/drivers/staging/sep/sep_driver.c -+++ b/drivers/staging/sep/sep_driver.c -@@ -222,6 +222,9 @@ static int sep_load_firmware(struct sep_device *sep) - return 0; - } - -+MODULE_FIRMWARE("sep/cache.image.bin"); -+MODULE_FIRMWARE("sep/resident.image.bin"); -+ - /** - * sep_map_and_alloc_shared_area - allocate shared block - * @sep: security processor --- -1.6.6 - diff --git a/debian/patches/features/all/module-firmware/0029-isight-firmware-declare-MODULE_FIRMWARE.patch b/debian/patches/features/all/module-firmware/0029-isight-firmware-declare-MODULE_FIRMWARE.patch deleted file mode 100644 index 548c290bd..000000000 --- a/debian/patches/features/all/module-firmware/0029-isight-firmware-declare-MODULE_FIRMWARE.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 34e37eaacc94a27d50151d1ab4fae67f1c3ffda5 Mon Sep 17 00:00:00 2001 -From: Ben Hutchings -Date: Sat, 7 Nov 2009 20:21:37 +0000 -Subject: [PATCH] isight-firmware: declare MODULE_FIRMWARE - ---- - drivers/usb/misc/isight_firmware.c | 2 ++ - 1 files changed, 2 insertions(+), 0 deletions(-) - -diff --git a/drivers/usb/misc/isight_firmware.c b/drivers/usb/misc/isight_firmware.c -index b897f65..1a88e27 100644 ---- a/drivers/usb/misc/isight_firmware.c -+++ b/drivers/usb/misc/isight_firmware.c -@@ -112,6 +112,8 @@ out: - return ret; - } - -+MODULE_FIRMWARE("isight.fw"); -+ - static void isight_firmware_disconnect(struct usb_interface *intf) - { - } --- -1.6.6 - diff --git a/debian/patches/features/all/module-firmware/0030-btmrvl-sdio-declare-MODULE_FIRMWARE.patch b/debian/patches/features/all/module-firmware/0030-btmrvl-sdio-declare-MODULE_FIRMWARE.patch deleted file mode 100644 index 1e48133de..000000000 --- a/debian/patches/features/all/module-firmware/0030-btmrvl-sdio-declare-MODULE_FIRMWARE.patch +++ /dev/null @@ -1,24 +0,0 @@ -From 2861453b1b5e022fd5e1294b8fbf39254440b661 Mon Sep 17 00:00:00 2001 -From: Ben Hutchings -Date: Sat, 7 Nov 2009 21:41:18 +0000 -Subject: [PATCH] Bluetooth: Declare MODULE_FIRMWARE for Marvell SDIO driver - -Signed-off-by: Ben Hutchings -Signed-off-by: Marcel Holtmann ---- - drivers/bluetooth/btmrvl_sdio.c | 2 ++ - 1 files changed, 2 insertions(+), 0 deletions(-) - -diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c -index d6aaf51..1e6eb1a 100644 ---- a/drivers/bluetooth/btmrvl_sdio.c -+++ b/drivers/bluetooth/btmrvl_sdio.c -@@ -1003,3 +1003,5 @@ MODULE_AUTHOR("Marvell International Ltd."); - MODULE_DESCRIPTION("Marvell BT-over-SDIO driver ver " VERSION); - MODULE_VERSION(VERSION); - MODULE_LICENSE("GPL v2"); -+MODULE_FIRMWARE("sd8688_helper.bin"); -+MODULE_FIRMWARE("sd8688.bin"); --- -1.6.6 - diff --git a/debian/patches/features/all/r8169-init-phy-return-error.patch b/debian/patches/features/all/r8169-init-phy-return-error.patch deleted file mode 100644 index f15fce26a..000000000 --- a/debian/patches/features/all/r8169-init-phy-return-error.patch +++ /dev/null @@ -1,72 +0,0 @@ -From 3b59832103a30e3c70251667793f90ab3bd1427b Mon Sep 17 00:00:00 2001 -From: Ben Hutchings -Date: Sun, 1 Nov 2009 22:35:15 +0000 -Subject: [PATCH 23/24] r8169: allow rtl_hw_phy_config() and rtl8169_init_phy() to return error codes - -This is preparation for loading PHY firmware, which may fail. ---- - drivers/net/r8169.c | 17 +++++++++++++---- - 1 files changed, 13 insertions(+), 4 deletions(-) - -diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c -index b753f4b..80a9d03 100644 ---- a/drivers/net/r8169.c -+++ b/drivers/net/r8169.c -@@ -1944,7 +1944,7 @@ static void rtl8102e_hw_phy_config(void __iomem *ioaddr) - rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init)); - } - --static void rtl_hw_phy_config(struct net_device *dev) -+static int rtl_hw_phy_config(struct net_device *dev) - { - struct rtl8169_private *tp = netdev_priv(dev); - void __iomem *ioaddr = tp->mmio_addr; -@@ -2013,6 +2013,8 @@ static void rtl_hw_phy_config(struct net_device *dev) - default: - break; - } -+ -+ return 0; - } - - static void rtl8169_phy_timer(unsigned long __opaque) -@@ -2117,11 +2119,14 @@ static void rtl8169_phy_reset(struct net_device *dev, - printk(KERN_ERR "%s: PHY reset failed.\n", dev->name); - } - --static void rtl8169_init_phy(struct net_device *dev, struct rtl8169_private *tp) -+static int rtl8169_init_phy(struct net_device *dev, struct rtl8169_private *tp) - { - void __iomem *ioaddr = tp->mmio_addr; -+ int rc; - -- rtl_hw_phy_config(dev); -+ rc = rtl_hw_phy_config(dev); -+ if (rc) -+ return rc; - - if (tp->mac_version <= RTL_GIGA_MAC_VER_06) { - dprintk("Set MAC Reg C+CR Offset 0x82h = 0x01h\n"); -@@ -2150,6 +2155,8 @@ static void rtl8169_init_phy(struct net_device *dev, struct rtl8169_private *tp) - - if ((RTL_R8(PHYstatus) & TBI_Enable) && netif_msg_link(tp)) - printk(KERN_INFO PFX "%s: TBI auto-negotiating\n", dev->name); -+ -+ return 0; - } - - static void rtl_rar_set(struct rtl8169_private *tp, u8 *addr) -@@ -2536,7 +2543,9 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) - dev->dev_addr[4], dev->dev_addr[5], xid, dev->irq); - } - -- rtl8169_init_phy(dev, tp); -+ rc = rtl8169_init_phy(dev, tp); -+ if (rc) -+ goto err_out_msi_5; - - /* - * Pretend we are using VLANs; This bypasses a nasty bug where --- -1.6.5.2 - diff --git a/debian/patches/features/all/r8169-rtl8168d-1-2-request_firmware.patch b/debian/patches/features/all/r8169-rtl8168d-1-2-request_firmware.patch deleted file mode 100644 index f70753266..000000000 --- a/debian/patches/features/all/r8169-rtl8168d-1-2-request_firmware.patch +++ /dev/null @@ -1,155 +0,0 @@ -From 6902a6e35ad0847c323680b3e12b909e872f0e6b Mon Sep 17 00:00:00 2001 -From: Ben Hutchings -Date: Sun, 1 Nov 2009 22:42:01 +0000 -Subject: [PATCH 24/24] r8169: remove firmware for RTL8169D PHY - -The recently added support for RTL8169D chips included some machine -code without accompanying source code. Replace this with use of the -firmware loader. - -Compile-tested only. ---- - drivers/net/Kconfig | 1 + - drivers/net/r8169.c | 60 ++++++++++++++++++++++++++++++++++++++++---------- - 2 files changed, 49 insertions(+), 12 deletions(-) - -diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig -index e19ca4b..4395c1e 100644 ---- a/drivers/net/Kconfig -+++ b/drivers/net/Kconfig -@@ -2170,6 +2170,7 @@ config R8169 - depends on PCI - select CRC32 - select MII -+ select FW_LOADER - ---help--- - Say Y here if you have a Realtek 8169 PCI Gigabit Ethernet adapter. - -diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c -index 80a9d03..8b6c57f 100644 ---- a/drivers/net/r8169.c -+++ b/drivers/net/r8169.c -@@ -23,6 +23,7 @@ - #include - #include - #include -+#include - - #include - #include -@@ -1359,6 +1360,23 @@ static void rtl_phy_write(void __iomem *ioaddr, struct phy_reg *regs, int len) - } - } - -+struct phy_reg_le { -+ __le16 reg; -+ __le16 val; -+}; -+ -+static void rtl_phy_write_fw(void __iomem *ioaddr, const struct firmware *fw) -+{ -+ const struct phy_reg_le *regs = (const struct phy_reg_le *)fw->data; -+ size_t len = fw->size / sizeof(*regs); -+ -+ while (len-- > 0) { -+ mdio_write(ioaddr, le16_to_cpu(regs->reg), -+ le16_to_cpu(regs->val)); -+ regs++; -+ } -+} -+ - static void rtl8169s_hw_phy_config(void __iomem *ioaddr) - { - struct phy_reg phy_reg_init[] = { -@@ -1691,7 +1709,7 @@ static void rtl8168c_4_hw_phy_config(void __iomem *ioaddr) - rtl8168c_3_hw_phy_config(ioaddr); - } - --static void rtl8168d_1_hw_phy_config(void __iomem *ioaddr) -+static int rtl8168d_1_hw_phy_config(struct rtl8169_private *tp) - { - static struct phy_reg phy_reg_init_0[] = { - { 0x1f, 0x0001 }, -@@ -1719,6 +1737,13 @@ static void rtl8168d_1_hw_phy_config(void __iomem *ioaddr) - { 0x05, 0x8332 }, - { 0x06, 0x5561 } - }; -+ void __iomem *ioaddr = tp->mmio_addr; -+ const struct firmware *fw; -+ int rc; -+ -+ rc = request_firmware(&fw, "rtl8168d-1.fw", &tp->pci_dev->dev); -+ if (rc) -+ return rc; - - rtl_phy_write(ioaddr, phy_reg_init_0, ARRAY_SIZE(phy_reg_init_0)); - -@@ -1776,12 +1801,15 @@ static void rtl8168d_1_hw_phy_config(void __iomem *ioaddr) - mdio_plus_minus(ioaddr, 0x02, 0x0100, 0x0600); - mdio_plus_minus(ioaddr, 0x03, 0x0000, 0xe000); - --#ifdef CONFIG_BROKEN -- rtl_phy_write(ioaddr, phy_reg_init_2, ARRAY_SIZE(phy_reg_init_2)); --#endif -+ rtl_phy_write_fw(ioaddr, fw); -+ -+ release_firmware(fw); -+ return 0; - } - --static void rtl8168d_2_hw_phy_config(void __iomem *ioaddr) -+MODULE_FIRMWARE("rtl8168d-1.fw"); -+ -+static int rtl8168d_2_hw_phy_config(struct rtl8169_private *tp) - { - static struct phy_reg phy_reg_init_0[] = { - { 0x1f, 0x0001 }, -@@ -1808,6 +1836,13 @@ static void rtl8168d_2_hw_phy_config(void __iomem *ioaddr) - { 0x05, 0x8332 }, - { 0x06, 0x5561 } - }; -+ void __iomem *ioaddr = tp->mmio_addr; -+ const struct firmware *fw; -+ int rc; -+ -+ rc = request_firmware(&fw, "rtl8168d-2.fw", &tp->pci_dev->dev); -+ if (rc) -+ return rc; - - rtl_phy_write(ioaddr, phy_reg_init_0, ARRAY_SIZE(phy_reg_init_0)); - -@@ -1861,11 +1896,14 @@ static void rtl8168d_2_hw_phy_config(void __iomem *ioaddr) - mdio_write(ioaddr, 0x1f, 0x0002); - mdio_patch(ioaddr, 0x0f, 0x0017); - --#ifdef CONFIG_BROKEN -- rtl_phy_write(ioaddr, phy_reg_init_1, ARRAY_SIZE(phy_reg_init_1)); --#endif -+ rtl_phy_write_fw(ioaddr, fw); -+ -+ release_firmware(fw); -+ return 0; - } - -+MODULE_FIRMWARE("rtl8168d-2.fw"); -+ - static void rtl8168d_3_hw_phy_config(void __iomem *ioaddr) - { - struct phy_reg phy_reg_init[] = { -@@ -2001,11 +2039,9 @@ static int rtl_hw_phy_config(struct net_device *dev) - rtl8168cp_2_hw_phy_config(ioaddr); - break; - case RTL_GIGA_MAC_VER_25: -- rtl8168d_1_hw_phy_config(ioaddr); -- break; -+ return rtl8168d_1_hw_phy_config(tp); - case RTL_GIGA_MAC_VER_26: -- rtl8168d_2_hw_phy_config(ioaddr); -- break; -+ return rtl8168d_2_hw_phy_config(tp); - case RTL_GIGA_MAC_VER_27: - rtl8168d_3_hw_phy_config(ioaddr); - break; --- -1.6.5.2 - diff --git a/debian/patches/features/all/sfc-2.6.33-rc1.patch b/debian/patches/features/all/sfc-2.6.33-rc1.patch deleted file mode 100644 index bc40014c4..000000000 --- a/debian/patches/features/all/sfc-2.6.33-rc1.patch +++ /dev/null @@ -1,23088 +0,0 @@ -diff --git a/drivers/net/sfc/Kconfig b/drivers/net/sfc/Kconfig -index 260aafa..a65c986 100644 ---- a/drivers/net/sfc/Kconfig -+++ b/drivers/net/sfc/Kconfig -@@ -1,5 +1,5 @@ - config SFC -- tristate "Solarflare Solarstorm SFC4000 support" -+ tristate "Solarflare Solarstorm SFC4000/SFC9000-family support" - depends on PCI && INET - select MDIO - select CRC32 -@@ -7,15 +7,16 @@ config SFC - select I2C_ALGOBIT - help - This driver supports 10-gigabit Ethernet cards based on -- the Solarflare Communications Solarstorm SFC4000 controller. -+ the Solarflare Communications Solarstorm SFC4000 and -+ SFC9000-family controllers. - - To compile this driver as a module, choose M here. The module - will be called sfc. - config SFC_MTD -- bool "Solarflare Solarstorm SFC4000 flash MTD support" -+ bool "Solarflare Solarstorm SFC4000/SFC9000-family MTD support" - depends on SFC && MTD && !(SFC=y && MTD=m) - default y - help -- This exposes the on-board flash memory as an MTD device (e.g. -- /dev/mtd1). This makes it possible to upload new boot code -- to the NIC. -+ This exposes the on-board flash memory as MTD devices (e.g. -+ /dev/mtd1). This makes it possible to upload new firmware -+ to the NIC. -diff --git a/drivers/net/sfc/Makefile b/drivers/net/sfc/Makefile -index b89f9be..1047b19 100644 ---- a/drivers/net/sfc/Makefile -+++ b/drivers/net/sfc/Makefile -@@ -1,6 +1,7 @@ --sfc-y += efx.o falcon.o tx.o rx.o falcon_gmac.o \ -- falcon_xmac.o selftest.o ethtool.o xfp_phy.o \ -- mdio_10g.o tenxpress.o boards.o sfe4001.o -+sfc-y += efx.o nic.o falcon.o siena.o tx.o rx.o \ -+ falcon_gmac.o falcon_xmac.o mcdi_mac.o \ -+ selftest.o ethtool.o qt202x_phy.o mdio_10g.o \ -+ tenxpress.o falcon_boards.o mcdi.o mcdi_phy.o - sfc-$(CONFIG_SFC_MTD) += mtd.o - - obj-$(CONFIG_SFC) += sfc.o -diff --git a/drivers/net/sfc/bitfield.h b/drivers/net/sfc/bitfield.h -index d54d84c..098ac2a 100644 ---- a/drivers/net/sfc/bitfield.h -+++ b/drivers/net/sfc/bitfield.h -@@ -1,7 +1,7 @@ - /**************************************************************************** - * Driver for Solarflare Solarstorm network controllers and boards - * Copyright 2005-2006 Fen Systems Ltd. -- * Copyright 2006-2008 Solarflare Communications Inc. -+ * Copyright 2006-2009 Solarflare Communications Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published -@@ -37,6 +37,8 @@ - #define EFX_DWORD_2_WIDTH 32 - #define EFX_DWORD_3_LBN 96 - #define EFX_DWORD_3_WIDTH 32 -+#define EFX_QWORD_0_LBN 0 -+#define EFX_QWORD_0_WIDTH 64 - - /* Specified attribute (e.g. LBN) of the specified field */ - #define EFX_VAL(field, attribute) field ## _ ## attribute -@@ -520,19 +522,6 @@ typedef union efx_oword { - #define EFX_SET_QWORD_FIELD EFX_SET_QWORD_FIELD32 - #endif - --#define EFX_SET_OWORD_FIELD_VER(efx, oword, field, value) do { \ -- if (falcon_rev(efx) >= FALCON_REV_B0) { \ -- EFX_SET_OWORD_FIELD((oword), field##_B0, (value)); \ -- } else { \ -- EFX_SET_OWORD_FIELD((oword), field##_A1, (value)); \ -- } \ --} while (0) -- --#define EFX_QWORD_FIELD_VER(efx, qword, field) \ -- (falcon_rev(efx) >= FALCON_REV_B0 ? \ -- EFX_QWORD_FIELD((qword), field##_B0) : \ -- EFX_QWORD_FIELD((qword), field##_A1)) -- - /* Used to avoid compiler warnings about shift range exceeding width - * of the data types when dma_addr_t is only 32 bits wide. - */ -diff --git a/drivers/net/sfc/boards.c b/drivers/net/sfc/boards.c -deleted file mode 100644 -index 4a4c74c..0000000 ---- a/drivers/net/sfc/boards.c -+++ /dev/null -@@ -1,328 +0,0 @@ --/**************************************************************************** -- * Driver for Solarflare Solarstorm network controllers and boards -- * Copyright 2007-2008 Solarflare Communications Inc. -- * -- * This program is free software; you can redistribute it and/or modify it -- * under the terms of the GNU General Public License version 2 as published -- * by the Free Software Foundation, incorporated herein by reference. -- */ -- --#include "net_driver.h" --#include "phy.h" --#include "boards.h" --#include "efx.h" --#include "workarounds.h" -- --/* Macros for unpacking the board revision */ --/* The revision info is in host byte order. */ --#define BOARD_TYPE(_rev) (_rev >> 8) --#define BOARD_MAJOR(_rev) ((_rev >> 4) & 0xf) --#define BOARD_MINOR(_rev) (_rev & 0xf) -- --/* Blink support. If the PHY has no auto-blink mode so we hang it off a timer */ --#define BLINK_INTERVAL (HZ/2) -- --static void blink_led_timer(unsigned long context) --{ -- struct efx_nic *efx = (struct efx_nic *)context; -- struct efx_blinker *bl = &efx->board_info.blinker; -- efx->board_info.set_id_led(efx, bl->state); -- bl->state = !bl->state; -- if (bl->resubmit) -- mod_timer(&bl->timer, jiffies + BLINK_INTERVAL); --} -- --static void board_blink(struct efx_nic *efx, bool blink) --{ -- struct efx_blinker *blinker = &efx->board_info.blinker; -- -- /* The rtnl mutex serialises all ethtool ioctls, so -- * nothing special needs doing here. */ -- if (blink) { -- blinker->resubmit = true; -- blinker->state = false; -- setup_timer(&blinker->timer, blink_led_timer, -- (unsigned long)efx); -- mod_timer(&blinker->timer, jiffies + BLINK_INTERVAL); -- } else { -- blinker->resubmit = false; -- if (blinker->timer.function) -- del_timer_sync(&blinker->timer); -- efx->board_info.init_leds(efx); -- } --} -- --/***************************************************************************** -- * Support for LM87 sensor chip used on several boards -- */ --#define LM87_REG_ALARMS1 0x41 --#define LM87_REG_ALARMS2 0x42 --#define LM87_IN_LIMITS(nr, _min, _max) \ -- 0x2B + (nr) * 2, _max, 0x2C + (nr) * 2, _min --#define LM87_AIN_LIMITS(nr, _min, _max) \ -- 0x3B + (nr), _max, 0x1A + (nr), _min --#define LM87_TEMP_INT_LIMITS(_min, _max) \ -- 0x39, _max, 0x3A, _min --#define LM87_TEMP_EXT1_LIMITS(_min, _max) \ -- 0x37, _max, 0x38, _min -- --#define LM87_ALARM_TEMP_INT 0x10 --#define LM87_ALARM_TEMP_EXT1 0x20 -- --#if defined(CONFIG_SENSORS_LM87) || defined(CONFIG_SENSORS_LM87_MODULE) -- --static int efx_init_lm87(struct efx_nic *efx, struct i2c_board_info *info, -- const u8 *reg_values) --{ -- struct i2c_client *client = i2c_new_device(&efx->i2c_adap, info); -- int rc; -- -- if (!client) -- return -EIO; -- -- while (*reg_values) { -- u8 reg = *reg_values++; -- u8 value = *reg_values++; -- rc = i2c_smbus_write_byte_data(client, reg, value); -- if (rc) -- goto err; -- } -- -- efx->board_info.hwmon_client = client; -- return 0; -- --err: -- i2c_unregister_device(client); -- return rc; --} -- --static void efx_fini_lm87(struct efx_nic *efx) --{ -- i2c_unregister_device(efx->board_info.hwmon_client); --} -- --static int efx_check_lm87(struct efx_nic *efx, unsigned mask) --{ -- struct i2c_client *client = efx->board_info.hwmon_client; -- s32 alarms1, alarms2; -- -- /* If link is up then do not monitor temperature */ -- if (EFX_WORKAROUND_7884(efx) && efx->link_up) -- return 0; -- -- alarms1 = i2c_smbus_read_byte_data(client, LM87_REG_ALARMS1); -- alarms2 = i2c_smbus_read_byte_data(client, LM87_REG_ALARMS2); -- if (alarms1 < 0) -- return alarms1; -- if (alarms2 < 0) -- return alarms2; -- alarms1 &= mask; -- alarms2 &= mask >> 8; -- if (alarms1 || alarms2) { -- EFX_ERR(efx, -- "LM87 detected a hardware failure (status %02x:%02x)" -- "%s%s\n", -- alarms1, alarms2, -- (alarms1 & LM87_ALARM_TEMP_INT) ? " INTERNAL" : "", -- (alarms1 & LM87_ALARM_TEMP_EXT1) ? " EXTERNAL" : ""); -- return -ERANGE; -- } -- -- return 0; --} -- --#else /* !CONFIG_SENSORS_LM87 */ -- --static inline int --efx_init_lm87(struct efx_nic *efx, struct i2c_board_info *info, -- const u8 *reg_values) --{ -- return 0; --} --static inline void efx_fini_lm87(struct efx_nic *efx) --{ --} --static inline int efx_check_lm87(struct efx_nic *efx, unsigned mask) --{ -- return 0; --} -- --#endif /* CONFIG_SENSORS_LM87 */ -- --/***************************************************************************** -- * Support for the SFE4002 -- * -- */ --static u8 sfe4002_lm87_channel = 0x03; /* use AIN not FAN inputs */ -- --static const u8 sfe4002_lm87_regs[] = { -- LM87_IN_LIMITS(0, 0x83, 0x91), /* 2.5V: 1.8V +/- 5% */ -- LM87_IN_LIMITS(1, 0x51, 0x5a), /* Vccp1: 1.2V +/- 5% */ -- LM87_IN_LIMITS(2, 0xb6, 0xca), /* 3.3V: 3.3V +/- 5% */ -- LM87_IN_LIMITS(3, 0xb0, 0xc9), /* 5V: 4.6-5.2V */ -- LM87_IN_LIMITS(4, 0xb0, 0xe0), /* 12V: 11-14V */ -- LM87_IN_LIMITS(5, 0x44, 0x4b), /* Vccp2: 1.0V +/- 5% */ -- LM87_AIN_LIMITS(0, 0xa0, 0xb2), /* AIN1: 1.66V +/- 5% */ -- LM87_AIN_LIMITS(1, 0x91, 0xa1), /* AIN2: 1.5V +/- 5% */ -- LM87_TEMP_INT_LIMITS(10, 60), /* board */ -- LM87_TEMP_EXT1_LIMITS(10, 70), /* Falcon */ -- 0 --}; -- --static struct i2c_board_info sfe4002_hwmon_info = { -- I2C_BOARD_INFO("lm87", 0x2e), -- .platform_data = &sfe4002_lm87_channel, --}; -- --/****************************************************************************/ --/* LED allocations. Note that on rev A0 boards the schematic and the reality -- * differ: red and green are swapped. Below is the fixed (A1) layout (there -- * are only 3 A0 boards in existence, so no real reason to make this -- * conditional). -- */ --#define SFE4002_FAULT_LED (2) /* Red */ --#define SFE4002_RX_LED (0) /* Green */ --#define SFE4002_TX_LED (1) /* Amber */ -- --static void sfe4002_init_leds(struct efx_nic *efx) --{ -- /* Set the TX and RX LEDs to reflect status and activity, and the -- * fault LED off */ -- xfp_set_led(efx, SFE4002_TX_LED, -- QUAKE_LED_TXLINK | QUAKE_LED_LINK_ACTSTAT); -- xfp_set_led(efx, SFE4002_RX_LED, -- QUAKE_LED_RXLINK | QUAKE_LED_LINK_ACTSTAT); -- xfp_set_led(efx, SFE4002_FAULT_LED, QUAKE_LED_OFF); --} -- --static void sfe4002_set_id_led(struct efx_nic *efx, bool state) --{ -- xfp_set_led(efx, SFE4002_FAULT_LED, state ? QUAKE_LED_ON : -- QUAKE_LED_OFF); --} -- --static int sfe4002_check_hw(struct efx_nic *efx) --{ -- /* A0 board rev. 4002s report a temperature fault the whole time -- * (bad sensor) so we mask it out. */ -- unsigned alarm_mask = -- (efx->board_info.major == 0 && efx->board_info.minor == 0) ? -- ~LM87_ALARM_TEMP_EXT1 : ~0; -- -- return efx_check_lm87(efx, alarm_mask); --} -- --static int sfe4002_init(struct efx_nic *efx) --{ -- int rc = efx_init_lm87(efx, &sfe4002_hwmon_info, sfe4002_lm87_regs); -- if (rc) -- return rc; -- efx->board_info.monitor = sfe4002_check_hw; -- efx->board_info.init_leds = sfe4002_init_leds; -- efx->board_info.set_id_led = sfe4002_set_id_led; -- efx->board_info.blink = board_blink; -- efx->board_info.fini = efx_fini_lm87; -- return 0; --} -- --/***************************************************************************** -- * Support for the SFN4112F -- * -- */ --static u8 sfn4112f_lm87_channel = 0x03; /* use AIN not FAN inputs */ -- --static const u8 sfn4112f_lm87_regs[] = { -- LM87_IN_LIMITS(0, 0x83, 0x91), /* 2.5V: 1.8V +/- 5% */ -- LM87_IN_LIMITS(1, 0x51, 0x5a), /* Vccp1: 1.2V +/- 5% */ -- LM87_IN_LIMITS(2, 0xb6, 0xca), /* 3.3V: 3.3V +/- 5% */ -- LM87_IN_LIMITS(4, 0xb0, 0xe0), /* 12V: 11-14V */ -- LM87_IN_LIMITS(5, 0x44, 0x4b), /* Vccp2: 1.0V +/- 5% */ -- LM87_AIN_LIMITS(1, 0x91, 0xa1), /* AIN2: 1.5V +/- 5% */ -- LM87_TEMP_INT_LIMITS(10, 60), /* board */ -- LM87_TEMP_EXT1_LIMITS(10, 70), /* Falcon */ -- 0 --}; -- --static struct i2c_board_info sfn4112f_hwmon_info = { -- I2C_BOARD_INFO("lm87", 0x2e), -- .platform_data = &sfn4112f_lm87_channel, --}; -- --#define SFN4112F_ACT_LED 0 --#define SFN4112F_LINK_LED 1 -- --static void sfn4112f_init_leds(struct efx_nic *efx) --{ -- xfp_set_led(efx, SFN4112F_ACT_LED, -- QUAKE_LED_RXLINK | QUAKE_LED_LINK_ACT); -- xfp_set_led(efx, SFN4112F_LINK_LED, -- QUAKE_LED_RXLINK | QUAKE_LED_LINK_STAT); --} -- --static void sfn4112f_set_id_led(struct efx_nic *efx, bool state) --{ -- xfp_set_led(efx, SFN4112F_LINK_LED, -- state ? QUAKE_LED_ON : QUAKE_LED_OFF); --} -- --static int sfn4112f_check_hw(struct efx_nic *efx) --{ -- /* Mask out unused sensors */ -- return efx_check_lm87(efx, ~0x48); --} -- --static int sfn4112f_init(struct efx_nic *efx) --{ -- int rc = efx_init_lm87(efx, &sfn4112f_hwmon_info, sfn4112f_lm87_regs); -- if (rc) -- return rc; -- efx->board_info.monitor = sfn4112f_check_hw; -- efx->board_info.init_leds = sfn4112f_init_leds; -- efx->board_info.set_id_led = sfn4112f_set_id_led; -- efx->board_info.blink = board_blink; -- efx->board_info.fini = efx_fini_lm87; -- return 0; --} -- --/* This will get expanded as board-specific details get moved out of the -- * PHY drivers. */ --struct efx_board_data { -- enum efx_board_type type; -- const char *ref_model; -- const char *gen_type; -- int (*init) (struct efx_nic *nic); --}; -- -- --static struct efx_board_data board_data[] = { -- { EFX_BOARD_SFE4001, "SFE4001", "10GBASE-T adapter", sfe4001_init }, -- { EFX_BOARD_SFE4002, "SFE4002", "XFP adapter", sfe4002_init }, -- { EFX_BOARD_SFN4111T, "SFN4111T", "100/1000/10GBASE-T adapter", -- sfn4111t_init }, -- { EFX_BOARD_SFN4112F, "SFN4112F", "SFP+ adapter", -- sfn4112f_init }, --}; -- --void efx_set_board_info(struct efx_nic *efx, u16 revision_info) --{ -- struct efx_board_data *data = NULL; -- int i; -- -- efx->board_info.type = BOARD_TYPE(revision_info); -- efx->board_info.major = BOARD_MAJOR(revision_info); -- efx->board_info.minor = BOARD_MINOR(revision_info); -- -- for (i = 0; i < ARRAY_SIZE(board_data); i++) -- if (board_data[i].type == efx->board_info.type) -- data = &board_data[i]; -- -- if (data) { -- EFX_INFO(efx, "board is %s rev %c%d\n", -- (efx->pci_dev->subsystem_vendor == EFX_VENDID_SFC) -- ? data->ref_model : data->gen_type, -- 'A' + efx->board_info.major, efx->board_info.minor); -- efx->board_info.init = data->init; -- } else { -- EFX_ERR(efx, "unknown board type %d\n", efx->board_info.type); -- } --} -diff --git a/drivers/net/sfc/boards.h b/drivers/net/sfc/boards.h -deleted file mode 100644 -index 44942de..0000000 ---- a/drivers/net/sfc/boards.h -+++ /dev/null -@@ -1,28 +0,0 @@ --/**************************************************************************** -- * Driver for Solarflare Solarstorm network controllers and boards -- * Copyright 2007-2008 Solarflare Communications Inc. -- * -- * This program is free software; you can redistribute it and/or modify it -- * under the terms of the GNU General Public License version 2 as published -- * by the Free Software Foundation, incorporated herein by reference. -- */ -- --#ifndef EFX_BOARDS_H --#define EFX_BOARDS_H -- --/* Board IDs (must fit in 8 bits) */ --enum efx_board_type { -- EFX_BOARD_SFE4001 = 1, -- EFX_BOARD_SFE4002 = 2, -- EFX_BOARD_SFN4111T = 0x51, -- EFX_BOARD_SFN4112F = 0x52, --}; -- --extern void efx_set_board_info(struct efx_nic *efx, u16 revision_info); -- --/* SFE4001 (10GBASE-T) */ --extern int sfe4001_init(struct efx_nic *efx); --/* SFN4111T (100/1000/10GBASE-T) */ --extern int sfn4111t_init(struct efx_nic *efx); -- --#endif -diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c -index cc4b2f9..f983e3b 100644 ---- a/drivers/net/sfc/efx.c -+++ b/drivers/net/sfc/efx.c -@@ -1,7 +1,7 @@ - /**************************************************************************** - * Driver for Solarflare Solarstorm network controllers and boards - * Copyright 2005-2006 Fen Systems Ltd. -- * Copyright 2005-2008 Solarflare Communications Inc. -+ * Copyright 2005-2009 Solarflare Communications Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published -@@ -21,12 +21,73 @@ - #include - #include - #include "net_driver.h" --#include "ethtool.h" --#include "tx.h" --#include "rx.h" - #include "efx.h" - #include "mdio_10g.h" --#include "falcon.h" -+#include "nic.h" -+ -+#include "mcdi.h" -+ -+/************************************************************************** -+ * -+ * Type name strings -+ * -+ ************************************************************************** -+ */ -+ -+/* Loopback mode names (see LOOPBACK_MODE()) */ -+const unsigned int efx_loopback_mode_max = LOOPBACK_MAX; -+const char *efx_loopback_mode_names[] = { -+ [LOOPBACK_NONE] = "NONE", -+ [LOOPBACK_DATA] = "DATAPATH", -+ [LOOPBACK_GMAC] = "GMAC", -+ [LOOPBACK_XGMII] = "XGMII", -+ [LOOPBACK_XGXS] = "XGXS", -+ [LOOPBACK_XAUI] = "XAUI", -+ [LOOPBACK_GMII] = "GMII", -+ [LOOPBACK_SGMII] = "SGMII", -+ [LOOPBACK_XGBR] = "XGBR", -+ [LOOPBACK_XFI] = "XFI", -+ [LOOPBACK_XAUI_FAR] = "XAUI_FAR", -+ [LOOPBACK_GMII_FAR] = "GMII_FAR", -+ [LOOPBACK_SGMII_FAR] = "SGMII_FAR", -+ [LOOPBACK_XFI_FAR] = "XFI_FAR", -+ [LOOPBACK_GPHY] = "GPHY", -+ [LOOPBACK_PHYXS] = "PHYXS", -+ [LOOPBACK_PCS] = "PCS", -+ [LOOPBACK_PMAPMD] = "PMA/PMD", -+ [LOOPBACK_XPORT] = "XPORT", -+ [LOOPBACK_XGMII_WS] = "XGMII_WS", -+ [LOOPBACK_XAUI_WS] = "XAUI_WS", -+ [LOOPBACK_XAUI_WS_FAR] = "XAUI_WS_FAR", -+ [LOOPBACK_XAUI_WS_NEAR] = "XAUI_WS_NEAR", -+ [LOOPBACK_GMII_WS] = "GMII_WS", -+ [LOOPBACK_XFI_WS] = "XFI_WS", -+ [LOOPBACK_XFI_WS_FAR] = "XFI_WS_FAR", -+ [LOOPBACK_PHYXS_WS] = "PHYXS_WS", -+}; -+ -+/* Interrupt mode names (see INT_MODE())) */ -+const unsigned int efx_interrupt_mode_max = EFX_INT_MODE_MAX; -+const char *efx_interrupt_mode_names[] = { -+ [EFX_INT_MODE_MSIX] = "MSI-X", -+ [EFX_INT_MODE_MSI] = "MSI", -+ [EFX_INT_MODE_LEGACY] = "legacy", -+}; -+ -+const unsigned int efx_reset_type_max = RESET_TYPE_MAX; -+const char *efx_reset_type_names[] = { -+ [RESET_TYPE_INVISIBLE] = "INVISIBLE", -+ [RESET_TYPE_ALL] = "ALL", -+ [RESET_TYPE_WORLD] = "WORLD", -+ [RESET_TYPE_DISABLE] = "DISABLE", -+ [RESET_TYPE_TX_WATCHDOG] = "TX_WATCHDOG", -+ [RESET_TYPE_INT_ERROR] = "INT_ERROR", -+ [RESET_TYPE_RX_RECOVERY] = "RX_RECOVERY", -+ [RESET_TYPE_RX_DESC_FETCH] = "RX_DESC_FETCH", -+ [RESET_TYPE_TX_DESC_FETCH] = "TX_DESC_FETCH", -+ [RESET_TYPE_TX_SKIP] = "TX_SKIP", -+ [RESET_TYPE_MC_FAILURE] = "MC_FAILURE", -+}; - - #define EFX_MAX_MTU (9 * 1024) - -@@ -145,7 +206,8 @@ static void efx_fini_channels(struct efx_nic *efx); - - #define EFX_ASSERT_RESET_SERIALISED(efx) \ - do { \ -- if (efx->state == STATE_RUNNING) \ -+ if ((efx->state == STATE_RUNNING) || \ -+ (efx->state == STATE_DISABLED)) \ - ASSERT_RTNL(); \ - } while (0) - -@@ -171,7 +233,7 @@ static int efx_process_channel(struct efx_channel *channel, int rx_quota) - !channel->enabled)) - return 0; - -- rx_packets = falcon_process_eventq(channel, rx_quota); -+ rx_packets = efx_nic_process_eventq(channel, rx_quota); - if (rx_packets == 0) - return 0; - -@@ -203,7 +265,7 @@ static inline void efx_channel_processed(struct efx_channel *channel) - channel->work_pending = false; - smp_wmb(); - -- falcon_eventq_read_ack(channel); -+ efx_nic_eventq_read_ack(channel); - } - - /* NAPI poll handler -@@ -228,26 +290,20 @@ static int efx_poll(struct napi_struct *napi, int budget) - if (channel->used_flags & EFX_USED_BY_RX && - efx->irq_rx_adaptive && - unlikely(++channel->irq_count == 1000)) { -- unsigned old_irq_moderation = channel->irq_moderation; -- - if (unlikely(channel->irq_mod_score < - irq_adapt_low_thresh)) { -- channel->irq_moderation = -- max_t(int, -- channel->irq_moderation - -- FALCON_IRQ_MOD_RESOLUTION, -- FALCON_IRQ_MOD_RESOLUTION); -+ if (channel->irq_moderation > 1) { -+ channel->irq_moderation -= 1; -+ efx->type->push_irq_moderation(channel); -+ } - } else if (unlikely(channel->irq_mod_score > - irq_adapt_high_thresh)) { -- channel->irq_moderation = -- min(channel->irq_moderation + -- FALCON_IRQ_MOD_RESOLUTION, -- efx->irq_rx_moderation); -+ if (channel->irq_moderation < -+ efx->irq_rx_moderation) { -+ channel->irq_moderation += 1; -+ efx->type->push_irq_moderation(channel); -+ } - } -- -- if (channel->irq_moderation != old_irq_moderation) -- falcon_set_int_moderation(channel); -- - channel->irq_count = 0; - channel->irq_mod_score = 0; - } -@@ -280,7 +336,7 @@ void efx_process_channel_now(struct efx_channel *channel) - BUG_ON(!channel->enabled); - - /* Disable interrupts and wait for ISRs to complete */ -- falcon_disable_interrupts(efx); -+ efx_nic_disable_interrupts(efx); - if (efx->legacy_irq) - synchronize_irq(efx->legacy_irq); - if (channel->irq) -@@ -290,14 +346,14 @@ void efx_process_channel_now(struct efx_channel *channel) - napi_disable(&channel->napi_str); - - /* Poll the channel */ -- efx_process_channel(channel, efx->type->evq_size); -+ efx_process_channel(channel, EFX_EVQ_SIZE); - - /* Ack the eventq. This may cause an interrupt to be generated - * when they are reenabled */ - efx_channel_processed(channel); - - napi_enable(&channel->napi_str); -- falcon_enable_interrupts(efx); -+ efx_nic_enable_interrupts(efx); - } - - /* Create event queue -@@ -309,7 +365,7 @@ static int efx_probe_eventq(struct efx_channel *channel) - { - EFX_LOG(channel->efx, "chan %d create event queue\n", channel->channel); - -- return falcon_probe_eventq(channel); -+ return efx_nic_probe_eventq(channel); - } - - /* Prepare channel's event queue */ -@@ -319,21 +375,21 @@ static void efx_init_eventq(struct efx_channel *channel) - - channel->eventq_read_ptr = 0; - -- falcon_init_eventq(channel); -+ efx_nic_init_eventq(channel); - } - - static void efx_fini_eventq(struct efx_channel *channel) - { - EFX_LOG(channel->efx, "chan %d fini event queue\n", channel->channel); - -- falcon_fini_eventq(channel); -+ efx_nic_fini_eventq(channel); - } - - static void efx_remove_eventq(struct efx_channel *channel) - { - EFX_LOG(channel->efx, "chan %d remove event queue\n", channel->channel); - -- falcon_remove_eventq(channel); -+ efx_nic_remove_eventq(channel); - } - - /************************************************************************** -@@ -499,7 +555,7 @@ static void efx_fini_channels(struct efx_nic *efx) - EFX_ASSERT_RESET_SERIALISED(efx); - BUG_ON(efx->port_enabled); - -- rc = falcon_flush_queues(efx); -+ rc = efx_nic_flush_queues(efx); - if (rc) - EFX_ERR(efx, "failed to flush queues\n"); - else -@@ -547,8 +603,10 @@ void efx_schedule_slow_fill(struct efx_rx_queue *rx_queue, int delay) - * netif_carrier_on/off) of the link status, and also maintains the - * link status's stop on the port's TX queue. - */ --static void efx_link_status_changed(struct efx_nic *efx) -+void efx_link_status_changed(struct efx_nic *efx) - { -+ struct efx_link_state *link_state = &efx->link_state; -+ - /* SFC Bug 5356: A net_dev notifier is registered, so we must ensure - * that no events are triggered between unregister_netdev() and the - * driver unloading. A more general condition is that NETDEV_CHANGE -@@ -561,19 +619,19 @@ static void efx_link_status_changed(struct efx_nic *efx) - return; - } - -- if (efx->link_up != netif_carrier_ok(efx->net_dev)) { -+ if (link_state->up != netif_carrier_ok(efx->net_dev)) { - efx->n_link_state_changes++; - -- if (efx->link_up) -+ if (link_state->up) - netif_carrier_on(efx->net_dev); - else - netif_carrier_off(efx->net_dev); - } - - /* Status message for kernel log */ -- if (efx->link_up) { -+ if (link_state->up) { - EFX_INFO(efx, "link up at %uMbps %s-duplex (MTU %d)%s\n", -- efx->link_speed, efx->link_fd ? "full" : "half", -+ link_state->speed, link_state->fd ? "full" : "half", - efx->net_dev->mtu, - (efx->promiscuous ? " [PROMISC]" : "")); - } else { -@@ -582,16 +640,49 @@ static void efx_link_status_changed(struct efx_nic *efx) - - } - -+void efx_link_set_advertising(struct efx_nic *efx, u32 advertising) -+{ -+ efx->link_advertising = advertising; -+ if (advertising) { -+ if (advertising & ADVERTISED_Pause) -+ efx->wanted_fc |= (EFX_FC_TX | EFX_FC_RX); -+ else -+ efx->wanted_fc &= ~(EFX_FC_TX | EFX_FC_RX); -+ if (advertising & ADVERTISED_Asym_Pause) -+ efx->wanted_fc ^= EFX_FC_TX; -+ } -+} -+ -+void efx_link_set_wanted_fc(struct efx_nic *efx, enum efx_fc_type wanted_fc) -+{ -+ efx->wanted_fc = wanted_fc; -+ if (efx->link_advertising) { -+ if (wanted_fc & EFX_FC_RX) -+ efx->link_advertising |= (ADVERTISED_Pause | -+ ADVERTISED_Asym_Pause); -+ else -+ efx->link_advertising &= ~(ADVERTISED_Pause | -+ ADVERTISED_Asym_Pause); -+ if (wanted_fc & EFX_FC_TX) -+ efx->link_advertising ^= ADVERTISED_Asym_Pause; -+ } -+} -+ - static void efx_fini_port(struct efx_nic *efx); - --/* This call reinitialises the MAC to pick up new PHY settings. The -- * caller must hold the mac_lock */ --void __efx_reconfigure_port(struct efx_nic *efx) -+/* Push loopback/power/transmit disable settings to the PHY, and reconfigure -+ * the MAC appropriately. All other PHY configuration changes are pushed -+ * through phy_op->set_settings(), and pushed asynchronously to the MAC -+ * through efx_monitor(). -+ * -+ * Callers must hold the mac_lock -+ */ -+int __efx_reconfigure_port(struct efx_nic *efx) - { -- WARN_ON(!mutex_is_locked(&efx->mac_lock)); -+ enum efx_phy_mode phy_mode; -+ int rc; - -- EFX_LOG(efx, "reconfiguring MAC from PHY settings on CPU %d\n", -- raw_smp_processor_id()); -+ WARN_ON(!mutex_is_locked(&efx->mac_lock)); - - /* Serialise the promiscuous flag with efx_set_multicast_list. */ - if (efx_dev_registered(efx)) { -@@ -599,61 +690,48 @@ void __efx_reconfigure_port(struct efx_nic *efx) - netif_addr_unlock_bh(efx->net_dev); - } - -- falcon_deconfigure_mac_wrapper(efx); -- -- /* Reconfigure the PHY, disabling transmit in mac level loopback. */ -+ /* Disable PHY transmit in mac level loopbacks */ -+ phy_mode = efx->phy_mode; - if (LOOPBACK_INTERNAL(efx)) - efx->phy_mode |= PHY_MODE_TX_DISABLED; - else - efx->phy_mode &= ~PHY_MODE_TX_DISABLED; -- efx->phy_op->reconfigure(efx); - -- if (falcon_switch_mac(efx)) -- goto fail; -+ rc = efx->type->reconfigure_port(efx); - -- efx->mac_op->reconfigure(efx); -- -- /* Inform kernel of loss/gain of carrier */ -- efx_link_status_changed(efx); -- return; -+ if (rc) -+ efx->phy_mode = phy_mode; - --fail: -- EFX_ERR(efx, "failed to reconfigure MAC\n"); -- efx->port_enabled = false; -- efx_fini_port(efx); -+ return rc; - } - - /* Reinitialise the MAC to pick up new PHY settings, even if the port is - * disabled. */ --void efx_reconfigure_port(struct efx_nic *efx) -+int efx_reconfigure_port(struct efx_nic *efx) - { -+ int rc; -+ - EFX_ASSERT_RESET_SERIALISED(efx); - - mutex_lock(&efx->mac_lock); -- __efx_reconfigure_port(efx); -+ rc = __efx_reconfigure_port(efx); - mutex_unlock(&efx->mac_lock); --} -- --/* Asynchronous efx_reconfigure_port work item. To speed up efx_flush_all() -- * we don't efx_reconfigure_port() if the port is disabled. Care is taken -- * in efx_stop_all() and efx_start_port() to prevent PHY events being lost */ --static void efx_phy_work(struct work_struct *data) --{ -- struct efx_nic *efx = container_of(data, struct efx_nic, phy_work); - -- mutex_lock(&efx->mac_lock); -- if (efx->port_enabled) -- __efx_reconfigure_port(efx); -- mutex_unlock(&efx->mac_lock); -+ return rc; - } - -+/* Asynchronous work item for changing MAC promiscuity and multicast -+ * hash. Avoid a drain/rx_ingress enable by reconfiguring the current -+ * MAC directly. */ - static void efx_mac_work(struct work_struct *data) - { - struct efx_nic *efx = container_of(data, struct efx_nic, mac_work); - - mutex_lock(&efx->mac_lock); -- if (efx->port_enabled) -- efx->mac_op->irq(efx); -+ if (efx->port_enabled) { -+ efx->type->push_multicast_hash(efx); -+ efx->mac_op->reconfigure(efx); -+ } - mutex_unlock(&efx->mac_lock); - } - -@@ -663,8 +741,8 @@ static int efx_probe_port(struct efx_nic *efx) - - EFX_LOG(efx, "create port\n"); - -- /* Connect up MAC/PHY operations table and read MAC address */ -- rc = falcon_probe_port(efx); -+ /* Connect up MAC/PHY operations table */ -+ rc = efx->type->probe_port(efx); - if (rc) - goto err; - -@@ -699,29 +777,33 @@ static int efx_init_port(struct efx_nic *efx) - - EFX_LOG(efx, "init port\n"); - -- rc = efx->phy_op->init(efx); -- if (rc) -- return rc; - mutex_lock(&efx->mac_lock); -- efx->phy_op->reconfigure(efx); -- rc = falcon_switch_mac(efx); -- mutex_unlock(&efx->mac_lock); -+ -+ rc = efx->phy_op->init(efx); - if (rc) -- goto fail; -- efx->mac_op->reconfigure(efx); -+ goto fail1; - - efx->port_initialized = true; -- efx_stats_enable(efx); -+ -+ /* Reconfigure the MAC before creating dma queues (required for -+ * Falcon/A1 where RX_INGR_EN/TX_DRAIN_EN isn't supported) */ -+ efx->mac_op->reconfigure(efx); -+ -+ /* Ensure the PHY advertises the correct flow control settings */ -+ rc = efx->phy_op->reconfigure(efx); -+ if (rc) -+ goto fail2; -+ -+ mutex_unlock(&efx->mac_lock); - return 0; - --fail: -+fail2: - efx->phy_op->fini(efx); -+fail1: -+ mutex_unlock(&efx->mac_lock); - return rc; - } - --/* Allow efx_reconfigure_port() to be scheduled, and close the window -- * between efx_stop_port and efx_flush_all whereby a previously scheduled -- * efx_phy_work()/efx_mac_work() may have been cancelled */ - static void efx_start_port(struct efx_nic *efx) - { - EFX_LOG(efx, "start port\n"); -@@ -729,15 +811,16 @@ static void efx_start_port(struct efx_nic *efx) - - mutex_lock(&efx->mac_lock); - efx->port_enabled = true; -- __efx_reconfigure_port(efx); -- efx->mac_op->irq(efx); -+ -+ /* efx_mac_work() might have been scheduled after efx_stop_port(), -+ * and then cancelled by efx_flush_all() */ -+ efx->type->push_multicast_hash(efx); -+ efx->mac_op->reconfigure(efx); -+ - mutex_unlock(&efx->mac_lock); - } - --/* Prevent efx_phy_work, efx_mac_work, and efx_monitor() from executing, -- * and efx_set_multicast_list() from scheduling efx_phy_work. efx_phy_work -- * and efx_mac_work may still be scheduled via NAPI processing until -- * efx_flush_all() is called */ -+/* Prevent efx_mac_work() and efx_monitor() from working */ - static void efx_stop_port(struct efx_nic *efx) - { - EFX_LOG(efx, "stop port\n"); -@@ -760,11 +843,10 @@ static void efx_fini_port(struct efx_nic *efx) - if (!efx->port_initialized) - return; - -- efx_stats_disable(efx); - efx->phy_op->fini(efx); - efx->port_initialized = false; - -- efx->link_up = false; -+ efx->link_state.up = false; - efx_link_status_changed(efx); - } - -@@ -772,7 +854,7 @@ static void efx_remove_port(struct efx_nic *efx) - { - EFX_LOG(efx, "destroying port\n"); - -- falcon_remove_port(efx); -+ efx->type->remove_port(efx); - } - - /************************************************************************** -@@ -824,9 +906,8 @@ static int efx_init_io(struct efx_nic *efx) - goto fail2; - } - -- efx->membase_phys = pci_resource_start(efx->pci_dev, -- efx->type->mem_bar); -- rc = pci_request_region(pci_dev, efx->type->mem_bar, "sfc"); -+ efx->membase_phys = pci_resource_start(efx->pci_dev, EFX_MEM_BAR); -+ rc = pci_request_region(pci_dev, EFX_MEM_BAR, "sfc"); - if (rc) { - EFX_ERR(efx, "request for memory BAR failed\n"); - rc = -EIO; -@@ -835,21 +916,20 @@ static int efx_init_io(struct efx_nic *efx) - efx->membase = ioremap_nocache(efx->membase_phys, - efx->type->mem_map_size); - if (!efx->membase) { -- EFX_ERR(efx, "could not map memory BAR %d at %llx+%x\n", -- efx->type->mem_bar, -+ EFX_ERR(efx, "could not map memory BAR at %llx+%x\n", - (unsigned long long)efx->membase_phys, - efx->type->mem_map_size); - rc = -ENOMEM; - goto fail4; - } -- EFX_LOG(efx, "memory BAR %u at %llx+%x (virtual %p)\n", -- efx->type->mem_bar, (unsigned long long)efx->membase_phys, -+ EFX_LOG(efx, "memory BAR at %llx+%x (virtual %p)\n", -+ (unsigned long long)efx->membase_phys, - efx->type->mem_map_size, efx->membase); - - return 0; - - fail4: -- pci_release_region(efx->pci_dev, efx->type->mem_bar); -+ pci_release_region(efx->pci_dev, EFX_MEM_BAR); - fail3: - efx->membase_phys = 0; - fail2: -@@ -868,7 +948,7 @@ static void efx_fini_io(struct efx_nic *efx) - } - - if (efx->membase_phys) { -- pci_release_region(efx->pci_dev, efx->type->mem_bar); -+ pci_release_region(efx->pci_dev, EFX_MEM_BAR); - efx->membase_phys = 0; - } - -@@ -1011,7 +1091,7 @@ static int efx_probe_nic(struct efx_nic *efx) - EFX_LOG(efx, "creating NIC\n"); - - /* Carry out hardware-type specific initialisation */ -- rc = falcon_probe_nic(efx); -+ rc = efx->type->probe(efx); - if (rc) - return rc; - -@@ -1032,7 +1112,7 @@ static void efx_remove_nic(struct efx_nic *efx) - EFX_LOG(efx, "destroying NIC\n"); - - efx_remove_interrupts(efx); -- falcon_remove_nic(efx); -+ efx->type->remove(efx); - } - - /************************************************************************** -@@ -1112,12 +1192,31 @@ static void efx_start_all(struct efx_nic *efx) - efx_for_each_channel(channel, efx) - efx_start_channel(channel); - -- falcon_enable_interrupts(efx); -- -- /* Start hardware monitor if we're in RUNNING */ -- if (efx->state == STATE_RUNNING) -+ efx_nic_enable_interrupts(efx); -+ -+ /* Switch to event based MCDI completions after enabling interrupts. -+ * If a reset has been scheduled, then we need to stay in polled mode. -+ * Rather than serialising efx_mcdi_mode_event() [which sleeps] and -+ * reset_pending [modified from an atomic context], we instead guarantee -+ * that efx_mcdi_mode_poll() isn't reverted erroneously */ -+ efx_mcdi_mode_event(efx); -+ if (efx->reset_pending != RESET_TYPE_NONE) -+ efx_mcdi_mode_poll(efx); -+ -+ /* Start the hardware monitor if there is one. Otherwise (we're link -+ * event driven), we have to poll the PHY because after an event queue -+ * flush, we could have a missed a link state change */ -+ if (efx->type->monitor != NULL) { - queue_delayed_work(efx->workqueue, &efx->monitor_work, - efx_monitor_interval); -+ } else { -+ mutex_lock(&efx->mac_lock); -+ if (efx->phy_op->poll(efx)) -+ efx_link_status_changed(efx); -+ mutex_unlock(&efx->mac_lock); -+ } -+ -+ efx->type->start_stats(efx); - } - - /* Flush all delayed work. Should only be called when no more delayed work -@@ -1136,8 +1235,6 @@ static void efx_flush_all(struct efx_nic *efx) - - /* Stop scheduled port reconfigurations */ - cancel_work_sync(&efx->mac_work); -- cancel_work_sync(&efx->phy_work); -- - } - - /* Quiesce hardware and software without bringing the link down. -@@ -1155,8 +1252,13 @@ static void efx_stop_all(struct efx_nic *efx) - if (!efx->port_enabled) - return; - -+ efx->type->stop_stats(efx); -+ -+ /* Switch to MCDI polling on Siena before disabling interrupts */ -+ efx_mcdi_mode_poll(efx); -+ - /* Disable interrupts and wait for ISR to complete */ -- falcon_disable_interrupts(efx); -+ efx_nic_disable_interrupts(efx); - if (efx->legacy_irq) - synchronize_irq(efx->legacy_irq); - efx_for_each_channel(channel, efx) { -@@ -1173,15 +1275,9 @@ static void efx_stop_all(struct efx_nic *efx) - * window to loose phy events */ - efx_stop_port(efx); - -- /* Flush efx_phy_work, efx_mac_work, refill_workqueue, monitor_work */ -+ /* Flush efx_mac_work(), refill_workqueue, monitor_work */ - efx_flush_all(efx); - -- /* Isolate the MAC from the TX and RX engines, so that queue -- * flushes will complete in a timely fashion. */ -- falcon_deconfigure_mac_wrapper(efx); -- msleep(10); /* Let the Rx FIFO drain */ -- falcon_drain_tx_fifo(efx); -- - /* Stop the kernel transmit interface late, so the watchdog - * timer isn't ticking over the flush */ - if (efx_dev_registered(efx)) { -@@ -1201,41 +1297,39 @@ static void efx_remove_all(struct efx_nic *efx) - efx_remove_nic(efx); - } - --/* A convinience function to safely flush all the queues */ --void efx_flush_queues(struct efx_nic *efx) --{ -- EFX_ASSERT_RESET_SERIALISED(efx); -- -- efx_stop_all(efx); -- -- efx_fini_channels(efx); -- efx_init_channels(efx); -- -- efx_start_all(efx); --} -- - /************************************************************************** - * - * Interrupt moderation - * - **************************************************************************/ - -+static unsigned irq_mod_ticks(int usecs, int resolution) -+{ -+ if (usecs <= 0) -+ return 0; /* cannot receive interrupts ahead of time :-) */ -+ if (usecs < resolution) -+ return 1; /* never round down to 0 */ -+ return usecs / resolution; -+} -+ - /* Set interrupt moderation parameters */ - void efx_init_irq_moderation(struct efx_nic *efx, int tx_usecs, int rx_usecs, - bool rx_adaptive) - { - struct efx_tx_queue *tx_queue; - struct efx_rx_queue *rx_queue; -+ unsigned tx_ticks = irq_mod_ticks(tx_usecs, EFX_IRQ_MOD_RESOLUTION); -+ unsigned rx_ticks = irq_mod_ticks(rx_usecs, EFX_IRQ_MOD_RESOLUTION); - - EFX_ASSERT_RESET_SERIALISED(efx); - - efx_for_each_tx_queue(tx_queue, efx) -- tx_queue->channel->irq_moderation = tx_usecs; -+ tx_queue->channel->irq_moderation = tx_ticks; - - efx->irq_rx_adaptive = rx_adaptive; -- efx->irq_rx_moderation = rx_usecs; -+ efx->irq_rx_moderation = rx_ticks; - efx_for_each_rx_queue(rx_queue, efx) -- rx_queue->channel->irq_moderation = rx_usecs; -+ rx_queue->channel->irq_moderation = rx_ticks; - } - - /************************************************************************** -@@ -1250,10 +1344,10 @@ static void efx_monitor(struct work_struct *data) - { - struct efx_nic *efx = container_of(data, struct efx_nic, - monitor_work.work); -- int rc; - - EFX_TRACE(efx, "hardware monitor executing on CPU %d\n", - raw_smp_processor_id()); -+ BUG_ON(efx->type->monitor == NULL); - - /* If the mac_lock is already held then it is likely a port - * reconfiguration is already in place, which will likely do -@@ -1262,15 +1356,7 @@ static void efx_monitor(struct work_struct *data) - goto out_requeue; - if (!efx->port_enabled) - goto out_unlock; -- rc = efx->board_info.monitor(efx); -- if (rc) { -- EFX_ERR(efx, "Board sensor %s; shutting down PHY\n", -- (rc == -ERANGE) ? "reported fault" : "failed"); -- efx->phy_mode |= PHY_MODE_LOW_POWER; -- falcon_sim_phy_event(efx); -- } -- efx->phy_op->poll(efx); -- efx->mac_op->poll(efx); -+ efx->type->monitor(efx); - - out_unlock: - mutex_unlock(&efx->mac_lock); -@@ -1374,6 +1460,12 @@ static int efx_net_open(struct net_device *net_dev) - return -EIO; - if (efx->phy_mode & PHY_MODE_SPECIAL) - return -EBUSY; -+ if (efx_mcdi_poll_reboot(efx) && efx_reset(efx, RESET_TYPE_ALL)) -+ return -EIO; -+ -+ /* Notify the kernel of the link state polled during driver load, -+ * before the monitor starts running */ -+ efx_link_status_changed(efx); - - efx_start_all(efx); - return 0; -@@ -1400,20 +1492,6 @@ static int efx_net_stop(struct net_device *net_dev) - return 0; - } - --void efx_stats_disable(struct efx_nic *efx) --{ -- spin_lock(&efx->stats_lock); -- ++efx->stats_disable_count; -- spin_unlock(&efx->stats_lock); --} -- --void efx_stats_enable(struct efx_nic *efx) --{ -- spin_lock(&efx->stats_lock); -- --efx->stats_disable_count; -- spin_unlock(&efx->stats_lock); --} -- - /* Context: process, dev_base_lock or RTNL held, non-blocking. */ - static struct net_device_stats *efx_net_stats(struct net_device *net_dev) - { -@@ -1421,17 +1499,9 @@ static struct net_device_stats *efx_net_stats(struct net_device *net_dev) - struct efx_mac_stats *mac_stats = &efx->mac_stats; - struct net_device_stats *stats = &net_dev->stats; - -- /* Update stats if possible, but do not wait if another thread -- * is updating them or if MAC stats fetches are temporarily -- * disabled; slightly stale stats are acceptable. -- */ -- if (!spin_trylock(&efx->stats_lock)) -- return stats; -- if (!efx->stats_disable_count) { -- efx->mac_op->update_stats(efx); -- falcon_update_nic_stats(efx); -- } -- spin_unlock(&efx->stats_lock); -+ spin_lock_bh(&efx->stats_lock); -+ efx->type->update_stats(efx); -+ spin_unlock_bh(&efx->stats_lock); - - stats->rx_packets = mac_stats->rx_packets; - stats->tx_packets = mac_stats->tx_packets; -@@ -1490,7 +1560,14 @@ static int efx_change_mtu(struct net_device *net_dev, int new_mtu) - EFX_LOG(efx, "changing MTU to %d\n", new_mtu); - - efx_fini_channels(efx); -+ -+ mutex_lock(&efx->mac_lock); -+ /* Reconfigure the MAC before enabling the dma queues so that -+ * the RX buffers don't overflow */ - net_dev->mtu = new_mtu; -+ efx->mac_op->reconfigure(efx); -+ mutex_unlock(&efx->mac_lock); -+ - efx_init_channels(efx); - - efx_start_all(efx); -@@ -1514,7 +1591,9 @@ static int efx_set_mac_address(struct net_device *net_dev, void *data) - memcpy(net_dev->dev_addr, new_addr, net_dev->addr_len); - - /* Reconfigure the MAC */ -- efx_reconfigure_port(efx); -+ mutex_lock(&efx->mac_lock); -+ efx->mac_op->reconfigure(efx); -+ mutex_unlock(&efx->mac_lock); - - return 0; - } -@@ -1525,16 +1604,14 @@ static void efx_set_multicast_list(struct net_device *net_dev) - struct efx_nic *efx = netdev_priv(net_dev); - struct dev_mc_list *mc_list = net_dev->mc_list; - union efx_multicast_hash *mc_hash = &efx->multicast_hash; -- bool promiscuous = !!(net_dev->flags & IFF_PROMISC); -- bool changed = (efx->promiscuous != promiscuous); - u32 crc; - int bit; - int i; - -- efx->promiscuous = promiscuous; -+ efx->promiscuous = !!(net_dev->flags & IFF_PROMISC); - - /* Build multicast hash table */ -- if (promiscuous || (net_dev->flags & IFF_ALLMULTI)) { -+ if (efx->promiscuous || (net_dev->flags & IFF_ALLMULTI)) { - memset(mc_hash, 0xff, sizeof(*mc_hash)); - } else { - memset(mc_hash, 0x00, sizeof(*mc_hash)); -@@ -1544,17 +1621,17 @@ static void efx_set_multicast_list(struct net_device *net_dev) - set_bit_le(bit, mc_hash->byte); - mc_list = mc_list->next; - } -- } -- -- if (!efx->port_enabled) -- /* Delay pushing settings until efx_start_port() */ -- return; - -- if (changed) -- queue_work(efx->workqueue, &efx->phy_work); -+ /* Broadcast packets go through the multicast hash filter. -+ * ether_crc_le() of the broadcast address is 0xbe2612ff -+ * so we always add bit 0xff to the mask. -+ */ -+ set_bit_le(0xff, mc_hash->byte); -+ } - -- /* Create and activate new global multicast hash table */ -- falcon_set_multicast_hash(efx); -+ if (efx->port_enabled) -+ queue_work(efx->workqueue, &efx->mac_work); -+ /* Otherwise efx_start_port() will do this */ - } - - static const struct net_device_ops efx_netdev_ops = { -@@ -1683,21 +1760,18 @@ static void efx_unregister_netdev(struct efx_nic *efx) - - /* Tears down the entire software state and most of the hardware state - * before reset. */ --void efx_reset_down(struct efx_nic *efx, enum reset_type method, -- struct ethtool_cmd *ecmd) -+void efx_reset_down(struct efx_nic *efx, enum reset_type method) - { - EFX_ASSERT_RESET_SERIALISED(efx); - -- efx_stats_disable(efx); - efx_stop_all(efx); - mutex_lock(&efx->mac_lock); - mutex_lock(&efx->spi_lock); - -- efx->phy_op->get_settings(efx, ecmd); -- - efx_fini_channels(efx); - if (efx->port_initialized && method != RESET_TYPE_INVISIBLE) - efx->phy_op->fini(efx); -+ efx->type->fini(efx); - } - - /* This function will always ensure that the locks acquired in -@@ -1705,79 +1779,67 @@ void efx_reset_down(struct efx_nic *efx, enum reset_type method, - * that we were unable to reinitialise the hardware, and the - * driver should be disabled. If ok is false, then the rx and tx - * engines are not restarted, pending a RESET_DISABLE. */ --int efx_reset_up(struct efx_nic *efx, enum reset_type method, -- struct ethtool_cmd *ecmd, bool ok) -+int efx_reset_up(struct efx_nic *efx, enum reset_type method, bool ok) - { - int rc; - - EFX_ASSERT_RESET_SERIALISED(efx); - -- rc = falcon_init_nic(efx); -+ rc = efx->type->init(efx); - if (rc) { - EFX_ERR(efx, "failed to initialise NIC\n"); -- ok = false; -+ goto fail; - } - -+ if (!ok) -+ goto fail; -+ - if (efx->port_initialized && method != RESET_TYPE_INVISIBLE) { -- if (ok) { -- rc = efx->phy_op->init(efx); -- if (rc) -- ok = false; -- } -- if (!ok) -- efx->port_initialized = false; -+ rc = efx->phy_op->init(efx); -+ if (rc) -+ goto fail; -+ if (efx->phy_op->reconfigure(efx)) -+ EFX_ERR(efx, "could not restore PHY settings\n"); - } - -- if (ok) { -- efx_init_channels(efx); -+ efx->mac_op->reconfigure(efx); - -- if (efx->phy_op->set_settings(efx, ecmd)) -- EFX_ERR(efx, "could not restore PHY settings\n"); -- } -+ efx_init_channels(efx); -+ -+ mutex_unlock(&efx->spi_lock); -+ mutex_unlock(&efx->mac_lock); -+ -+ efx_start_all(efx); -+ -+ return 0; -+ -+fail: -+ efx->port_initialized = false; - - mutex_unlock(&efx->spi_lock); - mutex_unlock(&efx->mac_lock); - -- if (ok) { -- efx_start_all(efx); -- efx_stats_enable(efx); -- } - return rc; - } - --/* Reset the NIC as transparently as possible. Do not reset the PHY -- * Note that the reset may fail, in which case the card will be left -- * in a most-probably-unusable state. -+/* Reset the NIC using the specified method. Note that the reset may -+ * fail, in which case the card will be left in an unusable state. - * -- * This function will sleep. You cannot reset from within an atomic -- * state; use efx_schedule_reset() instead. -- * -- * Grabs the rtnl_lock. -+ * Caller must hold the rtnl_lock. - */ --static int efx_reset(struct efx_nic *efx) -+int efx_reset(struct efx_nic *efx, enum reset_type method) - { -- struct ethtool_cmd ecmd; -- enum reset_type method = efx->reset_pending; -- int rc = 0; -+ int rc, rc2; -+ bool disabled; - -- /* Serialise with kernel interfaces */ -- rtnl_lock(); -+ EFX_INFO(efx, "resetting (%s)\n", RESET_TYPE(method)); - -- /* If we're not RUNNING then don't reset. Leave the reset_pending -- * flag set so that efx_pci_probe_main will be retried */ -- if (efx->state != STATE_RUNNING) { -- EFX_INFO(efx, "scheduled reset quenched. NIC not RUNNING\n"); -- goto out_unlock; -- } -+ efx_reset_down(efx, method); - -- EFX_INFO(efx, "resetting (%d)\n", method); -- -- efx_reset_down(efx, method, &ecmd); -- -- rc = falcon_reset_hw(efx, method); -+ rc = efx->type->reset(efx, method); - if (rc) { - EFX_ERR(efx, "failed to reset hardware\n"); -- goto out_disable; -+ goto out; - } - - /* Allow resets to be rescheduled. */ -@@ -1789,25 +1851,22 @@ static int efx_reset(struct efx_nic *efx) - * can respond to requests. */ - pci_set_master(efx->pci_dev); - -+out: - /* Leave device stopped if necessary */ -- if (method == RESET_TYPE_DISABLE) { -- efx_reset_up(efx, method, &ecmd, false); -- rc = -EIO; -- } else { -- rc = efx_reset_up(efx, method, &ecmd, true); -+ disabled = rc || method == RESET_TYPE_DISABLE; -+ rc2 = efx_reset_up(efx, method, !disabled); -+ if (rc2) { -+ disabled = true; -+ if (!rc) -+ rc = rc2; - } - --out_disable: -- if (rc) { -+ if (disabled) { - EFX_ERR(efx, "has been disabled\n"); - efx->state = STATE_DISABLED; -- dev_close(efx->net_dev); - } else { - EFX_LOG(efx, "reset complete\n"); - } -- --out_unlock: -- rtnl_unlock(); - return rc; - } - -@@ -1816,9 +1875,19 @@ out_unlock: - */ - static void efx_reset_work(struct work_struct *data) - { -- struct efx_nic *nic = container_of(data, struct efx_nic, reset_work); -+ struct efx_nic *efx = container_of(data, struct efx_nic, reset_work); -+ -+ /* If we're not RUNNING then don't reset. Leave the reset_pending -+ * flag set so that efx_pci_probe_main will be retried */ -+ if (efx->state != STATE_RUNNING) { -+ EFX_INFO(efx, "scheduled reset quenched. NIC not RUNNING\n"); -+ return; -+ } - -- efx_reset(nic); -+ rtnl_lock(); -+ if (efx_reset(efx, efx->reset_pending)) -+ dev_close(efx->net_dev); -+ rtnl_unlock(); - } - - void efx_schedule_reset(struct efx_nic *efx, enum reset_type type) -@@ -1843,18 +1912,24 @@ void efx_schedule_reset(struct efx_nic *efx, enum reset_type type) - case RESET_TYPE_TX_SKIP: - method = RESET_TYPE_INVISIBLE; - break; -+ case RESET_TYPE_MC_FAILURE: - default: - method = RESET_TYPE_ALL; - break; - } - - if (method != type) -- EFX_LOG(efx, "scheduling reset (%d:%d)\n", type, method); -+ EFX_LOG(efx, "scheduling %s reset for %s\n", -+ RESET_TYPE(method), RESET_TYPE(type)); - else -- EFX_LOG(efx, "scheduling reset (%d)\n", method); -+ EFX_LOG(efx, "scheduling %s reset\n", RESET_TYPE(method)); - - efx->reset_pending = method; - -+ /* efx_process_channel() will no longer read events once a -+ * reset is scheduled. So switch back to poll'd MCDI completions. */ -+ efx_mcdi_mode_poll(efx); -+ - queue_work(reset_workqueue, &efx->reset_work); - } - -@@ -1867,15 +1942,19 @@ void efx_schedule_reset(struct efx_nic *efx, enum reset_type type) - /* PCI device ID table */ - static struct pci_device_id efx_pci_table[] __devinitdata = { - {PCI_DEVICE(EFX_VENDID_SFC, FALCON_A_P_DEVID), -- .driver_data = (unsigned long) &falcon_a_nic_type}, -+ .driver_data = (unsigned long) &falcon_a1_nic_type}, - {PCI_DEVICE(EFX_VENDID_SFC, FALCON_B_P_DEVID), -- .driver_data = (unsigned long) &falcon_b_nic_type}, -+ .driver_data = (unsigned long) &falcon_b0_nic_type}, -+ {PCI_DEVICE(EFX_VENDID_SFC, BETHPAGE_A_P_DEVID), -+ .driver_data = (unsigned long) &siena_a0_nic_type}, -+ {PCI_DEVICE(EFX_VENDID_SFC, SIENA_A_P_DEVID), -+ .driver_data = (unsigned long) &siena_a0_nic_type}, - {0} /* end of list */ - }; - - /************************************************************************** - * -- * Dummy PHY/MAC/Board operations -+ * Dummy PHY/MAC operations - * - * Can be used for some unimplemented operations - * Needed so all function pointers are valid and do not have to be tested -@@ -1887,29 +1966,19 @@ int efx_port_dummy_op_int(struct efx_nic *efx) - return 0; - } - void efx_port_dummy_op_void(struct efx_nic *efx) {} --void efx_port_dummy_op_blink(struct efx_nic *efx, bool blink) {} -- --static struct efx_mac_operations efx_dummy_mac_operations = { -- .reconfigure = efx_port_dummy_op_void, -- .poll = efx_port_dummy_op_void, -- .irq = efx_port_dummy_op_void, --}; -+void efx_port_dummy_op_set_id_led(struct efx_nic *efx, enum efx_led_mode mode) -+{ -+} -+bool efx_port_dummy_op_poll(struct efx_nic *efx) -+{ -+ return false; -+} - - static struct efx_phy_operations efx_dummy_phy_operations = { - .init = efx_port_dummy_op_int, -- .reconfigure = efx_port_dummy_op_void, -- .poll = efx_port_dummy_op_void, -+ .reconfigure = efx_port_dummy_op_int, -+ .poll = efx_port_dummy_op_poll, - .fini = efx_port_dummy_op_void, -- .clear_interrupt = efx_port_dummy_op_void, --}; -- --static struct efx_board efx_dummy_board_info = { -- .init = efx_port_dummy_op_int, -- .init_leds = efx_port_dummy_op_void, -- .set_id_led = efx_port_dummy_op_blink, -- .monitor = efx_port_dummy_op_int, -- .blink = efx_port_dummy_op_blink, -- .fini = efx_port_dummy_op_void, - }; - - /************************************************************************** -@@ -1932,26 +2001,26 @@ static int efx_init_struct(struct efx_nic *efx, struct efx_nic_type *type, - /* Initialise common structures */ - memset(efx, 0, sizeof(*efx)); - spin_lock_init(&efx->biu_lock); -- spin_lock_init(&efx->phy_lock); -+ mutex_init(&efx->mdio_lock); - mutex_init(&efx->spi_lock); -+#ifdef CONFIG_SFC_MTD -+ INIT_LIST_HEAD(&efx->mtd_list); -+#endif - INIT_WORK(&efx->reset_work, efx_reset_work); - INIT_DELAYED_WORK(&efx->monitor_work, efx_monitor); - efx->pci_dev = pci_dev; - efx->state = STATE_INIT; - efx->reset_pending = RESET_TYPE_NONE; - strlcpy(efx->name, pci_name(pci_dev), sizeof(efx->name)); -- efx->board_info = efx_dummy_board_info; - - efx->net_dev = net_dev; - efx->rx_checksum_enabled = true; - spin_lock_init(&efx->netif_stop_lock); - spin_lock_init(&efx->stats_lock); -- efx->stats_disable_count = 1; - mutex_init(&efx->mac_lock); -- efx->mac_op = &efx_dummy_mac_operations; -+ efx->mac_op = type->default_mac_ops; - efx->phy_op = &efx_dummy_phy_operations; - efx->mdio.dev = net_dev; -- INIT_WORK(&efx->phy_work, efx_phy_work); - INIT_WORK(&efx->mac_work, efx_mac_work); - atomic_set(&efx->netif_stop_count, 1); - -@@ -1981,17 +2050,9 @@ static int efx_init_struct(struct efx_nic *efx, struct efx_nic_type *type, - - efx->type = type; - -- /* Sanity-check NIC type */ -- EFX_BUG_ON_PARANOID(efx->type->txd_ring_mask & -- (efx->type->txd_ring_mask + 1)); -- EFX_BUG_ON_PARANOID(efx->type->rxd_ring_mask & -- (efx->type->rxd_ring_mask + 1)); -- EFX_BUG_ON_PARANOID(efx->type->evq_size & -- (efx->type->evq_size - 1)); - /* As close as we can get to guaranteeing that we don't overflow */ -- EFX_BUG_ON_PARANOID(efx->type->evq_size < -- (efx->type->txd_ring_mask + 1 + -- efx->type->rxd_ring_mask + 1)); -+ BUILD_BUG_ON(EFX_EVQ_SIZE < EFX_TXQ_SIZE + EFX_RXQ_SIZE); -+ - EFX_BUG_ON_PARANOID(efx->type->phys_addr_channels > EFX_MAX_CHANNELS); - - /* Higher numbered interrupt modes are less capable! */ -@@ -2027,19 +2088,10 @@ static void efx_fini_struct(struct efx_nic *efx) - */ - static void efx_pci_remove_main(struct efx_nic *efx) - { -- EFX_ASSERT_RESET_SERIALISED(efx); -- -- /* Skip everything if we never obtained a valid membase */ -- if (!efx->membase) -- return; -- -+ efx_nic_fini_interrupt(efx); - efx_fini_channels(efx); - efx_fini_port(efx); -- -- /* Shutdown the board, then the NIC and board state */ -- efx->board_info.fini(efx); -- falcon_fini_interrupt(efx); -- -+ efx->type->fini(efx); - efx_fini_napi(efx); - efx_remove_all(efx); - } -@@ -2063,9 +2115,6 @@ static void efx_pci_remove(struct pci_dev *pci_dev) - /* Allow any queued efx_resets() to complete */ - rtnl_unlock(); - -- if (efx->membase == NULL) -- goto out; -- - efx_unregister_netdev(efx); - - efx_mtd_remove(efx); -@@ -2078,7 +2127,6 @@ static void efx_pci_remove(struct pci_dev *pci_dev) - - efx_pci_remove_main(efx); - --out: - efx_fini_io(efx); - EFX_LOG(efx, "shutdown successful\n"); - -@@ -2103,39 +2151,31 @@ static int efx_pci_probe_main(struct efx_nic *efx) - if (rc) - goto fail2; - -- /* Initialise the board */ -- rc = efx->board_info.init(efx); -- if (rc) { -- EFX_ERR(efx, "failed to initialise board\n"); -- goto fail3; -- } -- -- rc = falcon_init_nic(efx); -+ rc = efx->type->init(efx); - if (rc) { - EFX_ERR(efx, "failed to initialise NIC\n"); -- goto fail4; -+ goto fail3; - } - - rc = efx_init_port(efx); - if (rc) { - EFX_ERR(efx, "failed to initialise port\n"); -- goto fail5; -+ goto fail4; - } - - efx_init_channels(efx); - -- rc = falcon_init_interrupt(efx); -+ rc = efx_nic_init_interrupt(efx); - if (rc) -- goto fail6; -+ goto fail5; - - return 0; - -- fail6: -+ fail5: - efx_fini_channels(efx); - efx_fini_port(efx); -- fail5: - fail4: -- efx->board_info.fini(efx); -+ efx->type->fini(efx); - fail3: - efx_fini_napi(efx); - fail2: -@@ -2165,9 +2205,11 @@ static int __devinit efx_pci_probe(struct pci_dev *pci_dev, - net_dev = alloc_etherdev(sizeof(*efx)); - if (!net_dev) - return -ENOMEM; -- net_dev->features |= (NETIF_F_IP_CSUM | NETIF_F_SG | -+ net_dev->features |= (type->offload_features | NETIF_F_SG | - NETIF_F_HIGHDMA | NETIF_F_TSO | - NETIF_F_GRO); -+ if (type->offload_features & NETIF_F_V6_CSUM) -+ net_dev->features |= NETIF_F_TSO6; - /* Mask for features that also apply to VLAN devices */ - net_dev->vlan_features |= (NETIF_F_ALL_CSUM | NETIF_F_SG | - NETIF_F_HIGHDMA | NETIF_F_TSO); -@@ -2219,18 +2261,19 @@ static int __devinit efx_pci_probe(struct pci_dev *pci_dev, - goto fail4; - } - -- /* Switch to the running state before we expose the device to -- * the OS. This is to ensure that the initial gathering of -- * MAC stats succeeds. */ -+ /* Switch to the running state before we expose the device to the OS, -+ * so that dev_open()|efx_start_all() will actually start the device */ - efx->state = STATE_RUNNING; - -- efx_mtd_probe(efx); /* allowed to fail */ -- - rc = efx_register_netdev(efx); - if (rc) - goto fail5; - - EFX_LOG(efx, "initialisation successful\n"); -+ -+ rtnl_lock(); -+ efx_mtd_probe(efx); /* allowed to fail */ -+ rtnl_unlock(); - return 0; - - fail5: -@@ -2246,11 +2289,107 @@ static int __devinit efx_pci_probe(struct pci_dev *pci_dev, - return rc; - } - -+static int efx_pm_freeze(struct device *dev) -+{ -+ struct efx_nic *efx = pci_get_drvdata(to_pci_dev(dev)); -+ -+ efx->state = STATE_FINI; -+ -+ netif_device_detach(efx->net_dev); -+ -+ efx_stop_all(efx); -+ efx_fini_channels(efx); -+ -+ return 0; -+} -+ -+static int efx_pm_thaw(struct device *dev) -+{ -+ struct efx_nic *efx = pci_get_drvdata(to_pci_dev(dev)); -+ -+ efx->state = STATE_INIT; -+ -+ efx_init_channels(efx); -+ -+ mutex_lock(&efx->mac_lock); -+ efx->phy_op->reconfigure(efx); -+ mutex_unlock(&efx->mac_lock); -+ -+ efx_start_all(efx); -+ -+ netif_device_attach(efx->net_dev); -+ -+ efx->state = STATE_RUNNING; -+ -+ efx->type->resume_wol(efx); -+ -+ return 0; -+} -+ -+static int efx_pm_poweroff(struct device *dev) -+{ -+ struct pci_dev *pci_dev = to_pci_dev(dev); -+ struct efx_nic *efx = pci_get_drvdata(pci_dev); -+ -+ efx->type->fini(efx); -+ -+ efx->reset_pending = RESET_TYPE_NONE; -+ -+ pci_save_state(pci_dev); -+ return pci_set_power_state(pci_dev, PCI_D3hot); -+} -+ -+/* Used for both resume and restore */ -+static int efx_pm_resume(struct device *dev) -+{ -+ struct pci_dev *pci_dev = to_pci_dev(dev); -+ struct efx_nic *efx = pci_get_drvdata(pci_dev); -+ int rc; -+ -+ rc = pci_set_power_state(pci_dev, PCI_D0); -+ if (rc) -+ return rc; -+ pci_restore_state(pci_dev); -+ rc = pci_enable_device(pci_dev); -+ if (rc) -+ return rc; -+ pci_set_master(efx->pci_dev); -+ rc = efx->type->reset(efx, RESET_TYPE_ALL); -+ if (rc) -+ return rc; -+ rc = efx->type->init(efx); -+ if (rc) -+ return rc; -+ efx_pm_thaw(dev); -+ return 0; -+} -+ -+static int efx_pm_suspend(struct device *dev) -+{ -+ int rc; -+ -+ efx_pm_freeze(dev); -+ rc = efx_pm_poweroff(dev); -+ if (rc) -+ efx_pm_resume(dev); -+ return rc; -+} -+ -+static struct dev_pm_ops efx_pm_ops = { -+ .suspend = efx_pm_suspend, -+ .resume = efx_pm_resume, -+ .freeze = efx_pm_freeze, -+ .thaw = efx_pm_thaw, -+ .poweroff = efx_pm_poweroff, -+ .restore = efx_pm_resume, -+}; -+ - static struct pci_driver efx_pci_driver = { - .name = EFX_DRIVER_NAME, - .id_table = efx_pci_table, - .probe = efx_pci_probe, - .remove = efx_pci_remove, -+ .driver.pm = &efx_pm_ops, - }; - - /************************************************************************** -@@ -2314,8 +2453,8 @@ static void __exit efx_exit_module(void) - module_init(efx_init_module); - module_exit(efx_exit_module); - --MODULE_AUTHOR("Michael Brown and " -- "Solarflare Communications"); -+MODULE_AUTHOR("Solarflare Communications and " -+ "Michael Brown "); - MODULE_DESCRIPTION("Solarflare Communications network driver"); - MODULE_LICENSE("GPL"); - MODULE_DEVICE_TABLE(pci, efx_pci_table); -diff --git a/drivers/net/sfc/efx.h b/drivers/net/sfc/efx.h -index aecaf62..a615ac0 100644 ---- a/drivers/net/sfc/efx.h -+++ b/drivers/net/sfc/efx.h -@@ -1,7 +1,7 @@ - /**************************************************************************** - * Driver for Solarflare Solarstorm network controllers and boards - * Copyright 2005-2006 Fen Systems Ltd. -- * Copyright 2006-2008 Solarflare Communications Inc. -+ * Copyright 2006-2009 Solarflare Communications Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published -@@ -18,35 +18,64 @@ - #define FALCON_A_P_DEVID 0x0703 - #define FALCON_A_S_DEVID 0x6703 - #define FALCON_B_P_DEVID 0x0710 -+#define BETHPAGE_A_P_DEVID 0x0803 -+#define SIENA_A_P_DEVID 0x0813 -+ -+/* Solarstorm controllers use BAR 0 for I/O space and BAR 2(&3) for memory */ -+#define EFX_MEM_BAR 2 - - /* TX */ --extern netdev_tx_t efx_xmit(struct efx_nic *efx, -- struct efx_tx_queue *tx_queue, -- struct sk_buff *skb); -+extern int efx_probe_tx_queue(struct efx_tx_queue *tx_queue); -+extern void efx_remove_tx_queue(struct efx_tx_queue *tx_queue); -+extern void efx_init_tx_queue(struct efx_tx_queue *tx_queue); -+extern void efx_fini_tx_queue(struct efx_tx_queue *tx_queue); -+extern void efx_release_tx_buffers(struct efx_tx_queue *tx_queue); -+extern netdev_tx_t -+efx_hard_start_xmit(struct sk_buff *skb, struct net_device *net_dev); -+extern netdev_tx_t -+efx_enqueue_skb(struct efx_tx_queue *tx_queue, struct sk_buff *skb); -+extern void efx_xmit_done(struct efx_tx_queue *tx_queue, unsigned int index); - extern void efx_stop_queue(struct efx_nic *efx); - extern void efx_wake_queue(struct efx_nic *efx); -+#define EFX_TXQ_SIZE 1024 -+#define EFX_TXQ_MASK (EFX_TXQ_SIZE - 1) - - /* RX */ --extern void efx_xmit_done(struct efx_tx_queue *tx_queue, unsigned int index); -+extern int efx_probe_rx_queue(struct efx_rx_queue *rx_queue); -+extern void efx_remove_rx_queue(struct efx_rx_queue *rx_queue); -+extern void efx_init_rx_queue(struct efx_rx_queue *rx_queue); -+extern void efx_fini_rx_queue(struct efx_rx_queue *rx_queue); -+extern void efx_rx_strategy(struct efx_channel *channel); -+extern void efx_fast_push_rx_descriptors(struct efx_rx_queue *rx_queue); -+extern void efx_rx_work(struct work_struct *data); -+extern void __efx_rx_packet(struct efx_channel *channel, -+ struct efx_rx_buffer *rx_buf, bool checksummed); - extern void efx_rx_packet(struct efx_rx_queue *rx_queue, unsigned int index, - unsigned int len, bool checksummed, bool discard); - extern void efx_schedule_slow_fill(struct efx_rx_queue *rx_queue, int delay); -+#define EFX_RXQ_SIZE 1024 -+#define EFX_RXQ_MASK (EFX_RXQ_SIZE - 1) - - /* Channels */ - extern void efx_process_channel_now(struct efx_channel *channel); --extern void efx_flush_queues(struct efx_nic *efx); -+#define EFX_EVQ_SIZE 4096 -+#define EFX_EVQ_MASK (EFX_EVQ_SIZE - 1) - - /* Ports */ --extern void efx_stats_disable(struct efx_nic *efx); --extern void efx_stats_enable(struct efx_nic *efx); --extern void efx_reconfigure_port(struct efx_nic *efx); --extern void __efx_reconfigure_port(struct efx_nic *efx); -+extern int efx_reconfigure_port(struct efx_nic *efx); -+extern int __efx_reconfigure_port(struct efx_nic *efx); -+ -+/* Ethtool support */ -+extern int efx_ethtool_get_settings(struct net_device *net_dev, -+ struct ethtool_cmd *ecmd); -+extern int efx_ethtool_set_settings(struct net_device *net_dev, -+ struct ethtool_cmd *ecmd); -+extern const struct ethtool_ops efx_ethtool_ops; - - /* Reset handling */ --extern void efx_reset_down(struct efx_nic *efx, enum reset_type method, -- struct ethtool_cmd *ecmd); --extern int efx_reset_up(struct efx_nic *efx, enum reset_type method, -- struct ethtool_cmd *ecmd, bool ok); -+extern int efx_reset(struct efx_nic *efx, enum reset_type method); -+extern void efx_reset_down(struct efx_nic *efx, enum reset_type method); -+extern int efx_reset_up(struct efx_nic *efx, enum reset_type method, bool ok); - - /* Global */ - extern void efx_schedule_reset(struct efx_nic *efx, enum reset_type type); -@@ -60,7 +89,9 @@ extern void efx_hex_dump(const u8 *, unsigned int, const char *); - /* Dummy PHY ops for PHY drivers */ - extern int efx_port_dummy_op_int(struct efx_nic *efx); - extern void efx_port_dummy_op_void(struct efx_nic *efx); --extern void efx_port_dummy_op_blink(struct efx_nic *efx, bool blink); -+extern void -+efx_port_dummy_op_set_id_led(struct efx_nic *efx, enum efx_led_mode mode); -+extern bool efx_port_dummy_op_poll(struct efx_nic *efx); - - /* MTD */ - #ifdef CONFIG_SFC_MTD -@@ -84,4 +115,8 @@ static inline void efx_schedule_channel(struct efx_channel *channel) - napi_schedule(&channel->napi_str); - } - -+extern void efx_link_status_changed(struct efx_nic *efx); -+extern void efx_link_set_advertising(struct efx_nic *efx, u32); -+extern void efx_link_set_wanted_fc(struct efx_nic *efx, enum efx_fc_type); -+ - #endif /* EFX_EFX_H */ -diff --git a/drivers/net/sfc/enum.h b/drivers/net/sfc/enum.h -index 60cbc6e..384cfe3 100644 ---- a/drivers/net/sfc/enum.h -+++ b/drivers/net/sfc/enum.h -@@ -1,6 +1,6 @@ - /**************************************************************************** - * Driver for Solarflare Solarstorm network controllers and boards -- * Copyright 2007-2008 Solarflare Communications Inc. -+ * Copyright 2007-2009 Solarflare Communications Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published -@@ -13,44 +13,101 @@ - /** - * enum efx_loopback_mode - loopback modes - * @LOOPBACK_NONE: no loopback -- * @LOOPBACK_GMAC: loopback within GMAC at unspecified level -- * @LOOPBACK_XGMII: loopback within XMAC at XGMII level -- * @LOOPBACK_XGXS: loopback within XMAC at XGXS level -- * @LOOPBACK_XAUI: loopback within XMAC at XAUI level -+ * @LOOPBACK_DATA: data path loopback -+ * @LOOPBACK_GMAC: loopback within GMAC -+ * @LOOPBACK_XGMII: loopback after XMAC -+ * @LOOPBACK_XGXS: loopback within BPX after XGXS -+ * @LOOPBACK_XAUI: loopback within BPX before XAUI serdes -+ * @LOOPBACK_GMII: loopback within BPX after GMAC -+ * @LOOPBACK_SGMII: loopback within BPX within SGMII -+ * @LOOPBACK_XGBR: loopback within BPX within XGBR -+ * @LOOPBACK_XFI: loopback within BPX before XFI serdes -+ * @LOOPBACK_XAUI_FAR: loopback within BPX after XAUI serdes -+ * @LOOPBACK_GMII_FAR: loopback within BPX before SGMII -+ * @LOOPBACK_SGMII_FAR: loopback within BPX after SGMII -+ * @LOOPBACK_XFI_FAR: loopback after XFI serdes - * @LOOPBACK_GPHY: loopback within 1G PHY at unspecified level - * @LOOPBACK_PHYXS: loopback within 10G PHY at PHYXS level - * @LOOPBACK_PCS: loopback within 10G PHY at PCS level - * @LOOPBACK_PMAPMD: loopback within 10G PHY at PMAPMD level -- * @LOOPBACK_NETWORK: reflecting loopback (even further than furthest!) -+ * @LOOPBACK_XPORT: cross port loopback -+ * @LOOPBACK_XGMII_WS: wireside loopback excluding XMAC -+ * @LOOPBACK_XAUI_WS: wireside loopback within BPX within XAUI serdes -+ * @LOOPBACK_XAUI_WS_FAR: wireside loopback within BPX including XAUI serdes -+ * @LOOPBACK_XAUI_WS_NEAR: wireside loopback within BPX excluding XAUI serdes -+ * @LOOPBACK_GMII_WS: wireside loopback excluding GMAC -+ * @LOOPBACK_XFI_WS: wireside loopback excluding XFI serdes -+ * @LOOPBACK_XFI_WS_FAR: wireside loopback including XFI serdes -+ * @LOOPBACK_PHYXS_WS: wireside loopback within 10G PHY at PHYXS level - */ --/* Please keep in order and up-to-date w.r.t the following two #defines */ -+/* Please keep up-to-date w.r.t the following two #defines */ - enum efx_loopback_mode { - LOOPBACK_NONE = 0, -- LOOPBACK_GMAC = 1, -- LOOPBACK_XGMII = 2, -- LOOPBACK_XGXS = 3, -- LOOPBACK_XAUI = 4, -- LOOPBACK_GPHY = 5, -- LOOPBACK_PHYXS = 6, -- LOOPBACK_PCS = 7, -- LOOPBACK_PMAPMD = 8, -- LOOPBACK_NETWORK = 9, -+ LOOPBACK_DATA = 1, -+ LOOPBACK_GMAC = 2, -+ LOOPBACK_XGMII = 3, -+ LOOPBACK_XGXS = 4, -+ LOOPBACK_XAUI = 5, -+ LOOPBACK_GMII = 6, -+ LOOPBACK_SGMII = 7, -+ LOOPBACK_XGBR = 8, -+ LOOPBACK_XFI = 9, -+ LOOPBACK_XAUI_FAR = 10, -+ LOOPBACK_GMII_FAR = 11, -+ LOOPBACK_SGMII_FAR = 12, -+ LOOPBACK_XFI_FAR = 13, -+ LOOPBACK_GPHY = 14, -+ LOOPBACK_PHYXS = 15, -+ LOOPBACK_PCS = 16, -+ LOOPBACK_PMAPMD = 17, -+ LOOPBACK_XPORT = 18, -+ LOOPBACK_XGMII_WS = 19, -+ LOOPBACK_XAUI_WS = 20, -+ LOOPBACK_XAUI_WS_FAR = 21, -+ LOOPBACK_XAUI_WS_NEAR = 22, -+ LOOPBACK_GMII_WS = 23, -+ LOOPBACK_XFI_WS = 24, -+ LOOPBACK_XFI_WS_FAR = 25, -+ LOOPBACK_PHYXS_WS = 26, - LOOPBACK_MAX - }; -- - #define LOOPBACK_TEST_MAX LOOPBACK_PMAPMD - --extern const char *efx_loopback_mode_names[]; --#define LOOPBACK_MODE_NAME(mode) \ -- STRING_TABLE_LOOKUP(mode, efx_loopback_mode) --#define LOOPBACK_MODE(efx) \ -- LOOPBACK_MODE_NAME(efx->loopback_mode) -- - /* These loopbacks occur within the controller */ --#define LOOPBACKS_INTERNAL ((1 << LOOPBACK_GMAC) | \ -- (1 << LOOPBACK_XGMII)| \ -- (1 << LOOPBACK_XGXS) | \ -- (1 << LOOPBACK_XAUI)) -+#define LOOPBACKS_INTERNAL ((1 << LOOPBACK_DATA) | \ -+ (1 << LOOPBACK_GMAC) | \ -+ (1 << LOOPBACK_XGMII)| \ -+ (1 << LOOPBACK_XGXS) | \ -+ (1 << LOOPBACK_XAUI) | \ -+ (1 << LOOPBACK_GMII) | \ -+ (1 << LOOPBACK_SGMII) | \ -+ (1 << LOOPBACK_SGMII) | \ -+ (1 << LOOPBACK_XGBR) | \ -+ (1 << LOOPBACK_XFI) | \ -+ (1 << LOOPBACK_XAUI_FAR) | \ -+ (1 << LOOPBACK_GMII_FAR) | \ -+ (1 << LOOPBACK_SGMII_FAR) | \ -+ (1 << LOOPBACK_XFI_FAR) | \ -+ (1 << LOOPBACK_XGMII_WS) | \ -+ (1 << LOOPBACK_XAUI_WS) | \ -+ (1 << LOOPBACK_XAUI_WS_FAR) | \ -+ (1 << LOOPBACK_XAUI_WS_NEAR) | \ -+ (1 << LOOPBACK_GMII_WS) | \ -+ (1 << LOOPBACK_XFI_WS) | \ -+ (1 << LOOPBACK_XFI_WS_FAR)) -+ -+#define LOOPBACKS_WS ((1 << LOOPBACK_XGMII_WS) | \ -+ (1 << LOOPBACK_XAUI_WS) | \ -+ (1 << LOOPBACK_XAUI_WS_FAR) | \ -+ (1 << LOOPBACK_XAUI_WS_NEAR) | \ -+ (1 << LOOPBACK_GMII_WS) | \ -+ (1 << LOOPBACK_XFI_WS) | \ -+ (1 << LOOPBACK_XFI_WS_FAR) | \ -+ (1 << LOOPBACK_PHYXS_WS)) -+ -+#define LOOPBACKS_EXTERNAL(_efx) \ -+ ((_efx)->loopback_modes & ~LOOPBACKS_INTERNAL & \ -+ ~(1 << LOOPBACK_NONE)) - - #define LOOPBACK_MASK(_efx) \ - (1 << (_efx)->loopback_mode) -@@ -58,6 +115,9 @@ extern const char *efx_loopback_mode_names[]; - #define LOOPBACK_INTERNAL(_efx) \ - (!!(LOOPBACKS_INTERNAL & LOOPBACK_MASK(_efx))) - -+#define LOOPBACK_EXTERNAL(_efx) \ -+ (!!(LOOPBACK_MASK(_efx) & LOOPBACKS_EXTERNAL(_efx))) -+ - #define LOOPBACK_CHANGED(_from, _to, _mask) \ - (!!((LOOPBACK_MASK(_from) ^ LOOPBACK_MASK(_to)) & (_mask))) - -@@ -84,6 +144,7 @@ extern const char *efx_loopback_mode_names[]; - * @RESET_TYPE_RX_DESC_FETCH: pcie error during rx descriptor fetch - * @RESET_TYPE_TX_DESC_FETCH: pcie error during tx descriptor fetch - * @RESET_TYPE_TX_SKIP: hardware completed empty tx descriptors -+ * @RESET_TYPE_MC_FAILURE: MC reboot/assertion - */ - enum reset_type { - RESET_TYPE_NONE = -1, -@@ -98,6 +159,7 @@ enum reset_type { - RESET_TYPE_RX_DESC_FETCH, - RESET_TYPE_TX_DESC_FETCH, - RESET_TYPE_TX_SKIP, -+ RESET_TYPE_MC_FAILURE, - RESET_TYPE_MAX, - }; - -diff --git a/drivers/net/sfc/ethtool.c b/drivers/net/sfc/ethtool.c -index 45018f2..6c0bbed 100644 ---- a/drivers/net/sfc/ethtool.c -+++ b/drivers/net/sfc/ethtool.c -@@ -1,7 +1,7 @@ - /**************************************************************************** - * Driver for Solarflare Solarstorm network controllers and boards - * Copyright 2005-2006 Fen Systems Ltd. -- * Copyright 2006-2008 Solarflare Communications Inc. -+ * Copyright 2006-2009 Solarflare Communications Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published -@@ -10,30 +10,15 @@ - - #include - #include --#include - #include - #include "net_driver.h" - #include "workarounds.h" - #include "selftest.h" - #include "efx.h" --#include "ethtool.h" --#include "falcon.h" -+#include "nic.h" - #include "spi.h" - #include "mdio_10g.h" - --const char *efx_loopback_mode_names[] = { -- [LOOPBACK_NONE] = "NONE", -- [LOOPBACK_GMAC] = "GMAC", -- [LOOPBACK_XGMII] = "XGMII", -- [LOOPBACK_XGXS] = "XGXS", -- [LOOPBACK_XAUI] = "XAUI", -- [LOOPBACK_GPHY] = "GPHY", -- [LOOPBACK_PHYXS] = "PHYXS", -- [LOOPBACK_PCS] = "PCS", -- [LOOPBACK_PMAPMD] = "PMA/PMD", -- [LOOPBACK_NETWORK] = "NETWORK", --}; -- - struct ethtool_string { - char name[ETH_GSTRING_LEN]; - }; -@@ -167,6 +152,7 @@ static struct efx_ethtool_stat efx_ethtool_stats[] = { - EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_tobe_disc), - EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_ip_hdr_chksum_err), - EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_tcp_udp_chksum_err), -+ EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_mcast_mismatch), - EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_frm_trunc), - }; - -@@ -187,13 +173,15 @@ static int efx_ethtool_phys_id(struct net_device *net_dev, u32 count) - { - struct efx_nic *efx = netdev_priv(net_dev); - -- efx->board_info.blink(efx, 1); -- set_current_state(TASK_INTERRUPTIBLE); -- if (count) -- schedule_timeout(count * HZ); -- else -- schedule(); -- efx->board_info.blink(efx, 0); -+ do { -+ efx->type->set_id_led(efx, EFX_LED_ON); -+ schedule_timeout_interruptible(HZ / 2); -+ -+ efx->type->set_id_led(efx, EFX_LED_OFF); -+ schedule_timeout_interruptible(HZ / 2); -+ } while (!signal_pending(current) && --count != 0); -+ -+ efx->type->set_id_led(efx, EFX_LED_DEFAULT); - return 0; - } - -@@ -202,6 +190,7 @@ int efx_ethtool_get_settings(struct net_device *net_dev, - struct ethtool_cmd *ecmd) - { - struct efx_nic *efx = netdev_priv(net_dev); -+ struct efx_link_state *link_state = &efx->link_state; - - mutex_lock(&efx->mac_lock); - efx->phy_op->get_settings(efx, ecmd); -@@ -209,6 +198,13 @@ int efx_ethtool_get_settings(struct net_device *net_dev, - - /* Falcon GMAC does not support 1000Mbps HD */ - ecmd->supported &= ~SUPPORTED_1000baseT_Half; -+ /* Both MACs support pause frames (bidirectional and respond-only) */ -+ ecmd->supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause; -+ -+ if (LOOPBACK_INTERNAL(efx)) { -+ ecmd->speed = link_state->speed; -+ ecmd->duplex = link_state->fd ? DUPLEX_FULL : DUPLEX_HALF; -+ } - - return 0; - } -@@ -230,9 +226,6 @@ int efx_ethtool_set_settings(struct net_device *net_dev, - mutex_lock(&efx->mac_lock); - rc = efx->phy_op->set_settings(efx, ecmd); - mutex_unlock(&efx->mac_lock); -- if (!rc) -- efx_reconfigure_port(efx); -- - return rc; - } - -@@ -243,6 +236,9 @@ static void efx_ethtool_get_drvinfo(struct net_device *net_dev, - - strlcpy(info->driver, EFX_DRIVER_NAME, sizeof(info->driver)); - strlcpy(info->version, EFX_DRIVER_VERSION, sizeof(info->version)); -+ if (efx_nic_rev(efx) >= EFX_REV_SIENA_A0) -+ siena_print_fwver(efx, info->fw_version, -+ sizeof(info->fw_version)); - strlcpy(info->bus_info, pci_name(efx->pci_dev), sizeof(info->bus_info)); - } - -@@ -289,7 +285,7 @@ static void efx_fill_test(unsigned int test_index, - #define EFX_TX_QUEUE_NAME(_tx_queue) "txq%d", _tx_queue->queue - #define EFX_RX_QUEUE_NAME(_rx_queue) "rxq%d", _rx_queue->queue - #define EFX_LOOPBACK_NAME(_mode, _counter) \ -- "loopback.%s." _counter, LOOPBACK_MODE_NAME(mode) -+ "loopback.%s." _counter, STRING_TABLE_LOOKUP(_mode, efx_loopback_mode) - - /** - * efx_fill_loopback_test - fill in a block of loopback self-test entries -@@ -372,9 +368,21 @@ static int efx_ethtool_fill_self_tests(struct efx_nic *efx, - efx_fill_test(n++, strings, data, &tests->registers, - "core", 0, "registers", NULL); - -- for (i = 0; i < efx->phy_op->num_tests; i++) -- efx_fill_test(n++, strings, data, &tests->phy[i], -- "phy", 0, efx->phy_op->test_names[i], NULL); -+ if (efx->phy_op->run_tests != NULL) { -+ EFX_BUG_ON_PARANOID(efx->phy_op->test_name == NULL); -+ -+ for (i = 0; true; ++i) { -+ const char *name; -+ -+ EFX_BUG_ON_PARANOID(i >= EFX_MAX_PHY_TESTS); -+ name = efx->phy_op->test_name(efx, i); -+ if (name == NULL) -+ break; -+ -+ efx_fill_test(n++, strings, data, &tests->phy[i], -+ "phy", 0, name, NULL); -+ } -+ } - - /* Loopback tests */ - for (mode = LOOPBACK_NONE; mode <= LOOPBACK_TEST_MAX; mode++) { -@@ -463,6 +471,36 @@ static void efx_ethtool_get_stats(struct net_device *net_dev, - } - } - -+static int efx_ethtool_set_tso(struct net_device *net_dev, u32 enable) -+{ -+ struct efx_nic *efx __attribute__ ((unused)) = netdev_priv(net_dev); -+ unsigned long features; -+ -+ features = NETIF_F_TSO; -+ if (efx->type->offload_features & NETIF_F_V6_CSUM) -+ features |= NETIF_F_TSO6; -+ -+ if (enable) -+ net_dev->features |= features; -+ else -+ net_dev->features &= ~features; -+ -+ return 0; -+} -+ -+static int efx_ethtool_set_tx_csum(struct net_device *net_dev, u32 enable) -+{ -+ struct efx_nic *efx = netdev_priv(net_dev); -+ unsigned long features = efx->type->offload_features & NETIF_F_ALL_CSUM; -+ -+ if (enable) -+ net_dev->features |= features; -+ else -+ net_dev->features &= ~features; -+ -+ return 0; -+} -+ - static int efx_ethtool_set_rx_csum(struct net_device *net_dev, u32 enable) - { - struct efx_nic *efx = netdev_priv(net_dev); -@@ -537,7 +575,7 @@ static u32 efx_ethtool_get_link(struct net_device *net_dev) - { - struct efx_nic *efx = netdev_priv(net_dev); - -- return efx->link_up; -+ return efx->link_state.up; - } - - static int efx_ethtool_get_eeprom_len(struct net_device *net_dev) -@@ -562,7 +600,8 @@ static int efx_ethtool_get_eeprom(struct net_device *net_dev, - rc = mutex_lock_interruptible(&efx->spi_lock); - if (rc) - return rc; -- rc = falcon_spi_read(spi, eeprom->offset + EFX_EEPROM_BOOTCONFIG_START, -+ rc = falcon_spi_read(efx, spi, -+ eeprom->offset + EFX_EEPROM_BOOTCONFIG_START, - eeprom->len, &len, buf); - mutex_unlock(&efx->spi_lock); - -@@ -585,7 +624,8 @@ static int efx_ethtool_set_eeprom(struct net_device *net_dev, - rc = mutex_lock_interruptible(&efx->spi_lock); - if (rc) - return rc; -- rc = falcon_spi_write(spi, eeprom->offset + EFX_EEPROM_BOOTCONFIG_START, -+ rc = falcon_spi_write(efx, spi, -+ eeprom->offset + EFX_EEPROM_BOOTCONFIG_START, - eeprom->len, &len, buf); - mutex_unlock(&efx->spi_lock); - -@@ -618,6 +658,9 @@ static int efx_ethtool_get_coalesce(struct net_device *net_dev, - coalesce->use_adaptive_rx_coalesce = efx->irq_rx_adaptive; - coalesce->rx_coalesce_usecs_irq = efx->irq_rx_moderation; - -+ coalesce->tx_coalesce_usecs_irq *= EFX_IRQ_MOD_RESOLUTION; -+ coalesce->rx_coalesce_usecs_irq *= EFX_IRQ_MOD_RESOLUTION; -+ - return 0; - } - -@@ -656,13 +699,8 @@ static int efx_ethtool_set_coalesce(struct net_device *net_dev, - } - - efx_init_irq_moderation(efx, tx_usecs, rx_usecs, adaptive); -- -- /* Reset channel to pick up new moderation value. Note that -- * this may change the value of the irq_moderation field -- * (e.g. to allow for hardware timer granularity). -- */ - efx_for_each_channel(channel, efx) -- falcon_set_int_moderation(channel); -+ efx->type->push_irq_moderation(channel); - - return 0; - } -@@ -671,8 +709,12 @@ static int efx_ethtool_set_pauseparam(struct net_device *net_dev, - struct ethtool_pauseparam *pause) - { - struct efx_nic *efx = netdev_priv(net_dev); -- enum efx_fc_type wanted_fc; -+ enum efx_fc_type wanted_fc, old_fc; -+ u32 old_adv; - bool reset; -+ int rc = 0; -+ -+ mutex_lock(&efx->mac_lock); - - wanted_fc = ((pause->rx_pause ? EFX_FC_RX : 0) | - (pause->tx_pause ? EFX_FC_TX : 0) | -@@ -680,14 +722,14 @@ static int efx_ethtool_set_pauseparam(struct net_device *net_dev, - - if ((wanted_fc & EFX_FC_TX) && !(wanted_fc & EFX_FC_RX)) { - EFX_LOG(efx, "Flow control unsupported: tx ON rx OFF\n"); -- return -EINVAL; -+ rc = -EINVAL; -+ goto out; - } - -- if (!(efx->phy_op->mmds & MDIO_DEVS_AN) && -- (wanted_fc & EFX_FC_AUTO)) { -- EFX_LOG(efx, "PHY does not support flow control " -- "autonegotiation\n"); -- return -EINVAL; -+ if ((wanted_fc & EFX_FC_AUTO) && !efx->link_advertising) { -+ EFX_LOG(efx, "Autonegotiation is disabled\n"); -+ rc = -EINVAL; -+ goto out; - } - - /* TX flow control may automatically turn itself off if the -@@ -697,27 +739,40 @@ static int efx_ethtool_set_pauseparam(struct net_device *net_dev, - * and fix it be cycling transmit flow control on this end. */ - reset = (wanted_fc & EFX_FC_TX) && !(efx->wanted_fc & EFX_FC_TX); - if (EFX_WORKAROUND_11482(efx) && reset) { -- if (falcon_rev(efx) >= FALCON_REV_B0) { -+ if (efx_nic_rev(efx) == EFX_REV_FALCON_B0) { - /* Recover by resetting the EM block */ -- if (efx->link_up) -- falcon_drain_tx_fifo(efx); -+ falcon_stop_nic_stats(efx); -+ falcon_drain_tx_fifo(efx); -+ efx->mac_op->reconfigure(efx); -+ falcon_start_nic_stats(efx); - } else { - /* Schedule a reset to recover */ - efx_schedule_reset(efx, RESET_TYPE_INVISIBLE); - } - } - -- /* Try to push the pause parameters */ -- mutex_lock(&efx->mac_lock); -+ old_adv = efx->link_advertising; -+ old_fc = efx->wanted_fc; -+ efx_link_set_wanted_fc(efx, wanted_fc); -+ if (efx->link_advertising != old_adv || -+ (efx->wanted_fc ^ old_fc) & EFX_FC_AUTO) { -+ rc = efx->phy_op->reconfigure(efx); -+ if (rc) { -+ EFX_ERR(efx, "Unable to advertise requested flow " -+ "control setting\n"); -+ goto out; -+ } -+ } - -- efx->wanted_fc = wanted_fc; -- if (efx->phy_op->mmds & MDIO_DEVS_AN) -- mdio45_ethtool_spauseparam_an(&efx->mdio, pause); -- __efx_reconfigure_port(efx); -+ /* Reconfigure the MAC. The PHY *may* generate a link state change event -+ * if the user just changed the advertised capabilities, but there's no -+ * harm doing this twice */ -+ efx->mac_op->reconfigure(efx); - -+out: - mutex_unlock(&efx->mac_lock); - -- return 0; -+ return rc; - } - - static void efx_ethtool_get_pauseparam(struct net_device *net_dev, -@@ -731,6 +786,50 @@ static void efx_ethtool_get_pauseparam(struct net_device *net_dev, - } - - -+static void efx_ethtool_get_wol(struct net_device *net_dev, -+ struct ethtool_wolinfo *wol) -+{ -+ struct efx_nic *efx = netdev_priv(net_dev); -+ return efx->type->get_wol(efx, wol); -+} -+ -+ -+static int efx_ethtool_set_wol(struct net_device *net_dev, -+ struct ethtool_wolinfo *wol) -+{ -+ struct efx_nic *efx = netdev_priv(net_dev); -+ return efx->type->set_wol(efx, wol->wolopts); -+} -+ -+extern int efx_ethtool_reset(struct net_device *net_dev, u32 *flags) -+{ -+ struct efx_nic *efx = netdev_priv(net_dev); -+ enum reset_type method; -+ enum { -+ ETH_RESET_EFX_INVISIBLE = (ETH_RESET_DMA | ETH_RESET_FILTER | -+ ETH_RESET_OFFLOAD | ETH_RESET_MAC) -+ }; -+ -+ /* Check for minimal reset flags */ -+ if ((*flags & ETH_RESET_EFX_INVISIBLE) != ETH_RESET_EFX_INVISIBLE) -+ return -EINVAL; -+ *flags ^= ETH_RESET_EFX_INVISIBLE; -+ method = RESET_TYPE_INVISIBLE; -+ -+ if (*flags & ETH_RESET_PHY) { -+ *flags ^= ETH_RESET_PHY; -+ method = RESET_TYPE_ALL; -+ } -+ -+ if ((*flags & efx->type->reset_world_flags) == -+ efx->type->reset_world_flags) { -+ *flags ^= efx->type->reset_world_flags; -+ method = RESET_TYPE_WORLD; -+ } -+ -+ return efx_reset(efx, method); -+} -+ - const struct ethtool_ops efx_ethtool_ops = { - .get_settings = efx_ethtool_get_settings, - .set_settings = efx_ethtool_set_settings, -@@ -747,11 +846,13 @@ const struct ethtool_ops efx_ethtool_ops = { - .get_rx_csum = efx_ethtool_get_rx_csum, - .set_rx_csum = efx_ethtool_set_rx_csum, - .get_tx_csum = ethtool_op_get_tx_csum, -- .set_tx_csum = ethtool_op_set_tx_csum, -+ /* Need to enable/disable IPv6 too */ -+ .set_tx_csum = efx_ethtool_set_tx_csum, - .get_sg = ethtool_op_get_sg, - .set_sg = ethtool_op_set_sg, - .get_tso = ethtool_op_get_tso, -- .set_tso = ethtool_op_set_tso, -+ /* Need to enable/disable TSO-IPv6 too */ -+ .set_tso = efx_ethtool_set_tso, - .get_flags = ethtool_op_get_flags, - .set_flags = ethtool_op_set_flags, - .get_sset_count = efx_ethtool_get_sset_count, -@@ -759,4 +860,7 @@ const struct ethtool_ops efx_ethtool_ops = { - .get_strings = efx_ethtool_get_strings, - .phys_id = efx_ethtool_phys_id, - .get_ethtool_stats = efx_ethtool_get_stats, -+ .get_wol = efx_ethtool_get_wol, -+ .set_wol = efx_ethtool_set_wol, -+ .reset = efx_ethtool_reset, - }; -diff --git a/drivers/net/sfc/ethtool.h b/drivers/net/sfc/ethtool.h -deleted file mode 100644 -index 295ead4..0000000 ---- a/drivers/net/sfc/ethtool.h -+++ /dev/null -@@ -1,27 +0,0 @@ --/**************************************************************************** -- * Driver for Solarflare Solarstorm network controllers and boards -- * Copyright 2005 Fen Systems Ltd. -- * Copyright 2006 Solarflare Communications Inc. -- * -- * This program is free software; you can redistribute it and/or modify it -- * under the terms of the GNU General Public License version 2 as published -- * by the Free Software Foundation, incorporated herein by reference. -- */ -- --#ifndef EFX_ETHTOOL_H --#define EFX_ETHTOOL_H -- --#include "net_driver.h" -- --/* -- * Ethtool support -- */ -- --extern int efx_ethtool_get_settings(struct net_device *net_dev, -- struct ethtool_cmd *ecmd); --extern int efx_ethtool_set_settings(struct net_device *net_dev, -- struct ethtool_cmd *ecmd); -- --extern const struct ethtool_ops efx_ethtool_ops; -- --#endif /* EFX_ETHTOOL_H */ -diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c -index c049364..17afcd2 100644 ---- a/drivers/net/sfc/falcon.c -+++ b/drivers/net/sfc/falcon.c -@@ -1,7 +1,7 @@ - /**************************************************************************** - * Driver for Solarflare Solarstorm network controllers and boards - * Copyright 2005-2006 Fen Systems Ltd. -- * Copyright 2006-2008 Solarflare Communications Inc. -+ * Copyright 2006-2009 Solarflare Communications Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published -@@ -14,66 +14,20 @@ - #include - #include - #include --#include - #include - #include "net_driver.h" - #include "bitfield.h" - #include "efx.h" - #include "mac.h" - #include "spi.h" --#include "falcon.h" --#include "falcon_hwdefs.h" --#include "falcon_io.h" -+#include "nic.h" -+#include "regs.h" -+#include "io.h" - #include "mdio_10g.h" - #include "phy.h" --#include "boards.h" - #include "workarounds.h" - --/* Falcon hardware control. -- * Falcon is the internal codename for the SFC4000 controller that is -- * present in SFE400X evaluation boards -- */ -- --/** -- * struct falcon_nic_data - Falcon NIC state -- * @next_buffer_table: First available buffer table id -- * @pci_dev2: The secondary PCI device if present -- * @i2c_data: Operations and state for I2C bit-bashing algorithm -- * @int_error_count: Number of internal errors seen recently -- * @int_error_expire: Time at which error count will be expired -- */ --struct falcon_nic_data { -- unsigned next_buffer_table; -- struct pci_dev *pci_dev2; -- struct i2c_algo_bit_data i2c_data; -- -- unsigned int_error_count; -- unsigned long int_error_expire; --}; -- --/************************************************************************** -- * -- * Configurable values -- * -- ************************************************************************** -- */ -- --static int disable_dma_stats; -- --/* This is set to 16 for a good reason. In summary, if larger than -- * 16, the descriptor cache holds more than a default socket -- * buffer's worth of packets (for UDP we can only have at most one -- * socket buffer's worth outstanding). This combined with the fact -- * that we only get 1 TX event per descriptor cache means the NIC -- * goes idle. -- */ --#define TX_DC_ENTRIES 16 --#define TX_DC_ENTRIES_ORDER 0 --#define TX_DC_BASE 0x130000 -- --#define RX_DC_ENTRIES 64 --#define RX_DC_ENTRIES_ORDER 2 --#define RX_DC_BASE 0x100000 -+/* Hardware control for SFC4000 (aka Falcon). */ - - static const unsigned int - /* "Large" EEPROM device: Atmel AT25640 or similar -@@ -89,104 +43,6 @@ default_flash_type = ((17 << SPI_DEV_TYPE_SIZE_LBN) - | (15 << SPI_DEV_TYPE_ERASE_SIZE_LBN) - | (8 << SPI_DEV_TYPE_BLOCK_SIZE_LBN)); - --/* RX FIFO XOFF watermark -- * -- * When the amount of the RX FIFO increases used increases past this -- * watermark send XOFF. Only used if RX flow control is enabled (ethtool -A) -- * This also has an effect on RX/TX arbitration -- */ --static int rx_xoff_thresh_bytes = -1; --module_param(rx_xoff_thresh_bytes, int, 0644); --MODULE_PARM_DESC(rx_xoff_thresh_bytes, "RX fifo XOFF threshold"); -- --/* RX FIFO XON watermark -- * -- * When the amount of the RX FIFO used decreases below this -- * watermark send XON. Only used if TX flow control is enabled (ethtool -A) -- * This also has an effect on RX/TX arbitration -- */ --static int rx_xon_thresh_bytes = -1; --module_param(rx_xon_thresh_bytes, int, 0644); --MODULE_PARM_DESC(rx_xon_thresh_bytes, "RX fifo XON threshold"); -- --/* TX descriptor ring size - min 512 max 4k */ --#define FALCON_TXD_RING_ORDER TX_DESCQ_SIZE_1K --#define FALCON_TXD_RING_SIZE 1024 --#define FALCON_TXD_RING_MASK (FALCON_TXD_RING_SIZE - 1) -- --/* RX descriptor ring size - min 512 max 4k */ --#define FALCON_RXD_RING_ORDER RX_DESCQ_SIZE_1K --#define FALCON_RXD_RING_SIZE 1024 --#define FALCON_RXD_RING_MASK (FALCON_RXD_RING_SIZE - 1) -- --/* Event queue size - max 32k */ --#define FALCON_EVQ_ORDER EVQ_SIZE_4K --#define FALCON_EVQ_SIZE 4096 --#define FALCON_EVQ_MASK (FALCON_EVQ_SIZE - 1) -- --/* If FALCON_MAX_INT_ERRORS internal errors occur within -- * FALCON_INT_ERROR_EXPIRE seconds, we consider the NIC broken and -- * disable it. -- */ --#define FALCON_INT_ERROR_EXPIRE 3600 --#define FALCON_MAX_INT_ERRORS 5 -- --/* We poll for events every FLUSH_INTERVAL ms, and check FLUSH_POLL_COUNT times -- */ --#define FALCON_FLUSH_INTERVAL 10 --#define FALCON_FLUSH_POLL_COUNT 100 -- --/************************************************************************** -- * -- * Falcon constants -- * -- ************************************************************************** -- */ -- --/* DMA address mask */ --#define FALCON_DMA_MASK DMA_BIT_MASK(46) -- --/* TX DMA length mask (13-bit) */ --#define FALCON_TX_DMA_MASK (4096 - 1) -- --/* Size and alignment of special buffers (4KB) */ --#define FALCON_BUF_SIZE 4096 -- --/* Dummy SRAM size code */ --#define SRM_NB_BSZ_ONCHIP_ONLY (-1) -- --#define FALCON_IS_DUAL_FUNC(efx) \ -- (falcon_rev(efx) < FALCON_REV_B0) -- --/************************************************************************** -- * -- * Falcon hardware access -- * -- **************************************************************************/ -- --/* Read the current event from the event queue */ --static inline efx_qword_t *falcon_event(struct efx_channel *channel, -- unsigned int index) --{ -- return (((efx_qword_t *) (channel->eventq.addr)) + index); --} -- --/* See if an event is present -- * -- * We check both the high and low dword of the event for all ones. We -- * wrote all ones when we cleared the event, and no valid event can -- * have all ones in either its high or low dwords. This approach is -- * robust against reordering. -- * -- * Note that using a single 64-bit comparison is incorrect; even -- * though the CPU read will be atomic, the DMA write may not be. -- */ --static inline int falcon_event_present(efx_qword_t *event) --{ -- return (!(EFX_DWORD_IS_ALL_ONES(event->dword[0]) | -- EFX_DWORD_IS_ALL_ONES(event->dword[1]))); --} -- - /************************************************************************** - * - * I2C bus - this is a bit-bashing interface using GPIO pins -@@ -200,9 +56,9 @@ static void falcon_setsda(void *data, int state) - struct efx_nic *efx = (struct efx_nic *)data; - efx_oword_t reg; - -- falcon_read(efx, ®, GPIO_CTL_REG_KER); -- EFX_SET_OWORD_FIELD(reg, GPIO3_OEN, !state); -- falcon_write(efx, ®, GPIO_CTL_REG_KER); -+ efx_reado(efx, ®, FR_AB_GPIO_CTL); -+ EFX_SET_OWORD_FIELD(reg, FRF_AB_GPIO3_OEN, !state); -+ efx_writeo(efx, ®, FR_AB_GPIO_CTL); - } - - static void falcon_setscl(void *data, int state) -@@ -210,9 +66,9 @@ static void falcon_setscl(void *data, int state) - struct efx_nic *efx = (struct efx_nic *)data; - efx_oword_t reg; - -- falcon_read(efx, ®, GPIO_CTL_REG_KER); -- EFX_SET_OWORD_FIELD(reg, GPIO0_OEN, !state); -- falcon_write(efx, ®, GPIO_CTL_REG_KER); -+ efx_reado(efx, ®, FR_AB_GPIO_CTL); -+ EFX_SET_OWORD_FIELD(reg, FRF_AB_GPIO0_OEN, !state); -+ efx_writeo(efx, ®, FR_AB_GPIO_CTL); - } - - static int falcon_getsda(void *data) -@@ -220,8 +76,8 @@ static int falcon_getsda(void *data) - struct efx_nic *efx = (struct efx_nic *)data; - efx_oword_t reg; - -- falcon_read(efx, ®, GPIO_CTL_REG_KER); -- return EFX_OWORD_FIELD(reg, GPIO3_IN); -+ efx_reado(efx, ®, FR_AB_GPIO_CTL); -+ return EFX_OWORD_FIELD(reg, FRF_AB_GPIO3_IN); - } - - static int falcon_getscl(void *data) -@@ -229,8 +85,8 @@ static int falcon_getscl(void *data) - struct efx_nic *efx = (struct efx_nic *)data; - efx_oword_t reg; - -- falcon_read(efx, ®, GPIO_CTL_REG_KER); -- return EFX_OWORD_FIELD(reg, GPIO0_IN); -+ efx_reado(efx, ®, FR_AB_GPIO_CTL); -+ return EFX_OWORD_FIELD(reg, FRF_AB_GPIO0_IN); - } - - static struct i2c_algo_bit_data falcon_i2c_bit_operations = { -@@ -243,1115 +99,39 @@ static struct i2c_algo_bit_data falcon_i2c_bit_operations = { - .timeout = DIV_ROUND_UP(HZ, 20), - }; - --/************************************************************************** -- * -- * Falcon special buffer handling -- * Special buffers are used for event queues and the TX and RX -- * descriptor rings. -- * -- *************************************************************************/ -- --/* -- * Initialise a Falcon special buffer -- * -- * This will define a buffer (previously allocated via -- * falcon_alloc_special_buffer()) in Falcon's buffer table, allowing -- * it to be used for event queues, descriptor rings etc. -- */ --static void --falcon_init_special_buffer(struct efx_nic *efx, -- struct efx_special_buffer *buffer) --{ -- efx_qword_t buf_desc; -- int index; -- dma_addr_t dma_addr; -- int i; -- -- EFX_BUG_ON_PARANOID(!buffer->addr); -- -- /* Write buffer descriptors to NIC */ -- for (i = 0; i < buffer->entries; i++) { -- index = buffer->index + i; -- dma_addr = buffer->dma_addr + (i * 4096); -- EFX_LOG(efx, "mapping special buffer %d at %llx\n", -- index, (unsigned long long)dma_addr); -- EFX_POPULATE_QWORD_4(buf_desc, -- IP_DAT_BUF_SIZE, IP_DAT_BUF_SIZE_4K, -- BUF_ADR_REGION, 0, -- BUF_ADR_FBUF, (dma_addr >> 12), -- BUF_OWNER_ID_FBUF, 0); -- falcon_write_sram(efx, &buf_desc, index); -- } --} -- --/* Unmaps a buffer from Falcon and clears the buffer table entries */ --static void --falcon_fini_special_buffer(struct efx_nic *efx, -- struct efx_special_buffer *buffer) --{ -- efx_oword_t buf_tbl_upd; -- unsigned int start = buffer->index; -- unsigned int end = (buffer->index + buffer->entries - 1); -- -- if (!buffer->entries) -- return; -- -- EFX_LOG(efx, "unmapping special buffers %d-%d\n", -- buffer->index, buffer->index + buffer->entries - 1); -- -- EFX_POPULATE_OWORD_4(buf_tbl_upd, -- BUF_UPD_CMD, 0, -- BUF_CLR_CMD, 1, -- BUF_CLR_END_ID, end, -- BUF_CLR_START_ID, start); -- falcon_write(efx, &buf_tbl_upd, BUF_TBL_UPD_REG_KER); --} -- --/* -- * Allocate a new Falcon special buffer -- * -- * This allocates memory for a new buffer, clears it and allocates a -- * new buffer ID range. It does not write into Falcon's buffer table. -- * -- * This call will allocate 4KB buffers, since Falcon can't use 8KB -- * buffers for event queues and descriptor rings. -- */ --static int falcon_alloc_special_buffer(struct efx_nic *efx, -- struct efx_special_buffer *buffer, -- unsigned int len) --{ -- struct falcon_nic_data *nic_data = efx->nic_data; -- -- len = ALIGN(len, FALCON_BUF_SIZE); -- -- buffer->addr = pci_alloc_consistent(efx->pci_dev, len, -- &buffer->dma_addr); -- if (!buffer->addr) -- return -ENOMEM; -- buffer->len = len; -- buffer->entries = len / FALCON_BUF_SIZE; -- BUG_ON(buffer->dma_addr & (FALCON_BUF_SIZE - 1)); -- -- /* All zeros is a potentially valid event so memset to 0xff */ -- memset(buffer->addr, 0xff, len); -- -- /* Select new buffer ID */ -- buffer->index = nic_data->next_buffer_table; -- nic_data->next_buffer_table += buffer->entries; -- -- EFX_LOG(efx, "allocating special buffers %d-%d at %llx+%x " -- "(virt %p phys %llx)\n", buffer->index, -- buffer->index + buffer->entries - 1, -- (u64)buffer->dma_addr, len, -- buffer->addr, (u64)virt_to_phys(buffer->addr)); -- -- return 0; --} -- --static void falcon_free_special_buffer(struct efx_nic *efx, -- struct efx_special_buffer *buffer) --{ -- if (!buffer->addr) -- return; -- -- EFX_LOG(efx, "deallocating special buffers %d-%d at %llx+%x " -- "(virt %p phys %llx)\n", buffer->index, -- buffer->index + buffer->entries - 1, -- (u64)buffer->dma_addr, buffer->len, -- buffer->addr, (u64)virt_to_phys(buffer->addr)); -- -- pci_free_consistent(efx->pci_dev, buffer->len, buffer->addr, -- buffer->dma_addr); -- buffer->addr = NULL; -- buffer->entries = 0; --} -- --/************************************************************************** -- * -- * Falcon generic buffer handling -- * These buffers are used for interrupt status and MAC stats -- * -- **************************************************************************/ -- --static int falcon_alloc_buffer(struct efx_nic *efx, -- struct efx_buffer *buffer, unsigned int len) --{ -- buffer->addr = pci_alloc_consistent(efx->pci_dev, len, -- &buffer->dma_addr); -- if (!buffer->addr) -- return -ENOMEM; -- buffer->len = len; -- memset(buffer->addr, 0, len); -- return 0; --} -- --static void falcon_free_buffer(struct efx_nic *efx, struct efx_buffer *buffer) --{ -- if (buffer->addr) { -- pci_free_consistent(efx->pci_dev, buffer->len, -- buffer->addr, buffer->dma_addr); -- buffer->addr = NULL; -- } --} -- --/************************************************************************** -- * -- * Falcon TX path -- * -- **************************************************************************/ -- --/* Returns a pointer to the specified transmit descriptor in the TX -- * descriptor queue belonging to the specified channel. -- */ --static inline efx_qword_t *falcon_tx_desc(struct efx_tx_queue *tx_queue, -- unsigned int index) --{ -- return (((efx_qword_t *) (tx_queue->txd.addr)) + index); --} -- --/* This writes to the TX_DESC_WPTR; write pointer for TX descriptor ring */ --static inline void falcon_notify_tx_desc(struct efx_tx_queue *tx_queue) --{ -- unsigned write_ptr; -- efx_dword_t reg; -- -- write_ptr = tx_queue->write_count & FALCON_TXD_RING_MASK; -- EFX_POPULATE_DWORD_1(reg, TX_DESC_WPTR_DWORD, write_ptr); -- falcon_writel_page(tx_queue->efx, ®, -- TX_DESC_UPD_REG_KER_DWORD, tx_queue->queue); --} -- -- --/* For each entry inserted into the software descriptor ring, create a -- * descriptor in the hardware TX descriptor ring (in host memory), and -- * write a doorbell. -- */ --void falcon_push_buffers(struct efx_tx_queue *tx_queue) --{ -- -- struct efx_tx_buffer *buffer; -- efx_qword_t *txd; -- unsigned write_ptr; -- -- BUG_ON(tx_queue->write_count == tx_queue->insert_count); -- -- do { -- write_ptr = tx_queue->write_count & FALCON_TXD_RING_MASK; -- buffer = &tx_queue->buffer[write_ptr]; -- txd = falcon_tx_desc(tx_queue, write_ptr); -- ++tx_queue->write_count; -- -- /* Create TX descriptor ring entry */ -- EFX_POPULATE_QWORD_5(*txd, -- TX_KER_PORT, 0, -- TX_KER_CONT, buffer->continuation, -- TX_KER_BYTE_CNT, buffer->len, -- TX_KER_BUF_REGION, 0, -- TX_KER_BUF_ADR, buffer->dma_addr); -- } while (tx_queue->write_count != tx_queue->insert_count); -- -- wmb(); /* Ensure descriptors are written before they are fetched */ -- falcon_notify_tx_desc(tx_queue); --} -- --/* Allocate hardware resources for a TX queue */ --int falcon_probe_tx(struct efx_tx_queue *tx_queue) --{ -- struct efx_nic *efx = tx_queue->efx; -- return falcon_alloc_special_buffer(efx, &tx_queue->txd, -- FALCON_TXD_RING_SIZE * -- sizeof(efx_qword_t)); --} -- --void falcon_init_tx(struct efx_tx_queue *tx_queue) --{ -- efx_oword_t tx_desc_ptr; -- struct efx_nic *efx = tx_queue->efx; -- -- tx_queue->flushed = false; -- -- /* Pin TX descriptor ring */ -- falcon_init_special_buffer(efx, &tx_queue->txd); -- -- /* Push TX descriptor ring to card */ -- EFX_POPULATE_OWORD_10(tx_desc_ptr, -- TX_DESCQ_EN, 1, -- TX_ISCSI_DDIG_EN, 0, -- TX_ISCSI_HDIG_EN, 0, -- TX_DESCQ_BUF_BASE_ID, tx_queue->txd.index, -- TX_DESCQ_EVQ_ID, tx_queue->channel->channel, -- TX_DESCQ_OWNER_ID, 0, -- TX_DESCQ_LABEL, tx_queue->queue, -- TX_DESCQ_SIZE, FALCON_TXD_RING_ORDER, -- TX_DESCQ_TYPE, 0, -- TX_NON_IP_DROP_DIS_B0, 1); -- -- if (falcon_rev(efx) >= FALCON_REV_B0) { -- int csum = tx_queue->queue == EFX_TX_QUEUE_OFFLOAD_CSUM; -- EFX_SET_OWORD_FIELD(tx_desc_ptr, TX_IP_CHKSM_DIS_B0, !csum); -- EFX_SET_OWORD_FIELD(tx_desc_ptr, TX_TCP_CHKSM_DIS_B0, !csum); -- } -- -- falcon_write_table(efx, &tx_desc_ptr, efx->type->txd_ptr_tbl_base, -- tx_queue->queue); -- -- if (falcon_rev(efx) < FALCON_REV_B0) { -- efx_oword_t reg; -- -- /* Only 128 bits in this register */ -- BUILD_BUG_ON(EFX_TX_QUEUE_COUNT >= 128); -- -- falcon_read(efx, ®, TX_CHKSM_CFG_REG_KER_A1); -- if (tx_queue->queue == EFX_TX_QUEUE_OFFLOAD_CSUM) -- clear_bit_le(tx_queue->queue, (void *)®); -- else -- set_bit_le(tx_queue->queue, (void *)®); -- falcon_write(efx, ®, TX_CHKSM_CFG_REG_KER_A1); -- } --} -- --static void falcon_flush_tx_queue(struct efx_tx_queue *tx_queue) --{ -- struct efx_nic *efx = tx_queue->efx; -- efx_oword_t tx_flush_descq; -- -- /* Post a flush command */ -- EFX_POPULATE_OWORD_2(tx_flush_descq, -- TX_FLUSH_DESCQ_CMD, 1, -- TX_FLUSH_DESCQ, tx_queue->queue); -- falcon_write(efx, &tx_flush_descq, TX_FLUSH_DESCQ_REG_KER); --} -- --void falcon_fini_tx(struct efx_tx_queue *tx_queue) --{ -- struct efx_nic *efx = tx_queue->efx; -- efx_oword_t tx_desc_ptr; -- -- /* The queue should have been flushed */ -- WARN_ON(!tx_queue->flushed); -- -- /* Remove TX descriptor ring from card */ -- EFX_ZERO_OWORD(tx_desc_ptr); -- falcon_write_table(efx, &tx_desc_ptr, efx->type->txd_ptr_tbl_base, -- tx_queue->queue); -- -- /* Unpin TX descriptor ring */ -- falcon_fini_special_buffer(efx, &tx_queue->txd); --} -- --/* Free buffers backing TX queue */ --void falcon_remove_tx(struct efx_tx_queue *tx_queue) --{ -- falcon_free_special_buffer(tx_queue->efx, &tx_queue->txd); --} -- --/************************************************************************** -- * -- * Falcon RX path -- * -- **************************************************************************/ -- --/* Returns a pointer to the specified descriptor in the RX descriptor queue */ --static inline efx_qword_t *falcon_rx_desc(struct efx_rx_queue *rx_queue, -- unsigned int index) --{ -- return (((efx_qword_t *) (rx_queue->rxd.addr)) + index); --} -- --/* This creates an entry in the RX descriptor queue */ --static inline void falcon_build_rx_desc(struct efx_rx_queue *rx_queue, -- unsigned index) --{ -- struct efx_rx_buffer *rx_buf; -- efx_qword_t *rxd; -- -- rxd = falcon_rx_desc(rx_queue, index); -- rx_buf = efx_rx_buffer(rx_queue, index); -- EFX_POPULATE_QWORD_3(*rxd, -- RX_KER_BUF_SIZE, -- rx_buf->len - -- rx_queue->efx->type->rx_buffer_padding, -- RX_KER_BUF_REGION, 0, -- RX_KER_BUF_ADR, rx_buf->dma_addr); --} -- --/* This writes to the RX_DESC_WPTR register for the specified receive -- * descriptor ring. -- */ --void falcon_notify_rx_desc(struct efx_rx_queue *rx_queue) --{ -- efx_dword_t reg; -- unsigned write_ptr; -- -- while (rx_queue->notified_count != rx_queue->added_count) { -- falcon_build_rx_desc(rx_queue, -- rx_queue->notified_count & -- FALCON_RXD_RING_MASK); -- ++rx_queue->notified_count; -- } -- -- wmb(); -- write_ptr = rx_queue->added_count & FALCON_RXD_RING_MASK; -- EFX_POPULATE_DWORD_1(reg, RX_DESC_WPTR_DWORD, write_ptr); -- falcon_writel_page(rx_queue->efx, ®, -- RX_DESC_UPD_REG_KER_DWORD, rx_queue->queue); --} -- --int falcon_probe_rx(struct efx_rx_queue *rx_queue) --{ -- struct efx_nic *efx = rx_queue->efx; -- return falcon_alloc_special_buffer(efx, &rx_queue->rxd, -- FALCON_RXD_RING_SIZE * -- sizeof(efx_qword_t)); --} -- --void falcon_init_rx(struct efx_rx_queue *rx_queue) --{ -- efx_oword_t rx_desc_ptr; -- struct efx_nic *efx = rx_queue->efx; -- bool is_b0 = falcon_rev(efx) >= FALCON_REV_B0; -- bool iscsi_digest_en = is_b0; -- -- EFX_LOG(efx, "RX queue %d ring in special buffers %d-%d\n", -- rx_queue->queue, rx_queue->rxd.index, -- rx_queue->rxd.index + rx_queue->rxd.entries - 1); -- -- rx_queue->flushed = false; -- -- /* Pin RX descriptor ring */ -- falcon_init_special_buffer(efx, &rx_queue->rxd); -- -- /* Push RX descriptor ring to card */ -- EFX_POPULATE_OWORD_10(rx_desc_ptr, -- RX_ISCSI_DDIG_EN, iscsi_digest_en, -- RX_ISCSI_HDIG_EN, iscsi_digest_en, -- RX_DESCQ_BUF_BASE_ID, rx_queue->rxd.index, -- RX_DESCQ_EVQ_ID, rx_queue->channel->channel, -- RX_DESCQ_OWNER_ID, 0, -- RX_DESCQ_LABEL, rx_queue->queue, -- RX_DESCQ_SIZE, FALCON_RXD_RING_ORDER, -- RX_DESCQ_TYPE, 0 /* kernel queue */ , -- /* For >=B0 this is scatter so disable */ -- RX_DESCQ_JUMBO, !is_b0, -- RX_DESCQ_EN, 1); -- falcon_write_table(efx, &rx_desc_ptr, efx->type->rxd_ptr_tbl_base, -- rx_queue->queue); --} -- --static void falcon_flush_rx_queue(struct efx_rx_queue *rx_queue) --{ -- struct efx_nic *efx = rx_queue->efx; -- efx_oword_t rx_flush_descq; -- -- /* Post a flush command */ -- EFX_POPULATE_OWORD_2(rx_flush_descq, -- RX_FLUSH_DESCQ_CMD, 1, -- RX_FLUSH_DESCQ, rx_queue->queue); -- falcon_write(efx, &rx_flush_descq, RX_FLUSH_DESCQ_REG_KER); --} -- --void falcon_fini_rx(struct efx_rx_queue *rx_queue) --{ -- efx_oword_t rx_desc_ptr; -- struct efx_nic *efx = rx_queue->efx; -- -- /* The queue should already have been flushed */ -- WARN_ON(!rx_queue->flushed); -- -- /* Remove RX descriptor ring from card */ -- EFX_ZERO_OWORD(rx_desc_ptr); -- falcon_write_table(efx, &rx_desc_ptr, efx->type->rxd_ptr_tbl_base, -- rx_queue->queue); -- -- /* Unpin RX descriptor ring */ -- falcon_fini_special_buffer(efx, &rx_queue->rxd); --} -- --/* Free buffers backing RX queue */ --void falcon_remove_rx(struct efx_rx_queue *rx_queue) --{ -- falcon_free_special_buffer(rx_queue->efx, &rx_queue->rxd); --} -- --/************************************************************************** -- * -- * Falcon event queue processing -- * Event queues are processed by per-channel tasklets. -- * -- **************************************************************************/ -- --/* Update a channel's event queue's read pointer (RPTR) register -- * -- * This writes the EVQ_RPTR_REG register for the specified channel's -- * event queue. -- * -- * Note that EVQ_RPTR_REG contains the index of the "last read" event, -- * whereas channel->eventq_read_ptr contains the index of the "next to -- * read" event. -- */ --void falcon_eventq_read_ack(struct efx_channel *channel) --{ -- efx_dword_t reg; -- struct efx_nic *efx = channel->efx; -- -- EFX_POPULATE_DWORD_1(reg, EVQ_RPTR_DWORD, channel->eventq_read_ptr); -- falcon_writel_table(efx, ®, efx->type->evq_rptr_tbl_base, -- channel->channel); --} -- --/* Use HW to insert a SW defined event */ --void falcon_generate_event(struct efx_channel *channel, efx_qword_t *event) --{ -- efx_oword_t drv_ev_reg; -- -- EFX_POPULATE_OWORD_2(drv_ev_reg, -- DRV_EV_QID, channel->channel, -- DRV_EV_DATA, -- EFX_QWORD_FIELD64(*event, WHOLE_EVENT)); -- falcon_write(channel->efx, &drv_ev_reg, DRV_EV_REG_KER); --} -- --/* Handle a transmit completion event -- * -- * Falcon batches TX completion events; the message we receive is of -- * the form "complete all TX events up to this index". -- */ --static void falcon_handle_tx_event(struct efx_channel *channel, -- efx_qword_t *event) --{ -- unsigned int tx_ev_desc_ptr; -- unsigned int tx_ev_q_label; -- struct efx_tx_queue *tx_queue; -- struct efx_nic *efx = channel->efx; -- -- if (likely(EFX_QWORD_FIELD(*event, TX_EV_COMP))) { -- /* Transmit completion */ -- tx_ev_desc_ptr = EFX_QWORD_FIELD(*event, TX_EV_DESC_PTR); -- tx_ev_q_label = EFX_QWORD_FIELD(*event, TX_EV_Q_LABEL); -- tx_queue = &efx->tx_queue[tx_ev_q_label]; -- channel->irq_mod_score += -- (tx_ev_desc_ptr - tx_queue->read_count) & -- efx->type->txd_ring_mask; -- efx_xmit_done(tx_queue, tx_ev_desc_ptr); -- } else if (EFX_QWORD_FIELD(*event, TX_EV_WQ_FF_FULL)) { -- /* Rewrite the FIFO write pointer */ -- tx_ev_q_label = EFX_QWORD_FIELD(*event, TX_EV_Q_LABEL); -- tx_queue = &efx->tx_queue[tx_ev_q_label]; -- -- if (efx_dev_registered(efx)) -- netif_tx_lock(efx->net_dev); -- falcon_notify_tx_desc(tx_queue); -- if (efx_dev_registered(efx)) -- netif_tx_unlock(efx->net_dev); -- } else if (EFX_QWORD_FIELD(*event, TX_EV_PKT_ERR) && -- EFX_WORKAROUND_10727(efx)) { -- efx_schedule_reset(efx, RESET_TYPE_TX_DESC_FETCH); -- } else { -- EFX_ERR(efx, "channel %d unexpected TX event " -- EFX_QWORD_FMT"\n", channel->channel, -- EFX_QWORD_VAL(*event)); -- } --} -- --/* Detect errors included in the rx_evt_pkt_ok bit. */ --static void falcon_handle_rx_not_ok(struct efx_rx_queue *rx_queue, -- const efx_qword_t *event, -- bool *rx_ev_pkt_ok, -- bool *discard) --{ -- struct efx_nic *efx = rx_queue->efx; -- bool rx_ev_buf_owner_id_err, rx_ev_ip_hdr_chksum_err; -- bool rx_ev_tcp_udp_chksum_err, rx_ev_eth_crc_err; -- bool rx_ev_frm_trunc, rx_ev_drib_nib, rx_ev_tobe_disc; -- bool rx_ev_other_err, rx_ev_pause_frm; -- bool rx_ev_ip_frag_err, rx_ev_hdr_type, rx_ev_mcast_pkt; -- unsigned rx_ev_pkt_type; -- -- rx_ev_hdr_type = EFX_QWORD_FIELD(*event, RX_EV_HDR_TYPE); -- rx_ev_mcast_pkt = EFX_QWORD_FIELD(*event, RX_EV_MCAST_PKT); -- rx_ev_tobe_disc = EFX_QWORD_FIELD(*event, RX_EV_TOBE_DISC); -- rx_ev_pkt_type = EFX_QWORD_FIELD(*event, RX_EV_PKT_TYPE); -- rx_ev_buf_owner_id_err = EFX_QWORD_FIELD(*event, -- RX_EV_BUF_OWNER_ID_ERR); -- rx_ev_ip_frag_err = EFX_QWORD_FIELD(*event, RX_EV_IF_FRAG_ERR); -- rx_ev_ip_hdr_chksum_err = EFX_QWORD_FIELD(*event, -- RX_EV_IP_HDR_CHKSUM_ERR); -- rx_ev_tcp_udp_chksum_err = EFX_QWORD_FIELD(*event, -- RX_EV_TCP_UDP_CHKSUM_ERR); -- rx_ev_eth_crc_err = EFX_QWORD_FIELD(*event, RX_EV_ETH_CRC_ERR); -- rx_ev_frm_trunc = EFX_QWORD_FIELD(*event, RX_EV_FRM_TRUNC); -- rx_ev_drib_nib = ((falcon_rev(efx) >= FALCON_REV_B0) ? -- 0 : EFX_QWORD_FIELD(*event, RX_EV_DRIB_NIB)); -- rx_ev_pause_frm = EFX_QWORD_FIELD(*event, RX_EV_PAUSE_FRM_ERR); -- -- /* Every error apart from tobe_disc and pause_frm */ -- rx_ev_other_err = (rx_ev_drib_nib | rx_ev_tcp_udp_chksum_err | -- rx_ev_buf_owner_id_err | rx_ev_eth_crc_err | -- rx_ev_frm_trunc | rx_ev_ip_hdr_chksum_err); -- -- /* Count errors that are not in MAC stats. Ignore expected -- * checksum errors during self-test. */ -- if (rx_ev_frm_trunc) -- ++rx_queue->channel->n_rx_frm_trunc; -- else if (rx_ev_tobe_disc) -- ++rx_queue->channel->n_rx_tobe_disc; -- else if (!efx->loopback_selftest) { -- if (rx_ev_ip_hdr_chksum_err) -- ++rx_queue->channel->n_rx_ip_hdr_chksum_err; -- else if (rx_ev_tcp_udp_chksum_err) -- ++rx_queue->channel->n_rx_tcp_udp_chksum_err; -- } -- if (rx_ev_ip_frag_err) -- ++rx_queue->channel->n_rx_ip_frag_err; -- -- /* The frame must be discarded if any of these are true. */ -- *discard = (rx_ev_eth_crc_err | rx_ev_frm_trunc | rx_ev_drib_nib | -- rx_ev_tobe_disc | rx_ev_pause_frm); -- -- /* TOBE_DISC is expected on unicast mismatches; don't print out an -- * error message. FRM_TRUNC indicates RXDP dropped the packet due -- * to a FIFO overflow. -- */ --#ifdef EFX_ENABLE_DEBUG -- if (rx_ev_other_err) { -- EFX_INFO_RL(efx, " RX queue %d unexpected RX event " -- EFX_QWORD_FMT "%s%s%s%s%s%s%s%s\n", -- rx_queue->queue, EFX_QWORD_VAL(*event), -- rx_ev_buf_owner_id_err ? " [OWNER_ID_ERR]" : "", -- rx_ev_ip_hdr_chksum_err ? -- " [IP_HDR_CHKSUM_ERR]" : "", -- rx_ev_tcp_udp_chksum_err ? -- " [TCP_UDP_CHKSUM_ERR]" : "", -- rx_ev_eth_crc_err ? " [ETH_CRC_ERR]" : "", -- rx_ev_frm_trunc ? " [FRM_TRUNC]" : "", -- rx_ev_drib_nib ? " [DRIB_NIB]" : "", -- rx_ev_tobe_disc ? " [TOBE_DISC]" : "", -- rx_ev_pause_frm ? " [PAUSE]" : ""); -- } --#endif --} -- --/* Handle receive events that are not in-order. */ --static void falcon_handle_rx_bad_index(struct efx_rx_queue *rx_queue, -- unsigned index) --{ -- struct efx_nic *efx = rx_queue->efx; -- unsigned expected, dropped; -- -- expected = rx_queue->removed_count & FALCON_RXD_RING_MASK; -- dropped = ((index + FALCON_RXD_RING_SIZE - expected) & -- FALCON_RXD_RING_MASK); -- EFX_INFO(efx, "dropped %d events (index=%d expected=%d)\n", -- dropped, index, expected); -- -- efx_schedule_reset(efx, EFX_WORKAROUND_5676(efx) ? -- RESET_TYPE_RX_RECOVERY : RESET_TYPE_DISABLE); --} -- --/* Handle a packet received event -- * -- * Falcon silicon gives a "discard" flag if it's a unicast packet with the -- * wrong destination address -- * Also "is multicast" and "matches multicast filter" flags can be used to -- * discard non-matching multicast packets. -- */ --static void falcon_handle_rx_event(struct efx_channel *channel, -- const efx_qword_t *event) --{ -- unsigned int rx_ev_desc_ptr, rx_ev_byte_cnt; -- unsigned int rx_ev_hdr_type, rx_ev_mcast_pkt; -- unsigned expected_ptr; -- bool rx_ev_pkt_ok, discard = false, checksummed; -- struct efx_rx_queue *rx_queue; -- struct efx_nic *efx = channel->efx; -- -- /* Basic packet information */ -- rx_ev_byte_cnt = EFX_QWORD_FIELD(*event, RX_EV_BYTE_CNT); -- rx_ev_pkt_ok = EFX_QWORD_FIELD(*event, RX_EV_PKT_OK); -- rx_ev_hdr_type = EFX_QWORD_FIELD(*event, RX_EV_HDR_TYPE); -- WARN_ON(EFX_QWORD_FIELD(*event, RX_EV_JUMBO_CONT)); -- WARN_ON(EFX_QWORD_FIELD(*event, RX_EV_SOP) != 1); -- WARN_ON(EFX_QWORD_FIELD(*event, RX_EV_Q_LABEL) != channel->channel); -- -- rx_queue = &efx->rx_queue[channel->channel]; -- -- rx_ev_desc_ptr = EFX_QWORD_FIELD(*event, RX_EV_DESC_PTR); -- expected_ptr = rx_queue->removed_count & FALCON_RXD_RING_MASK; -- if (unlikely(rx_ev_desc_ptr != expected_ptr)) -- falcon_handle_rx_bad_index(rx_queue, rx_ev_desc_ptr); -- -- if (likely(rx_ev_pkt_ok)) { -- /* If packet is marked as OK and packet type is TCP/IPv4 or -- * UDP/IPv4, then we can rely on the hardware checksum. -- */ -- checksummed = RX_EV_HDR_TYPE_HAS_CHECKSUMS(rx_ev_hdr_type); -- } else { -- falcon_handle_rx_not_ok(rx_queue, event, &rx_ev_pkt_ok, -- &discard); -- checksummed = false; -- } -- -- /* Detect multicast packets that didn't match the filter */ -- rx_ev_mcast_pkt = EFX_QWORD_FIELD(*event, RX_EV_MCAST_PKT); -- if (rx_ev_mcast_pkt) { -- unsigned int rx_ev_mcast_hash_match = -- EFX_QWORD_FIELD(*event, RX_EV_MCAST_HASH_MATCH); -- -- if (unlikely(!rx_ev_mcast_hash_match)) -- discard = true; -- } -- -- channel->irq_mod_score += 2; -- -- /* Handle received packet */ -- efx_rx_packet(rx_queue, rx_ev_desc_ptr, rx_ev_byte_cnt, -- checksummed, discard); --} -- --/* Global events are basically PHY events */ --static void falcon_handle_global_event(struct efx_channel *channel, -- efx_qword_t *event) --{ -- struct efx_nic *efx = channel->efx; -- bool handled = false; -- -- if (EFX_QWORD_FIELD(*event, G_PHY0_INTR) || -- EFX_QWORD_FIELD(*event, G_PHY1_INTR) || -- EFX_QWORD_FIELD(*event, XG_PHY_INTR) || -- EFX_QWORD_FIELD(*event, XFP_PHY_INTR)) { -- efx->phy_op->clear_interrupt(efx); -- queue_work(efx->workqueue, &efx->phy_work); -- handled = true; -- } -- -- if ((falcon_rev(efx) >= FALCON_REV_B0) && -- EFX_QWORD_FIELD(*event, XG_MNT_INTR_B0)) { -- queue_work(efx->workqueue, &efx->mac_work); -- handled = true; -- } -- -- if (EFX_QWORD_FIELD_VER(efx, *event, RX_RECOVERY)) { -- EFX_ERR(efx, "channel %d seen global RX_RESET " -- "event. Resetting.\n", channel->channel); -- -- atomic_inc(&efx->rx_reset); -- efx_schedule_reset(efx, EFX_WORKAROUND_6555(efx) ? -- RESET_TYPE_RX_RECOVERY : RESET_TYPE_DISABLE); -- handled = true; -- } -- -- if (!handled) -- EFX_ERR(efx, "channel %d unknown global event " -- EFX_QWORD_FMT "\n", channel->channel, -- EFX_QWORD_VAL(*event)); --} -- --static void falcon_handle_driver_event(struct efx_channel *channel, -- efx_qword_t *event) --{ -- struct efx_nic *efx = channel->efx; -- unsigned int ev_sub_code; -- unsigned int ev_sub_data; -- -- ev_sub_code = EFX_QWORD_FIELD(*event, DRIVER_EV_SUB_CODE); -- ev_sub_data = EFX_QWORD_FIELD(*event, DRIVER_EV_SUB_DATA); -- -- switch (ev_sub_code) { -- case TX_DESCQ_FLS_DONE_EV_DECODE: -- EFX_TRACE(efx, "channel %d TXQ %d flushed\n", -- channel->channel, ev_sub_data); -- break; -- case RX_DESCQ_FLS_DONE_EV_DECODE: -- EFX_TRACE(efx, "channel %d RXQ %d flushed\n", -- channel->channel, ev_sub_data); -- break; -- case EVQ_INIT_DONE_EV_DECODE: -- EFX_LOG(efx, "channel %d EVQ %d initialised\n", -- channel->channel, ev_sub_data); -- break; -- case SRM_UPD_DONE_EV_DECODE: -- EFX_TRACE(efx, "channel %d SRAM update done\n", -- channel->channel); -- break; -- case WAKE_UP_EV_DECODE: -- EFX_TRACE(efx, "channel %d RXQ %d wakeup event\n", -- channel->channel, ev_sub_data); -- break; -- case TIMER_EV_DECODE: -- EFX_TRACE(efx, "channel %d RX queue %d timer expired\n", -- channel->channel, ev_sub_data); -- break; -- case RX_RECOVERY_EV_DECODE: -- EFX_ERR(efx, "channel %d seen DRIVER RX_RESET event. " -- "Resetting.\n", channel->channel); -- atomic_inc(&efx->rx_reset); -- efx_schedule_reset(efx, -- EFX_WORKAROUND_6555(efx) ? -- RESET_TYPE_RX_RECOVERY : -- RESET_TYPE_DISABLE); -- break; -- case RX_DSC_ERROR_EV_DECODE: -- EFX_ERR(efx, "RX DMA Q %d reports descriptor fetch error." -- " RX Q %d is disabled.\n", ev_sub_data, ev_sub_data); -- efx_schedule_reset(efx, RESET_TYPE_RX_DESC_FETCH); -- break; -- case TX_DSC_ERROR_EV_DECODE: -- EFX_ERR(efx, "TX DMA Q %d reports descriptor fetch error." -- " TX Q %d is disabled.\n", ev_sub_data, ev_sub_data); -- efx_schedule_reset(efx, RESET_TYPE_TX_DESC_FETCH); -- break; -- default: -- EFX_TRACE(efx, "channel %d unknown driver event code %d " -- "data %04x\n", channel->channel, ev_sub_code, -- ev_sub_data); -- break; -- } --} -- --int falcon_process_eventq(struct efx_channel *channel, int rx_quota) --{ -- unsigned int read_ptr; -- efx_qword_t event, *p_event; -- int ev_code; -- int rx_packets = 0; -- -- read_ptr = channel->eventq_read_ptr; -- -- do { -- p_event = falcon_event(channel, read_ptr); -- event = *p_event; -- -- if (!falcon_event_present(&event)) -- /* End of events */ -- break; -- -- EFX_TRACE(channel->efx, "channel %d event is "EFX_QWORD_FMT"\n", -- channel->channel, EFX_QWORD_VAL(event)); -- -- /* Clear this event by marking it all ones */ -- EFX_SET_QWORD(*p_event); -- -- ev_code = EFX_QWORD_FIELD(event, EV_CODE); -- -- switch (ev_code) { -- case RX_IP_EV_DECODE: -- falcon_handle_rx_event(channel, &event); -- ++rx_packets; -- break; -- case TX_IP_EV_DECODE: -- falcon_handle_tx_event(channel, &event); -- break; -- case DRV_GEN_EV_DECODE: -- channel->eventq_magic -- = EFX_QWORD_FIELD(event, EVQ_MAGIC); -- EFX_LOG(channel->efx, "channel %d received generated " -- "event "EFX_QWORD_FMT"\n", channel->channel, -- EFX_QWORD_VAL(event)); -- break; -- case GLOBAL_EV_DECODE: -- falcon_handle_global_event(channel, &event); -- break; -- case DRIVER_EV_DECODE: -- falcon_handle_driver_event(channel, &event); -- break; -- default: -- EFX_ERR(channel->efx, "channel %d unknown event type %d" -- " (data " EFX_QWORD_FMT ")\n", channel->channel, -- ev_code, EFX_QWORD_VAL(event)); -- } -- -- /* Increment read pointer */ -- read_ptr = (read_ptr + 1) & FALCON_EVQ_MASK; -- -- } while (rx_packets < rx_quota); -- -- channel->eventq_read_ptr = read_ptr; -- return rx_packets; --} -- --void falcon_set_int_moderation(struct efx_channel *channel) -+static void falcon_push_irq_moderation(struct efx_channel *channel) - { - efx_dword_t timer_cmd; - struct efx_nic *efx = channel->efx; - - /* Set timer register */ - if (channel->irq_moderation) { -- /* Round to resolution supported by hardware. The value we -- * program is based at 0. So actual interrupt moderation -- * achieved is ((x + 1) * res). -- */ -- channel->irq_moderation -= (channel->irq_moderation % -- FALCON_IRQ_MOD_RESOLUTION); -- if (channel->irq_moderation < FALCON_IRQ_MOD_RESOLUTION) -- channel->irq_moderation = FALCON_IRQ_MOD_RESOLUTION; - EFX_POPULATE_DWORD_2(timer_cmd, -- TIMER_MODE, TIMER_MODE_INT_HLDOFF, -- TIMER_VAL, -- channel->irq_moderation / -- FALCON_IRQ_MOD_RESOLUTION - 1); -+ FRF_AB_TC_TIMER_MODE, -+ FFE_BB_TIMER_MODE_INT_HLDOFF, -+ FRF_AB_TC_TIMER_VAL, -+ channel->irq_moderation - 1); - } else { - EFX_POPULATE_DWORD_2(timer_cmd, -- TIMER_MODE, TIMER_MODE_DIS, -- TIMER_VAL, 0); -+ FRF_AB_TC_TIMER_MODE, -+ FFE_BB_TIMER_MODE_DIS, -+ FRF_AB_TC_TIMER_VAL, 0); - } -- falcon_writel_page_locked(efx, &timer_cmd, TIMER_CMD_REG_KER, -- channel->channel); -- -+ BUILD_BUG_ON(FR_AA_TIMER_COMMAND_KER != FR_BZ_TIMER_COMMAND_P0); -+ efx_writed_page_locked(efx, &timer_cmd, FR_BZ_TIMER_COMMAND_P0, -+ channel->channel); - } - --/* Allocate buffer table entries for event queue */ --int falcon_probe_eventq(struct efx_channel *channel) --{ -- struct efx_nic *efx = channel->efx; -- unsigned int evq_size; -- -- evq_size = FALCON_EVQ_SIZE * sizeof(efx_qword_t); -- return falcon_alloc_special_buffer(efx, &channel->eventq, evq_size); --} -+static void falcon_deconfigure_mac_wrapper(struct efx_nic *efx); - --void falcon_init_eventq(struct efx_channel *channel) -+static void falcon_prepare_flush(struct efx_nic *efx) - { -- efx_oword_t evq_ptr; -- struct efx_nic *efx = channel->efx; -- -- EFX_LOG(efx, "channel %d event queue in special buffers %d-%d\n", -- channel->channel, channel->eventq.index, -- channel->eventq.index + channel->eventq.entries - 1); -- -- /* Pin event queue buffer */ -- falcon_init_special_buffer(efx, &channel->eventq); -+ falcon_deconfigure_mac_wrapper(efx); - -- /* Fill event queue with all ones (i.e. empty events) */ -- memset(channel->eventq.addr, 0xff, channel->eventq.len); -- -- /* Push event queue to card */ -- EFX_POPULATE_OWORD_3(evq_ptr, -- EVQ_EN, 1, -- EVQ_SIZE, FALCON_EVQ_ORDER, -- EVQ_BUF_BASE_ID, channel->eventq.index); -- falcon_write_table(efx, &evq_ptr, efx->type->evq_ptr_tbl_base, -- channel->channel); -- -- falcon_set_int_moderation(channel); --} -- --void falcon_fini_eventq(struct efx_channel *channel) --{ -- efx_oword_t eventq_ptr; -- struct efx_nic *efx = channel->efx; -- -- /* Remove event queue from card */ -- EFX_ZERO_OWORD(eventq_ptr); -- falcon_write_table(efx, &eventq_ptr, efx->type->evq_ptr_tbl_base, -- channel->channel); -- -- /* Unpin event queue */ -- falcon_fini_special_buffer(efx, &channel->eventq); --} -- --/* Free buffers backing event queue */ --void falcon_remove_eventq(struct efx_channel *channel) --{ -- falcon_free_special_buffer(channel->efx, &channel->eventq); --} -- -- --/* Generates a test event on the event queue. A subsequent call to -- * process_eventq() should pick up the event and place the value of -- * "magic" into channel->eventq_magic; -- */ --void falcon_generate_test_event(struct efx_channel *channel, unsigned int magic) --{ -- efx_qword_t test_event; -- -- EFX_POPULATE_QWORD_2(test_event, -- EV_CODE, DRV_GEN_EV_DECODE, -- EVQ_MAGIC, magic); -- falcon_generate_event(channel, &test_event); --} -- --void falcon_sim_phy_event(struct efx_nic *efx) --{ -- efx_qword_t phy_event; -- -- EFX_POPULATE_QWORD_1(phy_event, EV_CODE, GLOBAL_EV_DECODE); -- if (EFX_IS10G(efx)) -- EFX_SET_QWORD_FIELD(phy_event, XG_PHY_INTR, 1); -- else -- EFX_SET_QWORD_FIELD(phy_event, G_PHY0_INTR, 1); -- -- falcon_generate_event(&efx->channel[0], &phy_event); --} -- --/************************************************************************** -- * -- * Flush handling -- * -- **************************************************************************/ -- -- --static void falcon_poll_flush_events(struct efx_nic *efx) --{ -- struct efx_channel *channel = &efx->channel[0]; -- struct efx_tx_queue *tx_queue; -- struct efx_rx_queue *rx_queue; -- unsigned int read_ptr = channel->eventq_read_ptr; -- unsigned int end_ptr = (read_ptr - 1) & FALCON_EVQ_MASK; -- -- do { -- efx_qword_t *event = falcon_event(channel, read_ptr); -- int ev_code, ev_sub_code, ev_queue; -- bool ev_failed; -- -- if (!falcon_event_present(event)) -- break; -- -- ev_code = EFX_QWORD_FIELD(*event, EV_CODE); -- ev_sub_code = EFX_QWORD_FIELD(*event, DRIVER_EV_SUB_CODE); -- if (ev_code == DRIVER_EV_DECODE && -- ev_sub_code == TX_DESCQ_FLS_DONE_EV_DECODE) { -- ev_queue = EFX_QWORD_FIELD(*event, -- DRIVER_EV_TX_DESCQ_ID); -- if (ev_queue < EFX_TX_QUEUE_COUNT) { -- tx_queue = efx->tx_queue + ev_queue; -- tx_queue->flushed = true; -- } -- } else if (ev_code == DRIVER_EV_DECODE && -- ev_sub_code == RX_DESCQ_FLS_DONE_EV_DECODE) { -- ev_queue = EFX_QWORD_FIELD(*event, -- DRIVER_EV_RX_DESCQ_ID); -- ev_failed = EFX_QWORD_FIELD(*event, -- DRIVER_EV_RX_FLUSH_FAIL); -- if (ev_queue < efx->n_rx_queues) { -- rx_queue = efx->rx_queue + ev_queue; -- -- /* retry the rx flush */ -- if (ev_failed) -- falcon_flush_rx_queue(rx_queue); -- else -- rx_queue->flushed = true; -- } -- } -- -- read_ptr = (read_ptr + 1) & FALCON_EVQ_MASK; -- } while (read_ptr != end_ptr); --} -- --/* Handle tx and rx flushes at the same time, since they run in -- * parallel in the hardware and there's no reason for us to -- * serialise them */ --int falcon_flush_queues(struct efx_nic *efx) --{ -- struct efx_rx_queue *rx_queue; -- struct efx_tx_queue *tx_queue; -- int i; -- bool outstanding; -- -- /* Issue flush requests */ -- efx_for_each_tx_queue(tx_queue, efx) { -- tx_queue->flushed = false; -- falcon_flush_tx_queue(tx_queue); -- } -- efx_for_each_rx_queue(rx_queue, efx) { -- rx_queue->flushed = false; -- falcon_flush_rx_queue(rx_queue); -- } -- -- /* Poll the evq looking for flush completions. Since we're not pushing -- * any more rx or tx descriptors at this point, we're in no danger of -- * overflowing the evq whilst we wait */ -- for (i = 0; i < FALCON_FLUSH_POLL_COUNT; ++i) { -- msleep(FALCON_FLUSH_INTERVAL); -- falcon_poll_flush_events(efx); -- -- /* Check if every queue has been succesfully flushed */ -- outstanding = false; -- efx_for_each_tx_queue(tx_queue, efx) -- outstanding |= !tx_queue->flushed; -- efx_for_each_rx_queue(rx_queue, efx) -- outstanding |= !rx_queue->flushed; -- if (!outstanding) -- return 0; -- } -- -- /* Mark the queues as all flushed. We're going to return failure -- * leading to a reset, or fake up success anyway. "flushed" now -- * indicates that we tried to flush. */ -- efx_for_each_tx_queue(tx_queue, efx) { -- if (!tx_queue->flushed) -- EFX_ERR(efx, "tx queue %d flush command timed out\n", -- tx_queue->queue); -- tx_queue->flushed = true; -- } -- efx_for_each_rx_queue(rx_queue, efx) { -- if (!rx_queue->flushed) -- EFX_ERR(efx, "rx queue %d flush command timed out\n", -- rx_queue->queue); -- rx_queue->flushed = true; -- } -- -- if (EFX_WORKAROUND_7803(efx)) -- return 0; -- -- return -ETIMEDOUT; --} -- --/************************************************************************** -- * -- * Falcon hardware interrupts -- * The hardware interrupt handler does very little work; all the event -- * queue processing is carried out by per-channel tasklets. -- * -- **************************************************************************/ -- --/* Enable/disable/generate Falcon interrupts */ --static inline void falcon_interrupts(struct efx_nic *efx, int enabled, -- int force) --{ -- efx_oword_t int_en_reg_ker; -- -- EFX_POPULATE_OWORD_2(int_en_reg_ker, -- KER_INT_KER, force, -- DRV_INT_EN_KER, enabled); -- falcon_write(efx, &int_en_reg_ker, INT_EN_REG_KER); --} -- --void falcon_enable_interrupts(struct efx_nic *efx) --{ -- efx_oword_t int_adr_reg_ker; -- struct efx_channel *channel; -- -- EFX_ZERO_OWORD(*((efx_oword_t *) efx->irq_status.addr)); -- wmb(); /* Ensure interrupt vector is clear before interrupts enabled */ -- -- /* Program address */ -- EFX_POPULATE_OWORD_2(int_adr_reg_ker, -- NORM_INT_VEC_DIS_KER, EFX_INT_MODE_USE_MSI(efx), -- INT_ADR_KER, efx->irq_status.dma_addr); -- falcon_write(efx, &int_adr_reg_ker, INT_ADR_REG_KER); -- -- /* Enable interrupts */ -- falcon_interrupts(efx, 1, 0); -- -- /* Force processing of all the channels to get the EVQ RPTRs up to -- date */ -- efx_for_each_channel(channel, efx) -- efx_schedule_channel(channel); --} -- --void falcon_disable_interrupts(struct efx_nic *efx) --{ -- /* Disable interrupts */ -- falcon_interrupts(efx, 0, 0); --} -- --/* Generate a Falcon test interrupt -- * Interrupt must already have been enabled, otherwise nasty things -- * may happen. -- */ --void falcon_generate_interrupt(struct efx_nic *efx) --{ -- falcon_interrupts(efx, 1, 1); -+ /* Wait for the tx and rx fifo's to get to the next packet boundary -+ * (~1ms without back-pressure), then to drain the remainder of the -+ * fifo's at data path speeds (negligible), with a healthy margin. */ -+ msleep(10); - } - - /* Acknowledge a legacy interrupt from Falcon -@@ -1364,113 +144,17 @@ void falcon_generate_interrupt(struct efx_nic *efx) - * - * NB most hardware supports MSI interrupts - */ --static inline void falcon_irq_ack_a1(struct efx_nic *efx) --{ -- efx_dword_t reg; -- -- EFX_POPULATE_DWORD_1(reg, INT_ACK_DUMMY_DATA, 0xb7eb7e); -- falcon_writel(efx, ®, INT_ACK_REG_KER_A1); -- falcon_readl(efx, ®, WORK_AROUND_BROKEN_PCI_READS_REG_KER_A1); --} -- --/* Process a fatal interrupt -- * Disable bus mastering ASAP and schedule a reset -- */ --static irqreturn_t falcon_fatal_interrupt(struct efx_nic *efx) -+inline void falcon_irq_ack_a1(struct efx_nic *efx) - { -- struct falcon_nic_data *nic_data = efx->nic_data; -- efx_oword_t *int_ker = efx->irq_status.addr; -- efx_oword_t fatal_intr; -- int error, mem_perr; -- -- falcon_read(efx, &fatal_intr, FATAL_INTR_REG_KER); -- error = EFX_OWORD_FIELD(fatal_intr, INT_KER_ERROR); -- -- EFX_ERR(efx, "SYSTEM ERROR " EFX_OWORD_FMT " status " -- EFX_OWORD_FMT ": %s\n", EFX_OWORD_VAL(*int_ker), -- EFX_OWORD_VAL(fatal_intr), -- error ? "disabling bus mastering" : "no recognised error"); -- if (error == 0) -- goto out; -- -- /* If this is a memory parity error dump which blocks are offending */ -- mem_perr = EFX_OWORD_FIELD(fatal_intr, MEM_PERR_INT_KER); -- if (mem_perr) { -- efx_oword_t reg; -- falcon_read(efx, ®, MEM_STAT_REG_KER); -- EFX_ERR(efx, "SYSTEM ERROR: memory parity error " -- EFX_OWORD_FMT "\n", EFX_OWORD_VAL(reg)); -- } -- -- /* Disable both devices */ -- pci_clear_master(efx->pci_dev); -- if (FALCON_IS_DUAL_FUNC(efx)) -- pci_clear_master(nic_data->pci_dev2); -- falcon_disable_interrupts(efx); -- -- /* Count errors and reset or disable the NIC accordingly */ -- if (nic_data->int_error_count == 0 || -- time_after(jiffies, nic_data->int_error_expire)) { -- nic_data->int_error_count = 0; -- nic_data->int_error_expire = -- jiffies + FALCON_INT_ERROR_EXPIRE * HZ; -- } -- if (++nic_data->int_error_count < FALCON_MAX_INT_ERRORS) { -- EFX_ERR(efx, "SYSTEM ERROR - reset scheduled\n"); -- efx_schedule_reset(efx, RESET_TYPE_INT_ERROR); -- } else { -- EFX_ERR(efx, "SYSTEM ERROR - max number of errors seen." -- "NIC will be disabled\n"); -- efx_schedule_reset(efx, RESET_TYPE_DISABLE); -- } --out: -- return IRQ_HANDLED; --} -- --/* Handle a legacy interrupt from Falcon -- * Acknowledges the interrupt and schedule event queue processing. -- */ --static irqreturn_t falcon_legacy_interrupt_b0(int irq, void *dev_id) --{ -- struct efx_nic *efx = dev_id; -- efx_oword_t *int_ker = efx->irq_status.addr; -- irqreturn_t result = IRQ_NONE; -- struct efx_channel *channel; - efx_dword_t reg; -- u32 queues; -- int syserr; - -- /* Read the ISR which also ACKs the interrupts */ -- falcon_readl(efx, ®, INT_ISR0_B0); -- queues = EFX_EXTRACT_DWORD(reg, 0, 31); -- -- /* Check to see if we have a serious error condition */ -- syserr = EFX_OWORD_FIELD(*int_ker, FATAL_INT); -- if (unlikely(syserr)) -- return falcon_fatal_interrupt(efx); -- -- /* Schedule processing of any interrupting queues */ -- efx_for_each_channel(channel, efx) { -- if ((queues & 1) || -- falcon_event_present( -- falcon_event(channel, channel->eventq_read_ptr))) { -- efx_schedule_channel(channel); -- result = IRQ_HANDLED; -- } -- queues >>= 1; -- } -- -- if (result == IRQ_HANDLED) { -- efx->last_irq_cpu = raw_smp_processor_id(); -- EFX_TRACE(efx, "IRQ %d on CPU %d status " EFX_DWORD_FMT "\n", -- irq, raw_smp_processor_id(), EFX_DWORD_VAL(reg)); -- } -- -- return result; -+ EFX_POPULATE_DWORD_1(reg, FRF_AA_INT_ACK_KER_FIELD, 0xb7eb7e); -+ efx_writed(efx, ®, FR_AA_INT_ACK_KER); -+ efx_readd(efx, ®, FR_AA_WORK_AROUND_BROKEN_PCI_READS); - } - - --static irqreturn_t falcon_legacy_interrupt_a1(int irq, void *dev_id) -+irqreturn_t falcon_legacy_interrupt_a1(int irq, void *dev_id) - { - struct efx_nic *efx = dev_id; - efx_oword_t *int_ker = efx->irq_status.addr; -@@ -1491,15 +175,15 @@ static irqreturn_t falcon_legacy_interrupt_a1(int irq, void *dev_id) - irq, raw_smp_processor_id(), EFX_OWORD_VAL(*int_ker)); - - /* Check to see if we have a serious error condition */ -- syserr = EFX_OWORD_FIELD(*int_ker, FATAL_INT); -+ syserr = EFX_OWORD_FIELD(*int_ker, FSF_AZ_NET_IVEC_FATAL_INT); - if (unlikely(syserr)) -- return falcon_fatal_interrupt(efx); -+ return efx_nic_fatal_interrupt(efx); - - /* Determine interrupting queues, clear interrupt status - * register and acknowledge the device interrupt. - */ -- BUILD_BUG_ON(INT_EVQS_WIDTH > EFX_MAX_CHANNELS); -- queues = EFX_OWORD_FIELD(*int_ker, INT_EVQS); -+ BUILD_BUG_ON(FSF_AZ_NET_IVEC_INT_Q_WIDTH > EFX_MAX_CHANNELS); -+ queues = EFX_OWORD_FIELD(*int_ker, FSF_AZ_NET_IVEC_INT_Q); - EFX_ZERO_OWORD(*int_ker); - wmb(); /* Ensure the vector is cleared before interrupt ack */ - falcon_irq_ack_a1(efx); -@@ -1515,126 +199,6 @@ static irqreturn_t falcon_legacy_interrupt_a1(int irq, void *dev_id) - - return IRQ_HANDLED; - } -- --/* Handle an MSI interrupt from Falcon -- * -- * Handle an MSI hardware interrupt. This routine schedules event -- * queue processing. No interrupt acknowledgement cycle is necessary. -- * Also, we never need to check that the interrupt is for us, since -- * MSI interrupts cannot be shared. -- */ --static irqreturn_t falcon_msi_interrupt(int irq, void *dev_id) --{ -- struct efx_channel *channel = dev_id; -- struct efx_nic *efx = channel->efx; -- efx_oword_t *int_ker = efx->irq_status.addr; -- int syserr; -- -- efx->last_irq_cpu = raw_smp_processor_id(); -- EFX_TRACE(efx, "IRQ %d on CPU %d status " EFX_OWORD_FMT "\n", -- irq, raw_smp_processor_id(), EFX_OWORD_VAL(*int_ker)); -- -- /* Check to see if we have a serious error condition */ -- syserr = EFX_OWORD_FIELD(*int_ker, FATAL_INT); -- if (unlikely(syserr)) -- return falcon_fatal_interrupt(efx); -- -- /* Schedule processing of the channel */ -- efx_schedule_channel(channel); -- -- return IRQ_HANDLED; --} -- -- --/* Setup RSS indirection table. -- * This maps from the hash value of the packet to RXQ -- */ --static void falcon_setup_rss_indir_table(struct efx_nic *efx) --{ -- int i = 0; -- unsigned long offset; -- efx_dword_t dword; -- -- if (falcon_rev(efx) < FALCON_REV_B0) -- return; -- -- for (offset = RX_RSS_INDIR_TBL_B0; -- offset < RX_RSS_INDIR_TBL_B0 + 0x800; -- offset += 0x10) { -- EFX_POPULATE_DWORD_1(dword, RX_RSS_INDIR_ENT_B0, -- i % efx->n_rx_queues); -- falcon_writel(efx, &dword, offset); -- i++; -- } --} -- --/* Hook interrupt handler(s) -- * Try MSI and then legacy interrupts. -- */ --int falcon_init_interrupt(struct efx_nic *efx) --{ -- struct efx_channel *channel; -- int rc; -- -- if (!EFX_INT_MODE_USE_MSI(efx)) { -- irq_handler_t handler; -- if (falcon_rev(efx) >= FALCON_REV_B0) -- handler = falcon_legacy_interrupt_b0; -- else -- handler = falcon_legacy_interrupt_a1; -- -- rc = request_irq(efx->legacy_irq, handler, IRQF_SHARED, -- efx->name, efx); -- if (rc) { -- EFX_ERR(efx, "failed to hook legacy IRQ %d\n", -- efx->pci_dev->irq); -- goto fail1; -- } -- return 0; -- } -- -- /* Hook MSI or MSI-X interrupt */ -- efx_for_each_channel(channel, efx) { -- rc = request_irq(channel->irq, falcon_msi_interrupt, -- IRQF_PROBE_SHARED, /* Not shared */ -- channel->name, channel); -- if (rc) { -- EFX_ERR(efx, "failed to hook IRQ %d\n", channel->irq); -- goto fail2; -- } -- } -- -- return 0; -- -- fail2: -- efx_for_each_channel(channel, efx) -- free_irq(channel->irq, channel); -- fail1: -- return rc; --} -- --void falcon_fini_interrupt(struct efx_nic *efx) --{ -- struct efx_channel *channel; -- efx_oword_t reg; -- -- /* Disable MSI/MSI-X interrupts */ -- efx_for_each_channel(channel, efx) { -- if (channel->irq) -- free_irq(channel->irq, channel); -- } -- -- /* ACK legacy interrupt */ -- if (falcon_rev(efx) >= FALCON_REV_B0) -- falcon_read(efx, ®, INT_ISR0_B0); -- else -- falcon_irq_ack_a1(efx); -- -- /* Disable legacy interrupt */ -- if (efx->legacy_irq) -- free_irq(efx->legacy_irq, efx); --} -- - /************************************************************************** - * - * EEPROM/flash -@@ -1647,8 +211,8 @@ void falcon_fini_interrupt(struct efx_nic *efx) - static int falcon_spi_poll(struct efx_nic *efx) - { - efx_oword_t reg; -- falcon_read(efx, ®, EE_SPI_HCMD_REG_KER); -- return EFX_OWORD_FIELD(reg, EE_SPI_HCMD_CMD_EN) ? -EBUSY : 0; -+ efx_reado(efx, ®, FR_AB_EE_SPI_HCMD); -+ return EFX_OWORD_FIELD(reg, FRF_AB_EE_SPI_HCMD_CMD_EN) ? -EBUSY : 0; - } - - /* Wait for SPI command completion */ -@@ -1678,11 +242,10 @@ static int falcon_spi_wait(struct efx_nic *efx) - } - } - --int falcon_spi_cmd(const struct efx_spi_device *spi, -+int falcon_spi_cmd(struct efx_nic *efx, const struct efx_spi_device *spi, - unsigned int command, int address, - const void *in, void *out, size_t len) - { -- struct efx_nic *efx = spi->efx; - bool addressed = (address >= 0); - bool reading = (out != NULL); - efx_oword_t reg; -@@ -1700,27 +263,27 @@ int falcon_spi_cmd(const struct efx_spi_device *spi, - - /* Program address register, if we have an address */ - if (addressed) { -- EFX_POPULATE_OWORD_1(reg, EE_SPI_HADR_ADR, address); -- falcon_write(efx, ®, EE_SPI_HADR_REG_KER); -+ EFX_POPULATE_OWORD_1(reg, FRF_AB_EE_SPI_HADR_ADR, address); -+ efx_writeo(efx, ®, FR_AB_EE_SPI_HADR); - } - - /* Program data register, if we have data */ - if (in != NULL) { - memcpy(®, in, len); -- falcon_write(efx, ®, EE_SPI_HDATA_REG_KER); -+ efx_writeo(efx, ®, FR_AB_EE_SPI_HDATA); - } - - /* Issue read/write command */ - EFX_POPULATE_OWORD_7(reg, -- EE_SPI_HCMD_CMD_EN, 1, -- EE_SPI_HCMD_SF_SEL, spi->device_id, -- EE_SPI_HCMD_DABCNT, len, -- EE_SPI_HCMD_READ, reading, -- EE_SPI_HCMD_DUBCNT, 0, -- EE_SPI_HCMD_ADBCNT, -+ FRF_AB_EE_SPI_HCMD_CMD_EN, 1, -+ FRF_AB_EE_SPI_HCMD_SF_SEL, spi->device_id, -+ FRF_AB_EE_SPI_HCMD_DABCNT, len, -+ FRF_AB_EE_SPI_HCMD_READ, reading, -+ FRF_AB_EE_SPI_HCMD_DUBCNT, 0, -+ FRF_AB_EE_SPI_HCMD_ADBCNT, - (addressed ? spi->addr_len : 0), -- EE_SPI_HCMD_ENC, command); -- falcon_write(efx, ®, EE_SPI_HCMD_REG_KER); -+ FRF_AB_EE_SPI_HCMD_ENC, command); -+ efx_writeo(efx, ®, FR_AB_EE_SPI_HCMD); - - /* Wait for read/write to complete */ - rc = falcon_spi_wait(efx); -@@ -1729,7 +292,7 @@ int falcon_spi_cmd(const struct efx_spi_device *spi, - - /* Read data */ - if (out != NULL) { -- falcon_read(efx, ®, EE_SPI_HDATA_REG_KER); -+ efx_reado(efx, ®, FR_AB_EE_SPI_HDATA); - memcpy(out, ®, len); - } - -@@ -1751,15 +314,15 @@ efx_spi_munge_command(const struct efx_spi_device *spi, - } - - /* Wait up to 10 ms for buffered write completion */ --int falcon_spi_wait_write(const struct efx_spi_device *spi) -+int -+falcon_spi_wait_write(struct efx_nic *efx, const struct efx_spi_device *spi) - { -- struct efx_nic *efx = spi->efx; - unsigned long timeout = jiffies + 1 + DIV_ROUND_UP(HZ, 100); - u8 status; - int rc; - - for (;;) { -- rc = falcon_spi_cmd(spi, SPI_RDSR, -1, NULL, -+ rc = falcon_spi_cmd(efx, spi, SPI_RDSR, -1, NULL, - &status, sizeof(status)); - if (rc) - return rc; -@@ -1775,8 +338,8 @@ int falcon_spi_wait_write(const struct efx_spi_device *spi) - } - } - --int falcon_spi_read(const struct efx_spi_device *spi, loff_t start, -- size_t len, size_t *retlen, u8 *buffer) -+int falcon_spi_read(struct efx_nic *efx, const struct efx_spi_device *spi, -+ loff_t start, size_t len, size_t *retlen, u8 *buffer) - { - size_t block_len, pos = 0; - unsigned int command; -@@ -1786,7 +349,7 @@ int falcon_spi_read(const struct efx_spi_device *spi, loff_t start, - block_len = min(len - pos, FALCON_SPI_MAX_LEN); - - command = efx_spi_munge_command(spi, SPI_READ, start + pos); -- rc = falcon_spi_cmd(spi, command, start + pos, NULL, -+ rc = falcon_spi_cmd(efx, spi, command, start + pos, NULL, - buffer + pos, block_len); - if (rc) - break; -@@ -1805,8 +368,9 @@ int falcon_spi_read(const struct efx_spi_device *spi, loff_t start, - return rc; - } - --int falcon_spi_write(const struct efx_spi_device *spi, loff_t start, -- size_t len, size_t *retlen, const u8 *buffer) -+int -+falcon_spi_write(struct efx_nic *efx, const struct efx_spi_device *spi, -+ loff_t start, size_t len, size_t *retlen, const u8 *buffer) - { - u8 verify_buffer[FALCON_SPI_MAX_LEN]; - size_t block_len, pos = 0; -@@ -1814,24 +378,24 @@ int falcon_spi_write(const struct efx_spi_device *spi, loff_t start, - int rc = 0; - - while (pos < len) { -- rc = falcon_spi_cmd(spi, SPI_WREN, -1, NULL, NULL, 0); -+ rc = falcon_spi_cmd(efx, spi, SPI_WREN, -1, NULL, NULL, 0); - if (rc) - break; - - block_len = min(len - pos, - falcon_spi_write_limit(spi, start + pos)); - command = efx_spi_munge_command(spi, SPI_WRITE, start + pos); -- rc = falcon_spi_cmd(spi, command, start + pos, -+ rc = falcon_spi_cmd(efx, spi, command, start + pos, - buffer + pos, NULL, block_len); - if (rc) - break; - -- rc = falcon_spi_wait_write(spi); -+ rc = falcon_spi_wait_write(efx, spi); - if (rc) - break; - - command = efx_spi_munge_command(spi, SPI_READ, start + pos); -- rc = falcon_spi_cmd(spi, command, start + pos, -+ rc = falcon_spi_cmd(efx, spi, command, start + pos, - NULL, verify_buffer, block_len); - if (memcmp(verify_buffer, buffer + pos, block_len)) { - rc = -EIO; -@@ -1860,60 +424,70 @@ int falcon_spi_write(const struct efx_spi_device *spi, loff_t start, - ************************************************************************** - */ - --static int falcon_reset_macs(struct efx_nic *efx) -+static void falcon_push_multicast_hash(struct efx_nic *efx) - { -- efx_oword_t reg; -+ union efx_multicast_hash *mc_hash = &efx->multicast_hash; -+ -+ WARN_ON(!mutex_is_locked(&efx->mac_lock)); -+ -+ efx_writeo(efx, &mc_hash->oword[0], FR_AB_MAC_MC_HASH_REG0); -+ efx_writeo(efx, &mc_hash->oword[1], FR_AB_MAC_MC_HASH_REG1); -+} -+ -+static void falcon_reset_macs(struct efx_nic *efx) -+{ -+ struct falcon_nic_data *nic_data = efx->nic_data; -+ efx_oword_t reg, mac_ctrl; - int count; - -- if (falcon_rev(efx) < FALCON_REV_B0) { -+ if (efx_nic_rev(efx) < EFX_REV_FALCON_B0) { - /* It's not safe to use GLB_CTL_REG to reset the - * macs, so instead use the internal MAC resets - */ - if (!EFX_IS10G(efx)) { -- EFX_POPULATE_OWORD_1(reg, GM_SW_RST, 1); -- falcon_write(efx, ®, GM_CFG1_REG); -+ EFX_POPULATE_OWORD_1(reg, FRF_AB_GM_SW_RST, 1); -+ efx_writeo(efx, ®, FR_AB_GM_CFG1); - udelay(1000); - -- EFX_POPULATE_OWORD_1(reg, GM_SW_RST, 0); -- falcon_write(efx, ®, GM_CFG1_REG); -+ EFX_POPULATE_OWORD_1(reg, FRF_AB_GM_SW_RST, 0); -+ efx_writeo(efx, ®, FR_AB_GM_CFG1); - udelay(1000); -- return 0; -+ return; - } else { -- EFX_POPULATE_OWORD_1(reg, XM_CORE_RST, 1); -- falcon_write(efx, ®, XM_GLB_CFG_REG); -+ EFX_POPULATE_OWORD_1(reg, FRF_AB_XM_CORE_RST, 1); -+ efx_writeo(efx, ®, FR_AB_XM_GLB_CFG); - - for (count = 0; count < 10000; count++) { -- falcon_read(efx, ®, XM_GLB_CFG_REG); -- if (EFX_OWORD_FIELD(reg, XM_CORE_RST) == 0) -- return 0; -+ efx_reado(efx, ®, FR_AB_XM_GLB_CFG); -+ if (EFX_OWORD_FIELD(reg, FRF_AB_XM_CORE_RST) == -+ 0) -+ return; - udelay(10); - } - - EFX_ERR(efx, "timed out waiting for XMAC core reset\n"); -- return -ETIMEDOUT; - } - } - -- /* MAC stats will fail whilst the TX fifo is draining. Serialise -- * the drain sequence with the statistics fetch */ -- efx_stats_disable(efx); -+ /* Mac stats will fail whist the TX fifo is draining */ -+ WARN_ON(nic_data->stats_disable_count == 0); - -- falcon_read(efx, ®, MAC0_CTRL_REG_KER); -- EFX_SET_OWORD_FIELD(reg, TXFIFO_DRAIN_EN_B0, 1); -- falcon_write(efx, ®, MAC0_CTRL_REG_KER); -+ efx_reado(efx, &mac_ctrl, FR_AB_MAC_CTRL); -+ EFX_SET_OWORD_FIELD(mac_ctrl, FRF_BB_TXFIFO_DRAIN_EN, 1); -+ efx_writeo(efx, &mac_ctrl, FR_AB_MAC_CTRL); - -- falcon_read(efx, ®, GLB_CTL_REG_KER); -- EFX_SET_OWORD_FIELD(reg, RST_XGTX, 1); -- EFX_SET_OWORD_FIELD(reg, RST_XGRX, 1); -- EFX_SET_OWORD_FIELD(reg, RST_EM, 1); -- falcon_write(efx, ®, GLB_CTL_REG_KER); -+ efx_reado(efx, ®, FR_AB_GLB_CTL); -+ EFX_SET_OWORD_FIELD(reg, FRF_AB_RST_XGTX, 1); -+ EFX_SET_OWORD_FIELD(reg, FRF_AB_RST_XGRX, 1); -+ EFX_SET_OWORD_FIELD(reg, FRF_AB_RST_EM, 1); -+ efx_writeo(efx, ®, FR_AB_GLB_CTL); - - count = 0; - while (1) { -- falcon_read(efx, ®, GLB_CTL_REG_KER); -- if (!EFX_OWORD_FIELD(reg, RST_XGTX) && -- !EFX_OWORD_FIELD(reg, RST_XGRX) && -- !EFX_OWORD_FIELD(reg, RST_EM)) { -+ efx_reado(efx, ®, FR_AB_GLB_CTL); -+ if (!EFX_OWORD_FIELD(reg, FRF_AB_RST_XGTX) && -+ !EFX_OWORD_FIELD(reg, FRF_AB_RST_XGRX) && -+ !EFX_OWORD_FIELD(reg, FRF_AB_RST_EM)) { - EFX_LOG(efx, "Completed MAC reset after %d loops\n", - count); - break; -@@ -1926,55 +500,50 @@ static int falcon_reset_macs(struct efx_nic *efx) - udelay(10); - } - -- efx_stats_enable(efx); -- -- /* If we've reset the EM block and the link is up, then -- * we'll have to kick the XAUI link so the PHY can recover */ -- if (efx->link_up && EFX_IS10G(efx) && EFX_WORKAROUND_5147(efx)) -- falcon_reset_xaui(efx); -- -- return 0; -+ /* Ensure the correct MAC is selected before statistics -+ * are re-enabled by the caller */ -+ efx_writeo(efx, &mac_ctrl, FR_AB_MAC_CTRL); - } - - void falcon_drain_tx_fifo(struct efx_nic *efx) - { - efx_oword_t reg; - -- if ((falcon_rev(efx) < FALCON_REV_B0) || -+ if ((efx_nic_rev(efx) < EFX_REV_FALCON_B0) || - (efx->loopback_mode != LOOPBACK_NONE)) - return; - -- falcon_read(efx, ®, MAC0_CTRL_REG_KER); -+ efx_reado(efx, ®, FR_AB_MAC_CTRL); - /* There is no point in draining more than once */ -- if (EFX_OWORD_FIELD(reg, TXFIFO_DRAIN_EN_B0)) -+ if (EFX_OWORD_FIELD(reg, FRF_BB_TXFIFO_DRAIN_EN)) - return; - - falcon_reset_macs(efx); - } - --void falcon_deconfigure_mac_wrapper(struct efx_nic *efx) -+static void falcon_deconfigure_mac_wrapper(struct efx_nic *efx) - { - efx_oword_t reg; - -- if (falcon_rev(efx) < FALCON_REV_B0) -+ if (efx_nic_rev(efx) < EFX_REV_FALCON_B0) - return; - - /* Isolate the MAC -> RX */ -- falcon_read(efx, ®, RX_CFG_REG_KER); -- EFX_SET_OWORD_FIELD(reg, RX_INGR_EN_B0, 0); -- falcon_write(efx, ®, RX_CFG_REG_KER); -+ efx_reado(efx, ®, FR_AZ_RX_CFG); -+ EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_INGR_EN, 0); -+ efx_writeo(efx, ®, FR_AZ_RX_CFG); - -- if (!efx->link_up) -- falcon_drain_tx_fifo(efx); -+ /* Isolate TX -> MAC */ -+ falcon_drain_tx_fifo(efx); - } - - void falcon_reconfigure_mac_wrapper(struct efx_nic *efx) - { -+ struct efx_link_state *link_state = &efx->link_state; - efx_oword_t reg; - int link_speed; -- bool tx_fc; - -- switch (efx->link_speed) { -+ switch (link_state->speed) { - case 10000: link_speed = 3; break; - case 1000: link_speed = 2; break; - case 100: link_speed = 1; break; -@@ -1985,75 +554,139 @@ void falcon_reconfigure_mac_wrapper(struct efx_nic *efx) - * indefinitely held and TX queue can be flushed at any point - * while the link is down. */ - EFX_POPULATE_OWORD_5(reg, -- MAC_XOFF_VAL, 0xffff /* max pause time */, -- MAC_BCAD_ACPT, 1, -- MAC_UC_PROM, efx->promiscuous, -- MAC_LINK_STATUS, 1, /* always set */ -- MAC_SPEED, link_speed); -+ FRF_AB_MAC_XOFF_VAL, 0xffff /* max pause time */, -+ FRF_AB_MAC_BCAD_ACPT, 1, -+ FRF_AB_MAC_UC_PROM, efx->promiscuous, -+ FRF_AB_MAC_LINK_STATUS, 1, /* always set */ -+ FRF_AB_MAC_SPEED, link_speed); - /* On B0, MAC backpressure can be disabled and packets get - * discarded. */ -- if (falcon_rev(efx) >= FALCON_REV_B0) { -- EFX_SET_OWORD_FIELD(reg, TXFIFO_DRAIN_EN_B0, -- !efx->link_up); -+ if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0) { -+ EFX_SET_OWORD_FIELD(reg, FRF_BB_TXFIFO_DRAIN_EN, -+ !link_state->up); - } - -- falcon_write(efx, ®, MAC0_CTRL_REG_KER); -+ efx_writeo(efx, ®, FR_AB_MAC_CTRL); - - /* Restore the multicast hash registers. */ -- falcon_set_multicast_hash(efx); -- -- /* Transmission of pause frames when RX crosses the threshold is -- * covered by RX_XOFF_MAC_EN and XM_TX_CFG_REG:XM_FCNTL. -- * Action on receipt of pause frames is controller by XM_DIS_FCNTL */ -- tx_fc = !!(efx->link_fc & EFX_FC_TX); -- falcon_read(efx, ®, RX_CFG_REG_KER); -- EFX_SET_OWORD_FIELD_VER(efx, reg, RX_XOFF_MAC_EN, tx_fc); -+ falcon_push_multicast_hash(efx); - -+ efx_reado(efx, ®, FR_AZ_RX_CFG); -+ /* Enable XOFF signal from RX FIFO (we enabled it during NIC -+ * initialisation but it may read back as 0) */ -+ EFX_SET_OWORD_FIELD(reg, FRF_AZ_RX_XOFF_MAC_EN, 1); - /* Unisolate the MAC -> RX */ -- if (falcon_rev(efx) >= FALCON_REV_B0) -- EFX_SET_OWORD_FIELD(reg, RX_INGR_EN_B0, 1); -- falcon_write(efx, ®, RX_CFG_REG_KER); -+ if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0) -+ EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_INGR_EN, 1); -+ efx_writeo(efx, ®, FR_AZ_RX_CFG); - } - --int falcon_dma_stats(struct efx_nic *efx, unsigned int done_offset) -+static void falcon_stats_request(struct efx_nic *efx) - { -+ struct falcon_nic_data *nic_data = efx->nic_data; - efx_oword_t reg; -- u32 *dma_done; -- int i; - -- if (disable_dma_stats) -- return 0; -+ WARN_ON(nic_data->stats_pending); -+ WARN_ON(nic_data->stats_disable_count); - -- /* Statistics fetch will fail if the MAC is in TX drain */ -- if (falcon_rev(efx) >= FALCON_REV_B0) { -- efx_oword_t temp; -- falcon_read(efx, &temp, MAC0_CTRL_REG_KER); -- if (EFX_OWORD_FIELD(temp, TXFIFO_DRAIN_EN_B0)) -- return 0; -- } -+ if (nic_data->stats_dma_done == NULL) -+ return; /* no mac selected */ - -- dma_done = (efx->stats_buffer.addr + done_offset); -- *dma_done = FALCON_STATS_NOT_DONE; -+ *nic_data->stats_dma_done = FALCON_STATS_NOT_DONE; -+ nic_data->stats_pending = true; - wmb(); /* ensure done flag is clear */ - - /* Initiate DMA transfer of stats */ - EFX_POPULATE_OWORD_2(reg, -- MAC_STAT_DMA_CMD, 1, -- MAC_STAT_DMA_ADR, -+ FRF_AB_MAC_STAT_DMA_CMD, 1, -+ FRF_AB_MAC_STAT_DMA_ADR, - efx->stats_buffer.dma_addr); -- falcon_write(efx, ®, MAC0_STAT_DMA_REG_KER); -+ efx_writeo(efx, ®, FR_AB_MAC_STAT_DMA); - -- /* Wait for transfer to complete */ -- for (i = 0; i < 400; i++) { -- if (*(volatile u32 *)dma_done == FALCON_STATS_DONE) { -- rmb(); /* Ensure the stats are valid. */ -- return 0; -- } -- udelay(10); -+ mod_timer(&nic_data->stats_timer, round_jiffies_up(jiffies + HZ / 2)); -+} -+ -+static void falcon_stats_complete(struct efx_nic *efx) -+{ -+ struct falcon_nic_data *nic_data = efx->nic_data; -+ -+ if (!nic_data->stats_pending) -+ return; -+ -+ nic_data->stats_pending = 0; -+ if (*nic_data->stats_dma_done == FALCON_STATS_DONE) { -+ rmb(); /* read the done flag before the stats */ -+ efx->mac_op->update_stats(efx); -+ } else { -+ EFX_ERR(efx, "timed out waiting for statistics\n"); - } -+} - -- EFX_ERR(efx, "timed out waiting for statistics\n"); -- return -ETIMEDOUT; -+static void falcon_stats_timer_func(unsigned long context) -+{ -+ struct efx_nic *efx = (struct efx_nic *)context; -+ struct falcon_nic_data *nic_data = efx->nic_data; -+ -+ spin_lock(&efx->stats_lock); -+ -+ falcon_stats_complete(efx); -+ if (nic_data->stats_disable_count == 0) -+ falcon_stats_request(efx); -+ -+ spin_unlock(&efx->stats_lock); -+} -+ -+static void falcon_switch_mac(struct efx_nic *efx); -+ -+static bool falcon_loopback_link_poll(struct efx_nic *efx) -+{ -+ struct efx_link_state old_state = efx->link_state; -+ -+ WARN_ON(!mutex_is_locked(&efx->mac_lock)); -+ WARN_ON(!LOOPBACK_INTERNAL(efx)); -+ -+ efx->link_state.fd = true; -+ efx->link_state.fc = efx->wanted_fc; -+ efx->link_state.up = true; -+ -+ if (efx->loopback_mode == LOOPBACK_GMAC) -+ efx->link_state.speed = 1000; -+ else -+ efx->link_state.speed = 10000; -+ -+ return !efx_link_state_equal(&efx->link_state, &old_state); -+} -+ -+static int falcon_reconfigure_port(struct efx_nic *efx) -+{ -+ int rc; -+ -+ WARN_ON(efx_nic_rev(efx) > EFX_REV_FALCON_B0); -+ -+ /* Poll the PHY link state *before* reconfiguring it. This means we -+ * will pick up the correct speed (in loopback) to select the correct -+ * MAC. -+ */ -+ if (LOOPBACK_INTERNAL(efx)) -+ falcon_loopback_link_poll(efx); -+ else -+ efx->phy_op->poll(efx); -+ -+ falcon_stop_nic_stats(efx); -+ falcon_deconfigure_mac_wrapper(efx); -+ -+ falcon_switch_mac(efx); -+ -+ efx->phy_op->reconfigure(efx); -+ rc = efx->mac_op->reconfigure(efx); -+ BUG_ON(rc); -+ -+ falcon_start_nic_stats(efx); -+ -+ /* Synchronise efx->link_state with the kernel */ -+ efx_link_status_changed(efx); -+ -+ return 0; - } - - /************************************************************************** -@@ -2066,18 +699,18 @@ int falcon_dma_stats(struct efx_nic *efx, unsigned int done_offset) - /* Wait for GMII access to complete */ - static int falcon_gmii_wait(struct efx_nic *efx) - { -- efx_dword_t md_stat; -+ efx_oword_t md_stat; - int count; - - /* wait upto 50ms - taken max from datasheet */ - for (count = 0; count < 5000; count++) { -- falcon_readl(efx, &md_stat, MD_STAT_REG_KER); -- if (EFX_DWORD_FIELD(md_stat, MD_BSY) == 0) { -- if (EFX_DWORD_FIELD(md_stat, MD_LNFL) != 0 || -- EFX_DWORD_FIELD(md_stat, MD_BSERR) != 0) { -+ efx_reado(efx, &md_stat, FR_AB_MD_STAT); -+ if (EFX_OWORD_FIELD(md_stat, FRF_AB_MD_BSY) == 0) { -+ if (EFX_OWORD_FIELD(md_stat, FRF_AB_MD_LNFL) != 0 || -+ EFX_OWORD_FIELD(md_stat, FRF_AB_MD_BSERR) != 0) { - EFX_ERR(efx, "error from GMII access " -- EFX_DWORD_FMT"\n", -- EFX_DWORD_VAL(md_stat)); -+ EFX_OWORD_FMT"\n", -+ EFX_OWORD_VAL(md_stat)); - return -EIO; - } - return 0; -@@ -2099,7 +732,7 @@ static int falcon_mdio_write(struct net_device *net_dev, - EFX_REGDUMP(efx, "writing MDIO %d register %d.%d with 0x%04x\n", - prtad, devad, addr, value); - -- spin_lock_bh(&efx->phy_lock); -+ mutex_lock(&efx->mdio_lock); - - /* Check MDIO not currently being accessed */ - rc = falcon_gmii_wait(efx); -@@ -2107,34 +740,35 @@ static int falcon_mdio_write(struct net_device *net_dev, - goto out; - - /* Write the address/ID register */ -- EFX_POPULATE_OWORD_1(reg, MD_PHY_ADR, addr); -- falcon_write(efx, ®, MD_PHY_ADR_REG_KER); -+ EFX_POPULATE_OWORD_1(reg, FRF_AB_MD_PHY_ADR, addr); -+ efx_writeo(efx, ®, FR_AB_MD_PHY_ADR); - -- EFX_POPULATE_OWORD_2(reg, MD_PRT_ADR, prtad, MD_DEV_ADR, devad); -- falcon_write(efx, ®, MD_ID_REG_KER); -+ EFX_POPULATE_OWORD_2(reg, FRF_AB_MD_PRT_ADR, prtad, -+ FRF_AB_MD_DEV_ADR, devad); -+ efx_writeo(efx, ®, FR_AB_MD_ID); - - /* Write data */ -- EFX_POPULATE_OWORD_1(reg, MD_TXD, value); -- falcon_write(efx, ®, MD_TXD_REG_KER); -+ EFX_POPULATE_OWORD_1(reg, FRF_AB_MD_TXD, value); -+ efx_writeo(efx, ®, FR_AB_MD_TXD); - - EFX_POPULATE_OWORD_2(reg, -- MD_WRC, 1, -- MD_GC, 0); -- falcon_write(efx, ®, MD_CS_REG_KER); -+ FRF_AB_MD_WRC, 1, -+ FRF_AB_MD_GC, 0); -+ efx_writeo(efx, ®, FR_AB_MD_CS); - - /* Wait for data to be written */ - rc = falcon_gmii_wait(efx); - if (rc) { - /* Abort the write operation */ - EFX_POPULATE_OWORD_2(reg, -- MD_WRC, 0, -- MD_GC, 1); -- falcon_write(efx, ®, MD_CS_REG_KER); -+ FRF_AB_MD_WRC, 0, -+ FRF_AB_MD_GC, 1); -+ efx_writeo(efx, ®, FR_AB_MD_CS); - udelay(10); - } - -- out: -- spin_unlock_bh(&efx->phy_lock); -+out: -+ mutex_unlock(&efx->mdio_lock); - return rc; - } - -@@ -2146,152 +780,139 @@ static int falcon_mdio_read(struct net_device *net_dev, - efx_oword_t reg; - int rc; - -- spin_lock_bh(&efx->phy_lock); -+ mutex_lock(&efx->mdio_lock); - - /* Check MDIO not currently being accessed */ - rc = falcon_gmii_wait(efx); - if (rc) - goto out; - -- EFX_POPULATE_OWORD_1(reg, MD_PHY_ADR, addr); -- falcon_write(efx, ®, MD_PHY_ADR_REG_KER); -+ EFX_POPULATE_OWORD_1(reg, FRF_AB_MD_PHY_ADR, addr); -+ efx_writeo(efx, ®, FR_AB_MD_PHY_ADR); - -- EFX_POPULATE_OWORD_2(reg, MD_PRT_ADR, prtad, MD_DEV_ADR, devad); -- falcon_write(efx, ®, MD_ID_REG_KER); -+ EFX_POPULATE_OWORD_2(reg, FRF_AB_MD_PRT_ADR, prtad, -+ FRF_AB_MD_DEV_ADR, devad); -+ efx_writeo(efx, ®, FR_AB_MD_ID); - - /* Request data to be read */ -- EFX_POPULATE_OWORD_2(reg, MD_RDC, 1, MD_GC, 0); -- falcon_write(efx, ®, MD_CS_REG_KER); -+ EFX_POPULATE_OWORD_2(reg, FRF_AB_MD_RDC, 1, FRF_AB_MD_GC, 0); -+ efx_writeo(efx, ®, FR_AB_MD_CS); - - /* Wait for data to become available */ - rc = falcon_gmii_wait(efx); - if (rc == 0) { -- falcon_read(efx, ®, MD_RXD_REG_KER); -- rc = EFX_OWORD_FIELD(reg, MD_RXD); -+ efx_reado(efx, ®, FR_AB_MD_RXD); -+ rc = EFX_OWORD_FIELD(reg, FRF_AB_MD_RXD); - EFX_REGDUMP(efx, "read from MDIO %d register %d.%d, got %04x\n", - prtad, devad, addr, rc); - } else { - /* Abort the read operation */ - EFX_POPULATE_OWORD_2(reg, -- MD_RIC, 0, -- MD_GC, 1); -- falcon_write(efx, ®, MD_CS_REG_KER); -+ FRF_AB_MD_RIC, 0, -+ FRF_AB_MD_GC, 1); -+ efx_writeo(efx, ®, FR_AB_MD_CS); - - EFX_LOG(efx, "read from MDIO %d register %d.%d, got error %d\n", - prtad, devad, addr, rc); - } - -- out: -- spin_unlock_bh(&efx->phy_lock); -+out: -+ mutex_unlock(&efx->mdio_lock); - return rc; - } - --static int falcon_probe_phy(struct efx_nic *efx) -+static void falcon_clock_mac(struct efx_nic *efx) - { -- switch (efx->phy_type) { -- case PHY_TYPE_SFX7101: -- efx->phy_op = &falcon_sfx7101_phy_ops; -- break; -- case PHY_TYPE_SFT9001A: -- case PHY_TYPE_SFT9001B: -- efx->phy_op = &falcon_sft9001_phy_ops; -- break; -- case PHY_TYPE_QT2022C2: -- case PHY_TYPE_QT2025C: -- efx->phy_op = &falcon_xfp_phy_ops; -- break; -- default: -- EFX_ERR(efx, "Unknown PHY type %d\n", -- efx->phy_type); -- return -1; -- } -- -- if (efx->phy_op->macs & EFX_XMAC) -- efx->loopback_modes |= ((1 << LOOPBACK_XGMII) | -- (1 << LOOPBACK_XGXS) | -- (1 << LOOPBACK_XAUI)); -- if (efx->phy_op->macs & EFX_GMAC) -- efx->loopback_modes |= (1 << LOOPBACK_GMAC); -- efx->loopback_modes |= efx->phy_op->loopbacks; -+ unsigned strap_val; -+ efx_oword_t nic_stat; - -- return 0; -+ /* Configure the NIC generated MAC clock correctly */ -+ efx_reado(efx, &nic_stat, FR_AB_NIC_STAT); -+ strap_val = EFX_IS10G(efx) ? 5 : 3; -+ if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0) { -+ EFX_SET_OWORD_FIELD(nic_stat, FRF_BB_EE_STRAP_EN, 1); -+ EFX_SET_OWORD_FIELD(nic_stat, FRF_BB_EE_STRAP, strap_val); -+ efx_writeo(efx, &nic_stat, FR_AB_NIC_STAT); -+ } else { -+ /* Falcon A1 does not support 1G/10G speed switching -+ * and must not be used with a PHY that does. */ -+ BUG_ON(EFX_OWORD_FIELD(nic_stat, FRF_AB_STRAP_PINS) != -+ strap_val); -+ } - } - --int falcon_switch_mac(struct efx_nic *efx) -+static void falcon_switch_mac(struct efx_nic *efx) - { - struct efx_mac_operations *old_mac_op = efx->mac_op; -- efx_oword_t nic_stat; -- unsigned strap_val; -- int rc = 0; -- -- /* Don't try to fetch MAC stats while we're switching MACs */ -- efx_stats_disable(efx); -- -- /* Internal loopbacks override the phy speed setting */ -- if (efx->loopback_mode == LOOPBACK_GMAC) { -- efx->link_speed = 1000; -- efx->link_fd = true; -- } else if (LOOPBACK_INTERNAL(efx)) { -- efx->link_speed = 10000; -- efx->link_fd = true; -- } -+ struct falcon_nic_data *nic_data = efx->nic_data; -+ unsigned int stats_done_offset; - - WARN_ON(!mutex_is_locked(&efx->mac_lock)); -+ WARN_ON(nic_data->stats_disable_count == 0); -+ - efx->mac_op = (EFX_IS10G(efx) ? - &falcon_xmac_operations : &falcon_gmac_operations); - -- /* Always push the NIC_STAT_REG setting even if the mac hasn't -- * changed, because this function is run post online reset */ -- falcon_read(efx, &nic_stat, NIC_STAT_REG); -- strap_val = EFX_IS10G(efx) ? 5 : 3; -- if (falcon_rev(efx) >= FALCON_REV_B0) { -- EFX_SET_OWORD_FIELD(nic_stat, EE_STRAP_EN, 1); -- EFX_SET_OWORD_FIELD(nic_stat, EE_STRAP_OVR, strap_val); -- falcon_write(efx, &nic_stat, NIC_STAT_REG); -- } else { -- /* Falcon A1 does not support 1G/10G speed switching -- * and must not be used with a PHY that does. */ -- BUG_ON(EFX_OWORD_FIELD(nic_stat, STRAP_PINS) != strap_val); -- } -+ if (EFX_IS10G(efx)) -+ stats_done_offset = XgDmaDone_offset; -+ else -+ stats_done_offset = GDmaDone_offset; -+ nic_data->stats_dma_done = efx->stats_buffer.addr + stats_done_offset; - - if (old_mac_op == efx->mac_op) -- goto out; -+ return; -+ -+ falcon_clock_mac(efx); - - EFX_LOG(efx, "selected %cMAC\n", EFX_IS10G(efx) ? 'X' : 'G'); - /* Not all macs support a mac-level link state */ -- efx->mac_up = true; -- -- rc = falcon_reset_macs(efx); --out: -- efx_stats_enable(efx); -- return rc; -+ efx->xmac_poll_required = false; -+ falcon_reset_macs(efx); - } - - /* This call is responsible for hooking in the MAC and PHY operations */ --int falcon_probe_port(struct efx_nic *efx) -+static int falcon_probe_port(struct efx_nic *efx) - { - int rc; - -- /* Hook in PHY operations table */ -- rc = falcon_probe_phy(efx); -- if (rc) -- return rc; -+ switch (efx->phy_type) { -+ case PHY_TYPE_SFX7101: -+ efx->phy_op = &falcon_sfx7101_phy_ops; -+ break; -+ case PHY_TYPE_SFT9001A: -+ case PHY_TYPE_SFT9001B: -+ efx->phy_op = &falcon_sft9001_phy_ops; -+ break; -+ case PHY_TYPE_QT2022C2: -+ case PHY_TYPE_QT2025C: -+ efx->phy_op = &falcon_qt202x_phy_ops; -+ break; -+ default: -+ EFX_ERR(efx, "Unknown PHY type %d\n", -+ efx->phy_type); -+ return -ENODEV; -+ } - -- /* Set up MDIO structure for PHY */ -- efx->mdio.mmds = efx->phy_op->mmds; -- efx->mdio.mode_support = MDIO_SUPPORTS_C45 | MDIO_EMULATE_C22; -+ /* Fill out MDIO structure and loopback modes */ - efx->mdio.mdio_read = falcon_mdio_read; - efx->mdio.mdio_write = falcon_mdio_write; -+ rc = efx->phy_op->probe(efx); -+ if (rc != 0) -+ return rc; -+ -+ /* Initial assumption */ -+ efx->link_state.speed = 10000; -+ efx->link_state.fd = true; - - /* Hardware flow ctrl. FalconA RX FIFO too small for pause generation */ -- if (falcon_rev(efx) >= FALCON_REV_B0) -+ if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0) - efx->wanted_fc = EFX_FC_RX | EFX_FC_TX; - else - efx->wanted_fc = EFX_FC_RX; - - /* Allocate buffer for stats */ -- rc = falcon_alloc_buffer(efx, &efx->stats_buffer, -- FALCON_MAC_STATS_SIZE); -+ rc = efx_nic_alloc_buffer(efx, &efx->stats_buffer, -+ FALCON_MAC_STATS_SIZE); - if (rc) - return rc; - EFX_LOG(efx, "stats buffer at %llx (virt %p phys %llx)\n", -@@ -2302,40 +923,19 @@ int falcon_probe_port(struct efx_nic *efx) - return 0; - } - --void falcon_remove_port(struct efx_nic *efx) -+static void falcon_remove_port(struct efx_nic *efx) - { -- falcon_free_buffer(efx, &efx->stats_buffer); -+ efx_nic_free_buffer(efx, &efx->stats_buffer); - } - - /************************************************************************** - * -- * Multicast filtering -- * -- ************************************************************************** -- */ -- --void falcon_set_multicast_hash(struct efx_nic *efx) --{ -- union efx_multicast_hash *mc_hash = &efx->multicast_hash; -- -- /* Broadcast packets go through the multicast hash filter. -- * ether_crc_le() of the broadcast address is 0xbe2612ff -- * so we always add bit 0xff to the mask. -- */ -- set_bit_le(0xff, mc_hash->byte); -- -- falcon_write(efx, &mc_hash->oword[0], MAC_MCAST_HASH_REG0_KER); -- falcon_write(efx, &mc_hash->oword[1], MAC_MCAST_HASH_REG1_KER); --} -- -- --/************************************************************************** -- * - * Falcon test code - * - **************************************************************************/ - --int falcon_read_nvram(struct efx_nic *efx, struct falcon_nvconfig *nvconfig_out) -+static int -+falcon_read_nvram(struct efx_nic *efx, struct falcon_nvconfig *nvconfig_out) - { - struct falcon_nvconfig *nvconfig; - struct efx_spi_device *spi; -@@ -2351,10 +951,10 @@ int falcon_read_nvram(struct efx_nic *efx, struct falcon_nvconfig *nvconfig_out) - region = kmalloc(FALCON_NVCONFIG_END, GFP_KERNEL); - if (!region) - return -ENOMEM; -- nvconfig = region + NVCONFIG_OFFSET; -+ nvconfig = region + FALCON_NVCONFIG_OFFSET; - - mutex_lock(&efx->spi_lock); -- rc = falcon_spi_read(spi, 0, FALCON_NVCONFIG_END, NULL, region); -+ rc = falcon_spi_read(efx, spi, 0, FALCON_NVCONFIG_END, NULL, region); - mutex_unlock(&efx->spi_lock); - if (rc) { - EFX_ERR(efx, "Failed to read %s\n", -@@ -2367,7 +967,7 @@ int falcon_read_nvram(struct efx_nic *efx, struct falcon_nvconfig *nvconfig_out) - struct_ver = le16_to_cpu(nvconfig->board_struct_ver); - - rc = -EINVAL; -- if (magic_num != NVCONFIG_BOARD_MAGIC_NUM) { -+ if (magic_num != FALCON_NVCONFIG_BOARD_MAGIC_NUM) { - EFX_ERR(efx, "NVRAM bad magic 0x%x\n", magic_num); - goto out; - } -@@ -2398,107 +998,54 @@ int falcon_read_nvram(struct efx_nic *efx, struct falcon_nvconfig *nvconfig_out) - return rc; - } - --/* Registers tested in the falcon register test */ --static struct { -- unsigned address; -- efx_oword_t mask; --} efx_test_registers[] = { -- { ADR_REGION_REG_KER, -+static int falcon_test_nvram(struct efx_nic *efx) -+{ -+ return falcon_read_nvram(efx, NULL); -+} -+ -+static const struct efx_nic_register_test falcon_b0_register_tests[] = { -+ { FR_AZ_ADR_REGION, - EFX_OWORD32(0x0001FFFF, 0x0001FFFF, 0x0001FFFF, 0x0001FFFF) }, -- { RX_CFG_REG_KER, -+ { FR_AZ_RX_CFG, - EFX_OWORD32(0xFFFFFFFE, 0x00017FFF, 0x00000000, 0x00000000) }, -- { TX_CFG_REG_KER, -+ { FR_AZ_TX_CFG, - EFX_OWORD32(0x7FFF0037, 0x00000000, 0x00000000, 0x00000000) }, -- { TX_CFG2_REG_KER, -+ { FR_AZ_TX_RESERVED, - EFX_OWORD32(0xFFFEFE80, 0x1FFFFFFF, 0x020000FE, 0x007FFFFF) }, -- { MAC0_CTRL_REG_KER, -+ { FR_AB_MAC_CTRL, - EFX_OWORD32(0xFFFF0000, 0x00000000, 0x00000000, 0x00000000) }, -- { SRM_TX_DC_CFG_REG_KER, -+ { FR_AZ_SRM_TX_DC_CFG, - EFX_OWORD32(0x001FFFFF, 0x00000000, 0x00000000, 0x00000000) }, -- { RX_DC_CFG_REG_KER, -+ { FR_AZ_RX_DC_CFG, - EFX_OWORD32(0x0000000F, 0x00000000, 0x00000000, 0x00000000) }, -- { RX_DC_PF_WM_REG_KER, -+ { FR_AZ_RX_DC_PF_WM, - EFX_OWORD32(0x000003FF, 0x00000000, 0x00000000, 0x00000000) }, -- { DP_CTRL_REG, -+ { FR_BZ_DP_CTRL, - EFX_OWORD32(0x00000FFF, 0x00000000, 0x00000000, 0x00000000) }, -- { GM_CFG2_REG, -+ { FR_AB_GM_CFG2, - EFX_OWORD32(0x00007337, 0x00000000, 0x00000000, 0x00000000) }, -- { GMF_CFG0_REG, -+ { FR_AB_GMF_CFG0, - EFX_OWORD32(0x00001F1F, 0x00000000, 0x00000000, 0x00000000) }, -- { XM_GLB_CFG_REG, -+ { FR_AB_XM_GLB_CFG, - EFX_OWORD32(0x00000C68, 0x00000000, 0x00000000, 0x00000000) }, -- { XM_TX_CFG_REG, -+ { FR_AB_XM_TX_CFG, - EFX_OWORD32(0x00080164, 0x00000000, 0x00000000, 0x00000000) }, -- { XM_RX_CFG_REG, -+ { FR_AB_XM_RX_CFG, - EFX_OWORD32(0x07100A0C, 0x00000000, 0x00000000, 0x00000000) }, -- { XM_RX_PARAM_REG, -+ { FR_AB_XM_RX_PARAM, - EFX_OWORD32(0x00001FF8, 0x00000000, 0x00000000, 0x00000000) }, -- { XM_FC_REG, -+ { FR_AB_XM_FC, - EFX_OWORD32(0xFFFF0001, 0x00000000, 0x00000000, 0x00000000) }, -- { XM_ADR_LO_REG, -+ { FR_AB_XM_ADR_LO, - EFX_OWORD32(0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000) }, -- { XX_SD_CTL_REG, -+ { FR_AB_XX_SD_CTL, - EFX_OWORD32(0x0003FF0F, 0x00000000, 0x00000000, 0x00000000) }, - }; - --static bool efx_masked_compare_oword(const efx_oword_t *a, const efx_oword_t *b, -- const efx_oword_t *mask) -+static int falcon_b0_test_registers(struct efx_nic *efx) - { -- return ((a->u64[0] ^ b->u64[0]) & mask->u64[0]) || -- ((a->u64[1] ^ b->u64[1]) & mask->u64[1]); --} -- --int falcon_test_registers(struct efx_nic *efx) --{ -- unsigned address = 0, i, j; -- efx_oword_t mask, imask, original, reg, buf; -- -- /* Falcon should be in loopback to isolate the XMAC from the PHY */ -- WARN_ON(!LOOPBACK_INTERNAL(efx)); -- -- for (i = 0; i < ARRAY_SIZE(efx_test_registers); ++i) { -- address = efx_test_registers[i].address; -- mask = imask = efx_test_registers[i].mask; -- EFX_INVERT_OWORD(imask); -- -- falcon_read(efx, &original, address); -- -- /* bit sweep on and off */ -- for (j = 0; j < 128; j++) { -- if (!EFX_EXTRACT_OWORD32(mask, j, j)) -- continue; -- -- /* Test this testable bit can be set in isolation */ -- EFX_AND_OWORD(reg, original, mask); -- EFX_SET_OWORD32(reg, j, j, 1); -- -- falcon_write(efx, ®, address); -- falcon_read(efx, &buf, address); -- -- if (efx_masked_compare_oword(®, &buf, &mask)) -- goto fail; -- -- /* Test this testable bit can be cleared in isolation */ -- EFX_OR_OWORD(reg, original, mask); -- EFX_SET_OWORD32(reg, j, j, 0); -- -- falcon_write(efx, ®, address); -- falcon_read(efx, &buf, address); -- -- if (efx_masked_compare_oword(®, &buf, &mask)) -- goto fail; -- } -- -- falcon_write(efx, &original, address); -- } -- -- return 0; -- --fail: -- EFX_ERR(efx, "wrote "EFX_OWORD_FMT" read "EFX_OWORD_FMT -- " at address 0x%x mask "EFX_OWORD_FMT"\n", EFX_OWORD_VAL(reg), -- EFX_OWORD_VAL(buf), address, EFX_OWORD_VAL(mask)); -- return -EIO; -+ return efx_nic_test_registers(efx, falcon_b0_register_tests, -+ ARRAY_SIZE(falcon_b0_register_tests)); - } - - /************************************************************************** -@@ -2510,13 +1057,13 @@ fail: - - /* Resets NIC to known state. This routine must be called in process - * context and is allowed to sleep. */ --int falcon_reset_hw(struct efx_nic *efx, enum reset_type method) -+static int falcon_reset_hw(struct efx_nic *efx, enum reset_type method) - { - struct falcon_nic_data *nic_data = efx->nic_data; - efx_oword_t glb_ctl_reg_ker; - int rc; - -- EFX_LOG(efx, "performing hardware reset (%d)\n", method); -+ EFX_LOG(efx, "performing %s hardware reset\n", RESET_TYPE(method)); - - /* Initiate device reset */ - if (method == RESET_TYPE_WORLD) { -@@ -2526,7 +1073,7 @@ int falcon_reset_hw(struct efx_nic *efx, enum reset_type method) - "function prior to hardware reset\n"); - goto fail1; - } -- if (FALCON_IS_DUAL_FUNC(efx)) { -+ if (efx_nic_is_dual_func(efx)) { - rc = pci_save_state(nic_data->pci_dev2); - if (rc) { - EFX_ERR(efx, "failed to backup PCI state of " -@@ -2537,29 +1084,31 @@ int falcon_reset_hw(struct efx_nic *efx, enum reset_type method) - } - - EFX_POPULATE_OWORD_2(glb_ctl_reg_ker, -- EXT_PHY_RST_DUR, 0x7, -- SWRST, 1); -+ FRF_AB_EXT_PHY_RST_DUR, -+ FFE_AB_EXT_PHY_RST_DUR_10240US, -+ FRF_AB_SWRST, 1); - } else { -- int reset_phy = (method == RESET_TYPE_INVISIBLE ? -- EXCLUDE_FROM_RESET : 0); -- - EFX_POPULATE_OWORD_7(glb_ctl_reg_ker, -- EXT_PHY_RST_CTL, reset_phy, -- PCIE_CORE_RST_CTL, EXCLUDE_FROM_RESET, -- PCIE_NSTCK_RST_CTL, EXCLUDE_FROM_RESET, -- PCIE_SD_RST_CTL, EXCLUDE_FROM_RESET, -- EE_RST_CTL, EXCLUDE_FROM_RESET, -- EXT_PHY_RST_DUR, 0x7 /* 10ms */, -- SWRST, 1); -- } -- falcon_write(efx, &glb_ctl_reg_ker, GLB_CTL_REG_KER); -+ /* exclude PHY from "invisible" reset */ -+ FRF_AB_EXT_PHY_RST_CTL, -+ method == RESET_TYPE_INVISIBLE, -+ /* exclude EEPROM/flash and PCIe */ -+ FRF_AB_PCIE_CORE_RST_CTL, 1, -+ FRF_AB_PCIE_NSTKY_RST_CTL, 1, -+ FRF_AB_PCIE_SD_RST_CTL, 1, -+ FRF_AB_EE_RST_CTL, 1, -+ FRF_AB_EXT_PHY_RST_DUR, -+ FFE_AB_EXT_PHY_RST_DUR_10240US, -+ FRF_AB_SWRST, 1); -+ } -+ efx_writeo(efx, &glb_ctl_reg_ker, FR_AB_GLB_CTL); - - EFX_LOG(efx, "waiting for hardware reset\n"); - schedule_timeout_uninterruptible(HZ / 20); - - /* Restore PCI configuration if needed */ - if (method == RESET_TYPE_WORLD) { -- if (FALCON_IS_DUAL_FUNC(efx)) { -+ if (efx_nic_is_dual_func(efx)) { - rc = pci_restore_state(nic_data->pci_dev2); - if (rc) { - EFX_ERR(efx, "failed to restore PCI config for " -@@ -2577,8 +1126,8 @@ int falcon_reset_hw(struct efx_nic *efx, enum reset_type method) - } - - /* Assert that reset complete */ -- falcon_read(efx, &glb_ctl_reg_ker, GLB_CTL_REG_KER); -- if (EFX_OWORD_FIELD(glb_ctl_reg_ker, SWRST) != 0) { -+ efx_reado(efx, &glb_ctl_reg_ker, FR_AB_GLB_CTL); -+ if (EFX_OWORD_FIELD(glb_ctl_reg_ker, FRF_AB_SWRST) != 0) { - rc = -ETIMEDOUT; - EFX_ERR(efx, "timed out waiting for hardware reset\n"); - goto fail5; -@@ -2597,6 +1146,44 @@ fail5: - return rc; - } - -+static void falcon_monitor(struct efx_nic *efx) -+{ -+ bool link_changed; -+ int rc; -+ -+ BUG_ON(!mutex_is_locked(&efx->mac_lock)); -+ -+ rc = falcon_board(efx)->type->monitor(efx); -+ if (rc) { -+ EFX_ERR(efx, "Board sensor %s; shutting down PHY\n", -+ (rc == -ERANGE) ? "reported fault" : "failed"); -+ efx->phy_mode |= PHY_MODE_LOW_POWER; -+ rc = __efx_reconfigure_port(efx); -+ WARN_ON(rc); -+ } -+ -+ if (LOOPBACK_INTERNAL(efx)) -+ link_changed = falcon_loopback_link_poll(efx); -+ else -+ link_changed = efx->phy_op->poll(efx); -+ -+ if (link_changed) { -+ falcon_stop_nic_stats(efx); -+ falcon_deconfigure_mac_wrapper(efx); -+ -+ falcon_switch_mac(efx); -+ rc = efx->mac_op->reconfigure(efx); -+ BUG_ON(rc); -+ -+ falcon_start_nic_stats(efx); -+ -+ efx_link_status_changed(efx); -+ } -+ -+ if (EFX_IS10G(efx)) -+ falcon_poll_xmac(efx); -+} -+ - /* Zeroes out the SRAM contents. This routine must be called in - * process context and is allowed to sleep. - */ -@@ -2606,16 +1193,16 @@ static int falcon_reset_sram(struct efx_nic *efx) - int count; - - /* Set the SRAM wake/sleep GPIO appropriately. */ -- falcon_read(efx, &gpio_cfg_reg_ker, GPIO_CTL_REG_KER); -- EFX_SET_OWORD_FIELD(gpio_cfg_reg_ker, GPIO1_OEN, 1); -- EFX_SET_OWORD_FIELD(gpio_cfg_reg_ker, GPIO1_OUT, 1); -- falcon_write(efx, &gpio_cfg_reg_ker, GPIO_CTL_REG_KER); -+ efx_reado(efx, &gpio_cfg_reg_ker, FR_AB_GPIO_CTL); -+ EFX_SET_OWORD_FIELD(gpio_cfg_reg_ker, FRF_AB_GPIO1_OEN, 1); -+ EFX_SET_OWORD_FIELD(gpio_cfg_reg_ker, FRF_AB_GPIO1_OUT, 1); -+ efx_writeo(efx, &gpio_cfg_reg_ker, FR_AB_GPIO_CTL); - - /* Initiate SRAM reset */ - EFX_POPULATE_OWORD_2(srm_cfg_reg_ker, -- SRAM_OOB_BT_INIT_EN, 1, -- SRM_NUM_BANKS_AND_BANK_SIZE, 0); -- falcon_write(efx, &srm_cfg_reg_ker, SRM_CFG_REG_KER); -+ FRF_AZ_SRM_INIT_EN, 1, -+ FRF_AZ_SRM_NB_SZ, 0); -+ efx_writeo(efx, &srm_cfg_reg_ker, FR_AZ_SRM_CFG); - - /* Wait for SRAM reset to complete */ - count = 0; -@@ -2626,8 +1213,8 @@ static int falcon_reset_sram(struct efx_nic *efx) - schedule_timeout_uninterruptible(HZ / 50); - - /* Check for reset complete */ -- falcon_read(efx, &srm_cfg_reg_ker, SRM_CFG_REG_KER); -- if (!EFX_OWORD_FIELD(srm_cfg_reg_ker, SRAM_OOB_BT_INIT_EN)) { -+ efx_reado(efx, &srm_cfg_reg_ker, FR_AZ_SRM_CFG); -+ if (!EFX_OWORD_FIELD(srm_cfg_reg_ker, FRF_AZ_SRM_INIT_EN)) { - EFX_LOG(efx, "SRAM reset complete\n"); - - return 0; -@@ -2663,8 +1250,6 @@ static int falcon_spi_device_init(struct efx_nic *efx, - spi_device->block_size = - 1 << SPI_DEV_TYPE_FIELD(device_type, - SPI_DEV_TYPE_BLOCK_SIZE); -- -- spi_device->efx = efx; - } else { - spi_device = NULL; - } -@@ -2674,7 +1259,6 @@ static int falcon_spi_device_init(struct efx_nic *efx, - return 0; - } - -- - static void falcon_remove_spi_devices(struct efx_nic *efx) - { - kfree(efx->spi_eeprom); -@@ -2712,16 +1296,16 @@ static int falcon_probe_nvconfig(struct efx_nic *efx) - board_rev = le16_to_cpu(v2->board_revision); - - if (le16_to_cpu(nvconfig->board_struct_ver) >= 3) { -- __le32 fl = v3->spi_device_type[EE_SPI_FLASH]; -- __le32 ee = v3->spi_device_type[EE_SPI_EEPROM]; -- rc = falcon_spi_device_init(efx, &efx->spi_flash, -- EE_SPI_FLASH, -- le32_to_cpu(fl)); -+ rc = falcon_spi_device_init( -+ efx, &efx->spi_flash, FFE_AB_SPI_DEVICE_FLASH, -+ le32_to_cpu(v3->spi_device_type -+ [FFE_AB_SPI_DEVICE_FLASH])); - if (rc) - goto fail2; -- rc = falcon_spi_device_init(efx, &efx->spi_eeprom, -- EE_SPI_EEPROM, -- le32_to_cpu(ee)); -+ rc = falcon_spi_device_init( -+ efx, &efx->spi_eeprom, FFE_AB_SPI_DEVICE_EEPROM, -+ le32_to_cpu(v3->spi_device_type -+ [FFE_AB_SPI_DEVICE_EEPROM])); - if (rc) - goto fail2; - } -@@ -2732,7 +1316,7 @@ static int falcon_probe_nvconfig(struct efx_nic *efx) - - EFX_LOG(efx, "PHY is %d phy_id %d\n", efx->phy_type, efx->mdio.prtad); - -- efx_set_board_info(efx, board_rev); -+ falcon_probe_board(efx, board_rev); - - kfree(nvconfig); - return 0; -@@ -2744,89 +1328,49 @@ static int falcon_probe_nvconfig(struct efx_nic *efx) - return rc; - } - --/* Probe the NIC variant (revision, ASIC vs FPGA, function count, port -- * count, port speed). Set workaround and feature flags accordingly. -- */ --static int falcon_probe_nic_variant(struct efx_nic *efx) --{ -- efx_oword_t altera_build; -- efx_oword_t nic_stat; -- -- falcon_read(efx, &altera_build, ALTERA_BUILD_REG_KER); -- if (EFX_OWORD_FIELD(altera_build, VER_ALL)) { -- EFX_ERR(efx, "Falcon FPGA not supported\n"); -- return -ENODEV; -- } -- -- falcon_read(efx, &nic_stat, NIC_STAT_REG); -- -- switch (falcon_rev(efx)) { -- case FALCON_REV_A0: -- case 0xff: -- EFX_ERR(efx, "Falcon rev A0 not supported\n"); -- return -ENODEV; -- -- case FALCON_REV_A1: -- if (EFX_OWORD_FIELD(nic_stat, STRAP_PCIE) == 0) { -- EFX_ERR(efx, "Falcon rev A1 PCI-X not supported\n"); -- return -ENODEV; -- } -- break; -- -- case FALCON_REV_B0: -- break; -- -- default: -- EFX_ERR(efx, "Unknown Falcon rev %d\n", falcon_rev(efx)); -- return -ENODEV; -- } -- -- /* Initial assumed speed */ -- efx->link_speed = EFX_OWORD_FIELD(nic_stat, STRAP_10G) ? 10000 : 1000; -- -- return 0; --} -- - /* Probe all SPI devices on the NIC */ - static void falcon_probe_spi_devices(struct efx_nic *efx) - { - efx_oword_t nic_stat, gpio_ctl, ee_vpd_cfg; - int boot_dev; - -- falcon_read(efx, &gpio_ctl, GPIO_CTL_REG_KER); -- falcon_read(efx, &nic_stat, NIC_STAT_REG); -- falcon_read(efx, &ee_vpd_cfg, EE_VPD_CFG_REG_KER); -+ efx_reado(efx, &gpio_ctl, FR_AB_GPIO_CTL); -+ efx_reado(efx, &nic_stat, FR_AB_NIC_STAT); -+ efx_reado(efx, &ee_vpd_cfg, FR_AB_EE_VPD_CFG0); - -- if (EFX_OWORD_FIELD(gpio_ctl, BOOTED_USING_NVDEVICE)) { -- boot_dev = (EFX_OWORD_FIELD(nic_stat, SF_PRST) ? -- EE_SPI_FLASH : EE_SPI_EEPROM); -+ if (EFX_OWORD_FIELD(gpio_ctl, FRF_AB_GPIO3_PWRUP_VALUE)) { -+ boot_dev = (EFX_OWORD_FIELD(nic_stat, FRF_AB_SF_PRST) ? -+ FFE_AB_SPI_DEVICE_FLASH : FFE_AB_SPI_DEVICE_EEPROM); - EFX_LOG(efx, "Booted from %s\n", -- boot_dev == EE_SPI_FLASH ? "flash" : "EEPROM"); -+ boot_dev == FFE_AB_SPI_DEVICE_FLASH ? "flash" : "EEPROM"); - } else { - /* Disable VPD and set clock dividers to safe - * values for initial programming. */ - boot_dev = -1; - EFX_LOG(efx, "Booted from internal ASIC settings;" - " setting SPI config\n"); -- EFX_POPULATE_OWORD_3(ee_vpd_cfg, EE_VPD_EN, 0, -+ EFX_POPULATE_OWORD_3(ee_vpd_cfg, FRF_AB_EE_VPD_EN, 0, - /* 125 MHz / 7 ~= 20 MHz */ -- EE_SF_CLOCK_DIV, 7, -+ FRF_AB_EE_SF_CLOCK_DIV, 7, - /* 125 MHz / 63 ~= 2 MHz */ -- EE_EE_CLOCK_DIV, 63); -- falcon_write(efx, &ee_vpd_cfg, EE_VPD_CFG_REG_KER); -+ FRF_AB_EE_EE_CLOCK_DIV, 63); -+ efx_writeo(efx, &ee_vpd_cfg, FR_AB_EE_VPD_CFG0); - } - -- if (boot_dev == EE_SPI_FLASH) -- falcon_spi_device_init(efx, &efx->spi_flash, EE_SPI_FLASH, -+ if (boot_dev == FFE_AB_SPI_DEVICE_FLASH) -+ falcon_spi_device_init(efx, &efx->spi_flash, -+ FFE_AB_SPI_DEVICE_FLASH, - default_flash_type); -- if (boot_dev == EE_SPI_EEPROM) -- falcon_spi_device_init(efx, &efx->spi_eeprom, EE_SPI_EEPROM, -+ if (boot_dev == FFE_AB_SPI_DEVICE_EEPROM) -+ falcon_spi_device_init(efx, &efx->spi_eeprom, -+ FFE_AB_SPI_DEVICE_EEPROM, - large_eeprom_type); - } - --int falcon_probe_nic(struct efx_nic *efx) -+static int falcon_probe_nic(struct efx_nic *efx) - { - struct falcon_nic_data *nic_data; -+ struct falcon_board *board; - int rc; - - /* Allocate storage for hardware specific data */ -@@ -2835,15 +1379,33 @@ int falcon_probe_nic(struct efx_nic *efx) - return -ENOMEM; - efx->nic_data = nic_data; - -- /* Determine number of ports etc. */ -- rc = falcon_probe_nic_variant(efx); -- if (rc) -+ rc = -ENODEV; -+ -+ if (efx_nic_fpga_ver(efx) != 0) { -+ EFX_ERR(efx, "Falcon FPGA not supported\n"); - goto fail1; -+ } - -- /* Probe secondary function if expected */ -- if (FALCON_IS_DUAL_FUNC(efx)) { -- struct pci_dev *dev = pci_dev_get(efx->pci_dev); -+ if (efx_nic_rev(efx) <= EFX_REV_FALCON_A1) { -+ efx_oword_t nic_stat; -+ struct pci_dev *dev; -+ u8 pci_rev = efx->pci_dev->revision; -+ -+ if ((pci_rev == 0xff) || (pci_rev == 0)) { -+ EFX_ERR(efx, "Falcon rev A0 not supported\n"); -+ goto fail1; -+ } -+ efx_reado(efx, &nic_stat, FR_AB_NIC_STAT); -+ if (EFX_OWORD_FIELD(nic_stat, FRF_AB_STRAP_10G) == 0) { -+ EFX_ERR(efx, "Falcon rev A1 1G not supported\n"); -+ goto fail1; -+ } -+ if (EFX_OWORD_FIELD(nic_stat, FRF_AA_STRAP_PCIE) == 0) { -+ EFX_ERR(efx, "Falcon rev A1 PCI-X not supported\n"); -+ goto fail1; -+ } - -+ dev = pci_dev_get(efx->pci_dev); - while ((dev = pci_get_device(EFX_VENDID_SFC, FALCON_A_S_DEVID, - dev))) { - if (dev->bus == efx->pci_dev->bus && -@@ -2867,7 +1429,7 @@ int falcon_probe_nic(struct efx_nic *efx) - } - - /* Allocate memory for INT_KER */ -- rc = falcon_alloc_buffer(efx, &efx->irq_status, sizeof(efx_oword_t)); -+ rc = efx_nic_alloc_buffer(efx, &efx->irq_status, sizeof(efx_oword_t)); - if (rc) - goto fail4; - BUG_ON(efx->irq_status.dma_addr & 0x0f); -@@ -2884,21 +1446,36 @@ int falcon_probe_nic(struct efx_nic *efx) - goto fail5; - - /* Initialise I2C adapter */ -- efx->i2c_adap.owner = THIS_MODULE; -- nic_data->i2c_data = falcon_i2c_bit_operations; -- nic_data->i2c_data.data = efx; -- efx->i2c_adap.algo_data = &nic_data->i2c_data; -- efx->i2c_adap.dev.parent = &efx->pci_dev->dev; -- strlcpy(efx->i2c_adap.name, "SFC4000 GPIO", sizeof(efx->i2c_adap.name)); -- rc = i2c_bit_add_bus(&efx->i2c_adap); -+ board = falcon_board(efx); -+ board->i2c_adap.owner = THIS_MODULE; -+ board->i2c_data = falcon_i2c_bit_operations; -+ board->i2c_data.data = efx; -+ board->i2c_adap.algo_data = &board->i2c_data; -+ board->i2c_adap.dev.parent = &efx->pci_dev->dev; -+ strlcpy(board->i2c_adap.name, "SFC4000 GPIO", -+ sizeof(board->i2c_adap.name)); -+ rc = i2c_bit_add_bus(&board->i2c_adap); - if (rc) - goto fail5; - -+ rc = falcon_board(efx)->type->init(efx); -+ if (rc) { -+ EFX_ERR(efx, "failed to initialise board\n"); -+ goto fail6; -+ } -+ -+ nic_data->stats_disable_count = 1; -+ setup_timer(&nic_data->stats_timer, &falcon_stats_timer_func, -+ (unsigned long)efx); -+ - return 0; - -+ fail6: -+ BUG_ON(i2c_del_adapter(&board->i2c_adap)); -+ memset(&board->i2c_adap, 0, sizeof(board->i2c_adap)); - fail5: - falcon_remove_spi_devices(efx); -- falcon_free_buffer(efx, &efx->irq_status); -+ efx_nic_free_buffer(efx, &efx->irq_status); - fail4: - fail3: - if (nic_data->pci_dev2) { -@@ -2911,166 +1488,147 @@ int falcon_probe_nic(struct efx_nic *efx) - return rc; - } - -+static void falcon_init_rx_cfg(struct efx_nic *efx) -+{ -+ /* Prior to Siena the RX DMA engine will split each frame at -+ * intervals of RX_USR_BUF_SIZE (32-byte units). We set it to -+ * be so large that that never happens. */ -+ const unsigned huge_buf_size = (3 * 4096) >> 5; -+ /* RX control FIFO thresholds (32 entries) */ -+ const unsigned ctrl_xon_thr = 20; -+ const unsigned ctrl_xoff_thr = 25; -+ /* RX data FIFO thresholds (256-byte units; size varies) */ -+ int data_xon_thr = efx_nic_rx_xon_thresh >> 8; -+ int data_xoff_thr = efx_nic_rx_xoff_thresh >> 8; -+ efx_oword_t reg; -+ -+ efx_reado(efx, ®, FR_AZ_RX_CFG); -+ if (efx_nic_rev(efx) <= EFX_REV_FALCON_A1) { -+ /* Data FIFO size is 5.5K */ -+ if (data_xon_thr < 0) -+ data_xon_thr = 512 >> 8; -+ if (data_xoff_thr < 0) -+ data_xoff_thr = 2048 >> 8; -+ EFX_SET_OWORD_FIELD(reg, FRF_AA_RX_DESC_PUSH_EN, 0); -+ EFX_SET_OWORD_FIELD(reg, FRF_AA_RX_USR_BUF_SIZE, -+ huge_buf_size); -+ EFX_SET_OWORD_FIELD(reg, FRF_AA_RX_XON_MAC_TH, data_xon_thr); -+ EFX_SET_OWORD_FIELD(reg, FRF_AA_RX_XOFF_MAC_TH, data_xoff_thr); -+ EFX_SET_OWORD_FIELD(reg, FRF_AA_RX_XON_TX_TH, ctrl_xon_thr); -+ EFX_SET_OWORD_FIELD(reg, FRF_AA_RX_XOFF_TX_TH, ctrl_xoff_thr); -+ } else { -+ /* Data FIFO size is 80K; register fields moved */ -+ if (data_xon_thr < 0) -+ data_xon_thr = 27648 >> 8; /* ~3*max MTU */ -+ if (data_xoff_thr < 0) -+ data_xoff_thr = 54272 >> 8; /* ~80Kb - 3*max MTU */ -+ EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_DESC_PUSH_EN, 0); -+ EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_USR_BUF_SIZE, -+ huge_buf_size); -+ EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_XON_MAC_TH, data_xon_thr); -+ EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_XOFF_MAC_TH, data_xoff_thr); -+ EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_XON_TX_TH, ctrl_xon_thr); -+ EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_XOFF_TX_TH, ctrl_xoff_thr); -+ EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_INGR_EN, 1); -+ } -+ /* Always enable XOFF signal from RX FIFO. We enable -+ * or disable transmission of pause frames at the MAC. */ -+ EFX_SET_OWORD_FIELD(reg, FRF_AZ_RX_XOFF_MAC_EN, 1); -+ efx_writeo(efx, ®, FR_AZ_RX_CFG); -+} -+ - /* This call performs hardware-specific global initialisation, such as - * defining the descriptor cache sizes and number of RSS channels. - * It does not set up any buffers, descriptor rings or event queues. - */ --int falcon_init_nic(struct efx_nic *efx) -+static int falcon_init_nic(struct efx_nic *efx) - { - efx_oword_t temp; -- unsigned thresh; - int rc; - - /* Use on-chip SRAM */ -- falcon_read(efx, &temp, NIC_STAT_REG); -- EFX_SET_OWORD_FIELD(temp, ONCHIP_SRAM, 1); -- falcon_write(efx, &temp, NIC_STAT_REG); -+ efx_reado(efx, &temp, FR_AB_NIC_STAT); -+ EFX_SET_OWORD_FIELD(temp, FRF_AB_ONCHIP_SRAM, 1); -+ efx_writeo(efx, &temp, FR_AB_NIC_STAT); - - /* Set the source of the GMAC clock */ -- if (falcon_rev(efx) == FALCON_REV_B0) { -- falcon_read(efx, &temp, GPIO_CTL_REG_KER); -- EFX_SET_OWORD_FIELD(temp, GPIO_USE_NIC_CLK, true); -- falcon_write(efx, &temp, GPIO_CTL_REG_KER); -+ if (efx_nic_rev(efx) == EFX_REV_FALCON_B0) { -+ efx_reado(efx, &temp, FR_AB_GPIO_CTL); -+ EFX_SET_OWORD_FIELD(temp, FRF_AB_USE_NIC_CLK, true); -+ efx_writeo(efx, &temp, FR_AB_GPIO_CTL); - } - -- /* Set buffer table mode */ -- EFX_POPULATE_OWORD_1(temp, BUF_TBL_MODE, BUF_TBL_MODE_FULL); -- falcon_write(efx, &temp, BUF_TBL_CFG_REG_KER); -+ /* Select the correct MAC */ -+ falcon_clock_mac(efx); - - rc = falcon_reset_sram(efx); - if (rc) - return rc; - -- /* Set positions of descriptor caches in SRAM. */ -- EFX_POPULATE_OWORD_1(temp, SRM_TX_DC_BASE_ADR, TX_DC_BASE / 8); -- falcon_write(efx, &temp, SRM_TX_DC_CFG_REG_KER); -- EFX_POPULATE_OWORD_1(temp, SRM_RX_DC_BASE_ADR, RX_DC_BASE / 8); -- falcon_write(efx, &temp, SRM_RX_DC_CFG_REG_KER); -- -- /* Set TX descriptor cache size. */ -- BUILD_BUG_ON(TX_DC_ENTRIES != (16 << TX_DC_ENTRIES_ORDER)); -- EFX_POPULATE_OWORD_1(temp, TX_DC_SIZE, TX_DC_ENTRIES_ORDER); -- falcon_write(efx, &temp, TX_DC_CFG_REG_KER); -- -- /* Set RX descriptor cache size. Set low watermark to size-8, as -- * this allows most efficient prefetching. -- */ -- BUILD_BUG_ON(RX_DC_ENTRIES != (16 << RX_DC_ENTRIES_ORDER)); -- EFX_POPULATE_OWORD_1(temp, RX_DC_SIZE, RX_DC_ENTRIES_ORDER); -- falcon_write(efx, &temp, RX_DC_CFG_REG_KER); -- EFX_POPULATE_OWORD_1(temp, RX_DC_PF_LWM, RX_DC_ENTRIES - 8); -- falcon_write(efx, &temp, RX_DC_PF_WM_REG_KER); -- - /* Clear the parity enables on the TX data fifos as - * they produce false parity errors because of timing issues - */ - if (EFX_WORKAROUND_5129(efx)) { -- falcon_read(efx, &temp, SPARE_REG_KER); -- EFX_SET_OWORD_FIELD(temp, MEM_PERR_EN_TX_DATA, 0); -- falcon_write(efx, &temp, SPARE_REG_KER); -+ efx_reado(efx, &temp, FR_AZ_CSR_SPARE); -+ EFX_SET_OWORD_FIELD(temp, FRF_AB_MEM_PERR_EN_TX_DATA, 0); -+ efx_writeo(efx, &temp, FR_AZ_CSR_SPARE); - } - -- /* Enable all the genuinely fatal interrupts. (They are still -- * masked by the overall interrupt mask, controlled by -- * falcon_interrupts()). -- * -- * Note: All other fatal interrupts are enabled -- */ -- EFX_POPULATE_OWORD_3(temp, -- ILL_ADR_INT_KER_EN, 1, -- RBUF_OWN_INT_KER_EN, 1, -- TBUF_OWN_INT_KER_EN, 1); -- EFX_INVERT_OWORD(temp); -- falcon_write(efx, &temp, FATAL_INTR_REG_KER); -- - if (EFX_WORKAROUND_7244(efx)) { -- falcon_read(efx, &temp, RX_FILTER_CTL_REG); -- EFX_SET_OWORD_FIELD(temp, UDP_FULL_SRCH_LIMIT, 8); -- EFX_SET_OWORD_FIELD(temp, UDP_WILD_SRCH_LIMIT, 8); -- EFX_SET_OWORD_FIELD(temp, TCP_FULL_SRCH_LIMIT, 8); -- EFX_SET_OWORD_FIELD(temp, TCP_WILD_SRCH_LIMIT, 8); -- falcon_write(efx, &temp, RX_FILTER_CTL_REG); -+ efx_reado(efx, &temp, FR_BZ_RX_FILTER_CTL); -+ EFX_SET_OWORD_FIELD(temp, FRF_BZ_UDP_FULL_SRCH_LIMIT, 8); -+ EFX_SET_OWORD_FIELD(temp, FRF_BZ_UDP_WILD_SRCH_LIMIT, 8); -+ EFX_SET_OWORD_FIELD(temp, FRF_BZ_TCP_FULL_SRCH_LIMIT, 8); -+ EFX_SET_OWORD_FIELD(temp, FRF_BZ_TCP_WILD_SRCH_LIMIT, 8); -+ efx_writeo(efx, &temp, FR_BZ_RX_FILTER_CTL); - } - -- falcon_setup_rss_indir_table(efx); -- -+ /* XXX This is documented only for Falcon A0/A1 */ - /* Setup RX. Wait for descriptor is broken and must - * be disabled. RXDP recovery shouldn't be needed, but is. - */ -- falcon_read(efx, &temp, RX_SELF_RST_REG_KER); -- EFX_SET_OWORD_FIELD(temp, RX_NODESC_WAIT_DIS, 1); -- EFX_SET_OWORD_FIELD(temp, RX_RECOVERY_EN, 1); -+ efx_reado(efx, &temp, FR_AA_RX_SELF_RST); -+ EFX_SET_OWORD_FIELD(temp, FRF_AA_RX_NODESC_WAIT_DIS, 1); -+ EFX_SET_OWORD_FIELD(temp, FRF_AA_RX_SELF_RST_EN, 1); - if (EFX_WORKAROUND_5583(efx)) -- EFX_SET_OWORD_FIELD(temp, RX_ISCSI_DIS, 1); -- falcon_write(efx, &temp, RX_SELF_RST_REG_KER); -- -- /* Disable the ugly timer-based TX DMA backoff and allow TX DMA to be -- * controlled by the RX FIFO fill level. Set arbitration to one pkt/Q. -- */ -- falcon_read(efx, &temp, TX_CFG2_REG_KER); -- EFX_SET_OWORD_FIELD(temp, TX_RX_SPACER, 0xfe); -- EFX_SET_OWORD_FIELD(temp, TX_RX_SPACER_EN, 1); -- EFX_SET_OWORD_FIELD(temp, TX_ONE_PKT_PER_Q, 1); -- EFX_SET_OWORD_FIELD(temp, TX_CSR_PUSH_EN, 0); -- EFX_SET_OWORD_FIELD(temp, TX_DIS_NON_IP_EV, 1); -- /* Enable SW_EV to inherit in char driver - assume harmless here */ -- EFX_SET_OWORD_FIELD(temp, TX_SW_EV_EN, 1); -- /* Prefetch threshold 2 => fetch when descriptor cache half empty */ -- EFX_SET_OWORD_FIELD(temp, TX_PREF_THRESHOLD, 2); -- /* Squash TX of packets of 16 bytes or less */ -- if (falcon_rev(efx) >= FALCON_REV_B0 && EFX_WORKAROUND_9141(efx)) -- EFX_SET_OWORD_FIELD(temp, TX_FLUSH_MIN_LEN_EN_B0, 1); -- falcon_write(efx, &temp, TX_CFG2_REG_KER); -+ EFX_SET_OWORD_FIELD(temp, FRF_AA_RX_ISCSI_DIS, 1); -+ efx_writeo(efx, &temp, FR_AA_RX_SELF_RST); - - /* Do not enable TX_NO_EOP_DISC_EN, since it limits packets to 16 - * descriptors (which is bad). - */ -- falcon_read(efx, &temp, TX_CFG_REG_KER); -- EFX_SET_OWORD_FIELD(temp, TX_NO_EOP_DISC_EN, 0); -- falcon_write(efx, &temp, TX_CFG_REG_KER); -- -- /* RX config */ -- falcon_read(efx, &temp, RX_CFG_REG_KER); -- EFX_SET_OWORD_FIELD_VER(efx, temp, RX_DESC_PUSH_EN, 0); -- if (EFX_WORKAROUND_7575(efx)) -- EFX_SET_OWORD_FIELD_VER(efx, temp, RX_USR_BUF_SIZE, -- (3 * 4096) / 32); -- if (falcon_rev(efx) >= FALCON_REV_B0) -- EFX_SET_OWORD_FIELD(temp, RX_INGR_EN_B0, 1); -- -- /* RX FIFO flow control thresholds */ -- thresh = ((rx_xon_thresh_bytes >= 0) ? -- rx_xon_thresh_bytes : efx->type->rx_xon_thresh); -- EFX_SET_OWORD_FIELD_VER(efx, temp, RX_XON_MAC_TH, thresh / 256); -- thresh = ((rx_xoff_thresh_bytes >= 0) ? -- rx_xoff_thresh_bytes : efx->type->rx_xoff_thresh); -- EFX_SET_OWORD_FIELD_VER(efx, temp, RX_XOFF_MAC_TH, thresh / 256); -- /* RX control FIFO thresholds [32 entries] */ -- EFX_SET_OWORD_FIELD_VER(efx, temp, RX_XON_TX_TH, 20); -- EFX_SET_OWORD_FIELD_VER(efx, temp, RX_XOFF_TX_TH, 25); -- falcon_write(efx, &temp, RX_CFG_REG_KER); -+ efx_reado(efx, &temp, FR_AZ_TX_CFG); -+ EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_NO_EOP_DISC_EN, 0); -+ efx_writeo(efx, &temp, FR_AZ_TX_CFG); -+ -+ falcon_init_rx_cfg(efx); - - /* Set destination of both TX and RX Flush events */ -- if (falcon_rev(efx) >= FALCON_REV_B0) { -- EFX_POPULATE_OWORD_1(temp, FLS_EVQ_ID, 0); -- falcon_write(efx, &temp, DP_CTRL_REG); -+ if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0) { -+ EFX_POPULATE_OWORD_1(temp, FRF_BZ_FLS_EVQ_ID, 0); -+ efx_writeo(efx, &temp, FR_BZ_DP_CTRL); - } - -+ efx_nic_init_common(efx); -+ - return 0; - } - --void falcon_remove_nic(struct efx_nic *efx) -+static void falcon_remove_nic(struct efx_nic *efx) - { - struct falcon_nic_data *nic_data = efx->nic_data; -+ struct falcon_board *board = falcon_board(efx); - int rc; - -+ board->type->fini(efx); -+ - /* Remove I2C adapter and clear it in preparation for a retry */ -- rc = i2c_del_adapter(&efx->i2c_adap); -+ rc = i2c_del_adapter(&board->i2c_adap); - BUG_ON(rc); -- memset(&efx->i2c_adap, 0, sizeof(efx->i2c_adap)); -+ memset(&board->i2c_adap, 0, sizeof(board->i2c_adap)); - - falcon_remove_spi_devices(efx); -- falcon_free_buffer(efx, &efx->irq_status); -+ efx_nic_free_buffer(efx, &efx->irq_status); - - falcon_reset_hw(efx, RESET_TYPE_ALL); - -@@ -3085,12 +1643,86 @@ void falcon_remove_nic(struct efx_nic *efx) - efx->nic_data = NULL; - } - --void falcon_update_nic_stats(struct efx_nic *efx) -+static void falcon_update_nic_stats(struct efx_nic *efx) - { -+ struct falcon_nic_data *nic_data = efx->nic_data; - efx_oword_t cnt; - -- falcon_read(efx, &cnt, RX_NODESC_DROP_REG_KER); -- efx->n_rx_nodesc_drop_cnt += EFX_OWORD_FIELD(cnt, RX_NODESC_DROP_CNT); -+ if (nic_data->stats_disable_count) -+ return; -+ -+ efx_reado(efx, &cnt, FR_AZ_RX_NODESC_DROP); -+ efx->n_rx_nodesc_drop_cnt += -+ EFX_OWORD_FIELD(cnt, FRF_AB_RX_NODESC_DROP_CNT); -+ -+ if (nic_data->stats_pending && -+ *nic_data->stats_dma_done == FALCON_STATS_DONE) { -+ nic_data->stats_pending = false; -+ rmb(); /* read the done flag before the stats */ -+ efx->mac_op->update_stats(efx); -+ } -+} -+ -+void falcon_start_nic_stats(struct efx_nic *efx) -+{ -+ struct falcon_nic_data *nic_data = efx->nic_data; -+ -+ spin_lock_bh(&efx->stats_lock); -+ if (--nic_data->stats_disable_count == 0) -+ falcon_stats_request(efx); -+ spin_unlock_bh(&efx->stats_lock); -+} -+ -+void falcon_stop_nic_stats(struct efx_nic *efx) -+{ -+ struct falcon_nic_data *nic_data = efx->nic_data; -+ int i; -+ -+ might_sleep(); -+ -+ spin_lock_bh(&efx->stats_lock); -+ ++nic_data->stats_disable_count; -+ spin_unlock_bh(&efx->stats_lock); -+ -+ del_timer_sync(&nic_data->stats_timer); -+ -+ /* Wait enough time for the most recent transfer to -+ * complete. */ -+ for (i = 0; i < 4 && nic_data->stats_pending; i++) { -+ if (*nic_data->stats_dma_done == FALCON_STATS_DONE) -+ break; -+ msleep(1); -+ } -+ -+ spin_lock_bh(&efx->stats_lock); -+ falcon_stats_complete(efx); -+ spin_unlock_bh(&efx->stats_lock); -+} -+ -+static void falcon_set_id_led(struct efx_nic *efx, enum efx_led_mode mode) -+{ -+ falcon_board(efx)->type->set_id_led(efx, mode); -+} -+ -+/************************************************************************** -+ * -+ * Wake on LAN -+ * -+ ************************************************************************** -+ */ -+ -+static void falcon_get_wol(struct efx_nic *efx, struct ethtool_wolinfo *wol) -+{ -+ wol->supported = 0; -+ wol->wolopts = 0; -+ memset(&wol->sopass, 0, sizeof(wol->sopass)); -+} -+ -+static int falcon_set_wol(struct efx_nic *efx, u32 type) -+{ -+ if (type != 0) -+ return -EINVAL; -+ return 0; - } - - /************************************************************************** -@@ -3100,50 +1732,91 @@ void falcon_update_nic_stats(struct efx_nic *efx) - ************************************************************************** - */ - --struct efx_nic_type falcon_a_nic_type = { -- .mem_bar = 2, -+struct efx_nic_type falcon_a1_nic_type = { -+ .probe = falcon_probe_nic, -+ .remove = falcon_remove_nic, -+ .init = falcon_init_nic, -+ .fini = efx_port_dummy_op_void, -+ .monitor = falcon_monitor, -+ .reset = falcon_reset_hw, -+ .probe_port = falcon_probe_port, -+ .remove_port = falcon_remove_port, -+ .prepare_flush = falcon_prepare_flush, -+ .update_stats = falcon_update_nic_stats, -+ .start_stats = falcon_start_nic_stats, -+ .stop_stats = falcon_stop_nic_stats, -+ .set_id_led = falcon_set_id_led, -+ .push_irq_moderation = falcon_push_irq_moderation, -+ .push_multicast_hash = falcon_push_multicast_hash, -+ .reconfigure_port = falcon_reconfigure_port, -+ .get_wol = falcon_get_wol, -+ .set_wol = falcon_set_wol, -+ .resume_wol = efx_port_dummy_op_void, -+ .test_nvram = falcon_test_nvram, -+ .default_mac_ops = &falcon_xmac_operations, -+ -+ .revision = EFX_REV_FALCON_A1, - .mem_map_size = 0x20000, -- .txd_ptr_tbl_base = TX_DESC_PTR_TBL_KER_A1, -- .rxd_ptr_tbl_base = RX_DESC_PTR_TBL_KER_A1, -- .buf_tbl_base = BUF_TBL_KER_A1, -- .evq_ptr_tbl_base = EVQ_PTR_TBL_KER_A1, -- .evq_rptr_tbl_base = EVQ_RPTR_REG_KER_A1, -- .txd_ring_mask = FALCON_TXD_RING_MASK, -- .rxd_ring_mask = FALCON_RXD_RING_MASK, -- .evq_size = FALCON_EVQ_SIZE, -- .max_dma_mask = FALCON_DMA_MASK, -- .tx_dma_mask = FALCON_TX_DMA_MASK, -- .bug5391_mask = 0xf, -- .rx_xoff_thresh = 2048, -- .rx_xon_thresh = 512, -+ .txd_ptr_tbl_base = FR_AA_TX_DESC_PTR_TBL_KER, -+ .rxd_ptr_tbl_base = FR_AA_RX_DESC_PTR_TBL_KER, -+ .buf_tbl_base = FR_AA_BUF_FULL_TBL_KER, -+ .evq_ptr_tbl_base = FR_AA_EVQ_PTR_TBL_KER, -+ .evq_rptr_tbl_base = FR_AA_EVQ_RPTR_KER, -+ .max_dma_mask = DMA_BIT_MASK(FSF_AZ_TX_KER_BUF_ADDR_WIDTH), - .rx_buffer_padding = 0x24, - .max_interrupt_mode = EFX_INT_MODE_MSI, - .phys_addr_channels = 4, -+ .tx_dc_base = 0x130000, -+ .rx_dc_base = 0x100000, -+ .offload_features = NETIF_F_IP_CSUM, -+ .reset_world_flags = ETH_RESET_IRQ, - }; - --struct efx_nic_type falcon_b_nic_type = { -- .mem_bar = 2, -+struct efx_nic_type falcon_b0_nic_type = { -+ .probe = falcon_probe_nic, -+ .remove = falcon_remove_nic, -+ .init = falcon_init_nic, -+ .fini = efx_port_dummy_op_void, -+ .monitor = falcon_monitor, -+ .reset = falcon_reset_hw, -+ .probe_port = falcon_probe_port, -+ .remove_port = falcon_remove_port, -+ .prepare_flush = falcon_prepare_flush, -+ .update_stats = falcon_update_nic_stats, -+ .start_stats = falcon_start_nic_stats, -+ .stop_stats = falcon_stop_nic_stats, -+ .set_id_led = falcon_set_id_led, -+ .push_irq_moderation = falcon_push_irq_moderation, -+ .push_multicast_hash = falcon_push_multicast_hash, -+ .reconfigure_port = falcon_reconfigure_port, -+ .get_wol = falcon_get_wol, -+ .set_wol = falcon_set_wol, -+ .resume_wol = efx_port_dummy_op_void, -+ .test_registers = falcon_b0_test_registers, -+ .test_nvram = falcon_test_nvram, -+ .default_mac_ops = &falcon_xmac_operations, -+ -+ .revision = EFX_REV_FALCON_B0, - /* Map everything up to and including the RSS indirection - * table. Don't map MSI-X table, MSI-X PBA since Linux - * requires that they not be mapped. */ -- .mem_map_size = RX_RSS_INDIR_TBL_B0 + 0x800, -- .txd_ptr_tbl_base = TX_DESC_PTR_TBL_KER_B0, -- .rxd_ptr_tbl_base = RX_DESC_PTR_TBL_KER_B0, -- .buf_tbl_base = BUF_TBL_KER_B0, -- .evq_ptr_tbl_base = EVQ_PTR_TBL_KER_B0, -- .evq_rptr_tbl_base = EVQ_RPTR_REG_KER_B0, -- .txd_ring_mask = FALCON_TXD_RING_MASK, -- .rxd_ring_mask = FALCON_RXD_RING_MASK, -- .evq_size = FALCON_EVQ_SIZE, -- .max_dma_mask = FALCON_DMA_MASK, -- .tx_dma_mask = FALCON_TX_DMA_MASK, -- .bug5391_mask = 0, -- .rx_xoff_thresh = 54272, /* ~80Kb - 3*max MTU */ -- .rx_xon_thresh = 27648, /* ~3*max MTU */ -+ .mem_map_size = (FR_BZ_RX_INDIRECTION_TBL + -+ FR_BZ_RX_INDIRECTION_TBL_STEP * -+ FR_BZ_RX_INDIRECTION_TBL_ROWS), -+ .txd_ptr_tbl_base = FR_BZ_TX_DESC_PTR_TBL, -+ .rxd_ptr_tbl_base = FR_BZ_RX_DESC_PTR_TBL, -+ .buf_tbl_base = FR_BZ_BUF_FULL_TBL, -+ .evq_ptr_tbl_base = FR_BZ_EVQ_PTR_TBL, -+ .evq_rptr_tbl_base = FR_BZ_EVQ_RPTR, -+ .max_dma_mask = DMA_BIT_MASK(FSF_AZ_TX_KER_BUF_ADDR_WIDTH), - .rx_buffer_padding = 0, - .max_interrupt_mode = EFX_INT_MODE_MSIX, - .phys_addr_channels = 32, /* Hardware limit is 64, but the legacy - * interrupt handler only supports 32 - * channels */ -+ .tx_dc_base = 0x130000, -+ .rx_dc_base = 0x100000, -+ .offload_features = NETIF_F_IP_CSUM, -+ .reset_world_flags = ETH_RESET_IRQ, - }; - -diff --git a/drivers/net/sfc/falcon.h b/drivers/net/sfc/falcon.h -deleted file mode 100644 -index 77f2e0d..0000000 ---- a/drivers/net/sfc/falcon.h -+++ /dev/null -@@ -1,145 +0,0 @@ --/**************************************************************************** -- * Driver for Solarflare Solarstorm network controllers and boards -- * Copyright 2005-2006 Fen Systems Ltd. -- * Copyright 2006-2008 Solarflare Communications Inc. -- * -- * This program is free software; you can redistribute it and/or modify it -- * under the terms of the GNU General Public License version 2 as published -- * by the Free Software Foundation, incorporated herein by reference. -- */ -- --#ifndef EFX_FALCON_H --#define EFX_FALCON_H -- --#include "net_driver.h" --#include "efx.h" -- --/* -- * Falcon hardware control -- */ -- --enum falcon_revision { -- FALCON_REV_A0 = 0, -- FALCON_REV_A1 = 1, -- FALCON_REV_B0 = 2, --}; -- --static inline int falcon_rev(struct efx_nic *efx) --{ -- return efx->pci_dev->revision; --} -- --extern struct efx_nic_type falcon_a_nic_type; --extern struct efx_nic_type falcon_b_nic_type; -- --/************************************************************************** -- * -- * Externs -- * -- ************************************************************************** -- */ -- --/* TX data path */ --extern int falcon_probe_tx(struct efx_tx_queue *tx_queue); --extern void falcon_init_tx(struct efx_tx_queue *tx_queue); --extern void falcon_fini_tx(struct efx_tx_queue *tx_queue); --extern void falcon_remove_tx(struct efx_tx_queue *tx_queue); --extern void falcon_push_buffers(struct efx_tx_queue *tx_queue); -- --/* RX data path */ --extern int falcon_probe_rx(struct efx_rx_queue *rx_queue); --extern void falcon_init_rx(struct efx_rx_queue *rx_queue); --extern void falcon_fini_rx(struct efx_rx_queue *rx_queue); --extern void falcon_remove_rx(struct efx_rx_queue *rx_queue); --extern void falcon_notify_rx_desc(struct efx_rx_queue *rx_queue); -- --/* Event data path */ --extern int falcon_probe_eventq(struct efx_channel *channel); --extern void falcon_init_eventq(struct efx_channel *channel); --extern void falcon_fini_eventq(struct efx_channel *channel); --extern void falcon_remove_eventq(struct efx_channel *channel); --extern int falcon_process_eventq(struct efx_channel *channel, int rx_quota); --extern void falcon_eventq_read_ack(struct efx_channel *channel); -- --/* Ports */ --extern int falcon_probe_port(struct efx_nic *efx); --extern void falcon_remove_port(struct efx_nic *efx); -- --/* MAC/PHY */ --extern int falcon_switch_mac(struct efx_nic *efx); --extern bool falcon_xaui_link_ok(struct efx_nic *efx); --extern int falcon_dma_stats(struct efx_nic *efx, -- unsigned int done_offset); --extern void falcon_drain_tx_fifo(struct efx_nic *efx); --extern void falcon_deconfigure_mac_wrapper(struct efx_nic *efx); --extern void falcon_reconfigure_mac_wrapper(struct efx_nic *efx); -- --/* Interrupts and test events */ --extern int falcon_init_interrupt(struct efx_nic *efx); --extern void falcon_enable_interrupts(struct efx_nic *efx); --extern void falcon_generate_test_event(struct efx_channel *channel, -- unsigned int magic); --extern void falcon_sim_phy_event(struct efx_nic *efx); --extern void falcon_generate_interrupt(struct efx_nic *efx); --extern void falcon_set_int_moderation(struct efx_channel *channel); --extern void falcon_disable_interrupts(struct efx_nic *efx); --extern void falcon_fini_interrupt(struct efx_nic *efx); -- --#define FALCON_IRQ_MOD_RESOLUTION 5 -- --/* Global Resources */ --extern int falcon_probe_nic(struct efx_nic *efx); --extern int falcon_probe_resources(struct efx_nic *efx); --extern int falcon_init_nic(struct efx_nic *efx); --extern int falcon_flush_queues(struct efx_nic *efx); --extern int falcon_reset_hw(struct efx_nic *efx, enum reset_type method); --extern void falcon_remove_resources(struct efx_nic *efx); --extern void falcon_remove_nic(struct efx_nic *efx); --extern void falcon_update_nic_stats(struct efx_nic *efx); --extern void falcon_set_multicast_hash(struct efx_nic *efx); --extern int falcon_reset_xaui(struct efx_nic *efx); -- --/* Tests */ --struct falcon_nvconfig; --extern int falcon_read_nvram(struct efx_nic *efx, -- struct falcon_nvconfig *nvconfig); --extern int falcon_test_registers(struct efx_nic *efx); -- --/************************************************************************** -- * -- * Falcon MAC stats -- * -- ************************************************************************** -- */ -- --#define FALCON_STAT_OFFSET(falcon_stat) EFX_VAL(falcon_stat, offset) --#define FALCON_STAT_WIDTH(falcon_stat) EFX_VAL(falcon_stat, WIDTH) -- --/* Retrieve statistic from statistics block */ --#define FALCON_STAT(efx, falcon_stat, efx_stat) do { \ -- if (FALCON_STAT_WIDTH(falcon_stat) == 16) \ -- (efx)->mac_stats.efx_stat += le16_to_cpu( \ -- *((__force __le16 *) \ -- (efx->stats_buffer.addr + \ -- FALCON_STAT_OFFSET(falcon_stat)))); \ -- else if (FALCON_STAT_WIDTH(falcon_stat) == 32) \ -- (efx)->mac_stats.efx_stat += le32_to_cpu( \ -- *((__force __le32 *) \ -- (efx->stats_buffer.addr + \ -- FALCON_STAT_OFFSET(falcon_stat)))); \ -- else \ -- (efx)->mac_stats.efx_stat += le64_to_cpu( \ -- *((__force __le64 *) \ -- (efx->stats_buffer.addr + \ -- FALCON_STAT_OFFSET(falcon_stat)))); \ -- } while (0) -- --#define FALCON_MAC_STATS_SIZE 0x100 -- --#define MAC_DATA_LBN 0 --#define MAC_DATA_WIDTH 32 -- --extern void falcon_generate_event(struct efx_channel *channel, -- efx_qword_t *event); -- --#endif /* EFX_FALCON_H */ -diff --git a/drivers/net/sfc/falcon_boards.c b/drivers/net/sfc/falcon_boards.c -new file mode 100644 -index 0000000..bf0b96a ---- /dev/null -+++ b/drivers/net/sfc/falcon_boards.c -@@ -0,0 +1,752 @@ -+/**************************************************************************** -+ * Driver for Solarflare Solarstorm network controllers and boards -+ * Copyright 2007-2009 Solarflare Communications Inc. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License version 2 as published -+ * by the Free Software Foundation, incorporated herein by reference. -+ */ -+ -+#include -+ -+#include "net_driver.h" -+#include "phy.h" -+#include "efx.h" -+#include "nic.h" -+#include "regs.h" -+#include "io.h" -+#include "workarounds.h" -+ -+/* Macros for unpacking the board revision */ -+/* The revision info is in host byte order. */ -+#define FALCON_BOARD_TYPE(_rev) (_rev >> 8) -+#define FALCON_BOARD_MAJOR(_rev) ((_rev >> 4) & 0xf) -+#define FALCON_BOARD_MINOR(_rev) (_rev & 0xf) -+ -+/* Board types */ -+#define FALCON_BOARD_SFE4001 0x01 -+#define FALCON_BOARD_SFE4002 0x02 -+#define FALCON_BOARD_SFN4111T 0x51 -+#define FALCON_BOARD_SFN4112F 0x52 -+ -+/***************************************************************************** -+ * Support for LM87 sensor chip used on several boards -+ */ -+#define LM87_REG_ALARMS1 0x41 -+#define LM87_REG_ALARMS2 0x42 -+#define LM87_IN_LIMITS(nr, _min, _max) \ -+ 0x2B + (nr) * 2, _max, 0x2C + (nr) * 2, _min -+#define LM87_AIN_LIMITS(nr, _min, _max) \ -+ 0x3B + (nr), _max, 0x1A + (nr), _min -+#define LM87_TEMP_INT_LIMITS(_min, _max) \ -+ 0x39, _max, 0x3A, _min -+#define LM87_TEMP_EXT1_LIMITS(_min, _max) \ -+ 0x37, _max, 0x38, _min -+ -+#define LM87_ALARM_TEMP_INT 0x10 -+#define LM87_ALARM_TEMP_EXT1 0x20 -+ -+#if defined(CONFIG_SENSORS_LM87) || defined(CONFIG_SENSORS_LM87_MODULE) -+ -+static int efx_init_lm87(struct efx_nic *efx, struct i2c_board_info *info, -+ const u8 *reg_values) -+{ -+ struct falcon_board *board = falcon_board(efx); -+ struct i2c_client *client = i2c_new_device(&board->i2c_adap, info); -+ int rc; -+ -+ if (!client) -+ return -EIO; -+ -+ while (*reg_values) { -+ u8 reg = *reg_values++; -+ u8 value = *reg_values++; -+ rc = i2c_smbus_write_byte_data(client, reg, value); -+ if (rc) -+ goto err; -+ } -+ -+ board->hwmon_client = client; -+ return 0; -+ -+err: -+ i2c_unregister_device(client); -+ return rc; -+} -+ -+static void efx_fini_lm87(struct efx_nic *efx) -+{ -+ i2c_unregister_device(falcon_board(efx)->hwmon_client); -+} -+ -+static int efx_check_lm87(struct efx_nic *efx, unsigned mask) -+{ -+ struct i2c_client *client = falcon_board(efx)->hwmon_client; -+ s32 alarms1, alarms2; -+ -+ /* If link is up then do not monitor temperature */ -+ if (EFX_WORKAROUND_7884(efx) && efx->link_state.up) -+ return 0; -+ -+ alarms1 = i2c_smbus_read_byte_data(client, LM87_REG_ALARMS1); -+ alarms2 = i2c_smbus_read_byte_data(client, LM87_REG_ALARMS2); -+ if (alarms1 < 0) -+ return alarms1; -+ if (alarms2 < 0) -+ return alarms2; -+ alarms1 &= mask; -+ alarms2 &= mask >> 8; -+ if (alarms1 || alarms2) { -+ EFX_ERR(efx, -+ "LM87 detected a hardware failure (status %02x:%02x)" -+ "%s%s\n", -+ alarms1, alarms2, -+ (alarms1 & LM87_ALARM_TEMP_INT) ? " INTERNAL" : "", -+ (alarms1 & LM87_ALARM_TEMP_EXT1) ? " EXTERNAL" : ""); -+ return -ERANGE; -+ } -+ -+ return 0; -+} -+ -+#else /* !CONFIG_SENSORS_LM87 */ -+ -+static inline int -+efx_init_lm87(struct efx_nic *efx, struct i2c_board_info *info, -+ const u8 *reg_values) -+{ -+ return 0; -+} -+static inline void efx_fini_lm87(struct efx_nic *efx) -+{ -+} -+static inline int efx_check_lm87(struct efx_nic *efx, unsigned mask) -+{ -+ return 0; -+} -+ -+#endif /* CONFIG_SENSORS_LM87 */ -+ -+/***************************************************************************** -+ * Support for the SFE4001 and SFN4111T NICs. -+ * -+ * The SFE4001 does not power-up fully at reset due to its high power -+ * consumption. We control its power via a PCA9539 I/O expander. -+ * Both boards have a MAX6647 temperature monitor which we expose to -+ * the lm90 driver. -+ * -+ * This also provides minimal support for reflashing the PHY, which is -+ * initiated by resetting it with the FLASH_CFG_1 pin pulled down. -+ * On SFE4001 rev A2 and later this is connected to the 3V3X output of -+ * the IO-expander; on the SFN4111T it is connected to Falcon's GPIO3. -+ * We represent reflash mode as PHY_MODE_SPECIAL and make it mutually -+ * exclusive with the network device being open. -+ */ -+ -+/************************************************************************** -+ * Support for I2C IO Expander device on SFE4001 -+ */ -+#define PCA9539 0x74 -+ -+#define P0_IN 0x00 -+#define P0_OUT 0x02 -+#define P0_INVERT 0x04 -+#define P0_CONFIG 0x06 -+ -+#define P0_EN_1V0X_LBN 0 -+#define P0_EN_1V0X_WIDTH 1 -+#define P0_EN_1V2_LBN 1 -+#define P0_EN_1V2_WIDTH 1 -+#define P0_EN_2V5_LBN 2 -+#define P0_EN_2V5_WIDTH 1 -+#define P0_EN_3V3X_LBN 3 -+#define P0_EN_3V3X_WIDTH 1 -+#define P0_EN_5V_LBN 4 -+#define P0_EN_5V_WIDTH 1 -+#define P0_SHORTEN_JTAG_LBN 5 -+#define P0_SHORTEN_JTAG_WIDTH 1 -+#define P0_X_TRST_LBN 6 -+#define P0_X_TRST_WIDTH 1 -+#define P0_DSP_RESET_LBN 7 -+#define P0_DSP_RESET_WIDTH 1 -+ -+#define P1_IN 0x01 -+#define P1_OUT 0x03 -+#define P1_INVERT 0x05 -+#define P1_CONFIG 0x07 -+ -+#define P1_AFE_PWD_LBN 0 -+#define P1_AFE_PWD_WIDTH 1 -+#define P1_DSP_PWD25_LBN 1 -+#define P1_DSP_PWD25_WIDTH 1 -+#define P1_RESERVED_LBN 2 -+#define P1_RESERVED_WIDTH 2 -+#define P1_SPARE_LBN 4 -+#define P1_SPARE_WIDTH 4 -+ -+/* Temperature Sensor */ -+#define MAX664X_REG_RSL 0x02 -+#define MAX664X_REG_WLHO 0x0B -+ -+static void sfe4001_poweroff(struct efx_nic *efx) -+{ -+ struct i2c_client *ioexp_client = falcon_board(efx)->ioexp_client; -+ struct i2c_client *hwmon_client = falcon_board(efx)->hwmon_client; -+ -+ /* Turn off all power rails and disable outputs */ -+ i2c_smbus_write_byte_data(ioexp_client, P0_OUT, 0xff); -+ i2c_smbus_write_byte_data(ioexp_client, P1_CONFIG, 0xff); -+ i2c_smbus_write_byte_data(ioexp_client, P0_CONFIG, 0xff); -+ -+ /* Clear any over-temperature alert */ -+ i2c_smbus_read_byte_data(hwmon_client, MAX664X_REG_RSL); -+} -+ -+static int sfe4001_poweron(struct efx_nic *efx) -+{ -+ struct i2c_client *ioexp_client = falcon_board(efx)->ioexp_client; -+ struct i2c_client *hwmon_client = falcon_board(efx)->hwmon_client; -+ unsigned int i, j; -+ int rc; -+ u8 out; -+ -+ /* Clear any previous over-temperature alert */ -+ rc = i2c_smbus_read_byte_data(hwmon_client, MAX664X_REG_RSL); -+ if (rc < 0) -+ return rc; -+ -+ /* Enable port 0 and port 1 outputs on IO expander */ -+ rc = i2c_smbus_write_byte_data(ioexp_client, P0_CONFIG, 0x00); -+ if (rc) -+ return rc; -+ rc = i2c_smbus_write_byte_data(ioexp_client, P1_CONFIG, -+ 0xff & ~(1 << P1_SPARE_LBN)); -+ if (rc) -+ goto fail_on; -+ -+ /* If PHY power is on, turn it all off and wait 1 second to -+ * ensure a full reset. -+ */ -+ rc = i2c_smbus_read_byte_data(ioexp_client, P0_OUT); -+ if (rc < 0) -+ goto fail_on; -+ out = 0xff & ~((0 << P0_EN_1V2_LBN) | (0 << P0_EN_2V5_LBN) | -+ (0 << P0_EN_3V3X_LBN) | (0 << P0_EN_5V_LBN) | -+ (0 << P0_EN_1V0X_LBN)); -+ if (rc != out) { -+ EFX_INFO(efx, "power-cycling PHY\n"); -+ rc = i2c_smbus_write_byte_data(ioexp_client, P0_OUT, out); -+ if (rc) -+ goto fail_on; -+ schedule_timeout_uninterruptible(HZ); -+ } -+ -+ for (i = 0; i < 20; ++i) { -+ /* Turn on 1.2V, 2.5V, 3.3V and 5V power rails */ -+ out = 0xff & ~((1 << P0_EN_1V2_LBN) | (1 << P0_EN_2V5_LBN) | -+ (1 << P0_EN_3V3X_LBN) | (1 << P0_EN_5V_LBN) | -+ (1 << P0_X_TRST_LBN)); -+ if (efx->phy_mode & PHY_MODE_SPECIAL) -+ out |= 1 << P0_EN_3V3X_LBN; -+ -+ rc = i2c_smbus_write_byte_data(ioexp_client, P0_OUT, out); -+ if (rc) -+ goto fail_on; -+ msleep(10); -+ -+ /* Turn on 1V power rail */ -+ out &= ~(1 << P0_EN_1V0X_LBN); -+ rc = i2c_smbus_write_byte_data(ioexp_client, P0_OUT, out); -+ if (rc) -+ goto fail_on; -+ -+ EFX_INFO(efx, "waiting for DSP boot (attempt %d)...\n", i); -+ -+ /* In flash config mode, DSP does not turn on AFE, so -+ * just wait 1 second. -+ */ -+ if (efx->phy_mode & PHY_MODE_SPECIAL) { -+ schedule_timeout_uninterruptible(HZ); -+ return 0; -+ } -+ -+ for (j = 0; j < 10; ++j) { -+ msleep(100); -+ -+ /* Check DSP has asserted AFE power line */ -+ rc = i2c_smbus_read_byte_data(ioexp_client, P1_IN); -+ if (rc < 0) -+ goto fail_on; -+ if (rc & (1 << P1_AFE_PWD_LBN)) -+ return 0; -+ } -+ } -+ -+ EFX_INFO(efx, "timed out waiting for DSP boot\n"); -+ rc = -ETIMEDOUT; -+fail_on: -+ sfe4001_poweroff(efx); -+ return rc; -+} -+ -+static int sfn4111t_reset(struct efx_nic *efx) -+{ -+ struct falcon_board *board = falcon_board(efx); -+ efx_oword_t reg; -+ -+ /* GPIO 3 and the GPIO register are shared with I2C, so block that */ -+ i2c_lock_adapter(&board->i2c_adap); -+ -+ /* Pull RST_N (GPIO 2) low then let it up again, setting the -+ * FLASH_CFG_1 strap (GPIO 3) appropriately. Only change the -+ * output enables; the output levels should always be 0 (low) -+ * and we rely on external pull-ups. */ -+ efx_reado(efx, ®, FR_AB_GPIO_CTL); -+ EFX_SET_OWORD_FIELD(reg, FRF_AB_GPIO2_OEN, true); -+ efx_writeo(efx, ®, FR_AB_GPIO_CTL); -+ msleep(1000); -+ EFX_SET_OWORD_FIELD(reg, FRF_AB_GPIO2_OEN, false); -+ EFX_SET_OWORD_FIELD(reg, FRF_AB_GPIO3_OEN, -+ !!(efx->phy_mode & PHY_MODE_SPECIAL)); -+ efx_writeo(efx, ®, FR_AB_GPIO_CTL); -+ msleep(1); -+ -+ i2c_unlock_adapter(&board->i2c_adap); -+ -+ ssleep(1); -+ return 0; -+} -+ -+static ssize_t show_phy_flash_cfg(struct device *dev, -+ struct device_attribute *attr, char *buf) -+{ -+ struct efx_nic *efx = pci_get_drvdata(to_pci_dev(dev)); -+ return sprintf(buf, "%d\n", !!(efx->phy_mode & PHY_MODE_SPECIAL)); -+} -+ -+static ssize_t set_phy_flash_cfg(struct device *dev, -+ struct device_attribute *attr, -+ const char *buf, size_t count) -+{ -+ struct efx_nic *efx = pci_get_drvdata(to_pci_dev(dev)); -+ enum efx_phy_mode old_mode, new_mode; -+ int err; -+ -+ rtnl_lock(); -+ old_mode = efx->phy_mode; -+ if (count == 0 || *buf == '0') -+ new_mode = old_mode & ~PHY_MODE_SPECIAL; -+ else -+ new_mode = PHY_MODE_SPECIAL; -+ if (old_mode == new_mode) { -+ err = 0; -+ } else if (efx->state != STATE_RUNNING || netif_running(efx->net_dev)) { -+ err = -EBUSY; -+ } else { -+ /* Reset the PHY, reconfigure the MAC and enable/disable -+ * MAC stats accordingly. */ -+ efx->phy_mode = new_mode; -+ if (new_mode & PHY_MODE_SPECIAL) -+ falcon_stop_nic_stats(efx); -+ if (falcon_board(efx)->type->id == FALCON_BOARD_SFE4001) -+ err = sfe4001_poweron(efx); -+ else -+ err = sfn4111t_reset(efx); -+ if (!err) -+ err = efx_reconfigure_port(efx); -+ if (!(new_mode & PHY_MODE_SPECIAL)) -+ falcon_start_nic_stats(efx); -+ } -+ rtnl_unlock(); -+ -+ return err ? err : count; -+} -+ -+static DEVICE_ATTR(phy_flash_cfg, 0644, show_phy_flash_cfg, set_phy_flash_cfg); -+ -+static void sfe4001_fini(struct efx_nic *efx) -+{ -+ struct falcon_board *board = falcon_board(efx); -+ -+ EFX_INFO(efx, "%s\n", __func__); -+ -+ device_remove_file(&efx->pci_dev->dev, &dev_attr_phy_flash_cfg); -+ sfe4001_poweroff(efx); -+ i2c_unregister_device(board->ioexp_client); -+ i2c_unregister_device(board->hwmon_client); -+} -+ -+static int sfe4001_check_hw(struct efx_nic *efx) -+{ -+ s32 status; -+ -+ /* If XAUI link is up then do not monitor */ -+ if (EFX_WORKAROUND_7884(efx) && !efx->xmac_poll_required) -+ return 0; -+ -+ /* Check the powered status of the PHY. Lack of power implies that -+ * the MAX6647 has shut down power to it, probably due to a temp. -+ * alarm. Reading the power status rather than the MAX6647 status -+ * directly because the later is read-to-clear and would thus -+ * start to power up the PHY again when polled, causing us to blip -+ * the power undesirably. -+ * We know we can read from the IO expander because we did -+ * it during power-on. Assume failure now is bad news. */ -+ status = i2c_smbus_read_byte_data(falcon_board(efx)->ioexp_client, P1_IN); -+ if (status >= 0 && -+ (status & ((1 << P1_AFE_PWD_LBN) | (1 << P1_DSP_PWD25_LBN))) != 0) -+ return 0; -+ -+ /* Use board power control, not PHY power control */ -+ sfe4001_poweroff(efx); -+ efx->phy_mode = PHY_MODE_OFF; -+ -+ return (status < 0) ? -EIO : -ERANGE; -+} -+ -+static struct i2c_board_info sfe4001_hwmon_info = { -+ I2C_BOARD_INFO("max6647", 0x4e), -+}; -+ -+/* This board uses an I2C expander to provider power to the PHY, which needs to -+ * be turned on before the PHY can be used. -+ * Context: Process context, rtnl lock held -+ */ -+static int sfe4001_init(struct efx_nic *efx) -+{ -+ struct falcon_board *board = falcon_board(efx); -+ int rc; -+ -+#if defined(CONFIG_SENSORS_LM90) || defined(CONFIG_SENSORS_LM90_MODULE) -+ board->hwmon_client = -+ i2c_new_device(&board->i2c_adap, &sfe4001_hwmon_info); -+#else -+ board->hwmon_client = -+ i2c_new_dummy(&board->i2c_adap, sfe4001_hwmon_info.addr); -+#endif -+ if (!board->hwmon_client) -+ return -EIO; -+ -+ /* Raise board/PHY high limit from 85 to 90 degrees Celsius */ -+ rc = i2c_smbus_write_byte_data(board->hwmon_client, -+ MAX664X_REG_WLHO, 90); -+ if (rc) -+ goto fail_hwmon; -+ -+ board->ioexp_client = i2c_new_dummy(&board->i2c_adap, PCA9539); -+ if (!board->ioexp_client) { -+ rc = -EIO; -+ goto fail_hwmon; -+ } -+ -+ if (efx->phy_mode & PHY_MODE_SPECIAL) { -+ /* PHY won't generate a 156.25 MHz clock and MAC stats fetch -+ * will fail. */ -+ falcon_stop_nic_stats(efx); -+ } -+ rc = sfe4001_poweron(efx); -+ if (rc) -+ goto fail_ioexp; -+ -+ rc = device_create_file(&efx->pci_dev->dev, &dev_attr_phy_flash_cfg); -+ if (rc) -+ goto fail_on; -+ -+ EFX_INFO(efx, "PHY is powered on\n"); -+ return 0; -+ -+fail_on: -+ sfe4001_poweroff(efx); -+fail_ioexp: -+ i2c_unregister_device(board->ioexp_client); -+fail_hwmon: -+ i2c_unregister_device(board->hwmon_client); -+ return rc; -+} -+ -+static int sfn4111t_check_hw(struct efx_nic *efx) -+{ -+ s32 status; -+ -+ /* If XAUI link is up then do not monitor */ -+ if (EFX_WORKAROUND_7884(efx) && !efx->xmac_poll_required) -+ return 0; -+ -+ /* Test LHIGH, RHIGH, FAULT, EOT and IOT alarms */ -+ status = i2c_smbus_read_byte_data(falcon_board(efx)->hwmon_client, -+ MAX664X_REG_RSL); -+ if (status < 0) -+ return -EIO; -+ if (status & 0x57) -+ return -ERANGE; -+ return 0; -+} -+ -+static void sfn4111t_fini(struct efx_nic *efx) -+{ -+ EFX_INFO(efx, "%s\n", __func__); -+ -+ device_remove_file(&efx->pci_dev->dev, &dev_attr_phy_flash_cfg); -+ i2c_unregister_device(falcon_board(efx)->hwmon_client); -+} -+ -+static struct i2c_board_info sfn4111t_a0_hwmon_info = { -+ I2C_BOARD_INFO("max6647", 0x4e), -+}; -+ -+static struct i2c_board_info sfn4111t_r5_hwmon_info = { -+ I2C_BOARD_INFO("max6646", 0x4d), -+}; -+ -+static void sfn4111t_init_phy(struct efx_nic *efx) -+{ -+ if (!(efx->phy_mode & PHY_MODE_SPECIAL)) { -+ if (sft9001_wait_boot(efx) != -EINVAL) -+ return; -+ -+ efx->phy_mode = PHY_MODE_SPECIAL; -+ falcon_stop_nic_stats(efx); -+ } -+ -+ sfn4111t_reset(efx); -+ sft9001_wait_boot(efx); -+} -+ -+static int sfn4111t_init(struct efx_nic *efx) -+{ -+ struct falcon_board *board = falcon_board(efx); -+ int rc; -+ -+ board->hwmon_client = -+ i2c_new_device(&board->i2c_adap, -+ (board->minor < 5) ? -+ &sfn4111t_a0_hwmon_info : -+ &sfn4111t_r5_hwmon_info); -+ if (!board->hwmon_client) -+ return -EIO; -+ -+ rc = device_create_file(&efx->pci_dev->dev, &dev_attr_phy_flash_cfg); -+ if (rc) -+ goto fail_hwmon; -+ -+ if (efx->phy_mode & PHY_MODE_SPECIAL) -+ /* PHY may not generate a 156.25 MHz clock and MAC -+ * stats fetch will fail. */ -+ falcon_stop_nic_stats(efx); -+ -+ return 0; -+ -+fail_hwmon: -+ i2c_unregister_device(board->hwmon_client); -+ return rc; -+} -+ -+/***************************************************************************** -+ * Support for the SFE4002 -+ * -+ */ -+static u8 sfe4002_lm87_channel = 0x03; /* use AIN not FAN inputs */ -+ -+static const u8 sfe4002_lm87_regs[] = { -+ LM87_IN_LIMITS(0, 0x83, 0x91), /* 2.5V: 1.8V +/- 5% */ -+ LM87_IN_LIMITS(1, 0x51, 0x5a), /* Vccp1: 1.2V +/- 5% */ -+ LM87_IN_LIMITS(2, 0xb6, 0xca), /* 3.3V: 3.3V +/- 5% */ -+ LM87_IN_LIMITS(3, 0xb0, 0xc9), /* 5V: 4.6-5.2V */ -+ LM87_IN_LIMITS(4, 0xb0, 0xe0), /* 12V: 11-14V */ -+ LM87_IN_LIMITS(5, 0x44, 0x4b), /* Vccp2: 1.0V +/- 5% */ -+ LM87_AIN_LIMITS(0, 0xa0, 0xb2), /* AIN1: 1.66V +/- 5% */ -+ LM87_AIN_LIMITS(1, 0x91, 0xa1), /* AIN2: 1.5V +/- 5% */ -+ LM87_TEMP_INT_LIMITS(10, 60), /* board */ -+ LM87_TEMP_EXT1_LIMITS(10, 70), /* Falcon */ -+ 0 -+}; -+ -+static struct i2c_board_info sfe4002_hwmon_info = { -+ I2C_BOARD_INFO("lm87", 0x2e), -+ .platform_data = &sfe4002_lm87_channel, -+}; -+ -+/****************************************************************************/ -+/* LED allocations. Note that on rev A0 boards the schematic and the reality -+ * differ: red and green are swapped. Below is the fixed (A1) layout (there -+ * are only 3 A0 boards in existence, so no real reason to make this -+ * conditional). -+ */ -+#define SFE4002_FAULT_LED (2) /* Red */ -+#define SFE4002_RX_LED (0) /* Green */ -+#define SFE4002_TX_LED (1) /* Amber */ -+ -+static void sfe4002_init_phy(struct efx_nic *efx) -+{ -+ /* Set the TX and RX LEDs to reflect status and activity, and the -+ * fault LED off */ -+ falcon_qt202x_set_led(efx, SFE4002_TX_LED, -+ QUAKE_LED_TXLINK | QUAKE_LED_LINK_ACTSTAT); -+ falcon_qt202x_set_led(efx, SFE4002_RX_LED, -+ QUAKE_LED_RXLINK | QUAKE_LED_LINK_ACTSTAT); -+ falcon_qt202x_set_led(efx, SFE4002_FAULT_LED, QUAKE_LED_OFF); -+} -+ -+static void sfe4002_set_id_led(struct efx_nic *efx, enum efx_led_mode mode) -+{ -+ falcon_qt202x_set_led( -+ efx, SFE4002_FAULT_LED, -+ (mode == EFX_LED_ON) ? QUAKE_LED_ON : QUAKE_LED_OFF); -+} -+ -+static int sfe4002_check_hw(struct efx_nic *efx) -+{ -+ struct falcon_board *board = falcon_board(efx); -+ -+ /* A0 board rev. 4002s report a temperature fault the whole time -+ * (bad sensor) so we mask it out. */ -+ unsigned alarm_mask = -+ (board->major == 0 && board->minor == 0) ? -+ ~LM87_ALARM_TEMP_EXT1 : ~0; -+ -+ return efx_check_lm87(efx, alarm_mask); -+} -+ -+static int sfe4002_init(struct efx_nic *efx) -+{ -+ return efx_init_lm87(efx, &sfe4002_hwmon_info, sfe4002_lm87_regs); -+} -+ -+/***************************************************************************** -+ * Support for the SFN4112F -+ * -+ */ -+static u8 sfn4112f_lm87_channel = 0x03; /* use AIN not FAN inputs */ -+ -+static const u8 sfn4112f_lm87_regs[] = { -+ LM87_IN_LIMITS(0, 0x83, 0x91), /* 2.5V: 1.8V +/- 5% */ -+ LM87_IN_LIMITS(1, 0x51, 0x5a), /* Vccp1: 1.2V +/- 5% */ -+ LM87_IN_LIMITS(2, 0xb6, 0xca), /* 3.3V: 3.3V +/- 5% */ -+ LM87_IN_LIMITS(4, 0xb0, 0xe0), /* 12V: 11-14V */ -+ LM87_IN_LIMITS(5, 0x44, 0x4b), /* Vccp2: 1.0V +/- 5% */ -+ LM87_AIN_LIMITS(1, 0x91, 0xa1), /* AIN2: 1.5V +/- 5% */ -+ LM87_TEMP_INT_LIMITS(10, 60), /* board */ -+ LM87_TEMP_EXT1_LIMITS(10, 70), /* Falcon */ -+ 0 -+}; -+ -+static struct i2c_board_info sfn4112f_hwmon_info = { -+ I2C_BOARD_INFO("lm87", 0x2e), -+ .platform_data = &sfn4112f_lm87_channel, -+}; -+ -+#define SFN4112F_ACT_LED 0 -+#define SFN4112F_LINK_LED 1 -+ -+static void sfn4112f_init_phy(struct efx_nic *efx) -+{ -+ falcon_qt202x_set_led(efx, SFN4112F_ACT_LED, -+ QUAKE_LED_RXLINK | QUAKE_LED_LINK_ACT); -+ falcon_qt202x_set_led(efx, SFN4112F_LINK_LED, -+ QUAKE_LED_RXLINK | QUAKE_LED_LINK_STAT); -+} -+ -+static void sfn4112f_set_id_led(struct efx_nic *efx, enum efx_led_mode mode) -+{ -+ int reg; -+ -+ switch (mode) { -+ case EFX_LED_OFF: -+ reg = QUAKE_LED_OFF; -+ break; -+ case EFX_LED_ON: -+ reg = QUAKE_LED_ON; -+ break; -+ default: -+ reg = QUAKE_LED_RXLINK | QUAKE_LED_LINK_STAT; -+ break; -+ } -+ -+ falcon_qt202x_set_led(efx, SFN4112F_LINK_LED, reg); -+} -+ -+static int sfn4112f_check_hw(struct efx_nic *efx) -+{ -+ /* Mask out unused sensors */ -+ return efx_check_lm87(efx, ~0x48); -+} -+ -+static int sfn4112f_init(struct efx_nic *efx) -+{ -+ return efx_init_lm87(efx, &sfn4112f_hwmon_info, sfn4112f_lm87_regs); -+} -+ -+static const struct falcon_board_type board_types[] = { -+ { -+ .id = FALCON_BOARD_SFE4001, -+ .ref_model = "SFE4001", -+ .gen_type = "10GBASE-T adapter", -+ .init = sfe4001_init, -+ .init_phy = efx_port_dummy_op_void, -+ .fini = sfe4001_fini, -+ .set_id_led = tenxpress_set_id_led, -+ .monitor = sfe4001_check_hw, -+ }, -+ { -+ .id = FALCON_BOARD_SFE4002, -+ .ref_model = "SFE4002", -+ .gen_type = "XFP adapter", -+ .init = sfe4002_init, -+ .init_phy = sfe4002_init_phy, -+ .fini = efx_fini_lm87, -+ .set_id_led = sfe4002_set_id_led, -+ .monitor = sfe4002_check_hw, -+ }, -+ { -+ .id = FALCON_BOARD_SFN4111T, -+ .ref_model = "SFN4111T", -+ .gen_type = "100/1000/10GBASE-T adapter", -+ .init = sfn4111t_init, -+ .init_phy = sfn4111t_init_phy, -+ .fini = sfn4111t_fini, -+ .set_id_led = tenxpress_set_id_led, -+ .monitor = sfn4111t_check_hw, -+ }, -+ { -+ .id = FALCON_BOARD_SFN4112F, -+ .ref_model = "SFN4112F", -+ .gen_type = "SFP+ adapter", -+ .init = sfn4112f_init, -+ .init_phy = sfn4112f_init_phy, -+ .fini = efx_fini_lm87, -+ .set_id_led = sfn4112f_set_id_led, -+ .monitor = sfn4112f_check_hw, -+ }, -+}; -+ -+static const struct falcon_board_type falcon_dummy_board = { -+ .init = efx_port_dummy_op_int, -+ .init_phy = efx_port_dummy_op_void, -+ .fini = efx_port_dummy_op_void, -+ .set_id_led = efx_port_dummy_op_set_id_led, -+ .monitor = efx_port_dummy_op_int, -+}; -+ -+void falcon_probe_board(struct efx_nic *efx, u16 revision_info) -+{ -+ struct falcon_board *board = falcon_board(efx); -+ u8 type_id = FALCON_BOARD_TYPE(revision_info); -+ int i; -+ -+ board->major = FALCON_BOARD_MAJOR(revision_info); -+ board->minor = FALCON_BOARD_MINOR(revision_info); -+ -+ for (i = 0; i < ARRAY_SIZE(board_types); i++) -+ if (board_types[i].id == type_id) -+ board->type = &board_types[i]; -+ -+ if (board->type) { -+ EFX_INFO(efx, "board is %s rev %c%d\n", -+ (efx->pci_dev->subsystem_vendor == EFX_VENDID_SFC) -+ ? board->type->ref_model : board->type->gen_type, -+ 'A' + board->major, board->minor); -+ } else { -+ EFX_ERR(efx, "unknown board type %d\n", type_id); -+ board->type = &falcon_dummy_board; -+ } -+} -diff --git a/drivers/net/sfc/falcon_gmac.c b/drivers/net/sfc/falcon_gmac.c -index 8865eae..7dadfcb 100644 ---- a/drivers/net/sfc/falcon_gmac.c -+++ b/drivers/net/sfc/falcon_gmac.c -@@ -1,7 +1,7 @@ - /**************************************************************************** - * Driver for Solarflare Solarstorm network controllers and boards - * Copyright 2005-2006 Fen Systems Ltd. -- * Copyright 2006-2008 Solarflare Communications Inc. -+ * Copyright 2006-2009 Solarflare Communications Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published -@@ -11,11 +11,10 @@ - #include - #include "net_driver.h" - #include "efx.h" --#include "falcon.h" -+#include "nic.h" - #include "mac.h" --#include "falcon_hwdefs.h" --#include "falcon_io.h" --#include "gmii.h" -+#include "regs.h" -+#include "io.h" - - /************************************************************************** - * -@@ -23,106 +22,109 @@ - * - *************************************************************************/ - --static void falcon_reconfigure_gmac(struct efx_nic *efx) -+static int falcon_reconfigure_gmac(struct efx_nic *efx) - { -+ struct efx_link_state *link_state = &efx->link_state; - bool loopback, tx_fc, rx_fc, bytemode; - int if_mode; - unsigned int max_frame_len; - efx_oword_t reg; - - /* Configuration register 1 */ -- tx_fc = (efx->link_fc & EFX_FC_TX) || !efx->link_fd; -- rx_fc = !!(efx->link_fc & EFX_FC_RX); -+ tx_fc = (link_state->fc & EFX_FC_TX) || !link_state->fd; -+ rx_fc = !!(link_state->fc & EFX_FC_RX); - loopback = (efx->loopback_mode == LOOPBACK_GMAC); -- bytemode = (efx->link_speed == 1000); -+ bytemode = (link_state->speed == 1000); - - EFX_POPULATE_OWORD_5(reg, -- GM_LOOP, loopback, -- GM_TX_EN, 1, -- GM_TX_FC_EN, tx_fc, -- GM_RX_EN, 1, -- GM_RX_FC_EN, rx_fc); -- falcon_write(efx, ®, GM_CFG1_REG); -+ FRF_AB_GM_LOOP, loopback, -+ FRF_AB_GM_TX_EN, 1, -+ FRF_AB_GM_TX_FC_EN, tx_fc, -+ FRF_AB_GM_RX_EN, 1, -+ FRF_AB_GM_RX_FC_EN, rx_fc); -+ efx_writeo(efx, ®, FR_AB_GM_CFG1); - udelay(10); - - /* Configuration register 2 */ - if_mode = (bytemode) ? 2 : 1; - EFX_POPULATE_OWORD_5(reg, -- GM_IF_MODE, if_mode, -- GM_PAD_CRC_EN, 1, -- GM_LEN_CHK, 1, -- GM_FD, efx->link_fd, -- GM_PAMBL_LEN, 0x7/*datasheet recommended */); -+ FRF_AB_GM_IF_MODE, if_mode, -+ FRF_AB_GM_PAD_CRC_EN, 1, -+ FRF_AB_GM_LEN_CHK, 1, -+ FRF_AB_GM_FD, link_state->fd, -+ FRF_AB_GM_PAMBL_LEN, 0x7/*datasheet recommended */); - -- falcon_write(efx, ®, GM_CFG2_REG); -+ efx_writeo(efx, ®, FR_AB_GM_CFG2); - udelay(10); - - /* Max frame len register */ - max_frame_len = EFX_MAX_FRAME_LEN(efx->net_dev->mtu); -- EFX_POPULATE_OWORD_1(reg, GM_MAX_FLEN, max_frame_len); -- falcon_write(efx, ®, GM_MAX_FLEN_REG); -+ EFX_POPULATE_OWORD_1(reg, FRF_AB_GM_MAX_FLEN, max_frame_len); -+ efx_writeo(efx, ®, FR_AB_GM_MAX_FLEN); - udelay(10); - - /* FIFO configuration register 0 */ - EFX_POPULATE_OWORD_5(reg, -- GMF_FTFENREQ, 1, -- GMF_STFENREQ, 1, -- GMF_FRFENREQ, 1, -- GMF_SRFENREQ, 1, -- GMF_WTMENREQ, 1); -- falcon_write(efx, ®, GMF_CFG0_REG); -+ FRF_AB_GMF_FTFENREQ, 1, -+ FRF_AB_GMF_STFENREQ, 1, -+ FRF_AB_GMF_FRFENREQ, 1, -+ FRF_AB_GMF_SRFENREQ, 1, -+ FRF_AB_GMF_WTMENREQ, 1); -+ efx_writeo(efx, ®, FR_AB_GMF_CFG0); - udelay(10); - - /* FIFO configuration register 1 */ - EFX_POPULATE_OWORD_2(reg, -- GMF_CFGFRTH, 0x12, -- GMF_CFGXOFFRTX, 0xffff); -- falcon_write(efx, ®, GMF_CFG1_REG); -+ FRF_AB_GMF_CFGFRTH, 0x12, -+ FRF_AB_GMF_CFGXOFFRTX, 0xffff); -+ efx_writeo(efx, ®, FR_AB_GMF_CFG1); - udelay(10); - - /* FIFO configuration register 2 */ - EFX_POPULATE_OWORD_2(reg, -- GMF_CFGHWM, 0x3f, -- GMF_CFGLWM, 0xa); -- falcon_write(efx, ®, GMF_CFG2_REG); -+ FRF_AB_GMF_CFGHWM, 0x3f, -+ FRF_AB_GMF_CFGLWM, 0xa); -+ efx_writeo(efx, ®, FR_AB_GMF_CFG2); - udelay(10); - - /* FIFO configuration register 3 */ - EFX_POPULATE_OWORD_2(reg, -- GMF_CFGHWMFT, 0x1c, -- GMF_CFGFTTH, 0x08); -- falcon_write(efx, ®, GMF_CFG3_REG); -+ FRF_AB_GMF_CFGHWMFT, 0x1c, -+ FRF_AB_GMF_CFGFTTH, 0x08); -+ efx_writeo(efx, ®, FR_AB_GMF_CFG3); - udelay(10); - - /* FIFO configuration register 4 */ -- EFX_POPULATE_OWORD_1(reg, GMF_HSTFLTRFRM_PAUSE, 1); -- falcon_write(efx, ®, GMF_CFG4_REG); -+ EFX_POPULATE_OWORD_1(reg, FRF_AB_GMF_HSTFLTRFRM_PAUSE, 1); -+ efx_writeo(efx, ®, FR_AB_GMF_CFG4); - udelay(10); - - /* FIFO configuration register 5 */ -- falcon_read(efx, ®, GMF_CFG5_REG); -- EFX_SET_OWORD_FIELD(reg, GMF_CFGBYTMODE, bytemode); -- EFX_SET_OWORD_FIELD(reg, GMF_CFGHDPLX, !efx->link_fd); -- EFX_SET_OWORD_FIELD(reg, GMF_HSTDRPLT64, !efx->link_fd); -- EFX_SET_OWORD_FIELD(reg, GMF_HSTFLTRFRMDC_PAUSE, 0); -- falcon_write(efx, ®, GMF_CFG5_REG); -+ efx_reado(efx, ®, FR_AB_GMF_CFG5); -+ EFX_SET_OWORD_FIELD(reg, FRF_AB_GMF_CFGBYTMODE, bytemode); -+ EFX_SET_OWORD_FIELD(reg, FRF_AB_GMF_CFGHDPLX, !link_state->fd); -+ EFX_SET_OWORD_FIELD(reg, FRF_AB_GMF_HSTDRPLT64, !link_state->fd); -+ EFX_SET_OWORD_FIELD(reg, FRF_AB_GMF_HSTFLTRFRMDC_PAUSE, 0); -+ efx_writeo(efx, ®, FR_AB_GMF_CFG5); - udelay(10); - - /* MAC address */ - EFX_POPULATE_OWORD_4(reg, -- GM_HWADDR_5, efx->net_dev->dev_addr[5], -- GM_HWADDR_4, efx->net_dev->dev_addr[4], -- GM_HWADDR_3, efx->net_dev->dev_addr[3], -- GM_HWADDR_2, efx->net_dev->dev_addr[2]); -- falcon_write(efx, ®, GM_ADR1_REG); -+ FRF_AB_GM_ADR_B0, efx->net_dev->dev_addr[5], -+ FRF_AB_GM_ADR_B1, efx->net_dev->dev_addr[4], -+ FRF_AB_GM_ADR_B2, efx->net_dev->dev_addr[3], -+ FRF_AB_GM_ADR_B3, efx->net_dev->dev_addr[2]); -+ efx_writeo(efx, ®, FR_AB_GM_ADR1); - udelay(10); - EFX_POPULATE_OWORD_2(reg, -- GM_HWADDR_1, efx->net_dev->dev_addr[1], -- GM_HWADDR_0, efx->net_dev->dev_addr[0]); -- falcon_write(efx, ®, GM_ADR2_REG); -+ FRF_AB_GM_ADR_B4, efx->net_dev->dev_addr[1], -+ FRF_AB_GM_ADR_B5, efx->net_dev->dev_addr[0]); -+ efx_writeo(efx, ®, FR_AB_GM_ADR2); - udelay(10); - - falcon_reconfigure_mac_wrapper(efx); -+ -+ return 0; - } - - static void falcon_update_stats_gmac(struct efx_nic *efx) -@@ -130,11 +132,6 @@ static void falcon_update_stats_gmac(struct efx_nic *efx) - struct efx_mac_stats *mac_stats = &efx->mac_stats; - unsigned long old_rx_pause, old_tx_pause; - unsigned long new_rx_pause, new_tx_pause; -- int rc; -- -- rc = falcon_dma_stats(efx, GDmaDone_offset); -- if (rc) -- return; - - /* Pause frames are erroneously counted as errors (SFC bug 3269) */ - old_rx_pause = mac_stats->rx_pause; -@@ -221,9 +218,13 @@ static void falcon_update_stats_gmac(struct efx_nic *efx) - mac_stats->rx_lt64 = mac_stats->rx_good_lt64 + mac_stats->rx_bad_lt64; - } - -+static bool falcon_gmac_check_fault(struct efx_nic *efx) -+{ -+ return false; -+} -+ - struct efx_mac_operations falcon_gmac_operations = { - .reconfigure = falcon_reconfigure_gmac, - .update_stats = falcon_update_stats_gmac, -- .irq = efx_port_dummy_op_void, -- .poll = efx_port_dummy_op_void, -+ .check_fault = falcon_gmac_check_fault, - }; -diff --git a/drivers/net/sfc/falcon_hwdefs.h b/drivers/net/sfc/falcon_hwdefs.h -deleted file mode 100644 -index 2d22611..0000000 ---- a/drivers/net/sfc/falcon_hwdefs.h -+++ /dev/null -@@ -1,1333 +0,0 @@ --/**************************************************************************** -- * Driver for Solarflare Solarstorm network controllers and boards -- * Copyright 2005-2006 Fen Systems Ltd. -- * Copyright 2006-2008 Solarflare Communications Inc. -- * -- * This program is free software; you can redistribute it and/or modify it -- * under the terms of the GNU General Public License version 2 as published -- * by the Free Software Foundation, incorporated herein by reference. -- */ -- --#ifndef EFX_FALCON_HWDEFS_H --#define EFX_FALCON_HWDEFS_H -- --/* -- * Falcon hardware value definitions. -- * Falcon is the internal codename for the SFC4000 controller that is -- * present in SFE400X evaluation boards -- */ -- --/************************************************************************** -- * -- * Falcon registers -- * -- ************************************************************************** -- */ -- --/* Address region register */ --#define ADR_REGION_REG_KER 0x00 --#define ADR_REGION0_LBN 0 --#define ADR_REGION0_WIDTH 18 --#define ADR_REGION1_LBN 32 --#define ADR_REGION1_WIDTH 18 --#define ADR_REGION2_LBN 64 --#define ADR_REGION2_WIDTH 18 --#define ADR_REGION3_LBN 96 --#define ADR_REGION3_WIDTH 18 -- --/* Interrupt enable register */ --#define INT_EN_REG_KER 0x0010 --#define KER_INT_KER_LBN 3 --#define KER_INT_KER_WIDTH 1 --#define DRV_INT_EN_KER_LBN 0 --#define DRV_INT_EN_KER_WIDTH 1 -- --/* Interrupt status address register */ --#define INT_ADR_REG_KER 0x0030 --#define NORM_INT_VEC_DIS_KER_LBN 64 --#define NORM_INT_VEC_DIS_KER_WIDTH 1 --#define INT_ADR_KER_LBN 0 --#define INT_ADR_KER_WIDTH EFX_DMA_TYPE_WIDTH(64) /* not 46 for this one */ -- --/* Interrupt status register (B0 only) */ --#define INT_ISR0_B0 0x90 --#define INT_ISR1_B0 0xA0 -- --/* Interrupt acknowledge register (A0/A1 only) */ --#define INT_ACK_REG_KER_A1 0x0050 --#define INT_ACK_DUMMY_DATA_LBN 0 --#define INT_ACK_DUMMY_DATA_WIDTH 32 -- --/* Interrupt acknowledge work-around register (A0/A1 only )*/ --#define WORK_AROUND_BROKEN_PCI_READS_REG_KER_A1 0x0070 -- --/* SPI host command register */ --#define EE_SPI_HCMD_REG_KER 0x0100 --#define EE_SPI_HCMD_CMD_EN_LBN 31 --#define EE_SPI_HCMD_CMD_EN_WIDTH 1 --#define EE_WR_TIMER_ACTIVE_LBN 28 --#define EE_WR_TIMER_ACTIVE_WIDTH 1 --#define EE_SPI_HCMD_SF_SEL_LBN 24 --#define EE_SPI_HCMD_SF_SEL_WIDTH 1 --#define EE_SPI_EEPROM 0 --#define EE_SPI_FLASH 1 --#define EE_SPI_HCMD_DABCNT_LBN 16 --#define EE_SPI_HCMD_DABCNT_WIDTH 5 --#define EE_SPI_HCMD_READ_LBN 15 --#define EE_SPI_HCMD_READ_WIDTH 1 --#define EE_SPI_READ 1 --#define EE_SPI_WRITE 0 --#define EE_SPI_HCMD_DUBCNT_LBN 12 --#define EE_SPI_HCMD_DUBCNT_WIDTH 2 --#define EE_SPI_HCMD_ADBCNT_LBN 8 --#define EE_SPI_HCMD_ADBCNT_WIDTH 2 --#define EE_SPI_HCMD_ENC_LBN 0 --#define EE_SPI_HCMD_ENC_WIDTH 8 -- --/* SPI host address register */ --#define EE_SPI_HADR_REG_KER 0x0110 --#define EE_SPI_HADR_ADR_LBN 0 --#define EE_SPI_HADR_ADR_WIDTH 24 -- --/* SPI host data register */ --#define EE_SPI_HDATA_REG_KER 0x0120 -- --/* SPI/VPD config register */ --#define EE_VPD_CFG_REG_KER 0x0140 --#define EE_VPD_EN_LBN 0 --#define EE_VPD_EN_WIDTH 1 --#define EE_VPD_EN_AD9_MODE_LBN 1 --#define EE_VPD_EN_AD9_MODE_WIDTH 1 --#define EE_EE_CLOCK_DIV_LBN 112 --#define EE_EE_CLOCK_DIV_WIDTH 7 --#define EE_SF_CLOCK_DIV_LBN 120 --#define EE_SF_CLOCK_DIV_WIDTH 7 -- --/* PCIE CORE ACCESS REG */ --#define PCIE_CORE_ADDR_PCIE_DEVICE_CTRL_STAT 0x68 --#define PCIE_CORE_ADDR_PCIE_LINK_CTRL_STAT 0x70 --#define PCIE_CORE_ADDR_ACK_RPL_TIMER 0x700 --#define PCIE_CORE_ADDR_ACK_FREQ 0x70C -- --/* NIC status register */ --#define NIC_STAT_REG 0x0200 --#define EE_STRAP_EN_LBN 31 --#define EE_STRAP_EN_WIDTH 1 --#define EE_STRAP_OVR_LBN 24 --#define EE_STRAP_OVR_WIDTH 4 --#define ONCHIP_SRAM_LBN 16 --#define ONCHIP_SRAM_WIDTH 1 --#define SF_PRST_LBN 9 --#define SF_PRST_WIDTH 1 --#define EE_PRST_LBN 8 --#define EE_PRST_WIDTH 1 --#define STRAP_PINS_LBN 0 --#define STRAP_PINS_WIDTH 3 --/* These bit definitions are extrapolated from the list of numerical -- * values for STRAP_PINS. -- */ --#define STRAP_10G_LBN 2 --#define STRAP_10G_WIDTH 1 --#define STRAP_PCIE_LBN 0 --#define STRAP_PCIE_WIDTH 1 -- --#define BOOTED_USING_NVDEVICE_LBN 3 --#define BOOTED_USING_NVDEVICE_WIDTH 1 -- --/* GPIO control register */ --#define GPIO_CTL_REG_KER 0x0210 --#define GPIO_USE_NIC_CLK_LBN (30) --#define GPIO_USE_NIC_CLK_WIDTH (1) --#define GPIO_OUTPUTS_LBN (16) --#define GPIO_OUTPUTS_WIDTH (4) --#define GPIO_INPUTS_LBN (8) --#define GPIO_DIRECTION_LBN (24) --#define GPIO_DIRECTION_WIDTH (4) --#define GPIO_DIRECTION_OUT (1) --#define GPIO_SRAM_SLEEP (1 << 1) -- --#define GPIO3_OEN_LBN (GPIO_DIRECTION_LBN + 3) --#define GPIO3_OEN_WIDTH 1 --#define GPIO2_OEN_LBN (GPIO_DIRECTION_LBN + 2) --#define GPIO2_OEN_WIDTH 1 --#define GPIO1_OEN_LBN (GPIO_DIRECTION_LBN + 1) --#define GPIO1_OEN_WIDTH 1 --#define GPIO0_OEN_LBN (GPIO_DIRECTION_LBN + 0) --#define GPIO0_OEN_WIDTH 1 -- --#define GPIO3_OUT_LBN (GPIO_OUTPUTS_LBN + 3) --#define GPIO3_OUT_WIDTH 1 --#define GPIO2_OUT_LBN (GPIO_OUTPUTS_LBN + 2) --#define GPIO2_OUT_WIDTH 1 --#define GPIO1_OUT_LBN (GPIO_OUTPUTS_LBN + 1) --#define GPIO1_OUT_WIDTH 1 --#define GPIO0_OUT_LBN (GPIO_OUTPUTS_LBN + 0) --#define GPIO0_OUT_WIDTH 1 -- --#define GPIO3_IN_LBN (GPIO_INPUTS_LBN + 3) --#define GPIO3_IN_WIDTH 1 --#define GPIO2_IN_WIDTH 1 --#define GPIO1_IN_WIDTH 1 --#define GPIO0_IN_LBN (GPIO_INPUTS_LBN + 0) --#define GPIO0_IN_WIDTH 1 -- --/* Global control register */ --#define GLB_CTL_REG_KER 0x0220 --#define EXT_PHY_RST_CTL_LBN 63 --#define EXT_PHY_RST_CTL_WIDTH 1 --#define PCIE_SD_RST_CTL_LBN 61 --#define PCIE_SD_RST_CTL_WIDTH 1 -- --#define PCIE_NSTCK_RST_CTL_LBN 58 --#define PCIE_NSTCK_RST_CTL_WIDTH 1 --#define PCIE_CORE_RST_CTL_LBN 57 --#define PCIE_CORE_RST_CTL_WIDTH 1 --#define EE_RST_CTL_LBN 49 --#define EE_RST_CTL_WIDTH 1 --#define RST_XGRX_LBN 24 --#define RST_XGRX_WIDTH 1 --#define RST_XGTX_LBN 23 --#define RST_XGTX_WIDTH 1 --#define RST_EM_LBN 22 --#define RST_EM_WIDTH 1 --#define EXT_PHY_RST_DUR_LBN 1 --#define EXT_PHY_RST_DUR_WIDTH 3 --#define SWRST_LBN 0 --#define SWRST_WIDTH 1 --#define INCLUDE_IN_RESET 0 --#define EXCLUDE_FROM_RESET 1 -- --/* Fatal interrupt register */ --#define FATAL_INTR_REG_KER 0x0230 --#define RBUF_OWN_INT_KER_EN_LBN 39 --#define RBUF_OWN_INT_KER_EN_WIDTH 1 --#define TBUF_OWN_INT_KER_EN_LBN 38 --#define TBUF_OWN_INT_KER_EN_WIDTH 1 --#define ILL_ADR_INT_KER_EN_LBN 33 --#define ILL_ADR_INT_KER_EN_WIDTH 1 --#define MEM_PERR_INT_KER_LBN 8 --#define MEM_PERR_INT_KER_WIDTH 1 --#define INT_KER_ERROR_LBN 0 --#define INT_KER_ERROR_WIDTH 12 -- --#define DP_CTRL_REG 0x250 --#define FLS_EVQ_ID_LBN 0 --#define FLS_EVQ_ID_WIDTH 11 -- --#define MEM_STAT_REG_KER 0x260 -- --/* Debug probe register */ --#define DEBUG_BLK_SEL_MISC 7 --#define DEBUG_BLK_SEL_SERDES 6 --#define DEBUG_BLK_SEL_EM 5 --#define DEBUG_BLK_SEL_SR 4 --#define DEBUG_BLK_SEL_EV 3 --#define DEBUG_BLK_SEL_RX 2 --#define DEBUG_BLK_SEL_TX 1 --#define DEBUG_BLK_SEL_BIU 0 -- --/* FPGA build version */ --#define ALTERA_BUILD_REG_KER 0x0300 --#define VER_ALL_LBN 0 --#define VER_ALL_WIDTH 32 -- --/* Spare EEPROM bits register (flash 0x390) */ --#define SPARE_REG_KER 0x310 --#define MEM_PERR_EN_TX_DATA_LBN 72 --#define MEM_PERR_EN_TX_DATA_WIDTH 2 -- --/* Timer table for kernel access */ --#define TIMER_CMD_REG_KER 0x420 --#define TIMER_MODE_LBN 12 --#define TIMER_MODE_WIDTH 2 --#define TIMER_MODE_DIS 0 --#define TIMER_MODE_INT_HLDOFF 2 --#define TIMER_VAL_LBN 0 --#define TIMER_VAL_WIDTH 12 -- --/* Driver generated event register */ --#define DRV_EV_REG_KER 0x440 --#define DRV_EV_QID_LBN 64 --#define DRV_EV_QID_WIDTH 12 --#define DRV_EV_DATA_LBN 0 --#define DRV_EV_DATA_WIDTH 64 -- --/* Buffer table configuration register */ --#define BUF_TBL_CFG_REG_KER 0x600 --#define BUF_TBL_MODE_LBN 3 --#define BUF_TBL_MODE_WIDTH 1 --#define BUF_TBL_MODE_HALF 0 --#define BUF_TBL_MODE_FULL 1 -- --/* SRAM receive descriptor cache configuration register */ --#define SRM_RX_DC_CFG_REG_KER 0x610 --#define SRM_RX_DC_BASE_ADR_LBN 0 --#define SRM_RX_DC_BASE_ADR_WIDTH 21 -- --/* SRAM transmit descriptor cache configuration register */ --#define SRM_TX_DC_CFG_REG_KER 0x620 --#define SRM_TX_DC_BASE_ADR_LBN 0 --#define SRM_TX_DC_BASE_ADR_WIDTH 21 -- --/* SRAM configuration register */ --#define SRM_CFG_REG_KER 0x630 --#define SRAM_OOB_BT_INIT_EN_LBN 3 --#define SRAM_OOB_BT_INIT_EN_WIDTH 1 --#define SRM_NUM_BANKS_AND_BANK_SIZE_LBN 0 --#define SRM_NUM_BANKS_AND_BANK_SIZE_WIDTH 3 --#define SRM_NB_BSZ_1BANKS_2M 0 --#define SRM_NB_BSZ_1BANKS_4M 1 --#define SRM_NB_BSZ_1BANKS_8M 2 --#define SRM_NB_BSZ_DEFAULT 3 /* char driver will set the default */ --#define SRM_NB_BSZ_2BANKS_4M 4 --#define SRM_NB_BSZ_2BANKS_8M 5 --#define SRM_NB_BSZ_2BANKS_16M 6 --#define SRM_NB_BSZ_RESERVED 7 -- --/* Special buffer table update register */ --#define BUF_TBL_UPD_REG_KER 0x0650 --#define BUF_UPD_CMD_LBN 63 --#define BUF_UPD_CMD_WIDTH 1 --#define BUF_CLR_CMD_LBN 62 --#define BUF_CLR_CMD_WIDTH 1 --#define BUF_CLR_END_ID_LBN 32 --#define BUF_CLR_END_ID_WIDTH 20 --#define BUF_CLR_START_ID_LBN 0 --#define BUF_CLR_START_ID_WIDTH 20 -- --/* Receive configuration register */ --#define RX_CFG_REG_KER 0x800 -- --/* B0 */ --#define RX_INGR_EN_B0_LBN 47 --#define RX_INGR_EN_B0_WIDTH 1 --#define RX_DESC_PUSH_EN_B0_LBN 43 --#define RX_DESC_PUSH_EN_B0_WIDTH 1 --#define RX_XON_TX_TH_B0_LBN 33 --#define RX_XON_TX_TH_B0_WIDTH 5 --#define RX_XOFF_TX_TH_B0_LBN 28 --#define RX_XOFF_TX_TH_B0_WIDTH 5 --#define RX_USR_BUF_SIZE_B0_LBN 19 --#define RX_USR_BUF_SIZE_B0_WIDTH 9 --#define RX_XON_MAC_TH_B0_LBN 10 --#define RX_XON_MAC_TH_B0_WIDTH 9 --#define RX_XOFF_MAC_TH_B0_LBN 1 --#define RX_XOFF_MAC_TH_B0_WIDTH 9 --#define RX_XOFF_MAC_EN_B0_LBN 0 --#define RX_XOFF_MAC_EN_B0_WIDTH 1 -- --/* A1 */ --#define RX_DESC_PUSH_EN_A1_LBN 35 --#define RX_DESC_PUSH_EN_A1_WIDTH 1 --#define RX_XON_TX_TH_A1_LBN 25 --#define RX_XON_TX_TH_A1_WIDTH 5 --#define RX_XOFF_TX_TH_A1_LBN 20 --#define RX_XOFF_TX_TH_A1_WIDTH 5 --#define RX_USR_BUF_SIZE_A1_LBN 11 --#define RX_USR_BUF_SIZE_A1_WIDTH 9 --#define RX_XON_MAC_TH_A1_LBN 6 --#define RX_XON_MAC_TH_A1_WIDTH 5 --#define RX_XOFF_MAC_TH_A1_LBN 1 --#define RX_XOFF_MAC_TH_A1_WIDTH 5 --#define RX_XOFF_MAC_EN_A1_LBN 0 --#define RX_XOFF_MAC_EN_A1_WIDTH 1 -- --/* Receive filter control register */ --#define RX_FILTER_CTL_REG 0x810 --#define UDP_FULL_SRCH_LIMIT_LBN 32 --#define UDP_FULL_SRCH_LIMIT_WIDTH 8 --#define NUM_KER_LBN 24 --#define NUM_KER_WIDTH 2 --#define UDP_WILD_SRCH_LIMIT_LBN 16 --#define UDP_WILD_SRCH_LIMIT_WIDTH 8 --#define TCP_WILD_SRCH_LIMIT_LBN 8 --#define TCP_WILD_SRCH_LIMIT_WIDTH 8 --#define TCP_FULL_SRCH_LIMIT_LBN 0 --#define TCP_FULL_SRCH_LIMIT_WIDTH 8 -- --/* RX queue flush register */ --#define RX_FLUSH_DESCQ_REG_KER 0x0820 --#define RX_FLUSH_DESCQ_CMD_LBN 24 --#define RX_FLUSH_DESCQ_CMD_WIDTH 1 --#define RX_FLUSH_DESCQ_LBN 0 --#define RX_FLUSH_DESCQ_WIDTH 12 -- --/* Receive descriptor update register */ --#define RX_DESC_UPD_REG_KER_DWORD (0x830 + 12) --#define RX_DESC_WPTR_DWORD_LBN 0 --#define RX_DESC_WPTR_DWORD_WIDTH 12 -- --/* Receive descriptor cache configuration register */ --#define RX_DC_CFG_REG_KER 0x840 --#define RX_DC_SIZE_LBN 0 --#define RX_DC_SIZE_WIDTH 2 -- --#define RX_DC_PF_WM_REG_KER 0x850 --#define RX_DC_PF_LWM_LBN 0 --#define RX_DC_PF_LWM_WIDTH 6 -- --/* RX no descriptor drop counter */ --#define RX_NODESC_DROP_REG_KER 0x880 --#define RX_NODESC_DROP_CNT_LBN 0 --#define RX_NODESC_DROP_CNT_WIDTH 16 -- --/* RX black magic register */ --#define RX_SELF_RST_REG_KER 0x890 --#define RX_ISCSI_DIS_LBN 17 --#define RX_ISCSI_DIS_WIDTH 1 --#define RX_NODESC_WAIT_DIS_LBN 9 --#define RX_NODESC_WAIT_DIS_WIDTH 1 --#define RX_RECOVERY_EN_LBN 8 --#define RX_RECOVERY_EN_WIDTH 1 -- --/* TX queue flush register */ --#define TX_FLUSH_DESCQ_REG_KER 0x0a00 --#define TX_FLUSH_DESCQ_CMD_LBN 12 --#define TX_FLUSH_DESCQ_CMD_WIDTH 1 --#define TX_FLUSH_DESCQ_LBN 0 --#define TX_FLUSH_DESCQ_WIDTH 12 -- --/* Transmit descriptor update register */ --#define TX_DESC_UPD_REG_KER_DWORD (0xa10 + 12) --#define TX_DESC_WPTR_DWORD_LBN 0 --#define TX_DESC_WPTR_DWORD_WIDTH 12 -- --/* Transmit descriptor cache configuration register */ --#define TX_DC_CFG_REG_KER 0xa20 --#define TX_DC_SIZE_LBN 0 --#define TX_DC_SIZE_WIDTH 2 -- --/* Transmit checksum configuration register (A0/A1 only) */ --#define TX_CHKSM_CFG_REG_KER_A1 0xa30 -- --/* Transmit configuration register */ --#define TX_CFG_REG_KER 0xa50 --#define TX_NO_EOP_DISC_EN_LBN 5 --#define TX_NO_EOP_DISC_EN_WIDTH 1 -- --/* Transmit configuration register 2 */ --#define TX_CFG2_REG_KER 0xa80 --#define TX_CSR_PUSH_EN_LBN 89 --#define TX_CSR_PUSH_EN_WIDTH 1 --#define TX_RX_SPACER_LBN 64 --#define TX_RX_SPACER_WIDTH 8 --#define TX_SW_EV_EN_LBN 59 --#define TX_SW_EV_EN_WIDTH 1 --#define TX_RX_SPACER_EN_LBN 57 --#define TX_RX_SPACER_EN_WIDTH 1 --#define TX_PREF_THRESHOLD_LBN 19 --#define TX_PREF_THRESHOLD_WIDTH 2 --#define TX_ONE_PKT_PER_Q_LBN 18 --#define TX_ONE_PKT_PER_Q_WIDTH 1 --#define TX_DIS_NON_IP_EV_LBN 17 --#define TX_DIS_NON_IP_EV_WIDTH 1 --#define TX_FLUSH_MIN_LEN_EN_B0_LBN 7 --#define TX_FLUSH_MIN_LEN_EN_B0_WIDTH 1 -- --/* PHY management transmit data register */ --#define MD_TXD_REG_KER 0xc00 --#define MD_TXD_LBN 0 --#define MD_TXD_WIDTH 16 -- --/* PHY management receive data register */ --#define MD_RXD_REG_KER 0xc10 --#define MD_RXD_LBN 0 --#define MD_RXD_WIDTH 16 -- --/* PHY management configuration & status register */ --#define MD_CS_REG_KER 0xc20 --#define MD_GC_LBN 4 --#define MD_GC_WIDTH 1 --#define MD_RIC_LBN 2 --#define MD_RIC_WIDTH 1 --#define MD_RDC_LBN 1 --#define MD_RDC_WIDTH 1 --#define MD_WRC_LBN 0 --#define MD_WRC_WIDTH 1 -- --/* PHY management PHY address register */ --#define MD_PHY_ADR_REG_KER 0xc30 --#define MD_PHY_ADR_LBN 0 --#define MD_PHY_ADR_WIDTH 16 -- --/* PHY management ID register */ --#define MD_ID_REG_KER 0xc40 --#define MD_PRT_ADR_LBN 11 --#define MD_PRT_ADR_WIDTH 5 --#define MD_DEV_ADR_LBN 6 --#define MD_DEV_ADR_WIDTH 5 -- --/* PHY management status & mask register (DWORD read only) */ --#define MD_STAT_REG_KER 0xc50 --#define MD_BSERR_LBN 2 --#define MD_BSERR_WIDTH 1 --#define MD_LNFL_LBN 1 --#define MD_LNFL_WIDTH 1 --#define MD_BSY_LBN 0 --#define MD_BSY_WIDTH 1 -- --/* Port 0 and 1 MAC stats registers */ --#define MAC0_STAT_DMA_REG_KER 0xc60 --#define MAC_STAT_DMA_CMD_LBN 48 --#define MAC_STAT_DMA_CMD_WIDTH 1 --#define MAC_STAT_DMA_ADR_LBN 0 --#define MAC_STAT_DMA_ADR_WIDTH EFX_DMA_TYPE_WIDTH(46) -- --/* Port 0 and 1 MAC control registers */ --#define MAC0_CTRL_REG_KER 0xc80 --#define MAC_XOFF_VAL_LBN 16 --#define MAC_XOFF_VAL_WIDTH 16 --#define TXFIFO_DRAIN_EN_B0_LBN 7 --#define TXFIFO_DRAIN_EN_B0_WIDTH 1 --#define MAC_BCAD_ACPT_LBN 4 --#define MAC_BCAD_ACPT_WIDTH 1 --#define MAC_UC_PROM_LBN 3 --#define MAC_UC_PROM_WIDTH 1 --#define MAC_LINK_STATUS_LBN 2 --#define MAC_LINK_STATUS_WIDTH 1 --#define MAC_SPEED_LBN 0 --#define MAC_SPEED_WIDTH 2 -- --/* 10G XAUI XGXS default values */ --#define XX_TXDRV_DEQ_DEFAULT 0xe /* deq=.6 */ --#define XX_TXDRV_DTX_DEFAULT 0x5 /* 1.25 */ --#define XX_SD_CTL_DRV_DEFAULT 0 /* 20mA */ -- --/* Multicast address hash table */ --#define MAC_MCAST_HASH_REG0_KER 0xca0 --#define MAC_MCAST_HASH_REG1_KER 0xcb0 -- --/* GMAC configuration register 1 */ --#define GM_CFG1_REG 0xe00 --#define GM_SW_RST_LBN 31 --#define GM_SW_RST_WIDTH 1 --#define GM_LOOP_LBN 8 --#define GM_LOOP_WIDTH 1 --#define GM_RX_FC_EN_LBN 5 --#define GM_RX_FC_EN_WIDTH 1 --#define GM_TX_FC_EN_LBN 4 --#define GM_TX_FC_EN_WIDTH 1 --#define GM_RX_EN_LBN 2 --#define GM_RX_EN_WIDTH 1 --#define GM_TX_EN_LBN 0 --#define GM_TX_EN_WIDTH 1 -- --/* GMAC configuration register 2 */ --#define GM_CFG2_REG 0xe10 --#define GM_PAMBL_LEN_LBN 12 --#define GM_PAMBL_LEN_WIDTH 4 --#define GM_IF_MODE_LBN 8 --#define GM_IF_MODE_WIDTH 2 --#define GM_LEN_CHK_LBN 4 --#define GM_LEN_CHK_WIDTH 1 --#define GM_PAD_CRC_EN_LBN 2 --#define GM_PAD_CRC_EN_WIDTH 1 --#define GM_FD_LBN 0 --#define GM_FD_WIDTH 1 -- --/* GMAC maximum frame length register */ --#define GM_MAX_FLEN_REG 0xe40 --#define GM_MAX_FLEN_LBN 0 --#define GM_MAX_FLEN_WIDTH 16 -- --/* GMAC station address register 1 */ --#define GM_ADR1_REG 0xf00 --#define GM_HWADDR_5_LBN 24 --#define GM_HWADDR_5_WIDTH 8 --#define GM_HWADDR_4_LBN 16 --#define GM_HWADDR_4_WIDTH 8 --#define GM_HWADDR_3_LBN 8 --#define GM_HWADDR_3_WIDTH 8 --#define GM_HWADDR_2_LBN 0 --#define GM_HWADDR_2_WIDTH 8 -- --/* GMAC station address register 2 */ --#define GM_ADR2_REG 0xf10 --#define GM_HWADDR_1_LBN 24 --#define GM_HWADDR_1_WIDTH 8 --#define GM_HWADDR_0_LBN 16 --#define GM_HWADDR_0_WIDTH 8 -- --/* GMAC FIFO configuration register 0 */ --#define GMF_CFG0_REG 0xf20 --#define GMF_FTFENREQ_LBN 12 --#define GMF_FTFENREQ_WIDTH 1 --#define GMF_STFENREQ_LBN 11 --#define GMF_STFENREQ_WIDTH 1 --#define GMF_FRFENREQ_LBN 10 --#define GMF_FRFENREQ_WIDTH 1 --#define GMF_SRFENREQ_LBN 9 --#define GMF_SRFENREQ_WIDTH 1 --#define GMF_WTMENREQ_LBN 8 --#define GMF_WTMENREQ_WIDTH 1 -- --/* GMAC FIFO configuration register 1 */ --#define GMF_CFG1_REG 0xf30 --#define GMF_CFGFRTH_LBN 16 --#define GMF_CFGFRTH_WIDTH 5 --#define GMF_CFGXOFFRTX_LBN 0 --#define GMF_CFGXOFFRTX_WIDTH 16 -- --/* GMAC FIFO configuration register 2 */ --#define GMF_CFG2_REG 0xf40 --#define GMF_CFGHWM_LBN 16 --#define GMF_CFGHWM_WIDTH 6 --#define GMF_CFGLWM_LBN 0 --#define GMF_CFGLWM_WIDTH 6 -- --/* GMAC FIFO configuration register 3 */ --#define GMF_CFG3_REG 0xf50 --#define GMF_CFGHWMFT_LBN 16 --#define GMF_CFGHWMFT_WIDTH 6 --#define GMF_CFGFTTH_LBN 0 --#define GMF_CFGFTTH_WIDTH 6 -- --/* GMAC FIFO configuration register 4 */ --#define GMF_CFG4_REG 0xf60 --#define GMF_HSTFLTRFRM_PAUSE_LBN 12 --#define GMF_HSTFLTRFRM_PAUSE_WIDTH 12 -- --/* GMAC FIFO configuration register 5 */ --#define GMF_CFG5_REG 0xf70 --#define GMF_CFGHDPLX_LBN 22 --#define GMF_CFGHDPLX_WIDTH 1 --#define GMF_CFGBYTMODE_LBN 19 --#define GMF_CFGBYTMODE_WIDTH 1 --#define GMF_HSTDRPLT64_LBN 18 --#define GMF_HSTDRPLT64_WIDTH 1 --#define GMF_HSTFLTRFRMDC_PAUSE_LBN 12 --#define GMF_HSTFLTRFRMDC_PAUSE_WIDTH 1 -- --/* XGMAC address register low */ --#define XM_ADR_LO_REG 0x1200 --#define XM_ADR_3_LBN 24 --#define XM_ADR_3_WIDTH 8 --#define XM_ADR_2_LBN 16 --#define XM_ADR_2_WIDTH 8 --#define XM_ADR_1_LBN 8 --#define XM_ADR_1_WIDTH 8 --#define XM_ADR_0_LBN 0 --#define XM_ADR_0_WIDTH 8 -- --/* XGMAC address register high */ --#define XM_ADR_HI_REG 0x1210 --#define XM_ADR_5_LBN 8 --#define XM_ADR_5_WIDTH 8 --#define XM_ADR_4_LBN 0 --#define XM_ADR_4_WIDTH 8 -- --/* XGMAC global configuration */ --#define XM_GLB_CFG_REG 0x1220 --#define XM_RX_STAT_EN_LBN 11 --#define XM_RX_STAT_EN_WIDTH 1 --#define XM_TX_STAT_EN_LBN 10 --#define XM_TX_STAT_EN_WIDTH 1 --#define XM_RX_JUMBO_MODE_LBN 6 --#define XM_RX_JUMBO_MODE_WIDTH 1 --#define XM_INTCLR_MODE_LBN 3 --#define XM_INTCLR_MODE_WIDTH 1 --#define XM_CORE_RST_LBN 0 --#define XM_CORE_RST_WIDTH 1 -- --/* XGMAC transmit configuration */ --#define XM_TX_CFG_REG 0x1230 --#define XM_IPG_LBN 16 --#define XM_IPG_WIDTH 4 --#define XM_FCNTL_LBN 10 --#define XM_FCNTL_WIDTH 1 --#define XM_TXCRC_LBN 8 --#define XM_TXCRC_WIDTH 1 --#define XM_AUTO_PAD_LBN 5 --#define XM_AUTO_PAD_WIDTH 1 --#define XM_TX_PRMBL_LBN 2 --#define XM_TX_PRMBL_WIDTH 1 --#define XM_TXEN_LBN 1 --#define XM_TXEN_WIDTH 1 -- --/* XGMAC receive configuration */ --#define XM_RX_CFG_REG 0x1240 --#define XM_PASS_CRC_ERR_LBN 25 --#define XM_PASS_CRC_ERR_WIDTH 1 --#define XM_ACPT_ALL_MCAST_LBN 11 --#define XM_ACPT_ALL_MCAST_WIDTH 1 --#define XM_ACPT_ALL_UCAST_LBN 9 --#define XM_ACPT_ALL_UCAST_WIDTH 1 --#define XM_AUTO_DEPAD_LBN 8 --#define XM_AUTO_DEPAD_WIDTH 1 --#define XM_RXEN_LBN 1 --#define XM_RXEN_WIDTH 1 -- --/* XGMAC management interrupt mask register */ --#define XM_MGT_INT_MSK_REG_B0 0x1250 --#define XM_MSK_PRMBLE_ERR_LBN 2 --#define XM_MSK_PRMBLE_ERR_WIDTH 1 --#define XM_MSK_RMTFLT_LBN 1 --#define XM_MSK_RMTFLT_WIDTH 1 --#define XM_MSK_LCLFLT_LBN 0 --#define XM_MSK_LCLFLT_WIDTH 1 -- --/* XGMAC flow control register */ --#define XM_FC_REG 0x1270 --#define XM_PAUSE_TIME_LBN 16 --#define XM_PAUSE_TIME_WIDTH 16 --#define XM_DIS_FCNTL_LBN 0 --#define XM_DIS_FCNTL_WIDTH 1 -- --/* XGMAC pause time count register */ --#define XM_PAUSE_TIME_REG 0x1290 -- --/* XGMAC transmit parameter register */ --#define XM_TX_PARAM_REG 0x012d0 --#define XM_TX_JUMBO_MODE_LBN 31 --#define XM_TX_JUMBO_MODE_WIDTH 1 --#define XM_MAX_TX_FRM_SIZE_LBN 16 --#define XM_MAX_TX_FRM_SIZE_WIDTH 14 -- --/* XGMAC receive parameter register */ --#define XM_RX_PARAM_REG 0x12e0 --#define XM_MAX_RX_FRM_SIZE_LBN 0 --#define XM_MAX_RX_FRM_SIZE_WIDTH 14 -- --/* XGMAC management interrupt status register */ --#define XM_MGT_INT_REG_B0 0x12f0 --#define XM_PRMBLE_ERR 2 --#define XM_PRMBLE_WIDTH 1 --#define XM_RMTFLT_LBN 1 --#define XM_RMTFLT_WIDTH 1 --#define XM_LCLFLT_LBN 0 --#define XM_LCLFLT_WIDTH 1 -- --/* XGXS/XAUI powerdown/reset register */ --#define XX_PWR_RST_REG 0x1300 -- --#define XX_SD_RST_ACT_LBN 16 --#define XX_SD_RST_ACT_WIDTH 1 --#define XX_PWRDND_EN_LBN 15 --#define XX_PWRDND_EN_WIDTH 1 --#define XX_PWRDNC_EN_LBN 14 --#define XX_PWRDNC_EN_WIDTH 1 --#define XX_PWRDNB_EN_LBN 13 --#define XX_PWRDNB_EN_WIDTH 1 --#define XX_PWRDNA_EN_LBN 12 --#define XX_PWRDNA_EN_WIDTH 1 --#define XX_RSTPLLCD_EN_LBN 9 --#define XX_RSTPLLCD_EN_WIDTH 1 --#define XX_RSTPLLAB_EN_LBN 8 --#define XX_RSTPLLAB_EN_WIDTH 1 --#define XX_RESETD_EN_LBN 7 --#define XX_RESETD_EN_WIDTH 1 --#define XX_RESETC_EN_LBN 6 --#define XX_RESETC_EN_WIDTH 1 --#define XX_RESETB_EN_LBN 5 --#define XX_RESETB_EN_WIDTH 1 --#define XX_RESETA_EN_LBN 4 --#define XX_RESETA_EN_WIDTH 1 --#define XX_RSTXGXSRX_EN_LBN 2 --#define XX_RSTXGXSRX_EN_WIDTH 1 --#define XX_RSTXGXSTX_EN_LBN 1 --#define XX_RSTXGXSTX_EN_WIDTH 1 --#define XX_RST_XX_EN_LBN 0 --#define XX_RST_XX_EN_WIDTH 1 -- --/* XGXS/XAUI powerdown/reset control register */ --#define XX_SD_CTL_REG 0x1310 --#define XX_HIDRVD_LBN 15 --#define XX_HIDRVD_WIDTH 1 --#define XX_LODRVD_LBN 14 --#define XX_LODRVD_WIDTH 1 --#define XX_HIDRVC_LBN 13 --#define XX_HIDRVC_WIDTH 1 --#define XX_LODRVC_LBN 12 --#define XX_LODRVC_WIDTH 1 --#define XX_HIDRVB_LBN 11 --#define XX_HIDRVB_WIDTH 1 --#define XX_LODRVB_LBN 10 --#define XX_LODRVB_WIDTH 1 --#define XX_HIDRVA_LBN 9 --#define XX_HIDRVA_WIDTH 1 --#define XX_LODRVA_LBN 8 --#define XX_LODRVA_WIDTH 1 --#define XX_LPBKD_LBN 3 --#define XX_LPBKD_WIDTH 1 --#define XX_LPBKC_LBN 2 --#define XX_LPBKC_WIDTH 1 --#define XX_LPBKB_LBN 1 --#define XX_LPBKB_WIDTH 1 --#define XX_LPBKA_LBN 0 --#define XX_LPBKA_WIDTH 1 -- --#define XX_TXDRV_CTL_REG 0x1320 --#define XX_DEQD_LBN 28 --#define XX_DEQD_WIDTH 4 --#define XX_DEQC_LBN 24 --#define XX_DEQC_WIDTH 4 --#define XX_DEQB_LBN 20 --#define XX_DEQB_WIDTH 4 --#define XX_DEQA_LBN 16 --#define XX_DEQA_WIDTH 4 --#define XX_DTXD_LBN 12 --#define XX_DTXD_WIDTH 4 --#define XX_DTXC_LBN 8 --#define XX_DTXC_WIDTH 4 --#define XX_DTXB_LBN 4 --#define XX_DTXB_WIDTH 4 --#define XX_DTXA_LBN 0 --#define XX_DTXA_WIDTH 4 -- --/* XAUI XGXS core status register */ --#define XX_CORE_STAT_REG 0x1360 --#define XX_FORCE_SIG_LBN 24 --#define XX_FORCE_SIG_WIDTH 8 --#define XX_FORCE_SIG_DECODE_FORCED 0xff --#define XX_XGXS_LB_EN_LBN 23 --#define XX_XGXS_LB_EN_WIDTH 1 --#define XX_XGMII_LB_EN_LBN 22 --#define XX_XGMII_LB_EN_WIDTH 1 --#define XX_ALIGN_DONE_LBN 20 --#define XX_ALIGN_DONE_WIDTH 1 --#define XX_SYNC_STAT_LBN 16 --#define XX_SYNC_STAT_WIDTH 4 --#define XX_SYNC_STAT_DECODE_SYNCED 0xf --#define XX_COMMA_DET_LBN 12 --#define XX_COMMA_DET_WIDTH 4 --#define XX_COMMA_DET_DECODE_DETECTED 0xf --#define XX_COMMA_DET_RESET 0xf --#define XX_CHARERR_LBN 4 --#define XX_CHARERR_WIDTH 4 --#define XX_CHARERR_RESET 0xf --#define XX_DISPERR_LBN 0 --#define XX_DISPERR_WIDTH 4 --#define XX_DISPERR_RESET 0xf -- --/* Receive filter table */ --#define RX_FILTER_TBL0 0xF00000 -- --/* Receive descriptor pointer table */ --#define RX_DESC_PTR_TBL_KER_A1 0x11800 --#define RX_DESC_PTR_TBL_KER_B0 0xF40000 --#define RX_DESC_PTR_TBL_KER_P0 0x900 --#define RX_ISCSI_DDIG_EN_LBN 88 --#define RX_ISCSI_DDIG_EN_WIDTH 1 --#define RX_ISCSI_HDIG_EN_LBN 87 --#define RX_ISCSI_HDIG_EN_WIDTH 1 --#define RX_DESCQ_BUF_BASE_ID_LBN 36 --#define RX_DESCQ_BUF_BASE_ID_WIDTH 20 --#define RX_DESCQ_EVQ_ID_LBN 24 --#define RX_DESCQ_EVQ_ID_WIDTH 12 --#define RX_DESCQ_OWNER_ID_LBN 10 --#define RX_DESCQ_OWNER_ID_WIDTH 14 --#define RX_DESCQ_LABEL_LBN 5 --#define RX_DESCQ_LABEL_WIDTH 5 --#define RX_DESCQ_SIZE_LBN 3 --#define RX_DESCQ_SIZE_WIDTH 2 --#define RX_DESCQ_SIZE_4K 3 --#define RX_DESCQ_SIZE_2K 2 --#define RX_DESCQ_SIZE_1K 1 --#define RX_DESCQ_SIZE_512 0 --#define RX_DESCQ_TYPE_LBN 2 --#define RX_DESCQ_TYPE_WIDTH 1 --#define RX_DESCQ_JUMBO_LBN 1 --#define RX_DESCQ_JUMBO_WIDTH 1 --#define RX_DESCQ_EN_LBN 0 --#define RX_DESCQ_EN_WIDTH 1 -- --/* Transmit descriptor pointer table */ --#define TX_DESC_PTR_TBL_KER_A1 0x11900 --#define TX_DESC_PTR_TBL_KER_B0 0xF50000 --#define TX_DESC_PTR_TBL_KER_P0 0xa40 --#define TX_NON_IP_DROP_DIS_B0_LBN 91 --#define TX_NON_IP_DROP_DIS_B0_WIDTH 1 --#define TX_IP_CHKSM_DIS_B0_LBN 90 --#define TX_IP_CHKSM_DIS_B0_WIDTH 1 --#define TX_TCP_CHKSM_DIS_B0_LBN 89 --#define TX_TCP_CHKSM_DIS_B0_WIDTH 1 --#define TX_DESCQ_EN_LBN 88 --#define TX_DESCQ_EN_WIDTH 1 --#define TX_ISCSI_DDIG_EN_LBN 87 --#define TX_ISCSI_DDIG_EN_WIDTH 1 --#define TX_ISCSI_HDIG_EN_LBN 86 --#define TX_ISCSI_HDIG_EN_WIDTH 1 --#define TX_DESCQ_BUF_BASE_ID_LBN 36 --#define TX_DESCQ_BUF_BASE_ID_WIDTH 20 --#define TX_DESCQ_EVQ_ID_LBN 24 --#define TX_DESCQ_EVQ_ID_WIDTH 12 --#define TX_DESCQ_OWNER_ID_LBN 10 --#define TX_DESCQ_OWNER_ID_WIDTH 14 --#define TX_DESCQ_LABEL_LBN 5 --#define TX_DESCQ_LABEL_WIDTH 5 --#define TX_DESCQ_SIZE_LBN 3 --#define TX_DESCQ_SIZE_WIDTH 2 --#define TX_DESCQ_SIZE_4K 3 --#define TX_DESCQ_SIZE_2K 2 --#define TX_DESCQ_SIZE_1K 1 --#define TX_DESCQ_SIZE_512 0 --#define TX_DESCQ_TYPE_LBN 1 --#define TX_DESCQ_TYPE_WIDTH 2 -- --/* Event queue pointer */ --#define EVQ_PTR_TBL_KER_A1 0x11a00 --#define EVQ_PTR_TBL_KER_B0 0xf60000 --#define EVQ_PTR_TBL_KER_P0 0x500 --#define EVQ_EN_LBN 23 --#define EVQ_EN_WIDTH 1 --#define EVQ_SIZE_LBN 20 --#define EVQ_SIZE_WIDTH 3 --#define EVQ_SIZE_32K 6 --#define EVQ_SIZE_16K 5 --#define EVQ_SIZE_8K 4 --#define EVQ_SIZE_4K 3 --#define EVQ_SIZE_2K 2 --#define EVQ_SIZE_1K 1 --#define EVQ_SIZE_512 0 --#define EVQ_BUF_BASE_ID_LBN 0 --#define EVQ_BUF_BASE_ID_WIDTH 20 -- --/* Event queue read pointer */ --#define EVQ_RPTR_REG_KER_A1 0x11b00 --#define EVQ_RPTR_REG_KER_B0 0xfa0000 --#define EVQ_RPTR_REG_KER_DWORD (EVQ_RPTR_REG_KER + 0) --#define EVQ_RPTR_DWORD_LBN 0 --#define EVQ_RPTR_DWORD_WIDTH 14 -- --/* RSS indirection table */ --#define RX_RSS_INDIR_TBL_B0 0xFB0000 --#define RX_RSS_INDIR_ENT_B0_LBN 0 --#define RX_RSS_INDIR_ENT_B0_WIDTH 6 -- --/* Special buffer descriptors (full-mode) */ --#define BUF_FULL_TBL_KER_A1 0x8000 --#define BUF_FULL_TBL_KER_B0 0x800000 --#define IP_DAT_BUF_SIZE_LBN 50 --#define IP_DAT_BUF_SIZE_WIDTH 1 --#define IP_DAT_BUF_SIZE_8K 1 --#define IP_DAT_BUF_SIZE_4K 0 --#define BUF_ADR_REGION_LBN 48 --#define BUF_ADR_REGION_WIDTH 2 --#define BUF_ADR_FBUF_LBN 14 --#define BUF_ADR_FBUF_WIDTH 34 --#define BUF_OWNER_ID_FBUF_LBN 0 --#define BUF_OWNER_ID_FBUF_WIDTH 14 -- --/* Transmit descriptor */ --#define TX_KER_PORT_LBN 63 --#define TX_KER_PORT_WIDTH 1 --#define TX_KER_CONT_LBN 62 --#define TX_KER_CONT_WIDTH 1 --#define TX_KER_BYTE_CNT_LBN 48 --#define TX_KER_BYTE_CNT_WIDTH 14 --#define TX_KER_BUF_REGION_LBN 46 --#define TX_KER_BUF_REGION_WIDTH 2 --#define TX_KER_BUF_REGION0_DECODE 0 --#define TX_KER_BUF_REGION1_DECODE 1 --#define TX_KER_BUF_REGION2_DECODE 2 --#define TX_KER_BUF_REGION3_DECODE 3 --#define TX_KER_BUF_ADR_LBN 0 --#define TX_KER_BUF_ADR_WIDTH EFX_DMA_TYPE_WIDTH(46) -- --/* Receive descriptor */ --#define RX_KER_BUF_SIZE_LBN 48 --#define RX_KER_BUF_SIZE_WIDTH 14 --#define RX_KER_BUF_REGION_LBN 46 --#define RX_KER_BUF_REGION_WIDTH 2 --#define RX_KER_BUF_REGION0_DECODE 0 --#define RX_KER_BUF_REGION1_DECODE 1 --#define RX_KER_BUF_REGION2_DECODE 2 --#define RX_KER_BUF_REGION3_DECODE 3 --#define RX_KER_BUF_ADR_LBN 0 --#define RX_KER_BUF_ADR_WIDTH EFX_DMA_TYPE_WIDTH(46) -- --/************************************************************************** -- * -- * Falcon events -- * -- ************************************************************************** -- */ -- --/* Event queue entries */ --#define EV_CODE_LBN 60 --#define EV_CODE_WIDTH 4 --#define RX_IP_EV_DECODE 0 --#define TX_IP_EV_DECODE 2 --#define DRIVER_EV_DECODE 5 --#define GLOBAL_EV_DECODE 6 --#define DRV_GEN_EV_DECODE 7 --#define WHOLE_EVENT_LBN 0 --#define WHOLE_EVENT_WIDTH 64 -- --/* Receive events */ --#define RX_EV_PKT_OK_LBN 56 --#define RX_EV_PKT_OK_WIDTH 1 --#define RX_EV_PAUSE_FRM_ERR_LBN 55 --#define RX_EV_PAUSE_FRM_ERR_WIDTH 1 --#define RX_EV_BUF_OWNER_ID_ERR_LBN 54 --#define RX_EV_BUF_OWNER_ID_ERR_WIDTH 1 --#define RX_EV_IF_FRAG_ERR_LBN 53 --#define RX_EV_IF_FRAG_ERR_WIDTH 1 --#define RX_EV_IP_HDR_CHKSUM_ERR_LBN 52 --#define RX_EV_IP_HDR_CHKSUM_ERR_WIDTH 1 --#define RX_EV_TCP_UDP_CHKSUM_ERR_LBN 51 --#define RX_EV_TCP_UDP_CHKSUM_ERR_WIDTH 1 --#define RX_EV_ETH_CRC_ERR_LBN 50 --#define RX_EV_ETH_CRC_ERR_WIDTH 1 --#define RX_EV_FRM_TRUNC_LBN 49 --#define RX_EV_FRM_TRUNC_WIDTH 1 --#define RX_EV_DRIB_NIB_LBN 48 --#define RX_EV_DRIB_NIB_WIDTH 1 --#define RX_EV_TOBE_DISC_LBN 47 --#define RX_EV_TOBE_DISC_WIDTH 1 --#define RX_EV_PKT_TYPE_LBN 44 --#define RX_EV_PKT_TYPE_WIDTH 3 --#define RX_EV_PKT_TYPE_ETH_DECODE 0 --#define RX_EV_PKT_TYPE_LLC_DECODE 1 --#define RX_EV_PKT_TYPE_JUMBO_DECODE 2 --#define RX_EV_PKT_TYPE_VLAN_DECODE 3 --#define RX_EV_PKT_TYPE_VLAN_LLC_DECODE 4 --#define RX_EV_PKT_TYPE_VLAN_JUMBO_DECODE 5 --#define RX_EV_HDR_TYPE_LBN 42 --#define RX_EV_HDR_TYPE_WIDTH 2 --#define RX_EV_HDR_TYPE_TCP_IPV4_DECODE 0 --#define RX_EV_HDR_TYPE_UDP_IPV4_DECODE 1 --#define RX_EV_HDR_TYPE_OTHER_IP_DECODE 2 --#define RX_EV_HDR_TYPE_NON_IP_DECODE 3 --#define RX_EV_HDR_TYPE_HAS_CHECKSUMS(hdr_type) \ -- ((hdr_type) <= RX_EV_HDR_TYPE_UDP_IPV4_DECODE) --#define RX_EV_MCAST_HASH_MATCH_LBN 40 --#define RX_EV_MCAST_HASH_MATCH_WIDTH 1 --#define RX_EV_MCAST_PKT_LBN 39 --#define RX_EV_MCAST_PKT_WIDTH 1 --#define RX_EV_Q_LABEL_LBN 32 --#define RX_EV_Q_LABEL_WIDTH 5 --#define RX_EV_JUMBO_CONT_LBN 31 --#define RX_EV_JUMBO_CONT_WIDTH 1 --#define RX_EV_BYTE_CNT_LBN 16 --#define RX_EV_BYTE_CNT_WIDTH 14 --#define RX_EV_SOP_LBN 15 --#define RX_EV_SOP_WIDTH 1 --#define RX_EV_DESC_PTR_LBN 0 --#define RX_EV_DESC_PTR_WIDTH 12 -- --/* Transmit events */ --#define TX_EV_PKT_ERR_LBN 38 --#define TX_EV_PKT_ERR_WIDTH 1 --#define TX_EV_Q_LABEL_LBN 32 --#define TX_EV_Q_LABEL_WIDTH 5 --#define TX_EV_WQ_FF_FULL_LBN 15 --#define TX_EV_WQ_FF_FULL_WIDTH 1 --#define TX_EV_COMP_LBN 12 --#define TX_EV_COMP_WIDTH 1 --#define TX_EV_DESC_PTR_LBN 0 --#define TX_EV_DESC_PTR_WIDTH 12 -- --/* Driver events */ --#define DRIVER_EV_SUB_CODE_LBN 56 --#define DRIVER_EV_SUB_CODE_WIDTH 4 --#define DRIVER_EV_SUB_DATA_LBN 0 --#define DRIVER_EV_SUB_DATA_WIDTH 14 --#define TX_DESCQ_FLS_DONE_EV_DECODE 0 --#define RX_DESCQ_FLS_DONE_EV_DECODE 1 --#define EVQ_INIT_DONE_EV_DECODE 2 --#define EVQ_NOT_EN_EV_DECODE 3 --#define RX_DESCQ_FLSFF_OVFL_EV_DECODE 4 --#define SRM_UPD_DONE_EV_DECODE 5 --#define WAKE_UP_EV_DECODE 6 --#define TX_PKT_NON_TCP_UDP_DECODE 9 --#define TIMER_EV_DECODE 10 --#define RX_RECOVERY_EV_DECODE 11 --#define RX_DSC_ERROR_EV_DECODE 14 --#define TX_DSC_ERROR_EV_DECODE 15 --#define DRIVER_EV_TX_DESCQ_ID_LBN 0 --#define DRIVER_EV_TX_DESCQ_ID_WIDTH 12 --#define DRIVER_EV_RX_FLUSH_FAIL_LBN 12 --#define DRIVER_EV_RX_FLUSH_FAIL_WIDTH 1 --#define DRIVER_EV_RX_DESCQ_ID_LBN 0 --#define DRIVER_EV_RX_DESCQ_ID_WIDTH 12 --#define SRM_CLR_EV_DECODE 0 --#define SRM_UPD_EV_DECODE 1 --#define SRM_ILLCLR_EV_DECODE 2 -- --/* Global events */ --#define RX_RECOVERY_B0_LBN 12 --#define RX_RECOVERY_B0_WIDTH 1 --#define XG_MNT_INTR_B0_LBN 11 --#define XG_MNT_INTR_B0_WIDTH 1 --#define RX_RECOVERY_A1_LBN 11 --#define RX_RECOVERY_A1_WIDTH 1 --#define XFP_PHY_INTR_LBN 10 --#define XFP_PHY_INTR_WIDTH 1 --#define XG_PHY_INTR_LBN 9 --#define XG_PHY_INTR_WIDTH 1 --#define G_PHY1_INTR_LBN 8 --#define G_PHY1_INTR_WIDTH 1 --#define G_PHY0_INTR_LBN 7 --#define G_PHY0_INTR_WIDTH 1 -- --/* Driver-generated test events */ --#define EVQ_MAGIC_LBN 0 --#define EVQ_MAGIC_WIDTH 32 -- --/************************************************************************** -- * -- * Falcon MAC stats -- * -- ************************************************************************** -- * -- */ -- --#define GRxGoodOct_offset 0x0 --#define GRxGoodOct_WIDTH 48 --#define GRxBadOct_offset 0x8 --#define GRxBadOct_WIDTH 48 --#define GRxMissPkt_offset 0x10 --#define GRxMissPkt_WIDTH 32 --#define GRxFalseCRS_offset 0x14 --#define GRxFalseCRS_WIDTH 32 --#define GRxPausePkt_offset 0x18 --#define GRxPausePkt_WIDTH 32 --#define GRxBadPkt_offset 0x1C --#define GRxBadPkt_WIDTH 32 --#define GRxUcastPkt_offset 0x20 --#define GRxUcastPkt_WIDTH 32 --#define GRxMcastPkt_offset 0x24 --#define GRxMcastPkt_WIDTH 32 --#define GRxBcastPkt_offset 0x28 --#define GRxBcastPkt_WIDTH 32 --#define GRxGoodLt64Pkt_offset 0x2C --#define GRxGoodLt64Pkt_WIDTH 32 --#define GRxBadLt64Pkt_offset 0x30 --#define GRxBadLt64Pkt_WIDTH 32 --#define GRx64Pkt_offset 0x34 --#define GRx64Pkt_WIDTH 32 --#define GRx65to127Pkt_offset 0x38 --#define GRx65to127Pkt_WIDTH 32 --#define GRx128to255Pkt_offset 0x3C --#define GRx128to255Pkt_WIDTH 32 --#define GRx256to511Pkt_offset 0x40 --#define GRx256to511Pkt_WIDTH 32 --#define GRx512to1023Pkt_offset 0x44 --#define GRx512to1023Pkt_WIDTH 32 --#define GRx1024to15xxPkt_offset 0x48 --#define GRx1024to15xxPkt_WIDTH 32 --#define GRx15xxtoJumboPkt_offset 0x4C --#define GRx15xxtoJumboPkt_WIDTH 32 --#define GRxGtJumboPkt_offset 0x50 --#define GRxGtJumboPkt_WIDTH 32 --#define GRxFcsErr64to15xxPkt_offset 0x54 --#define GRxFcsErr64to15xxPkt_WIDTH 32 --#define GRxFcsErr15xxtoJumboPkt_offset 0x58 --#define GRxFcsErr15xxtoJumboPkt_WIDTH 32 --#define GRxFcsErrGtJumboPkt_offset 0x5C --#define GRxFcsErrGtJumboPkt_WIDTH 32 --#define GTxGoodBadOct_offset 0x80 --#define GTxGoodBadOct_WIDTH 48 --#define GTxGoodOct_offset 0x88 --#define GTxGoodOct_WIDTH 48 --#define GTxSglColPkt_offset 0x90 --#define GTxSglColPkt_WIDTH 32 --#define GTxMultColPkt_offset 0x94 --#define GTxMultColPkt_WIDTH 32 --#define GTxExColPkt_offset 0x98 --#define GTxExColPkt_WIDTH 32 --#define GTxDefPkt_offset 0x9C --#define GTxDefPkt_WIDTH 32 --#define GTxLateCol_offset 0xA0 --#define GTxLateCol_WIDTH 32 --#define GTxExDefPkt_offset 0xA4 --#define GTxExDefPkt_WIDTH 32 --#define GTxPausePkt_offset 0xA8 --#define GTxPausePkt_WIDTH 32 --#define GTxBadPkt_offset 0xAC --#define GTxBadPkt_WIDTH 32 --#define GTxUcastPkt_offset 0xB0 --#define GTxUcastPkt_WIDTH 32 --#define GTxMcastPkt_offset 0xB4 --#define GTxMcastPkt_WIDTH 32 --#define GTxBcastPkt_offset 0xB8 --#define GTxBcastPkt_WIDTH 32 --#define GTxLt64Pkt_offset 0xBC --#define GTxLt64Pkt_WIDTH 32 --#define GTx64Pkt_offset 0xC0 --#define GTx64Pkt_WIDTH 32 --#define GTx65to127Pkt_offset 0xC4 --#define GTx65to127Pkt_WIDTH 32 --#define GTx128to255Pkt_offset 0xC8 --#define GTx128to255Pkt_WIDTH 32 --#define GTx256to511Pkt_offset 0xCC --#define GTx256to511Pkt_WIDTH 32 --#define GTx512to1023Pkt_offset 0xD0 --#define GTx512to1023Pkt_WIDTH 32 --#define GTx1024to15xxPkt_offset 0xD4 --#define GTx1024to15xxPkt_WIDTH 32 --#define GTx15xxtoJumboPkt_offset 0xD8 --#define GTx15xxtoJumboPkt_WIDTH 32 --#define GTxGtJumboPkt_offset 0xDC --#define GTxGtJumboPkt_WIDTH 32 --#define GTxNonTcpUdpPkt_offset 0xE0 --#define GTxNonTcpUdpPkt_WIDTH 16 --#define GTxMacSrcErrPkt_offset 0xE4 --#define GTxMacSrcErrPkt_WIDTH 16 --#define GTxIpSrcErrPkt_offset 0xE8 --#define GTxIpSrcErrPkt_WIDTH 16 --#define GDmaDone_offset 0xEC --#define GDmaDone_WIDTH 32 -- --#define XgRxOctets_offset 0x0 --#define XgRxOctets_WIDTH 48 --#define XgRxOctetsOK_offset 0x8 --#define XgRxOctetsOK_WIDTH 48 --#define XgRxPkts_offset 0x10 --#define XgRxPkts_WIDTH 32 --#define XgRxPktsOK_offset 0x14 --#define XgRxPktsOK_WIDTH 32 --#define XgRxBroadcastPkts_offset 0x18 --#define XgRxBroadcastPkts_WIDTH 32 --#define XgRxMulticastPkts_offset 0x1C --#define XgRxMulticastPkts_WIDTH 32 --#define XgRxUnicastPkts_offset 0x20 --#define XgRxUnicastPkts_WIDTH 32 --#define XgRxUndersizePkts_offset 0x24 --#define XgRxUndersizePkts_WIDTH 32 --#define XgRxOversizePkts_offset 0x28 --#define XgRxOversizePkts_WIDTH 32 --#define XgRxJabberPkts_offset 0x2C --#define XgRxJabberPkts_WIDTH 32 --#define XgRxUndersizeFCSerrorPkts_offset 0x30 --#define XgRxUndersizeFCSerrorPkts_WIDTH 32 --#define XgRxDropEvents_offset 0x34 --#define XgRxDropEvents_WIDTH 32 --#define XgRxFCSerrorPkts_offset 0x38 --#define XgRxFCSerrorPkts_WIDTH 32 --#define XgRxAlignError_offset 0x3C --#define XgRxAlignError_WIDTH 32 --#define XgRxSymbolError_offset 0x40 --#define XgRxSymbolError_WIDTH 32 --#define XgRxInternalMACError_offset 0x44 --#define XgRxInternalMACError_WIDTH 32 --#define XgRxControlPkts_offset 0x48 --#define XgRxControlPkts_WIDTH 32 --#define XgRxPausePkts_offset 0x4C --#define XgRxPausePkts_WIDTH 32 --#define XgRxPkts64Octets_offset 0x50 --#define XgRxPkts64Octets_WIDTH 32 --#define XgRxPkts65to127Octets_offset 0x54 --#define XgRxPkts65to127Octets_WIDTH 32 --#define XgRxPkts128to255Octets_offset 0x58 --#define XgRxPkts128to255Octets_WIDTH 32 --#define XgRxPkts256to511Octets_offset 0x5C --#define XgRxPkts256to511Octets_WIDTH 32 --#define XgRxPkts512to1023Octets_offset 0x60 --#define XgRxPkts512to1023Octets_WIDTH 32 --#define XgRxPkts1024to15xxOctets_offset 0x64 --#define XgRxPkts1024to15xxOctets_WIDTH 32 --#define XgRxPkts15xxtoMaxOctets_offset 0x68 --#define XgRxPkts15xxtoMaxOctets_WIDTH 32 --#define XgRxLengthError_offset 0x6C --#define XgRxLengthError_WIDTH 32 --#define XgTxPkts_offset 0x80 --#define XgTxPkts_WIDTH 32 --#define XgTxOctets_offset 0x88 --#define XgTxOctets_WIDTH 48 --#define XgTxMulticastPkts_offset 0x90 --#define XgTxMulticastPkts_WIDTH 32 --#define XgTxBroadcastPkts_offset 0x94 --#define XgTxBroadcastPkts_WIDTH 32 --#define XgTxUnicastPkts_offset 0x98 --#define XgTxUnicastPkts_WIDTH 32 --#define XgTxControlPkts_offset 0x9C --#define XgTxControlPkts_WIDTH 32 --#define XgTxPausePkts_offset 0xA0 --#define XgTxPausePkts_WIDTH 32 --#define XgTxPkts64Octets_offset 0xA4 --#define XgTxPkts64Octets_WIDTH 32 --#define XgTxPkts65to127Octets_offset 0xA8 --#define XgTxPkts65to127Octets_WIDTH 32 --#define XgTxPkts128to255Octets_offset 0xAC --#define XgTxPkts128to255Octets_WIDTH 32 --#define XgTxPkts256to511Octets_offset 0xB0 --#define XgTxPkts256to511Octets_WIDTH 32 --#define XgTxPkts512to1023Octets_offset 0xB4 --#define XgTxPkts512to1023Octets_WIDTH 32 --#define XgTxPkts1024to15xxOctets_offset 0xB8 --#define XgTxPkts1024to15xxOctets_WIDTH 32 --#define XgTxPkts1519toMaxOctets_offset 0xBC --#define XgTxPkts1519toMaxOctets_WIDTH 32 --#define XgTxUndersizePkts_offset 0xC0 --#define XgTxUndersizePkts_WIDTH 32 --#define XgTxOversizePkts_offset 0xC4 --#define XgTxOversizePkts_WIDTH 32 --#define XgTxNonTcpUdpPkt_offset 0xC8 --#define XgTxNonTcpUdpPkt_WIDTH 16 --#define XgTxMacSrcErrPkt_offset 0xCC --#define XgTxMacSrcErrPkt_WIDTH 16 --#define XgTxIpSrcErrPkt_offset 0xD0 --#define XgTxIpSrcErrPkt_WIDTH 16 --#define XgDmaDone_offset 0xD4 -- --#define FALCON_STATS_NOT_DONE 0x00000000 --#define FALCON_STATS_DONE 0xffffffff -- --/* Interrupt status register bits */ --#define FATAL_INT_LBN 64 --#define FATAL_INT_WIDTH 1 --#define INT_EVQS_LBN 40 --#define INT_EVQS_WIDTH 4 -- --/************************************************************************** -- * -- * Falcon non-volatile configuration -- * -- ************************************************************************** -- */ -- --/* Board configuration v2 (v1 is obsolete; later versions are compatible) */ --struct falcon_nvconfig_board_v2 { -- __le16 nports; -- u8 port0_phy_addr; -- u8 port0_phy_type; -- u8 port1_phy_addr; -- u8 port1_phy_type; -- __le16 asic_sub_revision; -- __le16 board_revision; --} __packed; -- --/* Board configuration v3 extra information */ --struct falcon_nvconfig_board_v3 { -- __le32 spi_device_type[2]; --} __packed; -- --/* Bit numbers for spi_device_type */ --#define SPI_DEV_TYPE_SIZE_LBN 0 --#define SPI_DEV_TYPE_SIZE_WIDTH 5 --#define SPI_DEV_TYPE_ADDR_LEN_LBN 6 --#define SPI_DEV_TYPE_ADDR_LEN_WIDTH 2 --#define SPI_DEV_TYPE_ERASE_CMD_LBN 8 --#define SPI_DEV_TYPE_ERASE_CMD_WIDTH 8 --#define SPI_DEV_TYPE_ERASE_SIZE_LBN 16 --#define SPI_DEV_TYPE_ERASE_SIZE_WIDTH 5 --#define SPI_DEV_TYPE_BLOCK_SIZE_LBN 24 --#define SPI_DEV_TYPE_BLOCK_SIZE_WIDTH 5 --#define SPI_DEV_TYPE_FIELD(type, field) \ -- (((type) >> EFX_LOW_BIT(field)) & EFX_MASK32(EFX_WIDTH(field))) -- --#define NVCONFIG_OFFSET 0x300 -- --#define NVCONFIG_BOARD_MAGIC_NUM 0xFA1C --struct falcon_nvconfig { -- efx_oword_t ee_vpd_cfg_reg; /* 0x300 */ -- u8 mac_address[2][8]; /* 0x310 */ -- efx_oword_t pcie_sd_ctl0123_reg; /* 0x320 */ -- efx_oword_t pcie_sd_ctl45_reg; /* 0x330 */ -- efx_oword_t pcie_pcs_ctl_stat_reg; /* 0x340 */ -- efx_oword_t hw_init_reg; /* 0x350 */ -- efx_oword_t nic_stat_reg; /* 0x360 */ -- efx_oword_t glb_ctl_reg; /* 0x370 */ -- efx_oword_t srm_cfg_reg; /* 0x380 */ -- efx_oword_t spare_reg; /* 0x390 */ -- __le16 board_magic_num; /* 0x3A0 */ -- __le16 board_struct_ver; -- __le16 board_checksum; -- struct falcon_nvconfig_board_v2 board_v2; -- efx_oword_t ee_base_page_reg; /* 0x3B0 */ -- struct falcon_nvconfig_board_v3 board_v3; --} __packed; -- --#endif /* EFX_FALCON_HWDEFS_H */ -diff --git a/drivers/net/sfc/falcon_io.h b/drivers/net/sfc/falcon_io.h -deleted file mode 100644 -index 8883092..0000000 ---- a/drivers/net/sfc/falcon_io.h -+++ /dev/null -@@ -1,258 +0,0 @@ --/**************************************************************************** -- * Driver for Solarflare Solarstorm network controllers and boards -- * Copyright 2005-2006 Fen Systems Ltd. -- * Copyright 2006-2008 Solarflare Communications Inc. -- * -- * This program is free software; you can redistribute it and/or modify it -- * under the terms of the GNU General Public License version 2 as published -- * by the Free Software Foundation, incorporated herein by reference. -- */ -- --#ifndef EFX_FALCON_IO_H --#define EFX_FALCON_IO_H -- --#include --#include -- --/************************************************************************** -- * -- * Falcon hardware access -- * -- ************************************************************************** -- * -- * Notes on locking strategy: -- * -- * Most Falcon registers require 16-byte (or 8-byte, for SRAM -- * registers) atomic writes which necessitates locking. -- * Under normal operation few writes to the Falcon BAR are made and these -- * registers (EVQ_RPTR_REG, RX_DESC_UPD_REG and TX_DESC_UPD_REG) are special -- * cased to allow 4-byte (hence lockless) accesses. -- * -- * It *is* safe to write to these 4-byte registers in the middle of an -- * access to an 8-byte or 16-byte register. We therefore use a -- * spinlock to protect accesses to the larger registers, but no locks -- * for the 4-byte registers. -- * -- * A write barrier is needed to ensure that DW3 is written after DW0/1/2 -- * due to the way the 16byte registers are "collected" in the Falcon BIU -- * -- * We also lock when carrying out reads, to ensure consistency of the -- * data (made possible since the BIU reads all 128 bits into a cache). -- * Reads are very rare, so this isn't a significant performance -- * impact. (Most data transferred from NIC to host is DMAed directly -- * into host memory). -- * -- * I/O BAR access uses locks for both reads and writes (but is only provided -- * for testing purposes). -- */ -- --/* Special buffer descriptors (Falcon SRAM) */ --#define BUF_TBL_KER_A1 0x18000 --#define BUF_TBL_KER_B0 0x800000 -- -- --#if BITS_PER_LONG == 64 --#define FALCON_USE_QWORD_IO 1 --#endif -- --#ifdef FALCON_USE_QWORD_IO --static inline void _falcon_writeq(struct efx_nic *efx, __le64 value, -- unsigned int reg) --{ -- __raw_writeq((__force u64)value, efx->membase + reg); --} --static inline __le64 _falcon_readq(struct efx_nic *efx, unsigned int reg) --{ -- return (__force __le64)__raw_readq(efx->membase + reg); --} --#endif -- --static inline void _falcon_writel(struct efx_nic *efx, __le32 value, -- unsigned int reg) --{ -- __raw_writel((__force u32)value, efx->membase + reg); --} --static inline __le32 _falcon_readl(struct efx_nic *efx, unsigned int reg) --{ -- return (__force __le32)__raw_readl(efx->membase + reg); --} -- --/* Writes to a normal 16-byte Falcon register, locking as appropriate. */ --static inline void falcon_write(struct efx_nic *efx, efx_oword_t *value, -- unsigned int reg) --{ -- unsigned long flags; -- -- EFX_REGDUMP(efx, "writing register %x with " EFX_OWORD_FMT "\n", reg, -- EFX_OWORD_VAL(*value)); -- -- spin_lock_irqsave(&efx->biu_lock, flags); --#ifdef FALCON_USE_QWORD_IO -- _falcon_writeq(efx, value->u64[0], reg + 0); -- wmb(); -- _falcon_writeq(efx, value->u64[1], reg + 8); --#else -- _falcon_writel(efx, value->u32[0], reg + 0); -- _falcon_writel(efx, value->u32[1], reg + 4); -- _falcon_writel(efx, value->u32[2], reg + 8); -- wmb(); -- _falcon_writel(efx, value->u32[3], reg + 12); --#endif -- mmiowb(); -- spin_unlock_irqrestore(&efx->biu_lock, flags); --} -- --/* Writes to an 8-byte Falcon SRAM register, locking as appropriate. */ --static inline void falcon_write_sram(struct efx_nic *efx, efx_qword_t *value, -- unsigned int index) --{ -- unsigned int reg = efx->type->buf_tbl_base + (index * sizeof(*value)); -- unsigned long flags; -- -- EFX_REGDUMP(efx, "writing SRAM register %x with " EFX_QWORD_FMT "\n", -- reg, EFX_QWORD_VAL(*value)); -- -- spin_lock_irqsave(&efx->biu_lock, flags); --#ifdef FALCON_USE_QWORD_IO -- _falcon_writeq(efx, value->u64[0], reg + 0); --#else -- _falcon_writel(efx, value->u32[0], reg + 0); -- wmb(); -- _falcon_writel(efx, value->u32[1], reg + 4); --#endif -- mmiowb(); -- spin_unlock_irqrestore(&efx->biu_lock, flags); --} -- --/* Write dword to Falcon register that allows partial writes -- * -- * Some Falcon registers (EVQ_RPTR_REG, RX_DESC_UPD_REG and -- * TX_DESC_UPD_REG) can be written to as a single dword. This allows -- * for lockless writes. -- */ --static inline void falcon_writel(struct efx_nic *efx, efx_dword_t *value, -- unsigned int reg) --{ -- EFX_REGDUMP(efx, "writing partial register %x with "EFX_DWORD_FMT"\n", -- reg, EFX_DWORD_VAL(*value)); -- -- /* No lock required */ -- _falcon_writel(efx, value->u32[0], reg); --} -- --/* Read from a Falcon register -- * -- * This reads an entire 16-byte Falcon register in one go, locking as -- * appropriate. It is essential to read the first dword first, as this -- * prompts Falcon to load the current value into the shadow register. -- */ --static inline void falcon_read(struct efx_nic *efx, efx_oword_t *value, -- unsigned int reg) --{ -- unsigned long flags; -- -- spin_lock_irqsave(&efx->biu_lock, flags); -- value->u32[0] = _falcon_readl(efx, reg + 0); -- rmb(); -- value->u32[1] = _falcon_readl(efx, reg + 4); -- value->u32[2] = _falcon_readl(efx, reg + 8); -- value->u32[3] = _falcon_readl(efx, reg + 12); -- spin_unlock_irqrestore(&efx->biu_lock, flags); -- -- EFX_REGDUMP(efx, "read from register %x, got " EFX_OWORD_FMT "\n", reg, -- EFX_OWORD_VAL(*value)); --} -- --/* This reads an 8-byte Falcon SRAM entry in one go. */ --static inline void falcon_read_sram(struct efx_nic *efx, efx_qword_t *value, -- unsigned int index) --{ -- unsigned int reg = efx->type->buf_tbl_base + (index * sizeof(*value)); -- unsigned long flags; -- -- spin_lock_irqsave(&efx->biu_lock, flags); --#ifdef FALCON_USE_QWORD_IO -- value->u64[0] = _falcon_readq(efx, reg + 0); --#else -- value->u32[0] = _falcon_readl(efx, reg + 0); -- rmb(); -- value->u32[1] = _falcon_readl(efx, reg + 4); --#endif -- spin_unlock_irqrestore(&efx->biu_lock, flags); -- -- EFX_REGDUMP(efx, "read from SRAM register %x, got "EFX_QWORD_FMT"\n", -- reg, EFX_QWORD_VAL(*value)); --} -- --/* Read dword from Falcon register that allows partial writes (sic) */ --static inline void falcon_readl(struct efx_nic *efx, efx_dword_t *value, -- unsigned int reg) --{ -- value->u32[0] = _falcon_readl(efx, reg); -- EFX_REGDUMP(efx, "read from register %x, got "EFX_DWORD_FMT"\n", -- reg, EFX_DWORD_VAL(*value)); --} -- --/* Write to a register forming part of a table */ --static inline void falcon_write_table(struct efx_nic *efx, efx_oword_t *value, -- unsigned int reg, unsigned int index) --{ -- falcon_write(efx, value, reg + index * sizeof(efx_oword_t)); --} -- --/* Read to a register forming part of a table */ --static inline void falcon_read_table(struct efx_nic *efx, efx_oword_t *value, -- unsigned int reg, unsigned int index) --{ -- falcon_read(efx, value, reg + index * sizeof(efx_oword_t)); --} -- --/* Write to a dword register forming part of a table */ --static inline void falcon_writel_table(struct efx_nic *efx, efx_dword_t *value, -- unsigned int reg, unsigned int index) --{ -- falcon_writel(efx, value, reg + index * sizeof(efx_oword_t)); --} -- --/* Page-mapped register block size */ --#define FALCON_PAGE_BLOCK_SIZE 0x2000 -- --/* Calculate offset to page-mapped register block */ --#define FALCON_PAGED_REG(page, reg) \ -- ((page) * FALCON_PAGE_BLOCK_SIZE + (reg)) -- --/* As for falcon_write(), but for a page-mapped register. */ --static inline void falcon_write_page(struct efx_nic *efx, efx_oword_t *value, -- unsigned int reg, unsigned int page) --{ -- falcon_write(efx, value, FALCON_PAGED_REG(page, reg)); --} -- --/* As for falcon_writel(), but for a page-mapped register. */ --static inline void falcon_writel_page(struct efx_nic *efx, efx_dword_t *value, -- unsigned int reg, unsigned int page) --{ -- falcon_writel(efx, value, FALCON_PAGED_REG(page, reg)); --} -- --/* Write dword to Falcon page-mapped register with an extra lock. -- * -- * As for falcon_writel_page(), but for a register that suffers from -- * SFC bug 3181. If writing to page 0, take out a lock so the BIU -- * collector cannot be confused. -- */ --static inline void falcon_writel_page_locked(struct efx_nic *efx, -- efx_dword_t *value, -- unsigned int reg, -- unsigned int page) --{ -- unsigned long flags = 0; -- -- if (page == 0) -- spin_lock_irqsave(&efx->biu_lock, flags); -- falcon_writel(efx, value, FALCON_PAGED_REG(page, reg)); -- if (page == 0) -- spin_unlock_irqrestore(&efx->biu_lock, flags); --} -- --#endif /* EFX_FALCON_IO_H */ -diff --git a/drivers/net/sfc/falcon_xmac.c b/drivers/net/sfc/falcon_xmac.c -index bec52ca..3da933f 100644 ---- a/drivers/net/sfc/falcon_xmac.c -+++ b/drivers/net/sfc/falcon_xmac.c -@@ -1,7 +1,7 @@ - /**************************************************************************** - * Driver for Solarflare Solarstorm network controllers and boards - * Copyright 2005-2006 Fen Systems Ltd. -- * Copyright 2006-2008 Solarflare Communications Inc. -+ * Copyright 2006-2009 Solarflare Communications Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published -@@ -11,13 +11,12 @@ - #include - #include "net_driver.h" - #include "efx.h" --#include "falcon.h" --#include "falcon_hwdefs.h" --#include "falcon_io.h" -+#include "nic.h" -+#include "regs.h" -+#include "io.h" - #include "mac.h" - #include "mdio_10g.h" - #include "phy.h" --#include "boards.h" - #include "workarounds.h" - - /************************************************************************** -@@ -36,43 +35,47 @@ static void falcon_setup_xaui(struct efx_nic *efx) - if (efx->phy_type == PHY_TYPE_NONE) - return; - -- falcon_read(efx, &sdctl, XX_SD_CTL_REG); -- EFX_SET_OWORD_FIELD(sdctl, XX_HIDRVD, XX_SD_CTL_DRV_DEFAULT); -- EFX_SET_OWORD_FIELD(sdctl, XX_LODRVD, XX_SD_CTL_DRV_DEFAULT); -- EFX_SET_OWORD_FIELD(sdctl, XX_HIDRVC, XX_SD_CTL_DRV_DEFAULT); -- EFX_SET_OWORD_FIELD(sdctl, XX_LODRVC, XX_SD_CTL_DRV_DEFAULT); -- EFX_SET_OWORD_FIELD(sdctl, XX_HIDRVB, XX_SD_CTL_DRV_DEFAULT); -- EFX_SET_OWORD_FIELD(sdctl, XX_LODRVB, XX_SD_CTL_DRV_DEFAULT); -- EFX_SET_OWORD_FIELD(sdctl, XX_HIDRVA, XX_SD_CTL_DRV_DEFAULT); -- EFX_SET_OWORD_FIELD(sdctl, XX_LODRVA, XX_SD_CTL_DRV_DEFAULT); -- falcon_write(efx, &sdctl, XX_SD_CTL_REG); -+ efx_reado(efx, &sdctl, FR_AB_XX_SD_CTL); -+ EFX_SET_OWORD_FIELD(sdctl, FRF_AB_XX_HIDRVD, FFE_AB_XX_SD_CTL_DRV_DEF); -+ EFX_SET_OWORD_FIELD(sdctl, FRF_AB_XX_LODRVD, FFE_AB_XX_SD_CTL_DRV_DEF); -+ EFX_SET_OWORD_FIELD(sdctl, FRF_AB_XX_HIDRVC, FFE_AB_XX_SD_CTL_DRV_DEF); -+ EFX_SET_OWORD_FIELD(sdctl, FRF_AB_XX_LODRVC, FFE_AB_XX_SD_CTL_DRV_DEF); -+ EFX_SET_OWORD_FIELD(sdctl, FRF_AB_XX_HIDRVB, FFE_AB_XX_SD_CTL_DRV_DEF); -+ EFX_SET_OWORD_FIELD(sdctl, FRF_AB_XX_LODRVB, FFE_AB_XX_SD_CTL_DRV_DEF); -+ EFX_SET_OWORD_FIELD(sdctl, FRF_AB_XX_HIDRVA, FFE_AB_XX_SD_CTL_DRV_DEF); -+ EFX_SET_OWORD_FIELD(sdctl, FRF_AB_XX_LODRVA, FFE_AB_XX_SD_CTL_DRV_DEF); -+ efx_writeo(efx, &sdctl, FR_AB_XX_SD_CTL); - - EFX_POPULATE_OWORD_8(txdrv, -- XX_DEQD, XX_TXDRV_DEQ_DEFAULT, -- XX_DEQC, XX_TXDRV_DEQ_DEFAULT, -- XX_DEQB, XX_TXDRV_DEQ_DEFAULT, -- XX_DEQA, XX_TXDRV_DEQ_DEFAULT, -- XX_DTXD, XX_TXDRV_DTX_DEFAULT, -- XX_DTXC, XX_TXDRV_DTX_DEFAULT, -- XX_DTXB, XX_TXDRV_DTX_DEFAULT, -- XX_DTXA, XX_TXDRV_DTX_DEFAULT); -- falcon_write(efx, &txdrv, XX_TXDRV_CTL_REG); -+ FRF_AB_XX_DEQD, FFE_AB_XX_TXDRV_DEQ_DEF, -+ FRF_AB_XX_DEQC, FFE_AB_XX_TXDRV_DEQ_DEF, -+ FRF_AB_XX_DEQB, FFE_AB_XX_TXDRV_DEQ_DEF, -+ FRF_AB_XX_DEQA, FFE_AB_XX_TXDRV_DEQ_DEF, -+ FRF_AB_XX_DTXD, FFE_AB_XX_TXDRV_DTX_DEF, -+ FRF_AB_XX_DTXC, FFE_AB_XX_TXDRV_DTX_DEF, -+ FRF_AB_XX_DTXB, FFE_AB_XX_TXDRV_DTX_DEF, -+ FRF_AB_XX_DTXA, FFE_AB_XX_TXDRV_DTX_DEF); -+ efx_writeo(efx, &txdrv, FR_AB_XX_TXDRV_CTL); - } - - int falcon_reset_xaui(struct efx_nic *efx) - { -+ struct falcon_nic_data *nic_data = efx->nic_data; - efx_oword_t reg; - int count; - -+ /* Don't fetch MAC statistics over an XMAC reset */ -+ WARN_ON(nic_data->stats_disable_count == 0); -+ - /* Start reset sequence */ -- EFX_POPULATE_DWORD_1(reg, XX_RST_XX_EN, 1); -- falcon_write(efx, ®, XX_PWR_RST_REG); -+ EFX_POPULATE_OWORD_1(reg, FRF_AB_XX_RST_XX_EN, 1); -+ efx_writeo(efx, ®, FR_AB_XX_PWR_RST); - - /* Wait up to 10 ms for completion, then reinitialise */ - for (count = 0; count < 1000; count++) { -- falcon_read(efx, ®, XX_PWR_RST_REG); -- if (EFX_OWORD_FIELD(reg, XX_RST_XX_EN) == 0 && -- EFX_OWORD_FIELD(reg, XX_SD_RST_ACT) == 0) { -+ efx_reado(efx, ®, FR_AB_XX_PWR_RST); -+ if (EFX_OWORD_FIELD(reg, FRF_AB_XX_RST_XX_EN) == 0 && -+ EFX_OWORD_FIELD(reg, FRF_AB_XX_SD_RST_ACT) == 0) { - falcon_setup_xaui(efx); - return 0; - } -@@ -86,30 +89,30 @@ static void falcon_mask_status_intr(struct efx_nic *efx, bool enable) - { - efx_oword_t reg; - -- if ((falcon_rev(efx) != FALCON_REV_B0) || LOOPBACK_INTERNAL(efx)) -+ if ((efx_nic_rev(efx) != EFX_REV_FALCON_B0) || LOOPBACK_INTERNAL(efx)) - return; - - /* We expect xgmii faults if the wireside link is up */ -- if (!EFX_WORKAROUND_5147(efx) || !efx->link_up) -+ if (!EFX_WORKAROUND_5147(efx) || !efx->link_state.up) - return; - - /* We can only use this interrupt to signal the negative edge of - * xaui_align [we have to poll the positive edge]. */ -- if (!efx->mac_up) -+ if (efx->xmac_poll_required) - return; - - /* Flush the ISR */ - if (enable) -- falcon_read(efx, ®, XM_MGT_INT_REG_B0); -+ efx_reado(efx, ®, FR_AB_XM_MGT_INT_MSK); - - EFX_POPULATE_OWORD_2(reg, -- XM_MSK_RMTFLT, !enable, -- XM_MSK_LCLFLT, !enable); -- falcon_write(efx, ®, XM_MGT_INT_MSK_REG_B0); -+ FRF_AB_XM_MSK_RMTFLT, !enable, -+ FRF_AB_XM_MSK_LCLFLT, !enable); -+ efx_writeo(efx, ®, FR_AB_XM_MGT_INT_MASK); - } - - /* Get status of XAUI link */ --bool falcon_xaui_link_ok(struct efx_nic *efx) -+static bool falcon_xaui_link_ok(struct efx_nic *efx) - { - efx_oword_t reg; - bool align_done, link_ok = false; -@@ -119,84 +122,79 @@ bool falcon_xaui_link_ok(struct efx_nic *efx) - return true; - - /* Read link status */ -- falcon_read(efx, ®, XX_CORE_STAT_REG); -+ efx_reado(efx, ®, FR_AB_XX_CORE_STAT); - -- align_done = EFX_OWORD_FIELD(reg, XX_ALIGN_DONE); -- sync_status = EFX_OWORD_FIELD(reg, XX_SYNC_STAT); -- if (align_done && (sync_status == XX_SYNC_STAT_DECODE_SYNCED)) -+ align_done = EFX_OWORD_FIELD(reg, FRF_AB_XX_ALIGN_DONE); -+ sync_status = EFX_OWORD_FIELD(reg, FRF_AB_XX_SYNC_STAT); -+ if (align_done && (sync_status == FFE_AB_XX_STAT_ALL_LANES)) - link_ok = true; - - /* Clear link status ready for next read */ -- EFX_SET_OWORD_FIELD(reg, XX_COMMA_DET, XX_COMMA_DET_RESET); -- EFX_SET_OWORD_FIELD(reg, XX_CHARERR, XX_CHARERR_RESET); -- EFX_SET_OWORD_FIELD(reg, XX_DISPERR, XX_DISPERR_RESET); -- falcon_write(efx, ®, XX_CORE_STAT_REG); -+ EFX_SET_OWORD_FIELD(reg, FRF_AB_XX_COMMA_DET, FFE_AB_XX_STAT_ALL_LANES); -+ EFX_SET_OWORD_FIELD(reg, FRF_AB_XX_CHAR_ERR, FFE_AB_XX_STAT_ALL_LANES); -+ EFX_SET_OWORD_FIELD(reg, FRF_AB_XX_DISPERR, FFE_AB_XX_STAT_ALL_LANES); -+ efx_writeo(efx, ®, FR_AB_XX_CORE_STAT); - - /* If the link is up, then check the phy side of the xaui link */ -- if (efx->link_up && link_ok) -- if (efx->phy_op->mmds & (1 << MDIO_MMD_PHYXS)) -+ if (efx->link_state.up && link_ok) -+ if (efx->mdio.mmds & (1 << MDIO_MMD_PHYXS)) - link_ok = efx_mdio_phyxgxs_lane_sync(efx); - - return link_ok; - } - --static void falcon_reconfigure_xmac_core(struct efx_nic *efx) -+void falcon_reconfigure_xmac_core(struct efx_nic *efx) - { - unsigned int max_frame_len; - efx_oword_t reg; -- bool rx_fc = !!(efx->link_fc & EFX_FC_RX); -+ bool rx_fc = !!(efx->link_state.fc & EFX_FC_RX); -+ bool tx_fc = !!(efx->link_state.fc & EFX_FC_TX); - - /* Configure MAC - cut-thru mode is hard wired on */ -- EFX_POPULATE_DWORD_3(reg, -- XM_RX_JUMBO_MODE, 1, -- XM_TX_STAT_EN, 1, -- XM_RX_STAT_EN, 1); -- falcon_write(efx, ®, XM_GLB_CFG_REG); -+ EFX_POPULATE_OWORD_3(reg, -+ FRF_AB_XM_RX_JUMBO_MODE, 1, -+ FRF_AB_XM_TX_STAT_EN, 1, -+ FRF_AB_XM_RX_STAT_EN, 1); -+ efx_writeo(efx, ®, FR_AB_XM_GLB_CFG); - - /* Configure TX */ -- EFX_POPULATE_DWORD_6(reg, -- XM_TXEN, 1, -- XM_TX_PRMBL, 1, -- XM_AUTO_PAD, 1, -- XM_TXCRC, 1, -- XM_FCNTL, 1, -- XM_IPG, 0x3); -- falcon_write(efx, ®, XM_TX_CFG_REG); -+ EFX_POPULATE_OWORD_6(reg, -+ FRF_AB_XM_TXEN, 1, -+ FRF_AB_XM_TX_PRMBL, 1, -+ FRF_AB_XM_AUTO_PAD, 1, -+ FRF_AB_XM_TXCRC, 1, -+ FRF_AB_XM_FCNTL, tx_fc, -+ FRF_AB_XM_IPG, 0x3); -+ efx_writeo(efx, ®, FR_AB_XM_TX_CFG); - - /* Configure RX */ -- EFX_POPULATE_DWORD_5(reg, -- XM_RXEN, 1, -- XM_AUTO_DEPAD, 0, -- XM_ACPT_ALL_MCAST, 1, -- XM_ACPT_ALL_UCAST, efx->promiscuous, -- XM_PASS_CRC_ERR, 1); -- falcon_write(efx, ®, XM_RX_CFG_REG); -+ EFX_POPULATE_OWORD_5(reg, -+ FRF_AB_XM_RXEN, 1, -+ FRF_AB_XM_AUTO_DEPAD, 0, -+ FRF_AB_XM_ACPT_ALL_MCAST, 1, -+ FRF_AB_XM_ACPT_ALL_UCAST, efx->promiscuous, -+ FRF_AB_XM_PASS_CRC_ERR, 1); -+ efx_writeo(efx, ®, FR_AB_XM_RX_CFG); - - /* Set frame length */ - max_frame_len = EFX_MAX_FRAME_LEN(efx->net_dev->mtu); -- EFX_POPULATE_DWORD_1(reg, XM_MAX_RX_FRM_SIZE, max_frame_len); -- falcon_write(efx, ®, XM_RX_PARAM_REG); -- EFX_POPULATE_DWORD_2(reg, -- XM_MAX_TX_FRM_SIZE, max_frame_len, -- XM_TX_JUMBO_MODE, 1); -- falcon_write(efx, ®, XM_TX_PARAM_REG); -- -- EFX_POPULATE_DWORD_2(reg, -- XM_PAUSE_TIME, 0xfffe, /* MAX PAUSE TIME */ -- XM_DIS_FCNTL, !rx_fc); -- falcon_write(efx, ®, XM_FC_REG); -+ EFX_POPULATE_OWORD_1(reg, FRF_AB_XM_MAX_RX_FRM_SIZE, max_frame_len); -+ efx_writeo(efx, ®, FR_AB_XM_RX_PARAM); -+ EFX_POPULATE_OWORD_2(reg, -+ FRF_AB_XM_MAX_TX_FRM_SIZE, max_frame_len, -+ FRF_AB_XM_TX_JUMBO_MODE, 1); -+ efx_writeo(efx, ®, FR_AB_XM_TX_PARAM); -+ -+ EFX_POPULATE_OWORD_2(reg, -+ FRF_AB_XM_PAUSE_TIME, 0xfffe, /* MAX PAUSE TIME */ -+ FRF_AB_XM_DIS_FCNTL, !rx_fc); -+ efx_writeo(efx, ®, FR_AB_XM_FC); - - /* Set MAC address */ -- EFX_POPULATE_DWORD_4(reg, -- XM_ADR_0, efx->net_dev->dev_addr[0], -- XM_ADR_1, efx->net_dev->dev_addr[1], -- XM_ADR_2, efx->net_dev->dev_addr[2], -- XM_ADR_3, efx->net_dev->dev_addr[3]); -- falcon_write(efx, ®, XM_ADR_LO_REG); -- EFX_POPULATE_DWORD_2(reg, -- XM_ADR_4, efx->net_dev->dev_addr[4], -- XM_ADR_5, efx->net_dev->dev_addr[5]); -- falcon_write(efx, ®, XM_ADR_HI_REG); -+ memcpy(®, &efx->net_dev->dev_addr[0], 4); -+ efx_writeo(efx, ®, FR_AB_XM_ADR_LO); -+ memcpy(®, &efx->net_dev->dev_addr[4], 2); -+ efx_writeo(efx, ®, FR_AB_XM_ADR_HI); - } - - static void falcon_reconfigure_xgxs_core(struct efx_nic *efx) -@@ -212,12 +210,13 @@ static void falcon_reconfigure_xgxs_core(struct efx_nic *efx) - bool old_xgmii_loopback, old_xgxs_loopback, old_xaui_loopback; - bool reset_xgxs; - -- falcon_read(efx, ®, XX_CORE_STAT_REG); -- old_xgxs_loopback = EFX_OWORD_FIELD(reg, XX_XGXS_LB_EN); -- old_xgmii_loopback = EFX_OWORD_FIELD(reg, XX_XGMII_LB_EN); -+ efx_reado(efx, ®, FR_AB_XX_CORE_STAT); -+ old_xgxs_loopback = EFX_OWORD_FIELD(reg, FRF_AB_XX_XGXS_LB_EN); -+ old_xgmii_loopback = -+ EFX_OWORD_FIELD(reg, FRF_AB_XX_XGMII_LB_EN); - -- falcon_read(efx, ®, XX_SD_CTL_REG); -- old_xaui_loopback = EFX_OWORD_FIELD(reg, XX_LPBKA); -+ efx_reado(efx, ®, FR_AB_XX_SD_CTL); -+ old_xaui_loopback = EFX_OWORD_FIELD(reg, FRF_AB_XX_LPBKA); - - /* The PHY driver may have turned XAUI off */ - reset_xgxs = ((xgxs_loopback != old_xgxs_loopback) || -@@ -228,45 +227,55 @@ static void falcon_reconfigure_xgxs_core(struct efx_nic *efx) - falcon_reset_xaui(efx); - } - -- falcon_read(efx, ®, XX_CORE_STAT_REG); -- EFX_SET_OWORD_FIELD(reg, XX_FORCE_SIG, -+ efx_reado(efx, ®, FR_AB_XX_CORE_STAT); -+ EFX_SET_OWORD_FIELD(reg, FRF_AB_XX_FORCE_SIG, - (xgxs_loopback || xaui_loopback) ? -- XX_FORCE_SIG_DECODE_FORCED : 0); -- EFX_SET_OWORD_FIELD(reg, XX_XGXS_LB_EN, xgxs_loopback); -- EFX_SET_OWORD_FIELD(reg, XX_XGMII_LB_EN, xgmii_loopback); -- falcon_write(efx, ®, XX_CORE_STAT_REG); -- -- falcon_read(efx, ®, XX_SD_CTL_REG); -- EFX_SET_OWORD_FIELD(reg, XX_LPBKD, xaui_loopback); -- EFX_SET_OWORD_FIELD(reg, XX_LPBKC, xaui_loopback); -- EFX_SET_OWORD_FIELD(reg, XX_LPBKB, xaui_loopback); -- EFX_SET_OWORD_FIELD(reg, XX_LPBKA, xaui_loopback); -- falcon_write(efx, ®, XX_SD_CTL_REG); -+ FFE_AB_XX_FORCE_SIG_ALL_LANES : 0); -+ EFX_SET_OWORD_FIELD(reg, FRF_AB_XX_XGXS_LB_EN, xgxs_loopback); -+ EFX_SET_OWORD_FIELD(reg, FRF_AB_XX_XGMII_LB_EN, xgmii_loopback); -+ efx_writeo(efx, ®, FR_AB_XX_CORE_STAT); -+ -+ efx_reado(efx, ®, FR_AB_XX_SD_CTL); -+ EFX_SET_OWORD_FIELD(reg, FRF_AB_XX_LPBKD, xaui_loopback); -+ EFX_SET_OWORD_FIELD(reg, FRF_AB_XX_LPBKC, xaui_loopback); -+ EFX_SET_OWORD_FIELD(reg, FRF_AB_XX_LPBKB, xaui_loopback); -+ EFX_SET_OWORD_FIELD(reg, FRF_AB_XX_LPBKA, xaui_loopback); -+ efx_writeo(efx, ®, FR_AB_XX_SD_CTL); - } - - --/* Try and bring the Falcon side of the Falcon-Phy XAUI link fails -- * to come back up. Bash it until it comes back up */ --static void falcon_check_xaui_link_up(struct efx_nic *efx, int tries) -+/* Try to bring up the Falcon side of the Falcon-Phy XAUI link */ -+static bool falcon_check_xaui_link_up(struct efx_nic *efx, int tries) - { -- efx->mac_up = falcon_xaui_link_ok(efx); -+ bool mac_up = falcon_xaui_link_ok(efx); - -- if ((efx->loopback_mode == LOOPBACK_NETWORK) || -+ if (LOOPBACK_MASK(efx) & LOOPBACKS_EXTERNAL(efx) & LOOPBACKS_WS || - efx_phy_mode_disabled(efx->phy_mode)) - /* XAUI link is expected to be down */ -- return; -+ return mac_up; - -- while (!efx->mac_up && tries) { -+ falcon_stop_nic_stats(efx); -+ -+ while (!mac_up && tries) { - EFX_LOG(efx, "bashing xaui\n"); - falcon_reset_xaui(efx); - udelay(200); - -- efx->mac_up = falcon_xaui_link_ok(efx); -+ mac_up = falcon_xaui_link_ok(efx); - --tries; - } -+ -+ falcon_start_nic_stats(efx); -+ -+ return mac_up; - } - --static void falcon_reconfigure_xmac(struct efx_nic *efx) -+static bool falcon_xmac_check_fault(struct efx_nic *efx) -+{ -+ return !falcon_check_xaui_link_up(efx, 5); -+} -+ -+static int falcon_reconfigure_xmac(struct efx_nic *efx) - { - falcon_mask_status_intr(efx, false); - -@@ -275,18 +284,15 @@ static void falcon_reconfigure_xmac(struct efx_nic *efx) - - falcon_reconfigure_mac_wrapper(efx); - -- falcon_check_xaui_link_up(efx, 5); -+ efx->xmac_poll_required = !falcon_check_xaui_link_up(efx, 5); - falcon_mask_status_intr(efx, true); -+ -+ return 0; - } - - static void falcon_update_stats_xmac(struct efx_nic *efx) - { - struct efx_mac_stats *mac_stats = &efx->mac_stats; -- int rc; -- -- rc = falcon_dma_stats(efx, XgDmaDone_offset); -- if (rc) -- return; - - /* Update MAC stats from DMAed values */ - FALCON_STAT(efx, XgRxOctets, rx_bytes); -@@ -344,35 +350,19 @@ static void falcon_update_stats_xmac(struct efx_nic *efx) - mac_stats->rx_control * 64); - } - --static void falcon_xmac_irq(struct efx_nic *efx) --{ -- /* The XGMII link has a transient fault, which indicates either: -- * - there's a transient xgmii fault -- * - falcon's end of the xaui link may need a kick -- * - the wire-side link may have gone down, but the lasi/poll() -- * hasn't noticed yet. -- * -- * We only want to even bother polling XAUI if we're confident it's -- * not (1) or (3). In both cases, the only reliable way to spot this -- * is to wait a bit. We do this here by forcing the mac link state -- * to down, and waiting for the mac poll to come round and check -- */ -- efx->mac_up = false; --} -- --static void falcon_poll_xmac(struct efx_nic *efx) -+void falcon_poll_xmac(struct efx_nic *efx) - { -- if (!EFX_WORKAROUND_5147(efx) || !efx->link_up || efx->mac_up) -+ if (!EFX_WORKAROUND_5147(efx) || !efx->link_state.up || -+ !efx->xmac_poll_required) - return; - - falcon_mask_status_intr(efx, false); -- falcon_check_xaui_link_up(efx, 1); -+ efx->xmac_poll_required = !falcon_check_xaui_link_up(efx, 1); - falcon_mask_status_intr(efx, true); - } - - struct efx_mac_operations falcon_xmac_operations = { - .reconfigure = falcon_reconfigure_xmac, - .update_stats = falcon_update_stats_xmac, -- .irq = falcon_xmac_irq, -- .poll = falcon_poll_xmac, -+ .check_fault = falcon_xmac_check_fault, - }; -diff --git a/drivers/net/sfc/gmii.h b/drivers/net/sfc/gmii.h -deleted file mode 100644 -index dfccaa7..0000000 ---- a/drivers/net/sfc/gmii.h -+++ /dev/null -@@ -1,60 +0,0 @@ --/**************************************************************************** -- * Driver for Solarflare Solarstorm network controllers and boards -- * Copyright 2005-2006 Fen Systems Ltd. -- * Copyright 2006-2008 Solarflare Communications Inc. -- * -- * This program is free software; you can redistribute it and/or modify it -- * under the terms of the GNU General Public License version 2 as published -- * by the Free Software Foundation, incorporated herein by reference. -- */ -- --#ifndef EFX_GMII_H --#define EFX_GMII_H -- --/* -- * GMII interface -- */ -- --#include -- --/* GMII registers, excluding registers already defined as MII -- * registers in mii.h -- */ --#define GMII_IER 0x12 /* Interrupt enable register */ --#define GMII_ISR 0x13 /* Interrupt status register */ -- --/* Interrupt enable register */ --#define IER_ANEG_ERR 0x8000 /* Bit 15 - autonegotiation error */ --#define IER_SPEED_CHG 0x4000 /* Bit 14 - speed changed */ --#define IER_DUPLEX_CHG 0x2000 /* Bit 13 - duplex changed */ --#define IER_PAGE_RCVD 0x1000 /* Bit 12 - page received */ --#define IER_ANEG_DONE 0x0800 /* Bit 11 - autonegotiation complete */ --#define IER_LINK_CHG 0x0400 /* Bit 10 - link status changed */ --#define IER_SYM_ERR 0x0200 /* Bit 9 - symbol error */ --#define IER_FALSE_CARRIER 0x0100 /* Bit 8 - false carrier */ --#define IER_FIFO_ERR 0x0080 /* Bit 7 - FIFO over/underflow */ --#define IER_MDIX_CHG 0x0040 /* Bit 6 - MDI crossover changed */ --#define IER_DOWNSHIFT 0x0020 /* Bit 5 - downshift */ --#define IER_ENERGY 0x0010 /* Bit 4 - energy detect */ --#define IER_DTE_POWER 0x0004 /* Bit 2 - DTE power detect */ --#define IER_POLARITY_CHG 0x0002 /* Bit 1 - polarity changed */ --#define IER_JABBER 0x0001 /* Bit 0 - jabber */ -- --/* Interrupt status register */ --#define ISR_ANEG_ERR 0x8000 /* Bit 15 - autonegotiation error */ --#define ISR_SPEED_CHG 0x4000 /* Bit 14 - speed changed */ --#define ISR_DUPLEX_CHG 0x2000 /* Bit 13 - duplex changed */ --#define ISR_PAGE_RCVD 0x1000 /* Bit 12 - page received */ --#define ISR_ANEG_DONE 0x0800 /* Bit 11 - autonegotiation complete */ --#define ISR_LINK_CHG 0x0400 /* Bit 10 - link status changed */ --#define ISR_SYM_ERR 0x0200 /* Bit 9 - symbol error */ --#define ISR_FALSE_CARRIER 0x0100 /* Bit 8 - false carrier */ --#define ISR_FIFO_ERR 0x0080 /* Bit 7 - FIFO over/underflow */ --#define ISR_MDIX_CHG 0x0040 /* Bit 6 - MDI crossover changed */ --#define ISR_DOWNSHIFT 0x0020 /* Bit 5 - downshift */ --#define ISR_ENERGY 0x0010 /* Bit 4 - energy detect */ --#define ISR_DTE_POWER 0x0004 /* Bit 2 - DTE power detect */ --#define ISR_POLARITY_CHG 0x0002 /* Bit 1 - polarity changed */ --#define ISR_JABBER 0x0001 /* Bit 0 - jabber */ -- --#endif /* EFX_GMII_H */ -diff --git a/drivers/net/sfc/io.h b/drivers/net/sfc/io.h -new file mode 100644 -index 0000000..b89177c ---- /dev/null -+++ b/drivers/net/sfc/io.h -@@ -0,0 +1,256 @@ -+/**************************************************************************** -+ * Driver for Solarflare Solarstorm network controllers and boards -+ * Copyright 2005-2006 Fen Systems Ltd. -+ * Copyright 2006-2009 Solarflare Communications Inc. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License version 2 as published -+ * by the Free Software Foundation, incorporated herein by reference. -+ */ -+ -+#ifndef EFX_IO_H -+#define EFX_IO_H -+ -+#include -+#include -+ -+/************************************************************************** -+ * -+ * NIC register I/O -+ * -+ ************************************************************************** -+ * -+ * Notes on locking strategy: -+ * -+ * Most NIC registers require 16-byte (or 8-byte, for SRAM) atomic writes -+ * which necessitates locking. -+ * Under normal operation few writes to NIC registers are made and these -+ * registers (EVQ_RPTR_REG, RX_DESC_UPD_REG and TX_DESC_UPD_REG) are special -+ * cased to allow 4-byte (hence lockless) accesses. -+ * -+ * It *is* safe to write to these 4-byte registers in the middle of an -+ * access to an 8-byte or 16-byte register. We therefore use a -+ * spinlock to protect accesses to the larger registers, but no locks -+ * for the 4-byte registers. -+ * -+ * A write barrier is needed to ensure that DW3 is written after DW0/1/2 -+ * due to the way the 16byte registers are "collected" in the BIU. -+ * -+ * We also lock when carrying out reads, to ensure consistency of the -+ * data (made possible since the BIU reads all 128 bits into a cache). -+ * Reads are very rare, so this isn't a significant performance -+ * impact. (Most data transferred from NIC to host is DMAed directly -+ * into host memory). -+ * -+ * I/O BAR access uses locks for both reads and writes (but is only provided -+ * for testing purposes). -+ */ -+ -+#if BITS_PER_LONG == 64 -+#define EFX_USE_QWORD_IO 1 -+#endif -+ -+#ifdef EFX_USE_QWORD_IO -+static inline void _efx_writeq(struct efx_nic *efx, __le64 value, -+ unsigned int reg) -+{ -+ __raw_writeq((__force u64)value, efx->membase + reg); -+} -+static inline __le64 _efx_readq(struct efx_nic *efx, unsigned int reg) -+{ -+ return (__force __le64)__raw_readq(efx->membase + reg); -+} -+#endif -+ -+static inline void _efx_writed(struct efx_nic *efx, __le32 value, -+ unsigned int reg) -+{ -+ __raw_writel((__force u32)value, efx->membase + reg); -+} -+static inline __le32 _efx_readd(struct efx_nic *efx, unsigned int reg) -+{ -+ return (__force __le32)__raw_readl(efx->membase + reg); -+} -+ -+/* Writes to a normal 16-byte Efx register, locking as appropriate. */ -+static inline void efx_writeo(struct efx_nic *efx, efx_oword_t *value, -+ unsigned int reg) -+{ -+ unsigned long flags __attribute__ ((unused)); -+ -+ EFX_REGDUMP(efx, "writing register %x with " EFX_OWORD_FMT "\n", reg, -+ EFX_OWORD_VAL(*value)); -+ -+ spin_lock_irqsave(&efx->biu_lock, flags); -+#ifdef EFX_USE_QWORD_IO -+ _efx_writeq(efx, value->u64[0], reg + 0); -+ wmb(); -+ _efx_writeq(efx, value->u64[1], reg + 8); -+#else -+ _efx_writed(efx, value->u32[0], reg + 0); -+ _efx_writed(efx, value->u32[1], reg + 4); -+ _efx_writed(efx, value->u32[2], reg + 8); -+ wmb(); -+ _efx_writed(efx, value->u32[3], reg + 12); -+#endif -+ mmiowb(); -+ spin_unlock_irqrestore(&efx->biu_lock, flags); -+} -+ -+/* Write an 8-byte NIC SRAM entry through the supplied mapping, -+ * locking as appropriate. */ -+static inline void efx_sram_writeq(struct efx_nic *efx, void __iomem *membase, -+ efx_qword_t *value, unsigned int index) -+{ -+ unsigned int addr = index * sizeof(*value); -+ unsigned long flags __attribute__ ((unused)); -+ -+ EFX_REGDUMP(efx, "writing SRAM address %x with " EFX_QWORD_FMT "\n", -+ addr, EFX_QWORD_VAL(*value)); -+ -+ spin_lock_irqsave(&efx->biu_lock, flags); -+#ifdef EFX_USE_QWORD_IO -+ __raw_writeq((__force u64)value->u64[0], membase + addr); -+#else -+ __raw_writel((__force u32)value->u32[0], membase + addr); -+ wmb(); -+ __raw_writel((__force u32)value->u32[1], membase + addr + 4); -+#endif -+ mmiowb(); -+ spin_unlock_irqrestore(&efx->biu_lock, flags); -+} -+ -+/* Write dword to NIC register that allows partial writes -+ * -+ * Some registers (EVQ_RPTR_REG, RX_DESC_UPD_REG and -+ * TX_DESC_UPD_REG) can be written to as a single dword. This allows -+ * for lockless writes. -+ */ -+static inline void efx_writed(struct efx_nic *efx, efx_dword_t *value, -+ unsigned int reg) -+{ -+ EFX_REGDUMP(efx, "writing partial register %x with "EFX_DWORD_FMT"\n", -+ reg, EFX_DWORD_VAL(*value)); -+ -+ /* No lock required */ -+ _efx_writed(efx, value->u32[0], reg); -+} -+ -+/* Read from a NIC register -+ * -+ * This reads an entire 16-byte register in one go, locking as -+ * appropriate. It is essential to read the first dword first, as this -+ * prompts the NIC to load the current value into the shadow register. -+ */ -+static inline void efx_reado(struct efx_nic *efx, efx_oword_t *value, -+ unsigned int reg) -+{ -+ unsigned long flags __attribute__ ((unused)); -+ -+ spin_lock_irqsave(&efx->biu_lock, flags); -+ value->u32[0] = _efx_readd(efx, reg + 0); -+ rmb(); -+ value->u32[1] = _efx_readd(efx, reg + 4); -+ value->u32[2] = _efx_readd(efx, reg + 8); -+ value->u32[3] = _efx_readd(efx, reg + 12); -+ spin_unlock_irqrestore(&efx->biu_lock, flags); -+ -+ EFX_REGDUMP(efx, "read from register %x, got " EFX_OWORD_FMT "\n", reg, -+ EFX_OWORD_VAL(*value)); -+} -+ -+/* Read an 8-byte SRAM entry through supplied mapping, -+ * locking as appropriate. */ -+static inline void efx_sram_readq(struct efx_nic *efx, void __iomem *membase, -+ efx_qword_t *value, unsigned int index) -+{ -+ unsigned int addr = index * sizeof(*value); -+ unsigned long flags __attribute__ ((unused)); -+ -+ spin_lock_irqsave(&efx->biu_lock, flags); -+#ifdef EFX_USE_QWORD_IO -+ value->u64[0] = (__force __le64)__raw_readq(membase + addr); -+#else -+ value->u32[0] = (__force __le32)__raw_readl(membase + addr); -+ rmb(); -+ value->u32[1] = (__force __le32)__raw_readl(membase + addr + 4); -+#endif -+ spin_unlock_irqrestore(&efx->biu_lock, flags); -+ -+ EFX_REGDUMP(efx, "read from SRAM address %x, got "EFX_QWORD_FMT"\n", -+ addr, EFX_QWORD_VAL(*value)); -+} -+ -+/* Read dword from register that allows partial writes (sic) */ -+static inline void efx_readd(struct efx_nic *efx, efx_dword_t *value, -+ unsigned int reg) -+{ -+ value->u32[0] = _efx_readd(efx, reg); -+ EFX_REGDUMP(efx, "read from register %x, got "EFX_DWORD_FMT"\n", -+ reg, EFX_DWORD_VAL(*value)); -+} -+ -+/* Write to a register forming part of a table */ -+static inline void efx_writeo_table(struct efx_nic *efx, efx_oword_t *value, -+ unsigned int reg, unsigned int index) -+{ -+ efx_writeo(efx, value, reg + index * sizeof(efx_oword_t)); -+} -+ -+/* Read to a register forming part of a table */ -+static inline void efx_reado_table(struct efx_nic *efx, efx_oword_t *value, -+ unsigned int reg, unsigned int index) -+{ -+ efx_reado(efx, value, reg + index * sizeof(efx_oword_t)); -+} -+ -+/* Write to a dword register forming part of a table */ -+static inline void efx_writed_table(struct efx_nic *efx, efx_dword_t *value, -+ unsigned int reg, unsigned int index) -+{ -+ efx_writed(efx, value, reg + index * sizeof(efx_oword_t)); -+} -+ -+/* Page-mapped register block size */ -+#define EFX_PAGE_BLOCK_SIZE 0x2000 -+ -+/* Calculate offset to page-mapped register block */ -+#define EFX_PAGED_REG(page, reg) \ -+ ((page) * EFX_PAGE_BLOCK_SIZE + (reg)) -+ -+/* As for efx_writeo(), but for a page-mapped register. */ -+static inline void efx_writeo_page(struct efx_nic *efx, efx_oword_t *value, -+ unsigned int reg, unsigned int page) -+{ -+ efx_writeo(efx, value, EFX_PAGED_REG(page, reg)); -+} -+ -+/* As for efx_writed(), but for a page-mapped register. */ -+static inline void efx_writed_page(struct efx_nic *efx, efx_dword_t *value, -+ unsigned int reg, unsigned int page) -+{ -+ efx_writed(efx, value, EFX_PAGED_REG(page, reg)); -+} -+ -+/* Write dword to page-mapped register with an extra lock. -+ * -+ * As for efx_writed_page(), but for a register that suffers from -+ * SFC bug 3181. Take out a lock so the BIU collector cannot be -+ * confused. */ -+static inline void efx_writed_page_locked(struct efx_nic *efx, -+ efx_dword_t *value, -+ unsigned int reg, -+ unsigned int page) -+{ -+ unsigned long flags __attribute__ ((unused)); -+ -+ if (page == 0) { -+ spin_lock_irqsave(&efx->biu_lock, flags); -+ efx_writed(efx, value, EFX_PAGED_REG(page, reg)); -+ spin_unlock_irqrestore(&efx->biu_lock, flags); -+ } else { -+ efx_writed(efx, value, EFX_PAGED_REG(page, reg)); -+ } -+} -+ -+#endif /* EFX_IO_H */ -diff --git a/drivers/net/sfc/mac.h b/drivers/net/sfc/mac.h -index 4e70742..f1aa5f3 100644 ---- a/drivers/net/sfc/mac.h -+++ b/drivers/net/sfc/mac.h -@@ -1,7 +1,7 @@ - /**************************************************************************** - * Driver for Solarflare Solarstorm network controllers and boards - * Copyright 2005-2006 Fen Systems Ltd. -- * Copyright 2006-2008 Solarflare Communications Inc. -+ * Copyright 2006-2009 Solarflare Communications Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published -@@ -15,5 +15,9 @@ - - extern struct efx_mac_operations falcon_gmac_operations; - extern struct efx_mac_operations falcon_xmac_operations; -+extern struct efx_mac_operations efx_mcdi_mac_operations; -+extern void falcon_reconfigure_xmac_core(struct efx_nic *efx); -+extern int efx_mcdi_mac_stats(struct efx_nic *efx, dma_addr_t dma_addr, -+ u32 dma_len, int enable, int clear); - - #endif -diff --git a/drivers/net/sfc/mcdi.c b/drivers/net/sfc/mcdi.c -new file mode 100644 -index 0000000..683353b ---- /dev/null -+++ b/drivers/net/sfc/mcdi.c -@@ -0,0 +1,1112 @@ -+/**************************************************************************** -+ * Driver for Solarflare Solarstorm network controllers and boards -+ * Copyright 2008-2009 Solarflare Communications Inc. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License version 2 as published -+ * by the Free Software Foundation, incorporated herein by reference. -+ */ -+ -+#include -+#include "net_driver.h" -+#include "nic.h" -+#include "io.h" -+#include "regs.h" -+#include "mcdi_pcol.h" -+#include "phy.h" -+ -+/************************************************************************** -+ * -+ * Management-Controller-to-Driver Interface -+ * -+ ************************************************************************** -+ */ -+ -+/* Software-defined structure to the shared-memory */ -+#define CMD_NOTIFY_PORT0 0 -+#define CMD_NOTIFY_PORT1 4 -+#define CMD_PDU_PORT0 0x008 -+#define CMD_PDU_PORT1 0x108 -+#define REBOOT_FLAG_PORT0 0x3f8 -+#define REBOOT_FLAG_PORT1 0x3fc -+ -+#define MCDI_RPC_TIMEOUT 10 /*seconds */ -+ -+#define MCDI_PDU(efx) \ -+ (efx_port_num(efx) ? CMD_PDU_PORT1 : CMD_PDU_PORT0) -+#define MCDI_DOORBELL(efx) \ -+ (efx_port_num(efx) ? CMD_NOTIFY_PORT1 : CMD_NOTIFY_PORT0) -+#define MCDI_REBOOT_FLAG(efx) \ -+ (efx_port_num(efx) ? REBOOT_FLAG_PORT1 : REBOOT_FLAG_PORT0) -+ -+#define SEQ_MASK \ -+ EFX_MASK32(EFX_WIDTH(MCDI_HEADER_SEQ)) -+ -+static inline struct efx_mcdi_iface *efx_mcdi(struct efx_nic *efx) -+{ -+ struct siena_nic_data *nic_data; -+ EFX_BUG_ON_PARANOID(efx_nic_rev(efx) < EFX_REV_SIENA_A0); -+ nic_data = efx->nic_data; -+ return &nic_data->mcdi; -+} -+ -+void efx_mcdi_init(struct efx_nic *efx) -+{ -+ struct efx_mcdi_iface *mcdi; -+ -+ if (efx_nic_rev(efx) < EFX_REV_SIENA_A0) -+ return; -+ -+ mcdi = efx_mcdi(efx); -+ init_waitqueue_head(&mcdi->wq); -+ spin_lock_init(&mcdi->iface_lock); -+ atomic_set(&mcdi->state, MCDI_STATE_QUIESCENT); -+ mcdi->mode = MCDI_MODE_POLL; -+ -+ (void) efx_mcdi_poll_reboot(efx); -+} -+ -+static void efx_mcdi_copyin(struct efx_nic *efx, unsigned cmd, -+ const u8 *inbuf, size_t inlen) -+{ -+ struct efx_mcdi_iface *mcdi = efx_mcdi(efx); -+ unsigned pdu = FR_CZ_MC_TREG_SMEM + MCDI_PDU(efx); -+ unsigned doorbell = FR_CZ_MC_TREG_SMEM + MCDI_DOORBELL(efx); -+ unsigned int i; -+ efx_dword_t hdr; -+ u32 xflags, seqno; -+ -+ BUG_ON(atomic_read(&mcdi->state) == MCDI_STATE_QUIESCENT); -+ BUG_ON(inlen & 3 || inlen >= 0x100); -+ -+ seqno = mcdi->seqno & SEQ_MASK; -+ xflags = 0; -+ if (mcdi->mode == MCDI_MODE_EVENTS) -+ xflags |= MCDI_HEADER_XFLAGS_EVREQ; -+ -+ EFX_POPULATE_DWORD_6(hdr, -+ MCDI_HEADER_RESPONSE, 0, -+ MCDI_HEADER_RESYNC, 1, -+ MCDI_HEADER_CODE, cmd, -+ MCDI_HEADER_DATALEN, inlen, -+ MCDI_HEADER_SEQ, seqno, -+ MCDI_HEADER_XFLAGS, xflags); -+ -+ efx_writed(efx, &hdr, pdu); -+ -+ for (i = 0; i < inlen; i += 4) -+ _efx_writed(efx, *((__le32 *)(inbuf + i)), pdu + 4 + i); -+ -+ /* Ensure the payload is written out before the header */ -+ wmb(); -+ -+ /* ring the doorbell with a distinctive value */ -+ _efx_writed(efx, (__force __le32) 0x45789abc, doorbell); -+} -+ -+static void efx_mcdi_copyout(struct efx_nic *efx, u8 *outbuf, size_t outlen) -+{ -+ struct efx_mcdi_iface *mcdi = efx_mcdi(efx); -+ unsigned int pdu = FR_CZ_MC_TREG_SMEM + MCDI_PDU(efx); -+ int i; -+ -+ BUG_ON(atomic_read(&mcdi->state) == MCDI_STATE_QUIESCENT); -+ BUG_ON(outlen & 3 || outlen >= 0x100); -+ -+ for (i = 0; i < outlen; i += 4) -+ *((__le32 *)(outbuf + i)) = _efx_readd(efx, pdu + 4 + i); -+} -+ -+static int efx_mcdi_poll(struct efx_nic *efx) -+{ -+ struct efx_mcdi_iface *mcdi = efx_mcdi(efx); -+ unsigned int time, finish; -+ unsigned int respseq, respcmd, error; -+ unsigned int pdu = FR_CZ_MC_TREG_SMEM + MCDI_PDU(efx); -+ unsigned int rc, spins; -+ efx_dword_t reg; -+ -+ /* Check for a reboot atomically with respect to efx_mcdi_copyout() */ -+ rc = efx_mcdi_poll_reboot(efx); -+ if (rc) -+ goto out; -+ -+ /* Poll for completion. Poll quickly (once a us) for the 1st jiffy, -+ * because generally mcdi responses are fast. After that, back off -+ * and poll once a jiffy (approximately) -+ */ -+ spins = TICK_USEC; -+ finish = get_seconds() + MCDI_RPC_TIMEOUT; -+ -+ while (1) { -+ if (spins != 0) { -+ --spins; -+ udelay(1); -+ } else -+ schedule(); -+ -+ time = get_seconds(); -+ -+ rmb(); -+ efx_readd(efx, ®, pdu); -+ -+ /* All 1's indicates that shared memory is in reset (and is -+ * not a valid header). Wait for it to come out reset before -+ * completing the command */ -+ if (EFX_DWORD_FIELD(reg, EFX_DWORD_0) != 0xffffffff && -+ EFX_DWORD_FIELD(reg, MCDI_HEADER_RESPONSE)) -+ break; -+ -+ if (time >= finish) -+ return -ETIMEDOUT; -+ } -+ -+ mcdi->resplen = EFX_DWORD_FIELD(reg, MCDI_HEADER_DATALEN); -+ respseq = EFX_DWORD_FIELD(reg, MCDI_HEADER_SEQ); -+ respcmd = EFX_DWORD_FIELD(reg, MCDI_HEADER_CODE); -+ error = EFX_DWORD_FIELD(reg, MCDI_HEADER_ERROR); -+ -+ if (error && mcdi->resplen == 0) { -+ EFX_ERR(efx, "MC rebooted\n"); -+ rc = EIO; -+ } else if ((respseq ^ mcdi->seqno) & SEQ_MASK) { -+ EFX_ERR(efx, "MC response mismatch tx seq 0x%x rx seq 0x%x\n", -+ respseq, mcdi->seqno); -+ rc = EIO; -+ } else if (error) { -+ efx_readd(efx, ®, pdu + 4); -+ switch (EFX_DWORD_FIELD(reg, EFX_DWORD_0)) { -+#define TRANSLATE_ERROR(name) \ -+ case MC_CMD_ERR_ ## name: \ -+ rc = name; \ -+ break -+ TRANSLATE_ERROR(ENOENT); -+ TRANSLATE_ERROR(EINTR); -+ TRANSLATE_ERROR(EACCES); -+ TRANSLATE_ERROR(EBUSY); -+ TRANSLATE_ERROR(EINVAL); -+ TRANSLATE_ERROR(EDEADLK); -+ TRANSLATE_ERROR(ENOSYS); -+ TRANSLATE_ERROR(ETIME); -+#undef TRANSLATE_ERROR -+ default: -+ rc = EIO; -+ break; -+ } -+ } else -+ rc = 0; -+ -+out: -+ mcdi->resprc = rc; -+ if (rc) -+ mcdi->resplen = 0; -+ -+ /* Return rc=0 like wait_event_timeout() */ -+ return 0; -+} -+ -+/* Test and clear MC-rebooted flag for this port/function */ -+int efx_mcdi_poll_reboot(struct efx_nic *efx) -+{ -+ unsigned int addr = FR_CZ_MC_TREG_SMEM + MCDI_REBOOT_FLAG(efx); -+ efx_dword_t reg; -+ uint32_t value; -+ -+ if (efx_nic_rev(efx) < EFX_REV_SIENA_A0) -+ return false; -+ -+ efx_readd(efx, ®, addr); -+ value = EFX_DWORD_FIELD(reg, EFX_DWORD_0); -+ -+ if (value == 0) -+ return 0; -+ -+ EFX_ZERO_DWORD(reg); -+ efx_writed(efx, ®, addr); -+ -+ if (value == MC_STATUS_DWORD_ASSERT) -+ return -EINTR; -+ else -+ return -EIO; -+} -+ -+static void efx_mcdi_acquire(struct efx_mcdi_iface *mcdi) -+{ -+ /* Wait until the interface becomes QUIESCENT and we win the race -+ * to mark it RUNNING. */ -+ wait_event(mcdi->wq, -+ atomic_cmpxchg(&mcdi->state, -+ MCDI_STATE_QUIESCENT, -+ MCDI_STATE_RUNNING) -+ == MCDI_STATE_QUIESCENT); -+} -+ -+static int efx_mcdi_await_completion(struct efx_nic *efx) -+{ -+ struct efx_mcdi_iface *mcdi = efx_mcdi(efx); -+ -+ if (wait_event_timeout( -+ mcdi->wq, -+ atomic_read(&mcdi->state) == MCDI_STATE_COMPLETED, -+ msecs_to_jiffies(MCDI_RPC_TIMEOUT * 1000)) == 0) -+ return -ETIMEDOUT; -+ -+ /* Check if efx_mcdi_set_mode() switched us back to polled completions. -+ * In which case, poll for completions directly. If efx_mcdi_ev_cpl() -+ * completed the request first, then we'll just end up completing the -+ * request again, which is safe. -+ * -+ * We need an smp_rmb() to synchronise with efx_mcdi_mode_poll(), which -+ * wait_event_timeout() implicitly provides. -+ */ -+ if (mcdi->mode == MCDI_MODE_POLL) -+ return efx_mcdi_poll(efx); -+ -+ return 0; -+} -+ -+static bool efx_mcdi_complete(struct efx_mcdi_iface *mcdi) -+{ -+ /* If the interface is RUNNING, then move to COMPLETED and wake any -+ * waiters. If the interface isn't in RUNNING then we've received a -+ * duplicate completion after we've already transitioned back to -+ * QUIESCENT. [A subsequent invocation would increment seqno, so would -+ * have failed the seqno check]. -+ */ -+ if (atomic_cmpxchg(&mcdi->state, -+ MCDI_STATE_RUNNING, -+ MCDI_STATE_COMPLETED) == MCDI_STATE_RUNNING) { -+ wake_up(&mcdi->wq); -+ return true; -+ } -+ -+ return false; -+} -+ -+static void efx_mcdi_release(struct efx_mcdi_iface *mcdi) -+{ -+ atomic_set(&mcdi->state, MCDI_STATE_QUIESCENT); -+ wake_up(&mcdi->wq); -+} -+ -+static void efx_mcdi_ev_cpl(struct efx_nic *efx, unsigned int seqno, -+ unsigned int datalen, unsigned int errno) -+{ -+ struct efx_mcdi_iface *mcdi = efx_mcdi(efx); -+ bool wake = false; -+ -+ spin_lock(&mcdi->iface_lock); -+ -+ if ((seqno ^ mcdi->seqno) & SEQ_MASK) { -+ if (mcdi->credits) -+ /* The request has been cancelled */ -+ --mcdi->credits; -+ else -+ EFX_ERR(efx, "MC response mismatch tx seq 0x%x rx " -+ "seq 0x%x\n", seqno, mcdi->seqno); -+ } else { -+ mcdi->resprc = errno; -+ mcdi->resplen = datalen; -+ -+ wake = true; -+ } -+ -+ spin_unlock(&mcdi->iface_lock); -+ -+ if (wake) -+ efx_mcdi_complete(mcdi); -+} -+ -+/* Issue the given command by writing the data into the shared memory PDU, -+ * ring the doorbell and wait for completion. Copyout the result. */ -+int efx_mcdi_rpc(struct efx_nic *efx, unsigned cmd, -+ const u8 *inbuf, size_t inlen, u8 *outbuf, size_t outlen, -+ size_t *outlen_actual) -+{ -+ struct efx_mcdi_iface *mcdi = efx_mcdi(efx); -+ int rc; -+ BUG_ON(efx_nic_rev(efx) < EFX_REV_SIENA_A0); -+ -+ efx_mcdi_acquire(mcdi); -+ -+ /* Serialise with efx_mcdi_ev_cpl() and efx_mcdi_ev_death() */ -+ spin_lock_bh(&mcdi->iface_lock); -+ ++mcdi->seqno; -+ spin_unlock_bh(&mcdi->iface_lock); -+ -+ efx_mcdi_copyin(efx, cmd, inbuf, inlen); -+ -+ if (mcdi->mode == MCDI_MODE_POLL) -+ rc = efx_mcdi_poll(efx); -+ else -+ rc = efx_mcdi_await_completion(efx); -+ -+ if (rc != 0) { -+ /* Close the race with efx_mcdi_ev_cpl() executing just too late -+ * and completing a request we've just cancelled, by ensuring -+ * that the seqno check therein fails. -+ */ -+ spin_lock_bh(&mcdi->iface_lock); -+ ++mcdi->seqno; -+ ++mcdi->credits; -+ spin_unlock_bh(&mcdi->iface_lock); -+ -+ EFX_ERR(efx, "MC command 0x%x inlen %d mode %d timed out\n", -+ cmd, (int)inlen, mcdi->mode); -+ } else { -+ size_t resplen; -+ -+ /* At the very least we need a memory barrier here to ensure -+ * we pick up changes from efx_mcdi_ev_cpl(). Protect against -+ * a spurious efx_mcdi_ev_cpl() running concurrently by -+ * acquiring the iface_lock. */ -+ spin_lock_bh(&mcdi->iface_lock); -+ rc = -mcdi->resprc; -+ resplen = mcdi->resplen; -+ spin_unlock_bh(&mcdi->iface_lock); -+ -+ if (rc == 0) { -+ efx_mcdi_copyout(efx, outbuf, -+ min(outlen, mcdi->resplen + 3) & ~0x3); -+ if (outlen_actual != NULL) -+ *outlen_actual = resplen; -+ } else if (cmd == MC_CMD_REBOOT && rc == -EIO) -+ ; /* Don't reset if MC_CMD_REBOOT returns EIO */ -+ else if (rc == -EIO || rc == -EINTR) { -+ EFX_ERR(efx, "MC fatal error %d\n", -rc); -+ efx_schedule_reset(efx, RESET_TYPE_MC_FAILURE); -+ } else -+ EFX_ERR(efx, "MC command 0x%x inlen %d failed rc=%d\n", -+ cmd, (int)inlen, -rc); -+ } -+ -+ efx_mcdi_release(mcdi); -+ return rc; -+} -+ -+void efx_mcdi_mode_poll(struct efx_nic *efx) -+{ -+ struct efx_mcdi_iface *mcdi; -+ -+ if (efx_nic_rev(efx) < EFX_REV_SIENA_A0) -+ return; -+ -+ mcdi = efx_mcdi(efx); -+ if (mcdi->mode == MCDI_MODE_POLL) -+ return; -+ -+ /* We can switch from event completion to polled completion, because -+ * mcdi requests are always completed in shared memory. We do this by -+ * switching the mode to POLL'd then completing the request. -+ * efx_mcdi_await_completion() will then call efx_mcdi_poll(). -+ * -+ * We need an smp_wmb() to synchronise with efx_mcdi_await_completion(), -+ * which efx_mcdi_complete() provides for us. -+ */ -+ mcdi->mode = MCDI_MODE_POLL; -+ -+ efx_mcdi_complete(mcdi); -+} -+ -+void efx_mcdi_mode_event(struct efx_nic *efx) -+{ -+ struct efx_mcdi_iface *mcdi; -+ -+ if (efx_nic_rev(efx) < EFX_REV_SIENA_A0) -+ return; -+ -+ mcdi = efx_mcdi(efx); -+ -+ if (mcdi->mode == MCDI_MODE_EVENTS) -+ return; -+ -+ /* We can't switch from polled to event completion in the middle of a -+ * request, because the completion method is specified in the request. -+ * So acquire the interface to serialise the requestors. We don't need -+ * to acquire the iface_lock to change the mode here, but we do need a -+ * write memory barrier ensure that efx_mcdi_rpc() sees it, which -+ * efx_mcdi_acquire() provides. -+ */ -+ efx_mcdi_acquire(mcdi); -+ mcdi->mode = MCDI_MODE_EVENTS; -+ efx_mcdi_release(mcdi); -+} -+ -+static void efx_mcdi_ev_death(struct efx_nic *efx, int rc) -+{ -+ struct efx_mcdi_iface *mcdi = efx_mcdi(efx); -+ -+ /* If there is an outstanding MCDI request, it has been terminated -+ * either by a BADASSERT or REBOOT event. If the mcdi interface is -+ * in polled mode, then do nothing because the MC reboot handler will -+ * set the header correctly. However, if the mcdi interface is waiting -+ * for a CMDDONE event it won't receive it [and since all MCDI events -+ * are sent to the same queue, we can't be racing with -+ * efx_mcdi_ev_cpl()] -+ * -+ * There's a race here with efx_mcdi_rpc(), because we might receive -+ * a REBOOT event *before* the request has been copied out. In polled -+ * mode (during startup) this is irrelevent, because efx_mcdi_complete() -+ * is ignored. In event mode, this condition is just an edge-case of -+ * receiving a REBOOT event after posting the MCDI request. Did the mc -+ * reboot before or after the copyout? The best we can do always is -+ * just return failure. -+ */ -+ spin_lock(&mcdi->iface_lock); -+ if (efx_mcdi_complete(mcdi)) { -+ if (mcdi->mode == MCDI_MODE_EVENTS) { -+ mcdi->resprc = rc; -+ mcdi->resplen = 0; -+ } -+ } else -+ /* Nobody was waiting for an MCDI request, so trigger a reset */ -+ efx_schedule_reset(efx, RESET_TYPE_MC_FAILURE); -+ -+ spin_unlock(&mcdi->iface_lock); -+} -+ -+static unsigned int efx_mcdi_event_link_speed[] = { -+ [MCDI_EVENT_LINKCHANGE_SPEED_100M] = 100, -+ [MCDI_EVENT_LINKCHANGE_SPEED_1G] = 1000, -+ [MCDI_EVENT_LINKCHANGE_SPEED_10G] = 10000, -+}; -+ -+ -+static void efx_mcdi_process_link_change(struct efx_nic *efx, efx_qword_t *ev) -+{ -+ u32 flags, fcntl, speed, lpa; -+ -+ speed = EFX_QWORD_FIELD(*ev, MCDI_EVENT_LINKCHANGE_SPEED); -+ EFX_BUG_ON_PARANOID(speed >= ARRAY_SIZE(efx_mcdi_event_link_speed)); -+ speed = efx_mcdi_event_link_speed[speed]; -+ -+ flags = EFX_QWORD_FIELD(*ev, MCDI_EVENT_LINKCHANGE_LINK_FLAGS); -+ fcntl = EFX_QWORD_FIELD(*ev, MCDI_EVENT_LINKCHANGE_FCNTL); -+ lpa = EFX_QWORD_FIELD(*ev, MCDI_EVENT_LINKCHANGE_LP_CAP); -+ -+ /* efx->link_state is only modified by efx_mcdi_phy_get_link(), -+ * which is only run after flushing the event queues. Therefore, it -+ * is safe to modify the link state outside of the mac_lock here. -+ */ -+ efx_mcdi_phy_decode_link(efx, &efx->link_state, speed, flags, fcntl); -+ -+ efx_mcdi_phy_check_fcntl(efx, lpa); -+ -+ efx_link_status_changed(efx); -+} -+ -+static const char *sensor_names[] = { -+ [MC_CMD_SENSOR_CONTROLLER_TEMP] = "Controller temp. sensor", -+ [MC_CMD_SENSOR_PHY_COMMON_TEMP] = "PHY shared temp. sensor", -+ [MC_CMD_SENSOR_CONTROLLER_COOLING] = "Controller cooling", -+ [MC_CMD_SENSOR_PHY0_TEMP] = "PHY 0 temp. sensor", -+ [MC_CMD_SENSOR_PHY0_COOLING] = "PHY 0 cooling", -+ [MC_CMD_SENSOR_PHY1_TEMP] = "PHY 1 temp. sensor", -+ [MC_CMD_SENSOR_PHY1_COOLING] = "PHY 1 cooling", -+ [MC_CMD_SENSOR_IN_1V0] = "1.0V supply sensor", -+ [MC_CMD_SENSOR_IN_1V2] = "1.2V supply sensor", -+ [MC_CMD_SENSOR_IN_1V8] = "1.8V supply sensor", -+ [MC_CMD_SENSOR_IN_2V5] = "2.5V supply sensor", -+ [MC_CMD_SENSOR_IN_3V3] = "3.3V supply sensor", -+ [MC_CMD_SENSOR_IN_12V0] = "12V supply sensor" -+}; -+ -+static const char *sensor_status_names[] = { -+ [MC_CMD_SENSOR_STATE_OK] = "OK", -+ [MC_CMD_SENSOR_STATE_WARNING] = "Warning", -+ [MC_CMD_SENSOR_STATE_FATAL] = "Fatal", -+ [MC_CMD_SENSOR_STATE_BROKEN] = "Device failure", -+}; -+ -+static void efx_mcdi_sensor_event(struct efx_nic *efx, efx_qword_t *ev) -+{ -+ unsigned int monitor, state, value; -+ const char *name, *state_txt; -+ monitor = EFX_QWORD_FIELD(*ev, MCDI_EVENT_SENSOREVT_MONITOR); -+ state = EFX_QWORD_FIELD(*ev, MCDI_EVENT_SENSOREVT_STATE); -+ value = EFX_QWORD_FIELD(*ev, MCDI_EVENT_SENSOREVT_VALUE); -+ /* Deal gracefully with the board having more drivers than we -+ * know about, but do not expect new sensor states. */ -+ name = (monitor >= ARRAY_SIZE(sensor_names)) -+ ? "No sensor name available" : -+ sensor_names[monitor]; -+ EFX_BUG_ON_PARANOID(state >= ARRAY_SIZE(sensor_status_names)); -+ state_txt = sensor_status_names[state]; -+ -+ EFX_ERR(efx, "Sensor %d (%s) reports condition '%s' for raw value %d\n", -+ monitor, name, state_txt, value); -+} -+ -+/* Called from falcon_process_eventq for MCDI events */ -+void efx_mcdi_process_event(struct efx_channel *channel, -+ efx_qword_t *event) -+{ -+ struct efx_nic *efx = channel->efx; -+ int code = EFX_QWORD_FIELD(*event, MCDI_EVENT_CODE); -+ u32 data = EFX_QWORD_FIELD(*event, MCDI_EVENT_DATA); -+ -+ switch (code) { -+ case MCDI_EVENT_CODE_BADSSERT: -+ EFX_ERR(efx, "MC watchdog or assertion failure at 0x%x\n", data); -+ efx_mcdi_ev_death(efx, EINTR); -+ break; -+ -+ case MCDI_EVENT_CODE_PMNOTICE: -+ EFX_INFO(efx, "MCDI PM event.\n"); -+ break; -+ -+ case MCDI_EVENT_CODE_CMDDONE: -+ efx_mcdi_ev_cpl(efx, -+ MCDI_EVENT_FIELD(*event, CMDDONE_SEQ), -+ MCDI_EVENT_FIELD(*event, CMDDONE_DATALEN), -+ MCDI_EVENT_FIELD(*event, CMDDONE_ERRNO)); -+ break; -+ -+ case MCDI_EVENT_CODE_LINKCHANGE: -+ efx_mcdi_process_link_change(efx, event); -+ break; -+ case MCDI_EVENT_CODE_SENSOREVT: -+ efx_mcdi_sensor_event(efx, event); -+ break; -+ case MCDI_EVENT_CODE_SCHEDERR: -+ EFX_INFO(efx, "MC Scheduler error address=0x%x\n", data); -+ break; -+ case MCDI_EVENT_CODE_REBOOT: -+ EFX_INFO(efx, "MC Reboot\n"); -+ efx_mcdi_ev_death(efx, EIO); -+ break; -+ case MCDI_EVENT_CODE_MAC_STATS_DMA: -+ /* MAC stats are gather lazily. We can ignore this. */ -+ break; -+ -+ default: -+ EFX_ERR(efx, "Unknown MCDI event 0x%x\n", code); -+ } -+} -+ -+/************************************************************************** -+ * -+ * Specific request functions -+ * -+ ************************************************************************** -+ */ -+ -+int efx_mcdi_fwver(struct efx_nic *efx, u64 *version, u32 *build) -+{ -+ u8 outbuf[ALIGN(MC_CMD_GET_VERSION_V1_OUT_LEN, 4)]; -+ size_t outlength; -+ const __le16 *ver_words; -+ int rc; -+ -+ BUILD_BUG_ON(MC_CMD_GET_VERSION_IN_LEN != 0); -+ -+ rc = efx_mcdi_rpc(efx, MC_CMD_GET_VERSION, NULL, 0, -+ outbuf, sizeof(outbuf), &outlength); -+ if (rc) -+ goto fail; -+ -+ if (outlength == MC_CMD_GET_VERSION_V0_OUT_LEN) { -+ *version = 0; -+ *build = MCDI_DWORD(outbuf, GET_VERSION_OUT_FIRMWARE); -+ return 0; -+ } -+ -+ if (outlength < MC_CMD_GET_VERSION_V1_OUT_LEN) { -+ rc = -EMSGSIZE; -+ goto fail; -+ } -+ -+ ver_words = (__le16 *)MCDI_PTR(outbuf, GET_VERSION_OUT_VERSION); -+ *version = (((u64)le16_to_cpu(ver_words[0]) << 48) | -+ ((u64)le16_to_cpu(ver_words[1]) << 32) | -+ ((u64)le16_to_cpu(ver_words[2]) << 16) | -+ le16_to_cpu(ver_words[3])); -+ *build = MCDI_DWORD(outbuf, GET_VERSION_OUT_FIRMWARE); -+ -+ return 0; -+ -+fail: -+ EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc); -+ return rc; -+} -+ -+int efx_mcdi_drv_attach(struct efx_nic *efx, bool driver_operating, -+ bool *was_attached) -+{ -+ u8 inbuf[MC_CMD_DRV_ATTACH_IN_LEN]; -+ u8 outbuf[MC_CMD_DRV_ATTACH_OUT_LEN]; -+ size_t outlen; -+ int rc; -+ -+ MCDI_SET_DWORD(inbuf, DRV_ATTACH_IN_NEW_STATE, -+ driver_operating ? 1 : 0); -+ MCDI_SET_DWORD(inbuf, DRV_ATTACH_IN_UPDATE, 1); -+ -+ rc = efx_mcdi_rpc(efx, MC_CMD_DRV_ATTACH, inbuf, sizeof(inbuf), -+ outbuf, sizeof(outbuf), &outlen); -+ if (rc) -+ goto fail; -+ if (outlen < MC_CMD_DRV_ATTACH_OUT_LEN) -+ goto fail; -+ -+ if (was_attached != NULL) -+ *was_attached = MCDI_DWORD(outbuf, DRV_ATTACH_OUT_OLD_STATE); -+ return 0; -+ -+fail: -+ EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc); -+ return rc; -+} -+ -+int efx_mcdi_get_board_cfg(struct efx_nic *efx, u8 *mac_address, -+ u16 *fw_subtype_list) -+{ -+ uint8_t outbuf[MC_CMD_GET_BOARD_CFG_OUT_LEN]; -+ size_t outlen; -+ int port_num = efx_port_num(efx); -+ int offset; -+ int rc; -+ -+ BUILD_BUG_ON(MC_CMD_GET_BOARD_CFG_IN_LEN != 0); -+ -+ rc = efx_mcdi_rpc(efx, MC_CMD_GET_BOARD_CFG, NULL, 0, -+ outbuf, sizeof(outbuf), &outlen); -+ if (rc) -+ goto fail; -+ -+ if (outlen < MC_CMD_GET_BOARD_CFG_OUT_LEN) { -+ rc = -EMSGSIZE; -+ goto fail; -+ } -+ -+ offset = (port_num) -+ ? MC_CMD_GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT1_OFST -+ : MC_CMD_GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT0_OFST; -+ if (mac_address) -+ memcpy(mac_address, outbuf + offset, ETH_ALEN); -+ if (fw_subtype_list) -+ memcpy(fw_subtype_list, -+ outbuf + MC_CMD_GET_BOARD_CFG_OUT_FW_SUBTYPE_LIST_OFST, -+ MC_CMD_GET_BOARD_CFG_OUT_FW_SUBTYPE_LIST_LEN); -+ -+ return 0; -+ -+fail: -+ EFX_ERR(efx, "%s: failed rc=%d len=%d\n", __func__, rc, (int)outlen); -+ -+ return rc; -+} -+ -+int efx_mcdi_log_ctrl(struct efx_nic *efx, bool evq, bool uart, u32 dest_evq) -+{ -+ u8 inbuf[MC_CMD_LOG_CTRL_IN_LEN]; -+ u32 dest = 0; -+ int rc; -+ -+ if (uart) -+ dest |= MC_CMD_LOG_CTRL_IN_LOG_DEST_UART; -+ if (evq) -+ dest |= MC_CMD_LOG_CTRL_IN_LOG_DEST_EVQ; -+ -+ MCDI_SET_DWORD(inbuf, LOG_CTRL_IN_LOG_DEST, dest); -+ MCDI_SET_DWORD(inbuf, LOG_CTRL_IN_LOG_DEST_EVQ, dest_evq); -+ -+ BUILD_BUG_ON(MC_CMD_LOG_CTRL_OUT_LEN != 0); -+ -+ rc = efx_mcdi_rpc(efx, MC_CMD_LOG_CTRL, inbuf, sizeof(inbuf), -+ NULL, 0, NULL); -+ if (rc) -+ goto fail; -+ -+ return 0; -+ -+fail: -+ EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc); -+ return rc; -+} -+ -+int efx_mcdi_nvram_types(struct efx_nic *efx, u32 *nvram_types_out) -+{ -+ u8 outbuf[MC_CMD_NVRAM_TYPES_OUT_LEN]; -+ size_t outlen; -+ int rc; -+ -+ BUILD_BUG_ON(MC_CMD_NVRAM_TYPES_IN_LEN != 0); -+ -+ rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_TYPES, NULL, 0, -+ outbuf, sizeof(outbuf), &outlen); -+ if (rc) -+ goto fail; -+ if (outlen < MC_CMD_NVRAM_TYPES_OUT_LEN) -+ goto fail; -+ -+ *nvram_types_out = MCDI_DWORD(outbuf, NVRAM_TYPES_OUT_TYPES); -+ return 0; -+ -+fail: -+ EFX_ERR(efx, "%s: failed rc=%d\n", -+ __func__, rc); -+ return rc; -+} -+ -+int efx_mcdi_nvram_info(struct efx_nic *efx, unsigned int type, -+ size_t *size_out, size_t *erase_size_out, -+ bool *protected_out) -+{ -+ u8 inbuf[MC_CMD_NVRAM_INFO_IN_LEN]; -+ u8 outbuf[MC_CMD_NVRAM_INFO_OUT_LEN]; -+ size_t outlen; -+ int rc; -+ -+ MCDI_SET_DWORD(inbuf, NVRAM_INFO_IN_TYPE, type); -+ -+ rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_INFO, inbuf, sizeof(inbuf), -+ outbuf, sizeof(outbuf), &outlen); -+ if (rc) -+ goto fail; -+ if (outlen < MC_CMD_NVRAM_INFO_OUT_LEN) -+ goto fail; -+ -+ *size_out = MCDI_DWORD(outbuf, NVRAM_INFO_OUT_SIZE); -+ *erase_size_out = MCDI_DWORD(outbuf, NVRAM_INFO_OUT_ERASESIZE); -+ *protected_out = !!(MCDI_DWORD(outbuf, NVRAM_INFO_OUT_FLAGS) & -+ (1 << MC_CMD_NVRAM_PROTECTED_LBN)); -+ return 0; -+ -+fail: -+ EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc); -+ return rc; -+} -+ -+int efx_mcdi_nvram_update_start(struct efx_nic *efx, unsigned int type) -+{ -+ u8 inbuf[MC_CMD_NVRAM_UPDATE_START_IN_LEN]; -+ int rc; -+ -+ MCDI_SET_DWORD(inbuf, NVRAM_UPDATE_START_IN_TYPE, type); -+ -+ BUILD_BUG_ON(MC_CMD_NVRAM_UPDATE_START_OUT_LEN != 0); -+ -+ rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_UPDATE_START, inbuf, sizeof(inbuf), -+ NULL, 0, NULL); -+ if (rc) -+ goto fail; -+ -+ return 0; -+ -+fail: -+ EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc); -+ return rc; -+} -+ -+int efx_mcdi_nvram_read(struct efx_nic *efx, unsigned int type, -+ loff_t offset, u8 *buffer, size_t length) -+{ -+ u8 inbuf[MC_CMD_NVRAM_READ_IN_LEN]; -+ u8 outbuf[MC_CMD_NVRAM_READ_OUT_LEN(length)]; -+ size_t outlen; -+ int rc; -+ -+ MCDI_SET_DWORD(inbuf, NVRAM_READ_IN_TYPE, type); -+ MCDI_SET_DWORD(inbuf, NVRAM_READ_IN_OFFSET, offset); -+ MCDI_SET_DWORD(inbuf, NVRAM_READ_IN_LENGTH, length); -+ -+ rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_READ, inbuf, sizeof(inbuf), -+ outbuf, sizeof(outbuf), &outlen); -+ if (rc) -+ goto fail; -+ -+ memcpy(buffer, MCDI_PTR(outbuf, NVRAM_READ_OUT_READ_BUFFER), length); -+ return 0; -+ -+fail: -+ EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc); -+ return rc; -+} -+ -+int efx_mcdi_nvram_write(struct efx_nic *efx, unsigned int type, -+ loff_t offset, const u8 *buffer, size_t length) -+{ -+ u8 inbuf[MC_CMD_NVRAM_WRITE_IN_LEN(length)]; -+ int rc; -+ -+ MCDI_SET_DWORD(inbuf, NVRAM_WRITE_IN_TYPE, type); -+ MCDI_SET_DWORD(inbuf, NVRAM_WRITE_IN_OFFSET, offset); -+ MCDI_SET_DWORD(inbuf, NVRAM_WRITE_IN_LENGTH, length); -+ memcpy(MCDI_PTR(inbuf, NVRAM_WRITE_IN_WRITE_BUFFER), buffer, length); -+ -+ BUILD_BUG_ON(MC_CMD_NVRAM_WRITE_OUT_LEN != 0); -+ -+ rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_WRITE, inbuf, sizeof(inbuf), -+ NULL, 0, NULL); -+ if (rc) -+ goto fail; -+ -+ return 0; -+ -+fail: -+ EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc); -+ return rc; -+} -+ -+int efx_mcdi_nvram_erase(struct efx_nic *efx, unsigned int type, -+ loff_t offset, size_t length) -+{ -+ u8 inbuf[MC_CMD_NVRAM_ERASE_IN_LEN]; -+ int rc; -+ -+ MCDI_SET_DWORD(inbuf, NVRAM_ERASE_IN_TYPE, type); -+ MCDI_SET_DWORD(inbuf, NVRAM_ERASE_IN_OFFSET, offset); -+ MCDI_SET_DWORD(inbuf, NVRAM_ERASE_IN_LENGTH, length); -+ -+ BUILD_BUG_ON(MC_CMD_NVRAM_ERASE_OUT_LEN != 0); -+ -+ rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_ERASE, inbuf, sizeof(inbuf), -+ NULL, 0, NULL); -+ if (rc) -+ goto fail; -+ -+ return 0; -+ -+fail: -+ EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc); -+ return rc; -+} -+ -+int efx_mcdi_nvram_update_finish(struct efx_nic *efx, unsigned int type) -+{ -+ u8 inbuf[MC_CMD_NVRAM_UPDATE_FINISH_IN_LEN]; -+ int rc; -+ -+ MCDI_SET_DWORD(inbuf, NVRAM_UPDATE_FINISH_IN_TYPE, type); -+ -+ BUILD_BUG_ON(MC_CMD_NVRAM_UPDATE_FINISH_OUT_LEN != 0); -+ -+ rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_UPDATE_FINISH, inbuf, sizeof(inbuf), -+ NULL, 0, NULL); -+ if (rc) -+ goto fail; -+ -+ return 0; -+ -+fail: -+ EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc); -+ return rc; -+} -+ -+int efx_mcdi_handle_assertion(struct efx_nic *efx) -+{ -+ union { -+ u8 asserts[MC_CMD_GET_ASSERTS_IN_LEN]; -+ u8 reboot[MC_CMD_REBOOT_IN_LEN]; -+ } inbuf; -+ u8 assertion[MC_CMD_GET_ASSERTS_OUT_LEN]; -+ unsigned int flags, index, ofst; -+ const char *reason; -+ size_t outlen; -+ int retry; -+ int rc; -+ -+ /* Check if the MC is in the assertion handler, retrying twice. Once -+ * because a boot-time assertion might cause this command to fail -+ * with EINTR. And once again because GET_ASSERTS can race with -+ * MC_CMD_REBOOT running on the other port. */ -+ retry = 2; -+ do { -+ MCDI_SET_DWORD(inbuf.asserts, GET_ASSERTS_IN_CLEAR, 0); -+ rc = efx_mcdi_rpc(efx, MC_CMD_GET_ASSERTS, -+ inbuf.asserts, MC_CMD_GET_ASSERTS_IN_LEN, -+ assertion, sizeof(assertion), &outlen); -+ } while ((rc == -EINTR || rc == -EIO) && retry-- > 0); -+ -+ if (rc) -+ return rc; -+ if (outlen < MC_CMD_GET_ASSERTS_OUT_LEN) -+ return -EINVAL; -+ -+ flags = MCDI_DWORD(assertion, GET_ASSERTS_OUT_GLOBAL_FLAGS); -+ if (flags == MC_CMD_GET_ASSERTS_FLAGS_NO_FAILS) -+ return 0; -+ -+ /* Reset the hardware atomically such that only one port with succeed. -+ * This command will succeed if a reboot is no longer required (because -+ * the other port did it first), but fail with EIO if it succeeds. -+ */ -+ BUILD_BUG_ON(MC_CMD_REBOOT_OUT_LEN != 0); -+ MCDI_SET_DWORD(inbuf.reboot, REBOOT_IN_FLAGS, -+ MC_CMD_REBOOT_FLAGS_AFTER_ASSERTION); -+ efx_mcdi_rpc(efx, MC_CMD_REBOOT, inbuf.reboot, MC_CMD_REBOOT_IN_LEN, -+ NULL, 0, NULL); -+ -+ /* Print out the assertion */ -+ reason = (flags == MC_CMD_GET_ASSERTS_FLAGS_SYS_FAIL) -+ ? "system-level assertion" -+ : (flags == MC_CMD_GET_ASSERTS_FLAGS_THR_FAIL) -+ ? "thread-level assertion" -+ : (flags == MC_CMD_GET_ASSERTS_FLAGS_WDOG_FIRED) -+ ? "watchdog reset" -+ : "unknown assertion"; -+ EFX_ERR(efx, "MCPU %s at PC = 0x%.8x in thread 0x%.8x\n", reason, -+ MCDI_DWORD(assertion, GET_ASSERTS_OUT_SAVED_PC_OFFS), -+ MCDI_DWORD(assertion, GET_ASSERTS_OUT_THREAD_OFFS)); -+ -+ /* Print out the registers */ -+ ofst = MC_CMD_GET_ASSERTS_OUT_GP_REGS_OFFS_OFST; -+ for (index = 1; index < 32; index++) { -+ EFX_ERR(efx, "R%.2d (?): 0x%.8x\n", index, -+ MCDI_DWORD2(assertion, ofst)); -+ ofst += sizeof(efx_dword_t); -+ } -+ -+ return 0; -+} -+ -+void efx_mcdi_set_id_led(struct efx_nic *efx, enum efx_led_mode mode) -+{ -+ u8 inbuf[MC_CMD_SET_ID_LED_IN_LEN]; -+ int rc; -+ -+ BUILD_BUG_ON(EFX_LED_OFF != MC_CMD_LED_OFF); -+ BUILD_BUG_ON(EFX_LED_ON != MC_CMD_LED_ON); -+ BUILD_BUG_ON(EFX_LED_DEFAULT != MC_CMD_LED_DEFAULT); -+ -+ BUILD_BUG_ON(MC_CMD_SET_ID_LED_OUT_LEN != 0); -+ -+ MCDI_SET_DWORD(inbuf, SET_ID_LED_IN_STATE, mode); -+ -+ rc = efx_mcdi_rpc(efx, MC_CMD_SET_ID_LED, inbuf, sizeof(inbuf), -+ NULL, 0, NULL); -+ if (rc) -+ EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc); -+} -+ -+int efx_mcdi_reset_port(struct efx_nic *efx) -+{ -+ int rc = efx_mcdi_rpc(efx, MC_CMD_PORT_RESET, NULL, 0, NULL, 0, NULL); -+ if (rc) -+ EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc); -+ return rc; -+} -+ -+int efx_mcdi_reset_mc(struct efx_nic *efx) -+{ -+ u8 inbuf[MC_CMD_REBOOT_IN_LEN]; -+ int rc; -+ -+ BUILD_BUG_ON(MC_CMD_REBOOT_OUT_LEN != 0); -+ MCDI_SET_DWORD(inbuf, REBOOT_IN_FLAGS, 0); -+ rc = efx_mcdi_rpc(efx, MC_CMD_REBOOT, inbuf, sizeof(inbuf), -+ NULL, 0, NULL); -+ /* White is black, and up is down */ -+ if (rc == -EIO) -+ return 0; -+ if (rc == 0) -+ rc = -EIO; -+ EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc); -+ return rc; -+} -+ -+int efx_mcdi_wol_filter_set(struct efx_nic *efx, u32 type, -+ const u8 *mac, int *id_out) -+{ -+ u8 inbuf[MC_CMD_WOL_FILTER_SET_IN_LEN]; -+ u8 outbuf[MC_CMD_WOL_FILTER_SET_OUT_LEN]; -+ size_t outlen; -+ int rc; -+ -+ MCDI_SET_DWORD(inbuf, WOL_FILTER_SET_IN_WOL_TYPE, type); -+ MCDI_SET_DWORD(inbuf, WOL_FILTER_SET_IN_FILTER_MODE, -+ MC_CMD_FILTER_MODE_SIMPLE); -+ memcpy(MCDI_PTR(inbuf, WOL_FILTER_SET_IN_MAGIC_MAC), mac, ETH_ALEN); -+ -+ rc = efx_mcdi_rpc(efx, MC_CMD_WOL_FILTER_SET, inbuf, sizeof(inbuf), -+ outbuf, sizeof(outbuf), &outlen); -+ if (rc) -+ goto fail; -+ -+ if (outlen < MC_CMD_WOL_FILTER_SET_OUT_LEN) { -+ rc = -EMSGSIZE; -+ goto fail; -+ } -+ -+ *id_out = (int)MCDI_DWORD(outbuf, WOL_FILTER_SET_OUT_FILTER_ID); -+ -+ return 0; -+ -+fail: -+ *id_out = -1; -+ EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc); -+ return rc; -+ -+} -+ -+ -+int -+efx_mcdi_wol_filter_set_magic(struct efx_nic *efx, const u8 *mac, int *id_out) -+{ -+ return efx_mcdi_wol_filter_set(efx, MC_CMD_WOL_TYPE_MAGIC, mac, id_out); -+} -+ -+ -+int efx_mcdi_wol_filter_get_magic(struct efx_nic *efx, int *id_out) -+{ -+ u8 outbuf[MC_CMD_WOL_FILTER_GET_OUT_LEN]; -+ size_t outlen; -+ int rc; -+ -+ rc = efx_mcdi_rpc(efx, MC_CMD_WOL_FILTER_GET, NULL, 0, -+ outbuf, sizeof(outbuf), &outlen); -+ if (rc) -+ goto fail; -+ -+ if (outlen < MC_CMD_WOL_FILTER_GET_OUT_LEN) { -+ rc = -EMSGSIZE; -+ goto fail; -+ } -+ -+ *id_out = (int)MCDI_DWORD(outbuf, WOL_FILTER_GET_OUT_FILTER_ID); -+ -+ return 0; -+ -+fail: -+ *id_out = -1; -+ EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc); -+ return rc; -+} -+ -+ -+int efx_mcdi_wol_filter_remove(struct efx_nic *efx, int id) -+{ -+ u8 inbuf[MC_CMD_WOL_FILTER_REMOVE_IN_LEN]; -+ int rc; -+ -+ MCDI_SET_DWORD(inbuf, WOL_FILTER_REMOVE_IN_FILTER_ID, (u32)id); -+ -+ rc = efx_mcdi_rpc(efx, MC_CMD_WOL_FILTER_REMOVE, inbuf, sizeof(inbuf), -+ NULL, 0, NULL); -+ if (rc) -+ goto fail; -+ -+ return 0; -+ -+fail: -+ EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc); -+ return rc; -+} -+ -+ -+int efx_mcdi_wol_filter_reset(struct efx_nic *efx) -+{ -+ int rc; -+ -+ rc = efx_mcdi_rpc(efx, MC_CMD_WOL_FILTER_RESET, NULL, 0, NULL, 0, NULL); -+ if (rc) -+ goto fail; -+ -+ return 0; -+ -+fail: -+ EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc); -+ return rc; -+} -+ -diff --git a/drivers/net/sfc/mcdi.h b/drivers/net/sfc/mcdi.h -new file mode 100644 -index 0000000..de91672 ---- /dev/null -+++ b/drivers/net/sfc/mcdi.h -@@ -0,0 +1,130 @@ -+/**************************************************************************** -+ * Driver for Solarflare Solarstorm network controllers and boards -+ * Copyright 2008-2009 Solarflare Communications Inc. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License version 2 as published -+ * by the Free Software Foundation, incorporated herein by reference. -+ */ -+ -+#ifndef EFX_MCDI_H -+#define EFX_MCDI_H -+ -+/** -+ * enum efx_mcdi_state -+ * @MCDI_STATE_QUIESCENT: No pending MCDI requests. If the caller holds the -+ * mcdi_lock then they are able to move to MCDI_STATE_RUNNING -+ * @MCDI_STATE_RUNNING: There is an MCDI request pending. Only the thread that -+ * moved into this state is allowed to move out of it. -+ * @MCDI_STATE_COMPLETED: An MCDI request has completed, but the owning thread -+ * has not yet consumed the result. For all other threads, equivalent to -+ * MCDI_STATE_RUNNING. -+ */ -+enum efx_mcdi_state { -+ MCDI_STATE_QUIESCENT, -+ MCDI_STATE_RUNNING, -+ MCDI_STATE_COMPLETED, -+}; -+ -+enum efx_mcdi_mode { -+ MCDI_MODE_POLL, -+ MCDI_MODE_EVENTS, -+}; -+ -+/** -+ * struct efx_mcdi_iface -+ * @state: Interface state. Waited for by mcdi_wq. -+ * @wq: Wait queue for threads waiting for state != STATE_RUNNING -+ * @iface_lock: Protects @credits, @seqno, @resprc, @resplen -+ * @mode: Poll for mcdi completion, or wait for an mcdi_event. -+ * Serialised by @lock -+ * @seqno: The next sequence number to use for mcdi requests. -+ * Serialised by @lock -+ * @credits: Number of spurious MCDI completion events allowed before we -+ * trigger a fatal error. Protected by @lock -+ * @resprc: Returned MCDI completion -+ * @resplen: Returned payload length -+ */ -+struct efx_mcdi_iface { -+ atomic_t state; -+ wait_queue_head_t wq; -+ spinlock_t iface_lock; -+ enum efx_mcdi_mode mode; -+ unsigned int credits; -+ unsigned int seqno; -+ unsigned int resprc; -+ size_t resplen; -+}; -+ -+extern void efx_mcdi_init(struct efx_nic *efx); -+ -+extern int efx_mcdi_rpc(struct efx_nic *efx, unsigned cmd, const u8 *inbuf, -+ size_t inlen, u8 *outbuf, size_t outlen, -+ size_t *outlen_actual); -+ -+extern int efx_mcdi_poll_reboot(struct efx_nic *efx); -+extern void efx_mcdi_mode_poll(struct efx_nic *efx); -+extern void efx_mcdi_mode_event(struct efx_nic *efx); -+ -+extern void efx_mcdi_process_event(struct efx_channel *channel, -+ efx_qword_t *event); -+ -+#define MCDI_PTR2(_buf, _ofst) \ -+ (((u8 *)_buf) + _ofst) -+#define MCDI_SET_DWORD2(_buf, _ofst, _value) \ -+ EFX_POPULATE_DWORD_1(*((efx_dword_t *)MCDI_PTR2(_buf, _ofst)), \ -+ EFX_DWORD_0, _value) -+#define MCDI_DWORD2(_buf, _ofst) \ -+ EFX_DWORD_FIELD(*((efx_dword_t *)MCDI_PTR2(_buf, _ofst)), \ -+ EFX_DWORD_0) -+#define MCDI_QWORD2(_buf, _ofst) \ -+ EFX_QWORD_FIELD64(*((efx_qword_t *)MCDI_PTR2(_buf, _ofst)), \ -+ EFX_QWORD_0) -+ -+#define MCDI_PTR(_buf, _ofst) \ -+ MCDI_PTR2(_buf, MC_CMD_ ## _ofst ## _OFST) -+#define MCDI_SET_DWORD(_buf, _ofst, _value) \ -+ MCDI_SET_DWORD2(_buf, MC_CMD_ ## _ofst ## _OFST, _value) -+#define MCDI_DWORD(_buf, _ofst) \ -+ MCDI_DWORD2(_buf, MC_CMD_ ## _ofst ## _OFST) -+#define MCDI_QWORD(_buf, _ofst) \ -+ MCDI_QWORD2(_buf, MC_CMD_ ## _ofst ## _OFST) -+ -+#define MCDI_EVENT_FIELD(_ev, _field) \ -+ EFX_QWORD_FIELD(_ev, MCDI_EVENT_ ## _field) -+ -+extern int efx_mcdi_fwver(struct efx_nic *efx, u64 *version, u32 *build); -+extern int efx_mcdi_drv_attach(struct efx_nic *efx, bool driver_operating, -+ bool *was_attached_out); -+extern int efx_mcdi_get_board_cfg(struct efx_nic *efx, u8 *mac_address, -+ u16 *fw_subtype_list); -+extern int efx_mcdi_log_ctrl(struct efx_nic *efx, bool evq, bool uart, -+ u32 dest_evq); -+extern int efx_mcdi_nvram_types(struct efx_nic *efx, u32 *nvram_types_out); -+extern int efx_mcdi_nvram_info(struct efx_nic *efx, unsigned int type, -+ size_t *size_out, size_t *erase_size_out, -+ bool *protected_out); -+extern int efx_mcdi_nvram_update_start(struct efx_nic *efx, -+ unsigned int type); -+extern int efx_mcdi_nvram_read(struct efx_nic *efx, unsigned int type, -+ loff_t offset, u8 *buffer, size_t length); -+extern int efx_mcdi_nvram_write(struct efx_nic *efx, unsigned int type, -+ loff_t offset, const u8 *buffer, -+ size_t length); -+extern int efx_mcdi_nvram_erase(struct efx_nic *efx, unsigned int type, -+ loff_t offset, size_t length); -+extern int efx_mcdi_nvram_update_finish(struct efx_nic *efx, -+ unsigned int type); -+extern int efx_mcdi_handle_assertion(struct efx_nic *efx); -+extern void efx_mcdi_set_id_led(struct efx_nic *efx, enum efx_led_mode mode); -+extern int efx_mcdi_reset_port(struct efx_nic *efx); -+extern int efx_mcdi_reset_mc(struct efx_nic *efx); -+extern int efx_mcdi_wol_filter_set(struct efx_nic *efx, u32 type, -+ const u8 *mac, int *id_out); -+extern int efx_mcdi_wol_filter_set_magic(struct efx_nic *efx, -+ const u8 *mac, int *id_out); -+extern int efx_mcdi_wol_filter_get_magic(struct efx_nic *efx, int *id_out); -+extern int efx_mcdi_wol_filter_remove(struct efx_nic *efx, int id); -+extern int efx_mcdi_wol_filter_reset(struct efx_nic *efx); -+ -+#endif /* EFX_MCDI_H */ -diff --git a/drivers/net/sfc/mcdi_mac.c b/drivers/net/sfc/mcdi_mac.c -new file mode 100644 -index 0000000..06d24a1 ---- /dev/null -+++ b/drivers/net/sfc/mcdi_mac.c -@@ -0,0 +1,152 @@ -+/**************************************************************************** -+ * Driver for Solarflare Solarstorm network controllers and boards -+ * Copyright 2009 Solarflare Communications Inc. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License version 2 as published -+ * by the Free Software Foundation, incorporated herein by reference. -+ */ -+ -+#include "net_driver.h" -+#include "efx.h" -+#include "mac.h" -+#include "mcdi.h" -+#include "mcdi_pcol.h" -+ -+static int efx_mcdi_set_mac(struct efx_nic *efx) -+{ -+ u32 reject, fcntl; -+ u8 cmdbytes[MC_CMD_SET_MAC_IN_LEN]; -+ -+ memcpy(cmdbytes + MC_CMD_SET_MAC_IN_ADDR_OFST, -+ efx->net_dev->dev_addr, ETH_ALEN); -+ -+ MCDI_SET_DWORD(cmdbytes, SET_MAC_IN_MTU, -+ EFX_MAX_FRAME_LEN(efx->net_dev->mtu)); -+ MCDI_SET_DWORD(cmdbytes, SET_MAC_IN_DRAIN, 0); -+ -+ /* The MCDI command provides for controlling accept/reject -+ * of broadcast packets too, but the driver doesn't currently -+ * expose this. */ -+ reject = (efx->promiscuous) ? 0 : -+ (1 << MC_CMD_SET_MAC_IN_REJECT_UNCST_LBN); -+ MCDI_SET_DWORD(cmdbytes, SET_MAC_IN_REJECT, reject); -+ -+ switch (efx->wanted_fc) { -+ case EFX_FC_RX | EFX_FC_TX: -+ fcntl = MC_CMD_FCNTL_BIDIR; -+ break; -+ case EFX_FC_RX: -+ fcntl = MC_CMD_FCNTL_RESPOND; -+ break; -+ default: -+ fcntl = MC_CMD_FCNTL_OFF; -+ break; -+ } -+ if (efx->wanted_fc & EFX_FC_AUTO) -+ fcntl = MC_CMD_FCNTL_AUTO; -+ -+ MCDI_SET_DWORD(cmdbytes, SET_MAC_IN_FCNTL, fcntl); -+ -+ return efx_mcdi_rpc(efx, MC_CMD_SET_MAC, cmdbytes, sizeof(cmdbytes), -+ NULL, 0, NULL); -+} -+ -+static int efx_mcdi_get_mac_faults(struct efx_nic *efx, u32 *faults) -+{ -+ u8 outbuf[MC_CMD_GET_LINK_OUT_LEN]; -+ size_t outlength; -+ int rc; -+ -+ BUILD_BUG_ON(MC_CMD_GET_LINK_IN_LEN != 0); -+ -+ rc = efx_mcdi_rpc(efx, MC_CMD_GET_LINK, NULL, 0, -+ outbuf, sizeof(outbuf), &outlength); -+ if (rc) -+ goto fail; -+ -+ *faults = MCDI_DWORD(outbuf, GET_LINK_OUT_MAC_FAULT); -+ return 0; -+ -+fail: -+ EFX_ERR(efx, "%s: failed rc=%d\n", -+ __func__, rc); -+ return rc; -+} -+ -+int efx_mcdi_mac_stats(struct efx_nic *efx, dma_addr_t dma_addr, -+ u32 dma_len, int enable, int clear) -+{ -+ u8 inbuf[MC_CMD_MAC_STATS_IN_LEN]; -+ int rc; -+ efx_dword_t *cmd_ptr; -+ int period = 1000; -+ u32 addr_hi; -+ u32 addr_lo; -+ -+ BUILD_BUG_ON(MC_CMD_MAC_STATS_OUT_LEN != 0); -+ -+ addr_lo = ((u64)dma_addr) >> 0; -+ addr_hi = ((u64)dma_addr) >> 32; -+ -+ MCDI_SET_DWORD(inbuf, MAC_STATS_IN_DMA_ADDR_LO, addr_lo); -+ MCDI_SET_DWORD(inbuf, MAC_STATS_IN_DMA_ADDR_HI, addr_hi); -+ cmd_ptr = (efx_dword_t *)MCDI_PTR(inbuf, MAC_STATS_IN_CMD); -+ if (enable) -+ EFX_POPULATE_DWORD_6(*cmd_ptr, -+ MC_CMD_MAC_STATS_CMD_DMA, 1, -+ MC_CMD_MAC_STATS_CMD_CLEAR, clear, -+ MC_CMD_MAC_STATS_CMD_PERIODIC_CHANGE, 1, -+ MC_CMD_MAC_STATS_CMD_PERIODIC_ENABLE, 1, -+ MC_CMD_MAC_STATS_CMD_PERIODIC_CLEAR, 0, -+ MC_CMD_MAC_STATS_CMD_PERIOD_MS, period); -+ else -+ EFX_POPULATE_DWORD_5(*cmd_ptr, -+ MC_CMD_MAC_STATS_CMD_DMA, 0, -+ MC_CMD_MAC_STATS_CMD_CLEAR, clear, -+ MC_CMD_MAC_STATS_CMD_PERIODIC_CHANGE, 1, -+ MC_CMD_MAC_STATS_CMD_PERIODIC_ENABLE, 0, -+ MC_CMD_MAC_STATS_CMD_PERIODIC_CLEAR, 0); -+ MCDI_SET_DWORD(inbuf, MAC_STATS_IN_DMA_LEN, dma_len); -+ -+ rc = efx_mcdi_rpc(efx, MC_CMD_MAC_STATS, inbuf, sizeof(inbuf), -+ NULL, 0, NULL); -+ if (rc) -+ goto fail; -+ -+ return 0; -+ -+fail: -+ EFX_ERR(efx, "%s: %s failed rc=%d\n", -+ __func__, enable ? "enable" : "disable", rc); -+ return rc; -+} -+ -+static int efx_mcdi_mac_reconfigure(struct efx_nic *efx) -+{ -+ int rc; -+ -+ rc = efx_mcdi_set_mac(efx); -+ if (rc != 0) -+ return rc; -+ -+ /* Restore the multicast hash registers. */ -+ efx->type->push_multicast_hash(efx); -+ -+ return 0; -+} -+ -+ -+static bool efx_mcdi_mac_check_fault(struct efx_nic *efx) -+{ -+ u32 faults; -+ int rc = efx_mcdi_get_mac_faults(efx, &faults); -+ return (rc != 0) || (faults != 0); -+} -+ -+ -+struct efx_mac_operations efx_mcdi_mac_operations = { -+ .reconfigure = efx_mcdi_mac_reconfigure, -+ .update_stats = efx_port_dummy_op_void, -+ .check_fault = efx_mcdi_mac_check_fault, -+}; -diff --git a/drivers/net/sfc/mcdi_pcol.h b/drivers/net/sfc/mcdi_pcol.h -new file mode 100644 -index 0000000..2a85360 ---- /dev/null -+++ b/drivers/net/sfc/mcdi_pcol.h -@@ -0,0 +1,1578 @@ -+/**************************************************************************** -+ * Driver for Solarflare Solarstorm network controllers and boards -+ * Copyright 2009 Solarflare Communications Inc. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License version 2 as published -+ * by the Free Software Foundation, incorporated herein by reference. -+ */ -+ -+ -+#ifndef MCDI_PCOL_H -+#define MCDI_PCOL_H -+ -+/* Values to be written into FMCR_CZ_RESET_STATE_REG to control boot. */ -+/* Power-on reset state */ -+#define MC_FW_STATE_POR (1) -+/* If this is set in MC_RESET_STATE_REG then it should be -+ * possible to jump into IMEM without loading code from flash. */ -+#define MC_FW_WARM_BOOT_OK (2) -+/* The MC main image has started to boot. */ -+#define MC_FW_STATE_BOOTING (4) -+/* The Scheduler has started. */ -+#define MC_FW_STATE_SCHED (8) -+ -+/* Values to be written to the per-port status dword in shared -+ * memory on reboot and assert */ -+#define MC_STATUS_DWORD_REBOOT (0xb007b007) -+#define MC_STATUS_DWORD_ASSERT (0xdeaddead) -+ -+/* The current version of the MCDI protocol. -+ * -+ * Note that the ROM burnt into the card only talks V0, so at the very -+ * least every driver must support version 0 and MCDI_PCOL_VERSION -+ */ -+#define MCDI_PCOL_VERSION 1 -+ -+/** -+ * MCDI version 1 -+ * -+ * Each MCDI request starts with an MCDI_HEADER, which is a 32byte -+ * structure, filled in by the client. -+ * -+ * 0 7 8 16 20 22 23 24 31 -+ * | CODE | R | LEN | SEQ | Rsvd | E | R | XFLAGS | -+ * | | | -+ * | | \--- Response -+ * | \------- Error -+ * \------------------------------ Resync (always set) -+ * -+ * The client writes it's request into MC shared memory, and rings the -+ * doorbell. Each request is completed by either by the MC writting -+ * back into shared memory, or by writting out an event. -+ * -+ * All MCDI commands support completion by shared memory response. Each -+ * request may also contain additional data (accounted for by HEADER.LEN), -+ * and some response's may also contain additional data (again, accounted -+ * for by HEADER.LEN). -+ * -+ * Some MCDI commands support completion by event, in which any associated -+ * response data is included in the event. -+ * -+ * The protocol requires one response to be delivered for every request, a -+ * request should not be sent unless the response for the previous request -+ * has been received (either by polling shared memory, or by receiving -+ * an event). -+ */ -+ -+/** Request/Response structure */ -+#define MCDI_HEADER_OFST 0 -+#define MCDI_HEADER_CODE_LBN 0 -+#define MCDI_HEADER_CODE_WIDTH 7 -+#define MCDI_HEADER_RESYNC_LBN 7 -+#define MCDI_HEADER_RESYNC_WIDTH 1 -+#define MCDI_HEADER_DATALEN_LBN 8 -+#define MCDI_HEADER_DATALEN_WIDTH 8 -+#define MCDI_HEADER_SEQ_LBN 16 -+#define MCDI_HEADER_RSVD_LBN 20 -+#define MCDI_HEADER_RSVD_WIDTH 2 -+#define MCDI_HEADER_SEQ_WIDTH 4 -+#define MCDI_HEADER_ERROR_LBN 22 -+#define MCDI_HEADER_ERROR_WIDTH 1 -+#define MCDI_HEADER_RESPONSE_LBN 23 -+#define MCDI_HEADER_RESPONSE_WIDTH 1 -+#define MCDI_HEADER_XFLAGS_LBN 24 -+#define MCDI_HEADER_XFLAGS_WIDTH 8 -+/* Request response using event */ -+#define MCDI_HEADER_XFLAGS_EVREQ 0x01 -+ -+/* Maximum number of payload bytes */ -+#define MCDI_CTL_SDU_LEN_MAX 0xfc -+ -+/* The MC can generate events for two reasons: -+ * - To complete a shared memory request if XFLAGS_EVREQ was set -+ * - As a notification (link state, i2c event), controlled -+ * via MC_CMD_LOG_CTRL -+ * -+ * Both events share a common structure: -+ * -+ * 0 32 33 36 44 52 60 -+ * | Data | Cont | Level | Src | Code | Rsvd | -+ * | -+ * \ There is another event pending in this notification -+ * -+ * If Code==CMDDONE, then the fields are further interpreted as: -+ * -+ * - LEVEL==INFO Command succeded -+ * - LEVEL==ERR Command failed -+ * -+ * 0 8 16 24 32 -+ * | Seq | Datalen | Errno | Rsvd | -+ * -+ * These fields are taken directly out of the standard MCDI header, i.e., -+ * LEVEL==ERR, Datalen == 0 => Reboot -+ * -+ * Events can be squirted out of the UART (using LOG_CTRL) without a -+ * MCDI header. An event can be distinguished from a MCDI response by -+ * examining the first byte which is 0xc0. This corresponds to the -+ * non-existent MCDI command MC_CMD_DEBUG_LOG. -+ * -+ * 0 7 8 -+ * | command | Resync | = 0xc0 -+ * -+ * Since the event is written in big-endian byte order, this works -+ * providing bits 56-63 of the event are 0xc0. -+ * -+ * 56 60 63 -+ * | Rsvd | Code | = 0xc0 -+ * -+ * Which means for convenience the event code is 0xc for all MC -+ * generated events. -+ */ -+#define FSE_AZ_EV_CODE_MCDI_EVRESPONSE 0xc -+ -+#define MCDI_EVENT_DATA_LBN 0 -+#define MCDI_EVENT_DATA_WIDTH 32 -+#define MCDI_EVENT_CONT_LBN 32 -+#define MCDI_EVENT_CONT_WIDTH 1 -+#define MCDI_EVENT_LEVEL_LBN 33 -+#define MCDI_EVENT_LEVEL_WIDTH 3 -+#define MCDI_EVENT_LEVEL_INFO (0) -+#define MCDI_EVENT_LEVEL_WARN (1) -+#define MCDI_EVENT_LEVEL_ERR (2) -+#define MCDI_EVENT_LEVEL_FATAL (3) -+#define MCDI_EVENT_SRC_LBN 36 -+#define MCDI_EVENT_SRC_WIDTH 8 -+#define MCDI_EVENT_CODE_LBN 44 -+#define MCDI_EVENT_CODE_WIDTH 8 -+#define MCDI_EVENT_CODE_BADSSERT (1) -+#define MCDI_EVENT_CODE_PMNOTICE (2) -+#define MCDI_EVENT_CODE_CMDDONE (3) -+#define MCDI_EVENT_CMDDONE_SEQ_LBN 0 -+#define MCDI_EVENT_CMDDONE_SEQ_WIDTH 8 -+#define MCDI_EVENT_CMDDONE_DATALEN_LBN 8 -+#define MCDI_EVENT_CMDDONE_DATALEN_WIDTH 8 -+#define MCDI_EVENT_CMDDONE_ERRNO_LBN 16 -+#define MCDI_EVENT_CMDDONE_ERRNO_WIDTH 8 -+#define MCDI_EVENT_CODE_LINKCHANGE (4) -+#define MCDI_EVENT_LINKCHANGE_LP_CAP_LBN 0 -+#define MCDI_EVENT_LINKCHANGE_LP_CAP_WIDTH 16 -+#define MCDI_EVENT_LINKCHANGE_SPEED_LBN 16 -+#define MCDI_EVENT_LINKCHANGE_SPEED_WIDTH 4 -+#define MCDI_EVENT_LINKCHANGE_SPEED_100M 1 -+#define MCDI_EVENT_LINKCHANGE_SPEED_1G 2 -+#define MCDI_EVENT_LINKCHANGE_SPEED_10G 3 -+#define MCDI_EVENT_LINKCHANGE_FCNTL_LBN 20 -+#define MCDI_EVENT_LINKCHANGE_FCNTL_WIDTH 4 -+#define MCDI_EVENT_LINKCHANGE_LINK_FLAGS_LBN 24 -+#define MCDI_EVENT_LINKCHANGE_LINK_FLAGS_WIDTH 8 -+#define MCDI_EVENT_CODE_SENSOREVT (5) -+#define MCDI_EVENT_SENSOREVT_MONITOR_LBN 0 -+#define MCDI_EVENT_SENSOREVT_MONITOR_WIDTH 8 -+#define MCDI_EVENT_SENSOREVT_STATE_LBN 8 -+#define MCDI_EVENT_SENSOREVT_STATE_WIDTH 8 -+#define MCDI_EVENT_SENSOREVT_VALUE_LBN 16 -+#define MCDI_EVENT_SENSOREVT_VALUE_WIDTH 16 -+#define MCDI_EVENT_CODE_SCHEDERR (6) -+#define MCDI_EVENT_CODE_REBOOT (7) -+#define MCDI_EVENT_CODE_MAC_STATS_DMA (8) -+#define MCDI_EVENT_MAC_STATS_DMA_GENERATION_LBN 0 -+#define MCDI_EVENT_MAC_STATS_DMA_GENERATION_WIDTH 32 -+ -+/* Non-existent command target */ -+#define MC_CMD_ERR_ENOENT 2 -+/* assert() has killed the MC */ -+#define MC_CMD_ERR_EINTR 4 -+/* Caller does not hold required locks */ -+#define MC_CMD_ERR_EACCES 13 -+/* Resource is currently unavailable (e.g. lock contention) */ -+#define MC_CMD_ERR_EBUSY 16 -+/* Invalid argument to target */ -+#define MC_CMD_ERR_EINVAL 22 -+/* Non-recursive resource is already acquired */ -+#define MC_CMD_ERR_EDEADLK 35 -+/* Operation not implemented */ -+#define MC_CMD_ERR_ENOSYS 38 -+/* Operation timed out */ -+#define MC_CMD_ERR_ETIME 62 -+ -+#define MC_CMD_ERR_CODE_OFST 0 -+ -+ -+/* MC_CMD_READ32: (debug, variadic out) -+ * Read multiple 32byte words from MC memory -+ */ -+#define MC_CMD_READ32 0x01 -+#define MC_CMD_READ32_IN_LEN 8 -+#define MC_CMD_READ32_IN_ADDR_OFST 0 -+#define MC_CMD_READ32_IN_NUMWORDS_OFST 4 -+#define MC_CMD_READ32_OUT_LEN(_numwords) \ -+ (4 * (_numwords)) -+#define MC_CMD_READ32_OUT_BUFFER_OFST 0 -+ -+/* MC_CMD_WRITE32: (debug, variadic in) -+ * Write multiple 32byte words to MC memory -+ */ -+#define MC_CMD_WRITE32 0x02 -+#define MC_CMD_WRITE32_IN_LEN(_numwords) (((_numwords) * 4) + 4) -+#define MC_CMD_WRITE32_IN_ADDR_OFST 0 -+#define MC_CMD_WRITE32_IN_BUFFER_OFST 4 -+#define MC_CMD_WRITE32_OUT_LEN 0 -+ -+/* MC_CMD_COPYCODE: (debug) -+ * Copy MC code between two locations and jump -+ */ -+#define MC_CMD_COPYCODE 0x03 -+#define MC_CMD_COPYCODE_IN_LEN 16 -+#define MC_CMD_COPYCODE_IN_SRC_ADDR_OFST 0 -+#define MC_CMD_COPYCODE_IN_DEST_ADDR_OFST 4 -+#define MC_CMD_COPYCODE_IN_NUMWORDS_OFST 8 -+#define MC_CMD_COPYCODE_IN_JUMP_OFST 12 -+/* Control should return to the caller rather than jumping */ -+#define MC_CMD_COPYCODE_JUMP_NONE 1 -+#define MC_CMD_COPYCODE_OUT_LEN 0 -+ -+/* MC_CMD_SET_FUNC: (debug) -+ * Select function for function-specific commands. -+ */ -+#define MC_CMD_SET_FUNC 0x04 -+#define MC_CMD_SET_FUNC_IN_LEN 4 -+#define MC_CMD_SET_FUNC_IN_FUNC_OFST 0 -+#define MC_CMD_SET_FUNC_OUT_LEN 0 -+ -+/* MC_CMD_GET_BOOT_STATUS: -+ * Get the instruction address from which the MC booted. -+ */ -+#define MC_CMD_GET_BOOT_STATUS 0x05 -+#define MC_CMD_GET_BOOT_STATUS_IN_LEN 0 -+#define MC_CMD_GET_BOOT_STATUS_OUT_LEN 8 -+#define MC_CMD_GET_BOOT_STATUS_OUT_BOOT_OFFSET_OFST 0 -+#define MC_CMD_GET_BOOT_STATUS_OUT_FLAGS_OFST 4 -+/* Reboot caused by watchdog */ -+#define MC_CMD_GET_BOOT_STATUS_FLAGS_WATCHDOG_LBN (0) -+#define MC_CMD_GET_BOOT_STATUS_FLAGS_WATCHDOG_WIDTH (1) -+/* MC booted from primary flash partition */ -+#define MC_CMD_GET_BOOT_STATUS_FLAGS_PRIMARY_LBN (1) -+#define MC_CMD_GET_BOOT_STATUS_FLAGS_PRIMARY_WIDTH (1) -+/* MC booted from backup flash partition */ -+#define MC_CMD_GET_BOOT_STATUS_FLAGS_BACKUP_LBN (2) -+#define MC_CMD_GET_BOOT_STATUS_FLAGS_BACKUP_WIDTH (1) -+ -+/* MC_CMD_GET_ASSERTS: (debug, variadic out) -+ * Get (and optionally clear) the current assertion status. -+ * -+ * Only OUT.GLOBAL_FLAGS is guaranteed to exist in the completion -+ * payload. The other fields will only be present if -+ * OUT.GLOBAL_FLAGS != NO_FAILS -+ */ -+#define MC_CMD_GET_ASSERTS 0x06 -+#define MC_CMD_GET_ASSERTS_IN_LEN 4 -+#define MC_CMD_GET_ASSERTS_IN_CLEAR_OFST 0 -+#define MC_CMD_GET_ASSERTS_OUT_LEN 140 -+/* Assertion status flag */ -+#define MC_CMD_GET_ASSERTS_OUT_GLOBAL_FLAGS_OFST 0 -+/*! No assertions have failed. */ -+#define MC_CMD_GET_ASSERTS_FLAGS_NO_FAILS 1 -+/*! A system-level assertion has failed. */ -+#define MC_CMD_GET_ASSERTS_FLAGS_SYS_FAIL 2 -+/*! A thread-level assertion has failed. */ -+#define MC_CMD_GET_ASSERTS_FLAGS_THR_FAIL 3 -+/*! The system was reset by the watchdog. */ -+#define MC_CMD_GET_ASSERTS_FLAGS_WDOG_FIRED 4 -+/* Failing PC value */ -+#define MC_CMD_GET_ASSERTS_OUT_SAVED_PC_OFFS_OFST 4 -+/* Saved GP regs */ -+#define MC_CMD_GET_ASSERTS_OUT_GP_REGS_OFFS_OFST 8 -+#define MC_CMD_GET_ASSERTS_OUT_GP_REGS_LEN 124 -+/* Failing thread address */ -+#define MC_CMD_GET_ASSERTS_OUT_THREAD_OFFS_OFST 132 -+ -+/* MC_CMD_LOG_CTRL: -+ * Determine the output stream for various events and messages -+ */ -+#define MC_CMD_LOG_CTRL 0x07 -+#define MC_CMD_LOG_CTRL_IN_LEN 8 -+#define MC_CMD_LOG_CTRL_IN_LOG_DEST_OFST 0 -+#define MC_CMD_LOG_CTRL_IN_LOG_DEST_UART (1) -+#define MC_CMD_LOG_CTRL_IN_LOG_DEST_EVQ (2) -+#define MC_CMD_LOG_CTRL_IN_LOG_DEST_EVQ_OFST 4 -+#define MC_CMD_LOG_CTRL_OUT_LEN 0 -+ -+/* MC_CMD_GET_VERSION: -+ * Get version information about the MC firmware -+ */ -+#define MC_CMD_GET_VERSION 0x08 -+#define MC_CMD_GET_VERSION_IN_LEN 0 -+#define MC_CMD_GET_VERSION_V0_OUT_LEN 4 -+#define MC_CMD_GET_VERSION_V1_OUT_LEN 32 -+#define MC_CMD_GET_VERSION_OUT_FIRMWARE_OFST 0 -+/* Reserved version number to indicate "any" version. */ -+#define MC_CMD_GET_VERSION_OUT_FIRMWARE_ANY 0xffffffff -+/* The version response of a boot ROM awaiting rescue */ -+#define MC_CMD_GET_VERSION_OUT_FIRMWARE_BOOTROM 0xb0070000 -+#define MC_CMD_GET_VERSION_V1_OUT_PCOL_OFST 4 -+/* 128bit mask of functions supported by the current firmware */ -+#define MC_CMD_GET_VERSION_V1_OUT_SUPPORTED_FUNCS_OFST 8 -+/* The command set exported by the boot ROM (MCDI v0) */ -+#define MC_CMD_GET_VERSION_V0_SUPPORTED_FUNCS { \ -+ (1 << MC_CMD_READ32) | \ -+ (1 << MC_CMD_WRITE32) | \ -+ (1 << MC_CMD_COPYCODE) | \ -+ (1 << MC_CMD_GET_VERSION), \ -+ 0, 0, 0 } -+#define MC_CMD_GET_VERSION_OUT_VERSION_OFST 24 -+ -+/* Vectors in the boot ROM */ -+/* Point to the copycode entry point. */ -+#define MC_BOOTROM_COPYCODE_VEC (0x7f4) -+/* Points to the recovery mode entry point. */ -+#define MC_BOOTROM_NOFLASH_VEC (0x7f8) -+ -+/* Test execution limits */ -+#define MC_TESTEXEC_VARIANT_COUNT 16 -+#define MC_TESTEXEC_RESULT_COUNT 7 -+ -+/* MC_CMD_SET_TESTVARS: (debug, variadic in) -+ * Write variant words for test. -+ * -+ * The user supplies a bitmap of the variants they wish to set. -+ * They must ensure that IN.LEN >= 4 + 4 * ffs(BITMAP) -+ */ -+#define MC_CMD_SET_TESTVARS 0x09 -+#define MC_CMD_SET_TESTVARS_IN_LEN(_numwords) \ -+ (4 + 4*(_numwords)) -+#define MC_CMD_SET_TESTVARS_IN_ARGS_BITMAP_OFST 0 -+/* Up to MC_TESTEXEC_VARIANT_COUNT of 32byte words start here */ -+#define MC_CMD_SET_TESTVARS_IN_ARGS_BUFFER_OFST 4 -+#define MC_CMD_SET_TESTVARS_OUT_LEN 0 -+ -+/* MC_CMD_GET_TESTRCS: (debug, variadic out) -+ * Return result words from test. -+ */ -+#define MC_CMD_GET_TESTRCS 0x0a -+#define MC_CMD_GET_TESTRCS_IN_LEN 4 -+#define MC_CMD_GET_TESTRCS_IN_NUMWORDS_OFST 0 -+#define MC_CMD_GET_TESTRCS_OUT_LEN(_numwords) \ -+ (4 * (_numwords)) -+#define MC_CMD_GET_TESTRCS_OUT_BUFFER_OFST 0 -+ -+/* MC_CMD_RUN_TEST: (debug) -+ * Run the test exported by this firmware image -+ */ -+#define MC_CMD_RUN_TEST 0x0b -+#define MC_CMD_RUN_TEST_IN_LEN 0 -+#define MC_CMD_RUN_TEST_OUT_LEN 0 -+ -+/* MC_CMD_CSR_READ32: (debug, variadic out) -+ * Read 32bit words from the indirect memory map -+ */ -+#define MC_CMD_CSR_READ32 0x0c -+#define MC_CMD_CSR_READ32_IN_LEN 12 -+#define MC_CMD_CSR_READ32_IN_ADDR_OFST 0 -+#define MC_CMD_CSR_READ32_IN_STEP_OFST 4 -+#define MC_CMD_CSR_READ32_IN_NUMWORDS_OFST 8 -+#define MC_CMD_CSR_READ32_OUT_LEN(_numwords) \ -+ (((_numwords) * 4) + 4) -+/* IN.NUMWORDS of 32bit words start here */ -+#define MC_CMD_CSR_READ32_OUT_BUFFER_OFST 0 -+#define MC_CMD_CSR_READ32_OUT_IREG_STATUS_OFST(_numwords) \ -+ ((_numwords) * 4) -+ -+/* MC_CMD_CSR_WRITE32: (debug, variadic in) -+ * Write 32bit dwords to the indirect memory map -+ */ -+#define MC_CMD_CSR_WRITE32 0x0d -+#define MC_CMD_CSR_WRITE32_IN_LEN(_numwords) \ -+ (((_numwords) * 4) + 8) -+#define MC_CMD_CSR_WRITE32_IN_ADDR_OFST 0 -+#define MC_CMD_CSR_WRITE32_IN_STEP_OFST 4 -+/* Multiple 32bit words of data to write start here */ -+#define MC_CMD_CSR_WRITE32_IN_BUFFER_OFST 8 -+#define MC_CMD_CSR_WRITE32_OUT_LEN 4 -+#define MC_CMD_CSR_WRITE32_OUT_STATUS_OFST 0 -+ -+/* MC_CMD_JTAG_WORK: (debug, fpga only) -+ * Process JTAG work buffer for RBF acceleration. -+ * -+ * Host: bit count, (up to) 32 words of data to clock out to JTAG -+ * (bits 1,0=TMS,TDO for first bit; bits 3,2=TMS,TDO for second bit, etc.) -+ * MC: bit count, (up to) 32 words of data clocked in from JTAG -+ * (bit 0=TDI for first bit, bit 1=TDI for second bit, etc.; [31:16] unused) -+ */ -+#define MC_CMD_JTAG_WORK 0x0e -+ -+/* MC_CMD_STACKINFO: (debug, variadic out) -+ * Get stack information -+ * -+ * Host: nothing -+ * MC: (thread ptr, stack size, free space) for each thread in system -+ */ -+#define MC_CMD_STACKINFO 0x0f -+ -+/* MC_CMD_MDIO_READ: -+ * MDIO register read -+ */ -+#define MC_CMD_MDIO_READ 0x10 -+#define MC_CMD_MDIO_READ_IN_LEN 16 -+#define MC_CMD_MDIO_READ_IN_BUS_OFST 0 -+#define MC_CMD_MDIO_READ_IN_PRTAD_OFST 4 -+#define MC_CMD_MDIO_READ_IN_DEVAD_OFST 8 -+#define MC_CMD_MDIO_READ_IN_ADDR_OFST 12 -+#define MC_CMD_MDIO_READ_OUT_LEN 8 -+#define MC_CMD_MDIO_READ_OUT_VALUE_OFST 0 -+#define MC_CMD_MDIO_READ_OUT_STATUS_OFST 4 -+ -+/* MC_CMD_MDIO_WRITE: -+ * MDIO register write -+ */ -+#define MC_CMD_MDIO_WRITE 0x11 -+#define MC_CMD_MDIO_WRITE_IN_LEN 20 -+#define MC_CMD_MDIO_WRITE_IN_BUS_OFST 0 -+#define MC_CMD_MDIO_WRITE_IN_PRTAD_OFST 4 -+#define MC_CMD_MDIO_WRITE_IN_DEVAD_OFST 8 -+#define MC_CMD_MDIO_WRITE_IN_ADDR_OFST 12 -+#define MC_CMD_MDIO_WRITE_IN_VALUE_OFST 16 -+#define MC_CMD_MDIO_WRITE_OUT_LEN 4 -+#define MC_CMD_MDIO_WRITE_OUT_STATUS_OFST 0 -+ -+/* By default all the MCDI MDIO operations perform clause45 mode. -+ * If you want to use clause22 then set DEVAD = MC_CMD_MDIO_CLAUSE22. -+ */ -+#define MC_CMD_MDIO_CLAUSE22 32 -+ -+/* There are two MDIO buses: one for the internal PHY, and one for external -+ * devices. -+ */ -+#define MC_CMD_MDIO_BUS_INTERNAL 0 -+#define MC_CMD_MDIO_BUS_EXTERNAL 1 -+ -+/* The MDIO commands return the raw status bits from the MDIO block. A "good" -+ * transaction should have the DONE bit set and all other bits clear. -+ */ -+#define MC_CMD_MDIO_STATUS_GOOD 0x08 -+ -+ -+/* MC_CMD_DBI_WRITE: (debug) -+ * Write DBI register(s) -+ * -+ * Host: address, byte-enables (and VF selection, and cs2 flag), -+ * value [,address ...] -+ * MC: nothing -+ */ -+#define MC_CMD_DBI_WRITE 0x12 -+#define MC_CMD_DBI_WRITE_IN_LEN(_numwords) \ -+ (12 * (_numwords)) -+#define MC_CMD_DBI_WRITE_IN_ADDRESS_OFST(_word) \ -+ (((_word) * 12) + 0) -+#define MC_CMD_DBI_WRITE_IN_BYTE_MASK_OFST(_word) \ -+ (((_word) * 12) + 4) -+#define MC_CMD_DBI_WRITE_IN_VALUE_OFST(_word) \ -+ (((_word) * 12) + 8) -+#define MC_CMD_DBI_WRITE_OUT_LEN 0 -+ -+/* MC_CMD_DBI_READ: (debug) -+ * Read DBI register(s) -+ * -+ * Host: address, [,address ...] -+ * MC: value [,value ...] -+ * (note: this does not support reading from VFs, but is retained for backwards -+ * compatibility; see MC_CMD_DBI_READX below) -+ */ -+#define MC_CMD_DBI_READ 0x13 -+#define MC_CMD_DBI_READ_IN_LEN(_numwords) \ -+ (4 * (_numwords)) -+#define MC_CMD_DBI_READ_OUT_LEN(_numwords) \ -+ (4 * (_numwords)) -+ -+/* MC_CMD_PORT_READ32: (debug) -+ * Read a 32-bit register from the indirect port register map. -+ * -+ * The port to access is implied by the Shared memory channel used. -+ */ -+#define MC_CMD_PORT_READ32 0x14 -+#define MC_CMD_PORT_READ32_IN_LEN 4 -+#define MC_CMD_PORT_READ32_IN_ADDR_OFST 0 -+#define MC_CMD_PORT_READ32_OUT_LEN 8 -+#define MC_CMD_PORT_READ32_OUT_VALUE_OFST 0 -+#define MC_CMD_PORT_READ32_OUT_STATUS_OFST 4 -+ -+/* MC_CMD_PORT_WRITE32: (debug) -+ * Write a 32-bit register to the indirect port register map. -+ * -+ * The port to access is implied by the Shared memory channel used. -+ */ -+#define MC_CMD_PORT_WRITE32 0x15 -+#define MC_CMD_PORT_WRITE32_IN_LEN 8 -+#define MC_CMD_PORT_WRITE32_IN_ADDR_OFST 0 -+#define MC_CMD_PORT_WRITE32_IN_VALUE_OFST 4 -+#define MC_CMD_PORT_WRITE32_OUT_LEN 4 -+#define MC_CMD_PORT_WRITE32_OUT_STATUS_OFST 0 -+ -+/* MC_CMD_PORT_READ128: (debug) -+ * Read a 128-bit register from indirect port register map -+ * -+ * The port to access is implied by the Shared memory channel used. -+ */ -+#define MC_CMD_PORT_READ128 0x16 -+#define MC_CMD_PORT_READ128_IN_LEN 4 -+#define MC_CMD_PORT_READ128_IN_ADDR_OFST 0 -+#define MC_CMD_PORT_READ128_OUT_LEN 20 -+#define MC_CMD_PORT_READ128_OUT_VALUE_OFST 0 -+#define MC_CMD_PORT_READ128_OUT_STATUS_OFST 16 -+ -+/* MC_CMD_PORT_WRITE128: (debug) -+ * Write a 128-bit register to indirect port register map. -+ * -+ * The port to access is implied by the Shared memory channel used. -+ */ -+#define MC_CMD_PORT_WRITE128 0x17 -+#define MC_CMD_PORT_WRITE128_IN_LEN 20 -+#define MC_CMD_PORT_WRITE128_IN_ADDR_OFST 0 -+#define MC_CMD_PORT_WRITE128_IN_VALUE_OFST 4 -+#define MC_CMD_PORT_WRITE128_OUT_LEN 4 -+#define MC_CMD_PORT_WRITE128_OUT_STATUS_OFST 0 -+ -+/* MC_CMD_GET_BOARD_CFG: -+ * Returns the MC firmware configuration structure -+ * -+ * The FW_SUBTYPE_LIST contains a 16-bit value for each of the 12 types of -+ * NVRAM area. The values are defined in the firmware/mc/platform/.c file -+ * for a specific board type, but otherwise have no meaning to the MC; they -+ * are used by the driver to manage selection of appropriate firmware updates. -+ */ -+#define MC_CMD_GET_BOARD_CFG 0x18 -+#define MC_CMD_GET_BOARD_CFG_IN_LEN 0 -+#define MC_CMD_GET_BOARD_CFG_OUT_LEN 96 -+#define MC_CMD_GET_BOARD_CFG_OUT_BOARD_TYPE_OFST 0 -+#define MC_CMD_GET_BOARD_CFG_OUT_BOARD_NAME_OFST 4 -+#define MC_CMD_GET_BOARD_CFG_OUT_BOARD_NAME_LEN 32 -+#define MC_CMD_GET_BOARD_CFG_OUT_CAPABILITIES_PORT0_OFST 36 -+#define MC_CMD_GET_BOARD_CFG_OUT_CAPABILITIES_PORT1_OFST 40 -+#define MC_CMD_GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT0_OFST 44 -+#define MC_CMD_GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT0_LEN 6 -+#define MC_CMD_GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT1_OFST 50 -+#define MC_CMD_GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT1_LEN 6 -+#define MC_CMD_GET_BOARD_CFG_OUT_MAC_COUNT_PORT0_OFST 56 -+#define MC_CMD_GET_BOARD_CFG_OUT_MAC_COUNT_PORT1_OFST 60 -+#define MC_CMD_GET_BOARD_CFG_OUT_MAC_STRIDE_PORT0_OFST 64 -+#define MC_CMD_GET_BOARD_CFG_OUT_MAC_STRIDE_PORT1_OFST 68 -+#define MC_CMD_GET_BOARD_CFG_OUT_FW_SUBTYPE_LIST_OFST 72 -+#define MC_CMD_GET_BOARD_CFG_OUT_FW_SUBTYPE_LIST_LEN 24 -+ -+/* MC_CMD_DBI_READX: (debug) -+ * Read DBI register(s) -- extended functionality -+ * -+ * Host: vf selection, address, [,vf selection ...] -+ * MC: value [,value ...] -+ */ -+#define MC_CMD_DBI_READX 0x19 -+#define MC_CMD_DBI_READX_IN_LEN(_numwords) \ -+ (8*(_numwords)) -+#define MC_CMD_DBI_READX_OUT_LEN(_numwords) \ -+ (4*(_numwords)) -+ -+/* MC_CMD_SET_RAND_SEED: -+ * Set the 16byte seed for the MC psuedo-random generator -+ */ -+#define MC_CMD_SET_RAND_SEED 0x1a -+#define MC_CMD_SET_RAND_SEED_IN_LEN 16 -+#define MC_CMD_SET_RAND_SEED_IN_SEED_OFST 0 -+#define MC_CMD_SET_RAND_SEED_OUT_LEN 0 -+ -+/* MC_CMD_LTSSM_HIST: (debug) -+ * Retrieve the history of the LTSSM, if the build supports it. -+ * -+ * Host: nothing -+ * MC: variable number of LTSSM values, as bytes -+ * The history is read-to-clear. -+ */ -+#define MC_CMD_LTSSM_HIST 0x1b -+ -+/* MC_CMD_DRV_ATTACH: -+ * Inform MCPU that this port is managed on the host (i.e. driver active) -+ */ -+#define MC_CMD_DRV_ATTACH 0x1c -+#define MC_CMD_DRV_ATTACH_IN_LEN 8 -+#define MC_CMD_DRV_ATTACH_IN_NEW_STATE_OFST 0 -+#define MC_CMD_DRV_ATTACH_IN_UPDATE_OFST 4 -+#define MC_CMD_DRV_ATTACH_OUT_LEN 4 -+#define MC_CMD_DRV_ATTACH_OUT_OLD_STATE_OFST 0 -+ -+/* MC_CMD_NCSI_PROD: (debug) -+ * Trigger an NC-SI event (and possibly an AEN in response) -+ */ -+#define MC_CMD_NCSI_PROD 0x1d -+#define MC_CMD_NCSI_PROD_IN_LEN 4 -+#define MC_CMD_NCSI_PROD_IN_EVENTS_OFST 0 -+#define MC_CMD_NCSI_PROD_LINKCHANGE_LBN 0 -+#define MC_CMD_NCSI_PROD_LINKCHANGE_WIDTH 1 -+#define MC_CMD_NCSI_PROD_RESET_LBN 1 -+#define MC_CMD_NCSI_PROD_RESET_WIDTH 1 -+#define MC_CMD_NCSI_PROD_DRVATTACH_LBN 2 -+#define MC_CMD_NCSI_PROD_DRVATTACH_WIDTH 1 -+#define MC_CMD_NCSI_PROD_OUT_LEN 0 -+ -+/* Enumeration */ -+#define MC_CMD_NCSI_PROD_LINKCHANGE 0 -+#define MC_CMD_NCSI_PROD_RESET 1 -+#define MC_CMD_NCSI_PROD_DRVATTACH 2 -+ -+/* MC_CMD_DEVEL: (debug) -+ * Reserved for development -+ */ -+#define MC_CMD_DEVEL 0x1e -+ -+/* MC_CMD_SHMUART: (debug) -+ * Route UART output to circular buffer in shared memory instead. -+ */ -+#define MC_CMD_SHMUART 0x1f -+#define MC_CMD_SHMUART_IN_FLAG_OFST 0 -+#define MC_CMD_SHMUART_IN_LEN 4 -+#define MC_CMD_SHMUART_OUT_LEN 0 -+ -+/* MC_CMD_PORT_RESET: -+ * Generic per-port reset. There is no equivalent for per-board reset. -+ * -+ * Locks required: None -+ * Return code: 0, ETIME -+ */ -+#define MC_CMD_PORT_RESET 0x20 -+#define MC_CMD_PORT_RESET_IN_LEN 0 -+#define MC_CMD_PORT_RESET_OUT_LEN 0 -+ -+/* MC_CMD_RESOURCE_LOCK: -+ * Generic resource lock/unlock interface. -+ * -+ * Locks required: None -+ * Return code: 0, -+ * EBUSY (if trylock is contended by other port), -+ * EDEADLK (if trylock is already acquired by this port) -+ * EINVAL (if unlock doesn't own the lock) -+ */ -+#define MC_CMD_RESOURCE_LOCK 0x21 -+#define MC_CMD_RESOURCE_LOCK_IN_LEN 8 -+#define MC_CMD_RESOURCE_LOCK_IN_ACTION_OFST 0 -+#define MC_CMD_RESOURCE_LOCK_ACTION_TRYLOCK 1 -+#define MC_CMD_RESOURCE_LOCK_ACTION_UNLOCK 0 -+#define MC_CMD_RESOURCE_LOCK_IN_RESOURCE_OFST 4 -+#define MC_CMD_RESOURCE_LOCK_I2C 2 -+#define MC_CMD_RESOURCE_LOCK_PHY 3 -+#define MC_CMD_RESOURCE_LOCK_OUT_LEN 0 -+ -+/* MC_CMD_SPI_COMMAND: (variadic in, variadic out) -+ * Read/Write to/from the SPI device. -+ * -+ * Locks required: SPI_LOCK -+ * Return code: 0, ETIME, EINVAL, EACCES (if SPI_LOCK is not held) -+ */ -+#define MC_CMD_SPI_COMMAND 0x22 -+#define MC_CMD_SPI_COMMAND_IN_LEN(_write_bytes) (12 + (_write_bytes)) -+#define MC_CMD_SPI_COMMAND_IN_ARGS_OFST 0 -+#define MC_CMD_SPI_COMMAND_IN_ARGS_ADDRESS_OFST 0 -+#define MC_CMD_SPI_COMMAND_IN_ARGS_READ_BYTES_OFST 4 -+#define MC_CMD_SPI_COMMAND_IN_ARGS_CHIP_SELECT_OFST 8 -+/* Data to write here */ -+#define MC_CMD_SPI_COMMAND_IN_WRITE_BUFFER_OFST 12 -+#define MC_CMD_SPI_COMMAND_OUT_LEN(_read_bytes) (_read_bytes) -+/* Data read here */ -+#define MC_CMD_SPI_COMMAND_OUT_READ_BUFFER_OFST 0 -+ -+/* MC_CMD_I2C_READ_WRITE: (variadic in, variadic out) -+ * Read/Write to/from the I2C bus. -+ * -+ * Locks required: I2C_LOCK -+ * Return code: 0, ETIME, EINVAL, EACCES (if I2C_LOCK is not held) -+ */ -+#define MC_CMD_I2C_RW 0x23 -+#define MC_CMD_I2C_RW_IN_LEN(_write_bytes) (8 + (_write_bytes)) -+#define MC_CMD_I2C_RW_IN_ARGS_OFST 0 -+#define MC_CMD_I2C_RW_IN_ARGS_ADDR_OFST 0 -+#define MC_CMD_I2C_RW_IN_ARGS_READ_BYTES_OFST 4 -+/* Data to write here */ -+#define MC_CMD_I2C_RW_IN_WRITE_BUFFER_OFSET 8 -+#define MC_CMD_I2C_RW_OUT_LEN(_read_bytes) (_read_bytes) -+/* Data read here */ -+#define MC_CMD_I2C_RW_OUT_READ_BUFFER_OFST 0 -+ -+/* Generic phy capability bitmask */ -+#define MC_CMD_PHY_CAP_10HDX_LBN 1 -+#define MC_CMD_PHY_CAP_10HDX_WIDTH 1 -+#define MC_CMD_PHY_CAP_10FDX_LBN 2 -+#define MC_CMD_PHY_CAP_10FDX_WIDTH 1 -+#define MC_CMD_PHY_CAP_100HDX_LBN 3 -+#define MC_CMD_PHY_CAP_100HDX_WIDTH 1 -+#define MC_CMD_PHY_CAP_100FDX_LBN 4 -+#define MC_CMD_PHY_CAP_100FDX_WIDTH 1 -+#define MC_CMD_PHY_CAP_1000HDX_LBN 5 -+#define MC_CMD_PHY_CAP_1000HDX_WIDTH 1 -+#define MC_CMD_PHY_CAP_1000FDX_LBN 6 -+#define MC_CMD_PHY_CAP_1000FDX_WIDTH 1 -+#define MC_CMD_PHY_CAP_10000FDX_LBN 7 -+#define MC_CMD_PHY_CAP_10000FDX_WIDTH 1 -+#define MC_CMD_PHY_CAP_PAUSE_LBN 8 -+#define MC_CMD_PHY_CAP_PAUSE_WIDTH 1 -+#define MC_CMD_PHY_CAP_ASYM_LBN 9 -+#define MC_CMD_PHY_CAP_ASYM_WIDTH 1 -+#define MC_CMD_PHY_CAP_AN_LBN 10 -+#define MC_CMD_PHY_CAP_AN_WIDTH 1 -+ -+/* Generic loopback enumeration */ -+#define MC_CMD_LOOPBACK_NONE 0 -+#define MC_CMD_LOOPBACK_DATA 1 -+#define MC_CMD_LOOPBACK_GMAC 2 -+#define MC_CMD_LOOPBACK_XGMII 3 -+#define MC_CMD_LOOPBACK_XGXS 4 -+#define MC_CMD_LOOPBACK_XAUI 5 -+#define MC_CMD_LOOPBACK_GMII 6 -+#define MC_CMD_LOOPBACK_SGMII 7 -+#define MC_CMD_LOOPBACK_XGBR 8 -+#define MC_CMD_LOOPBACK_XFI 9 -+#define MC_CMD_LOOPBACK_XAUI_FAR 10 -+#define MC_CMD_LOOPBACK_GMII_FAR 11 -+#define MC_CMD_LOOPBACK_SGMII_FAR 12 -+#define MC_CMD_LOOPBACK_XFI_FAR 13 -+#define MC_CMD_LOOPBACK_GPHY 14 -+#define MC_CMD_LOOPBACK_PHYXS 15 -+#define MC_CMD_LOOPBACK_PCS 16 -+#define MC_CMD_LOOPBACK_PMAPMD 17 -+#define MC_CMD_LOOPBACK_XPORT 18 -+#define MC_CMD_LOOPBACK_XGMII_WS 19 -+#define MC_CMD_LOOPBACK_XAUI_WS 20 -+#define MC_CMD_LOOPBACK_XAUI_WS_FAR 21 -+#define MC_CMD_LOOPBACK_XAUI_WS_NEAR 22 -+#define MC_CMD_LOOPBACK_GMII_WS 23 -+#define MC_CMD_LOOPBACK_XFI_WS 24 -+#define MC_CMD_LOOPBACK_XFI_WS_FAR 25 -+#define MC_CMD_LOOPBACK_PHYXS_WS 26 -+ -+/* Generic PHY statistics enumeration */ -+#define MC_CMD_OUI 0 -+#define MC_CMD_PMA_PMD_LINK_UP 1 -+#define MC_CMD_PMA_PMD_RX_FAULT 2 -+#define MC_CMD_PMA_PMD_TX_FAULT 3 -+#define MC_CMD_PMA_PMD_SIGNAL 4 -+#define MC_CMD_PMA_PMD_SNR_A 5 -+#define MC_CMD_PMA_PMD_SNR_B 6 -+#define MC_CMD_PMA_PMD_SNR_C 7 -+#define MC_CMD_PMA_PMD_SNR_D 8 -+#define MC_CMD_PCS_LINK_UP 9 -+#define MC_CMD_PCS_RX_FAULT 10 -+#define MC_CMD_PCS_TX_FAULT 11 -+#define MC_CMD_PCS_BER 12 -+#define MC_CMD_PCS_BLOCK_ERRORS 13 -+#define MC_CMD_PHYXS_LINK_UP 14 -+#define MC_CMD_PHYXS_RX_FAULT 15 -+#define MC_CMD_PHYXS_TX_FAULT 16 -+#define MC_CMD_PHYXS_ALIGN 17 -+#define MC_CMD_PHYXS_SYNC 18 -+#define MC_CMD_AN_LINK_UP 19 -+#define MC_CMD_AN_COMPLETE 20 -+#define MC_CMD_AN_10GBT_STATUS 21 -+#define MC_CMD_CL22_LINK_UP 22 -+#define MC_CMD_PHY_NSTATS 23 -+ -+/* MC_CMD_GET_PHY_CFG: -+ * Report PHY configuration. This guarantees to succeed even if the PHY is in -+ * a "zombie" state. -+ * -+ * Locks required: None -+ * Return code: 0 -+ */ -+#define MC_CMD_GET_PHY_CFG 0x24 -+ -+#define MC_CMD_GET_PHY_CFG_IN_LEN 0 -+#define MC_CMD_GET_PHY_CFG_OUT_LEN 72 -+ -+#define MC_CMD_GET_PHY_CFG_OUT_FLAGS_OFST 0 -+#define MC_CMD_GET_PHY_CFG_PRESENT_LBN 0 -+#define MC_CMD_GET_PHY_CFG_PRESENT_WIDTH 1 -+#define MC_CMD_GET_PHY_CFG_SHORTBIST_LBN 1 -+#define MC_CMD_GET_PHY_CFG_SHORTBIST_WIDTH 1 -+#define MC_CMD_GET_PHY_CFG_LONGBIST_LBN 2 -+#define MC_CMD_GET_PHY_CFG_LONGBIST_WIDTH 1 -+#define MC_CMD_GET_PHY_CFG_LOWPOWER_LBN 3 -+#define MC_CMD_GET_PHY_CFG_LOWPOWER_WIDTH 1 -+#define MC_CMD_GET_PHY_CFG_POWEROFF_LBN 4 -+#define MC_CMD_GET_PHY_CFG_POWEROFF_WIDTH 1 -+#define MC_CMD_GET_PHY_CFG_TXDIS_LBN 5 -+#define MC_CMD_GET_PHY_CFG_TXDIS_WIDTH 1 -+#define MC_CMD_GET_PHY_CFG_OUT_TYPE_OFST 4 -+/* Bitmask of supported capabilities */ -+#define MC_CMD_GET_PHY_CFG_OUT_SUPPORTED_CAP_OFST 8 -+#define MC_CMD_GET_PHY_CFG_OUT_CHANNEL_OFST 12 -+#define MC_CMD_GET_PHY_CFG_OUT_PRT_OFST 16 -+/* PHY statistics bitmap */ -+#define MC_CMD_GET_PHY_CFG_OUT_STATS_MASK_OFST 20 -+/* PHY type/name string */ -+#define MC_CMD_GET_PHY_CFG_OUT_NAME_OFST 24 -+#define MC_CMD_GET_PHY_CFG_OUT_NAME_LEN 20 -+#define MC_CMD_GET_PHY_CFG_OUT_MEDIA_TYPE_OFST 44 -+#define MC_CMD_MEDIA_XAUI 1 -+#define MC_CMD_MEDIA_CX4 2 -+#define MC_CMD_MEDIA_KX4 3 -+#define MC_CMD_MEDIA_XFP 4 -+#define MC_CMD_MEDIA_SFP_PLUS 5 -+#define MC_CMD_MEDIA_BASE_T 6 -+/* MDIO "MMDS" supported */ -+#define MC_CMD_GET_PHY_CFG_OUT_MMD_MASK_OFST 48 -+/* Native clause 22 */ -+#define MC_CMD_MMD_CLAUSE22 0 -+#define MC_CMD_MMD_CLAUSE45_PMAPMD 1 -+#define MC_CMD_MMD_CLAUSE45_WIS 2 -+#define MC_CMD_MMD_CLAUSE45_PCS 3 -+#define MC_CMD_MMD_CLAUSE45_PHYXS 4 -+#define MC_CMD_MMD_CLAUSE45_DTEXS 5 -+#define MC_CMD_MMD_CLAUSE45_TC 6 -+#define MC_CMD_MMD_CLAUSE45_AN 7 -+/* Clause22 proxied over clause45 by PHY */ -+#define MC_CMD_MMD_CLAUSE45_C22EXT 29 -+#define MC_CMD_MMD_CLAUSE45_VEND1 30 -+#define MC_CMD_MMD_CLAUSE45_VEND2 31 -+/* PHY stepping version */ -+#define MC_CMD_GET_PHY_CFG_OUT_REVISION_OFST 52 -+#define MC_CMD_GET_PHY_CFG_OUT_REVISION_LEN 20 -+ -+/* MC_CMD_START_PHY_BIST: -+ * Start a BIST test on the PHY. -+ * -+ * Locks required: PHY_LOCK if doing a PHY BIST -+ * Return code: 0, EINVAL, EACCES (if PHY_LOCK is not held) -+ */ -+#define MC_CMD_START_BIST 0x25 -+#define MC_CMD_START_BIST_IN_LEN 4 -+#define MC_CMD_START_BIST_TYPE_OFST 0 -+ -+/* Run the PHY's short BIST */ -+#define MC_CMD_PHY_BIST_SHORT 1 -+/* Run the PHY's long BIST */ -+#define MC_CMD_PHY_BIST_LONG 2 -+/* Run BIST on the currently selected BPX Serdes (XAUI or XFI) */ -+#define MC_CMD_BPX_SERDES_BIST 3 -+ -+/* MC_CMD_POLL_PHY_BIST: (variadic output) -+ * Poll for BIST completion -+ * -+ * Returns a single status code, and a binary blob of phy-specific -+ * bist output. If the driver can't succesfully parse the BIST output, -+ * it should still respect the Pass/Fail in OUT.RESULT. -+ * -+ * Locks required: PHY_LOCK if doing a PHY BIST -+ * Return code: 0, EACCES (if PHY_LOCK is not held) -+ */ -+#define MC_CMD_POLL_BIST 0x26 -+#define MC_CMD_POLL_BIST_IN_LEN 0 -+#define MC_CMD_POLL_BIST_OUT_LEN UNKNOWN -+#define MC_CMD_POLL_BIST_OUT_RESULT_OFST 0 -+#define MC_CMD_POLL_BIST_RUNNING 1 -+#define MC_CMD_POLL_BIST_PASSED 2 -+#define MC_CMD_POLL_BIST_FAILED 3 -+#define MC_CMD_POLL_BIST_TIMEOUT 4 -+#define MC_CMD_POLL_BIST_OUT_PRIVATE_OFST 4 -+ -+/* MC_CMD_PHY_SPI: (variadic in, variadic out) -+ * Read/Write/Erase the PHY SPI device -+ * -+ * Locks required: PHY_LOCK -+ * Return code: 0, ETIME, EINVAL, EACCES (if PHY_LOCK is not held) -+ */ -+#define MC_CMD_PHY_SPI 0x27 -+#define MC_CMD_PHY_SPI_IN_LEN(_write_bytes) (12 + (_write_bytes)) -+#define MC_CMD_PHY_SPI_IN_ARGS_OFST 0 -+#define MC_CMD_PHY_SPI_IN_ARGS_ADDR_OFST 0 -+#define MC_CMD_PHY_SPI_IN_ARGS_READ_BYTES_OFST 4 -+#define MC_CMD_PHY_SPI_IN_ARGS_ERASE_ALL_OFST 8 -+/* Data to write here */ -+#define MC_CMD_PHY_SPI_IN_WRITE_BUFFER_OFSET 12 -+#define MC_CMD_PHY_SPI_OUT_LEN(_read_bytes) (_read_bytes) -+/* Data read here */ -+#define MC_CMD_PHY_SPI_OUT_READ_BUFFER_OFST 0 -+ -+ -+/* MC_CMD_GET_LOOPBACK_MODES: -+ * Returns a bitmask of loopback modes evailable at each speed. -+ * -+ * Locks required: None -+ * Return code: 0 -+ */ -+#define MC_CMD_GET_LOOPBACK_MODES 0x28 -+#define MC_CMD_GET_LOOPBACK_MODES_IN_LEN 0 -+#define MC_CMD_GET_LOOPBACK_MODES_OUT_LEN 32 -+#define MC_CMD_GET_LOOPBACK_MODES_100M_OFST 0 -+#define MC_CMD_GET_LOOPBACK_MODES_1G_OFST 8 -+#define MC_CMD_GET_LOOPBACK_MODES_10G_OFST 16 -+#define MC_CMD_GET_LOOPBACK_MODES_SUGGESTED_OFST 24 -+ -+/* Flow control enumeration */ -+#define MC_CMD_FCNTL_OFF 0 -+#define MC_CMD_FCNTL_RESPOND 1 -+#define MC_CMD_FCNTL_BIDIR 2 -+/* Auto - Use what the link has autonegotiated -+ * - The driver should modify the advertised capabilities via SET_LINK.CAP -+ * to control the negotiated flow control mode. -+ * - Can only be set if the PHY supports PAUSE+ASYM capabilities -+ * - Never returned by GET_LINK as the value programmed into the MAC -+ */ -+#define MC_CMD_FCNTL_AUTO 3 -+ -+/* Generic mac fault bitmask */ -+#define MC_CMD_MAC_FAULT_XGMII_LOCAL_LBN 0 -+#define MC_CMD_MAC_FAULT_XGMII_LOCAL_WIDTH 1 -+#define MC_CMD_MAC_FAULT_XGMII_REMOTE_LBN 1 -+#define MC_CMD_MAC_FAULT_XGMII_REMOTE_WIDTH 1 -+#define MC_CMD_MAC_FAULT_SGMII_REMOTE_LBN 2 -+#define MC_CMD_MAC_FAULT_SGMII_REMOTE_WIDTH 1 -+ -+/* MC_CMD_GET_LINK: -+ * Read the unified MAC/PHY link state -+ * -+ * Locks required: None -+ * Return code: 0, ETIME -+ */ -+#define MC_CMD_GET_LINK 0x29 -+#define MC_CMD_GET_LINK_IN_LEN 0 -+#define MC_CMD_GET_LINK_OUT_LEN 28 -+/* near-side and link-partner advertised capabilities */ -+#define MC_CMD_GET_LINK_OUT_CAP_OFST 0 -+#define MC_CMD_GET_LINK_OUT_LP_CAP_OFST 4 -+/* Autonegotiated speed in mbit/s. The link may still be down -+ * even if this reads non-zero */ -+#define MC_CMD_GET_LINK_OUT_LINK_SPEED_OFST 8 -+#define MC_CMD_GET_LINK_OUT_LOOPBACK_MODE_OFST 12 -+#define MC_CMD_GET_LINK_OUT_FLAGS_OFST 16 -+/* Whether we have overall link up */ -+#define MC_CMD_GET_LINK_LINK_UP_LBN 0 -+#define MC_CMD_GET_LINK_LINK_UP_WIDTH 1 -+#define MC_CMD_GET_LINK_FULL_DUPLEX_LBN 1 -+#define MC_CMD_GET_LINK_FULL_DUPLEX_WIDTH 1 -+/* Whether we have link at the layers provided by the BPX */ -+#define MC_CMD_GET_LINK_BPX_LINK_LBN 2 -+#define MC_CMD_GET_LINK_BPX_LINK_WIDTH 1 -+/* Whether the PHY has external link */ -+#define MC_CMD_GET_LINK_PHY_LINK_LBN 3 -+#define MC_CMD_GET_LINK_PHY_LINK_WIDTH 1 -+#define MC_CMD_GET_LINK_OUT_FCNTL_OFST 20 -+#define MC_CMD_GET_LINK_OUT_MAC_FAULT_OFST 24 -+ -+/* MC_CMD_SET_LINK: -+ * Write the unified MAC/PHY link configuration -+ * -+ * A loopback speed of "0" is supported, and means -+ * (choose any available speed) -+ * -+ * Locks required: None -+ * Return code: 0, EINVAL, ETIME -+ */ -+#define MC_CMD_SET_LINK 0x2a -+#define MC_CMD_SET_LINK_IN_LEN 16 -+#define MC_CMD_SET_LINK_IN_CAP_OFST 0 -+#define MC_CMD_SET_LINK_IN_FLAGS_OFST 4 -+#define MC_CMD_SET_LINK_LOWPOWER_LBN 0 -+#define MC_CMD_SET_LINK_LOWPOWER_WIDTH 1 -+#define MC_CMD_SET_LINK_POWEROFF_LBN 1 -+#define MC_CMD_SET_LINK_POWEROFF_WIDTH 1 -+#define MC_CMD_SET_LINK_TXDIS_LBN 2 -+#define MC_CMD_SET_LINK_TXDIS_WIDTH 1 -+#define MC_CMD_SET_LINK_IN_LOOPBACK_MODE_OFST 8 -+#define MC_CMD_SET_LINK_IN_LOOPBACK_SPEED_OFST 12 -+#define MC_CMD_SET_LINK_OUT_LEN 0 -+ -+/* MC_CMD_SET_ID_LED: -+ * Set indentification LED state -+ * -+ * Locks required: None -+ * Return code: 0, EINVAL -+ */ -+#define MC_CMD_SET_ID_LED 0x2b -+#define MC_CMD_SET_ID_LED_IN_LEN 4 -+#define MC_CMD_SET_ID_LED_IN_STATE_OFST 0 -+#define MC_CMD_LED_OFF 0 -+#define MC_CMD_LED_ON 1 -+#define MC_CMD_LED_DEFAULT 2 -+#define MC_CMD_SET_ID_LED_OUT_LEN 0 -+ -+/* MC_CMD_SET_MAC: -+ * Set MAC configuration -+ * -+ * The MTU is the MTU programmed directly into the XMAC/GMAC -+ * (inclusive of EtherII, VLAN, bug16011 padding) -+ * -+ * Locks required: None -+ * Return code: 0, EINVAL -+ */ -+#define MC_CMD_SET_MAC 0x2c -+#define MC_CMD_SET_MAC_IN_LEN 24 -+#define MC_CMD_SET_MAC_IN_MTU_OFST 0 -+#define MC_CMD_SET_MAC_IN_DRAIN_OFST 4 -+#define MC_CMD_SET_MAC_IN_ADDR_OFST 8 -+#define MC_CMD_SET_MAC_IN_REJECT_OFST 16 -+#define MC_CMD_SET_MAC_IN_REJECT_UNCST_LBN 0 -+#define MC_CMD_SET_MAC_IN_REJECT_UNCST_WIDTH 1 -+#define MC_CMD_SET_MAC_IN_REJECT_BRDCST_LBN 1 -+#define MC_CMD_SET_MAC_IN_REJECT_BRDCST_WIDTH 1 -+#define MC_CMD_SET_MAC_IN_FCNTL_OFST 20 -+#define MC_CMD_SET_MAC_OUT_LEN 0 -+ -+/* MC_CMD_PHY_STATS: -+ * Get generic PHY statistics -+ * -+ * This call returns the statistics for a generic PHY, by direct DMA -+ * into host memory, in a sparse array (indexed by the enumerate). -+ * Each value is represented by a 32bit number. -+ * -+ * Locks required: None -+ * Returns: 0, ETIME -+ * Response methods: shared memory, event -+ */ -+#define MC_CMD_PHY_STATS 0x2d -+#define MC_CMD_PHY_STATS_IN_LEN 8 -+#define MC_CMD_PHY_STATS_IN_DMA_ADDR_LO_OFST 0 -+#define MC_CMD_PHY_STATS_IN_DMA_ADDR_HI_OFST 4 -+#define MC_CMD_PHY_STATS_OUT_LEN 0 -+ -+/* Unified MAC statistics enumeration */ -+#define MC_CMD_MAC_GENERATION_START 0 -+#define MC_CMD_MAC_TX_PKTS 1 -+#define MC_CMD_MAC_TX_PAUSE_PKTS 2 -+#define MC_CMD_MAC_TX_CONTROL_PKTS 3 -+#define MC_CMD_MAC_TX_UNICAST_PKTS 4 -+#define MC_CMD_MAC_TX_MULTICAST_PKTS 5 -+#define MC_CMD_MAC_TX_BROADCAST_PKTS 6 -+#define MC_CMD_MAC_TX_BYTES 7 -+#define MC_CMD_MAC_TX_BAD_BYTES 8 -+#define MC_CMD_MAC_TX_LT64_PKTS 9 -+#define MC_CMD_MAC_TX_64_PKTS 10 -+#define MC_CMD_MAC_TX_65_TO_127_PKTS 11 -+#define MC_CMD_MAC_TX_128_TO_255_PKTS 12 -+#define MC_CMD_MAC_TX_256_TO_511_PKTS 13 -+#define MC_CMD_MAC_TX_512_TO_1023_PKTS 14 -+#define MC_CMD_MAC_TX_1024_TO_15XX_PKTS 15 -+#define MC_CMD_MAC_TX_15XX_TO_JUMBO_PKTS 16 -+#define MC_CMD_MAC_TX_GTJUMBO_PKTS 17 -+#define MC_CMD_MAC_TX_BAD_FCS_PKTS 18 -+#define MC_CMD_MAC_TX_SINGLE_COLLISION_PKTS 19 -+#define MC_CMD_MAC_TX_MULTIPLE_COLLISION_PKTS 20 -+#define MC_CMD_MAC_TX_EXCESSIVE_COLLISION_PKTS 21 -+#define MC_CMD_MAC_TX_LATE_COLLISION_PKTS 22 -+#define MC_CMD_MAC_TX_DEFERRED_PKTS 23 -+#define MC_CMD_MAC_TX_EXCESSIVE_DEFERRED_PKTS 24 -+#define MC_CMD_MAC_TX_NON_TCPUDP_PKTS 25 -+#define MC_CMD_MAC_TX_MAC_SRC_ERR_PKTS 26 -+#define MC_CMD_MAC_TX_IP_SRC_ERR_PKTS 27 -+#define MC_CMD_MAC_RX_PKTS 28 -+#define MC_CMD_MAC_RX_PAUSE_PKTS 29 -+#define MC_CMD_MAC_RX_GOOD_PKTS 30 -+#define MC_CMD_MAC_RX_CONTROL_PKTS 31 -+#define MC_CMD_MAC_RX_UNICAST_PKTS 32 -+#define MC_CMD_MAC_RX_MULTICAST_PKTS 33 -+#define MC_CMD_MAC_RX_BROADCAST_PKTS 34 -+#define MC_CMD_MAC_RX_BYTES 35 -+#define MC_CMD_MAC_RX_BAD_BYTES 36 -+#define MC_CMD_MAC_RX_64_PKTS 37 -+#define MC_CMD_MAC_RX_65_TO_127_PKTS 38 -+#define MC_CMD_MAC_RX_128_TO_255_PKTS 39 -+#define MC_CMD_MAC_RX_256_TO_511_PKTS 40 -+#define MC_CMD_MAC_RX_512_TO_1023_PKTS 41 -+#define MC_CMD_MAC_RX_1024_TO_15XX_PKTS 42 -+#define MC_CMD_MAC_RX_15XX_TO_JUMBO_PKTS 43 -+#define MC_CMD_MAC_RX_GTJUMBO_PKTS 44 -+#define MC_CMD_MAC_RX_UNDERSIZE_PKTS 45 -+#define MC_CMD_MAC_RX_BAD_FCS_PKTS 46 -+#define MC_CMD_MAC_RX_OVERFLOW_PKTS 47 -+#define MC_CMD_MAC_RX_FALSE_CARRIER_PKTS 48 -+#define MC_CMD_MAC_RX_SYMBOL_ERROR_PKTS 49 -+#define MC_CMD_MAC_RX_ALIGN_ERROR_PKTS 50 -+#define MC_CMD_MAC_RX_LENGTH_ERROR_PKTS 51 -+#define MC_CMD_MAC_RX_INTERNAL_ERROR_PKTS 52 -+#define MC_CMD_MAC_RX_JABBER_PKTS 53 -+#define MC_CMD_MAC_RX_NODESC_DROPS 54 -+#define MC_CMD_MAC_RX_LANES01_CHAR_ERR 55 -+#define MC_CMD_MAC_RX_LANES23_CHAR_ERR 56 -+#define MC_CMD_MAC_RX_LANES01_DISP_ERR 57 -+#define MC_CMD_MAC_RX_LANES23_DISP_ERR 58 -+#define MC_CMD_MAC_RX_MATCH_FAULT 59 -+/* Insert new members here. */ -+#define MC_CMD_MAC_GENERATION_END 60 -+#define MC_CMD_MAC_NSTATS (MC_CMD_MAC_GENERATION_END+1) -+ -+/* MC_CMD_MAC_STATS: -+ * Get unified GMAC/XMAC statistics -+ * -+ * This call returns unified statistics maintained by the MC as it -+ * switches between the GMAC and XMAC. The MC will write out all -+ * supported stats. The driver should zero initialise the buffer to -+ * guarantee consistent results. -+ * -+ * Locks required: None -+ * Returns: 0 -+ * Response methods: shared memory, event -+ */ -+#define MC_CMD_MAC_STATS 0x2e -+#define MC_CMD_MAC_STATS_IN_LEN 16 -+#define MC_CMD_MAC_STATS_IN_DMA_ADDR_LO_OFST 0 -+#define MC_CMD_MAC_STATS_IN_DMA_ADDR_HI_OFST 4 -+#define MC_CMD_MAC_STATS_IN_CMD_OFST 8 -+#define MC_CMD_MAC_STATS_CMD_DMA_LBN 0 -+#define MC_CMD_MAC_STATS_CMD_DMA_WIDTH 1 -+#define MC_CMD_MAC_STATS_CMD_CLEAR_LBN 1 -+#define MC_CMD_MAC_STATS_CMD_CLEAR_WIDTH 1 -+#define MC_CMD_MAC_STATS_CMD_PERIODIC_CHANGE_LBN 2 -+#define MC_CMD_MAC_STATS_CMD_PERIODIC_CHANGE_WIDTH 1 -+/* Fields only relevent when PERIODIC_CHANGE is set */ -+#define MC_CMD_MAC_STATS_CMD_PERIODIC_ENABLE_LBN 3 -+#define MC_CMD_MAC_STATS_CMD_PERIODIC_ENABLE_WIDTH 1 -+#define MC_CMD_MAC_STATS_CMD_PERIODIC_CLEAR_LBN 4 -+#define MC_CMD_MAC_STATS_CMD_PERIODIC_CLEAR_WIDTH 1 -+#define MC_CMD_MAC_STATS_CMD_PERIOD_MS_LBN 16 -+#define MC_CMD_MAC_STATS_CMD_PERIOD_MS_WIDTH 16 -+#define MC_CMD_MAC_STATS_IN_DMA_LEN_OFST 12 -+ -+#define MC_CMD_MAC_STATS_OUT_LEN 0 -+ -+/* Callisto flags */ -+#define MC_CMD_SFT9001_ROBUST_LBN 0 -+#define MC_CMD_SFT9001_ROBUST_WIDTH 1 -+#define MC_CMD_SFT9001_SHORT_REACH_LBN 1 -+#define MC_CMD_SFT9001_SHORT_REACH_WIDTH 1 -+ -+/* MC_CMD_SFT9001_GET: -+ * Read current callisto specific setting -+ * -+ * Locks required: None -+ * Returns: 0, ETIME -+ */ -+#define MC_CMD_SFT9001_GET 0x30 -+#define MC_CMD_SFT9001_GET_IN_LEN 0 -+#define MC_CMD_SFT9001_GET_OUT_LEN 4 -+#define MC_CMD_SFT9001_GET_OUT_FLAGS_OFST 0 -+ -+/* MC_CMD_SFT9001_SET: -+ * Write current callisto specific setting -+ * -+ * Locks required: None -+ * Returns: 0, ETIME, EINVAL -+ */ -+#define MC_CMD_SFT9001_SET 0x31 -+#define MC_CMD_SFT9001_SET_IN_LEN 4 -+#define MC_CMD_SFT9001_SET_IN_FLAGS_OFST 0 -+#define MC_CMD_SFT9001_SET_OUT_LEN 0 -+ -+ -+/* MC_CMD_WOL_FILTER_SET: -+ * Set a WoL filter -+ * -+ * Locks required: None -+ * Returns: 0, EBUSY, EINVAL, ENOSYS -+ */ -+#define MC_CMD_WOL_FILTER_SET 0x32 -+#define MC_CMD_WOL_FILTER_SET_IN_LEN 192 /* 190 rounded up to a word */ -+#define MC_CMD_WOL_FILTER_SET_IN_FILTER_MODE_OFST 0 -+#define MC_CMD_WOL_FILTER_SET_IN_WOL_TYPE_OFST 4 -+ -+/* There is a union at offset 8, following defines overlap due to -+ * this */ -+#define MC_CMD_WOL_FILTER_SET_IN_DATA_OFST 8 -+ -+#define MC_CMD_WOL_FILTER_SET_IN_MAGIC_MAC_OFST \ -+ MC_CMD_WOL_FILTER_SET_IN_DATA_OFST -+ -+#define MC_CMD_WOL_FILTER_SET_IN_IPV4_SYN_SRC_IP_OFST \ -+ MC_CMD_WOL_FILTER_SET_IN_DATA_OFST -+#define MC_CMD_WOL_FILTER_SET_IN_IPV4_SYN_DST_IP_OFST \ -+ (MC_CMD_WOL_FILTER_SET_IN_DATA_OFST + 4) -+#define MC_CMD_WOL_FILTER_SET_IN_IPV4_SYN_SRC_PORT_OFST \ -+ (MC_CMD_WOL_FILTER_SET_IN_DATA_OFST + 8) -+#define MC_CMD_WOL_FILTER_SET_IN_IPV4_SYN_DST_PORT_OFST \ -+ (MC_CMD_WOL_FILTER_SET_IN_DATA_OFST + 10) -+ -+#define MC_CMD_WOL_FILTER_SET_IN_IPV6_SYN_SRC_IP_OFST \ -+ MC_CMD_WOL_FILTER_SET_IN_DATA_OFST -+#define MC_CMD_WOL_FILTER_SET_IN_IPV6_SYN_DST_IP_OFST \ -+ (MC_CMD_WOL_FILTER_SET_IN_DATA_OFST + 16) -+#define MC_CMD_WOL_FILTER_SET_IN_IPV6_SYN_SRC_PORT_OFST \ -+ (MC_CMD_WOL_FILTER_SET_IN_DATA_OFST + 32) -+#define MC_CMD_WOL_FILTER_SET_IN_IPV6_SYN_DST_PORT_OFST \ -+ (MC_CMD_WOL_FILTER_SET_IN_DATA_OFST + 34) -+ -+#define MC_CMD_WOL_FILTER_SET_IN_BITMAP_MASK_OFST \ -+ MC_CMD_WOL_FILTER_SET_IN_DATA_OFST -+#define MC_CMD_WOL_FILTER_SET_IN_BITMAP_OFST \ -+ (MC_CMD_WOL_FILTER_SET_IN_DATA_OFST + 48) -+#define MC_CMD_WOL_FILTER_SET_IN_BITMAP_LEN_OFST \ -+ (MC_CMD_WOL_FILTER_SET_IN_DATA_OFST + 176) -+#define MC_CMD_WOL_FILTER_SET_IN_BITMAP_LAYER3_OFST \ -+ (MC_CMD_WOL_FILTER_SET_IN_DATA_OFST + 177) -+#define MC_CMD_WOL_FILTER_SET_IN_BITMAP_LAYER4_OFST \ -+ (MC_CMD_WOL_FILTER_SET_IN_DATA_OFST + 178) -+ -+#define MC_CMD_WOL_FILTER_SET_OUT_LEN 4 -+#define MC_CMD_WOL_FILTER_SET_OUT_FILTER_ID_OFST 0 -+ -+/* WOL Filter types enumeration */ -+#define MC_CMD_WOL_TYPE_MAGIC 0x0 -+ /* unused 0x1 */ -+#define MC_CMD_WOL_TYPE_WIN_MAGIC 0x2 -+#define MC_CMD_WOL_TYPE_IPV4_SYN 0x3 -+#define MC_CMD_WOL_TYPE_IPV6_SYN 0x4 -+#define MC_CMD_WOL_TYPE_BITMAP 0x5 -+#define MC_CMD_WOL_TYPE_MAX 0x6 -+ -+#define MC_CMD_FILTER_MODE_SIMPLE 0x0 -+#define MC_CMD_FILTER_MODE_STRUCTURED 0xffffffff -+ -+/* MC_CMD_WOL_FILTER_REMOVE: -+ * Remove a WoL filter -+ * -+ * Locks required: None -+ * Returns: 0, EINVAL, ENOSYS -+ */ -+#define MC_CMD_WOL_FILTER_REMOVE 0x33 -+#define MC_CMD_WOL_FILTER_REMOVE_IN_LEN 4 -+#define MC_CMD_WOL_FILTER_REMOVE_IN_FILTER_ID_OFST 0 -+#define MC_CMD_WOL_FILTER_REMOVE_OUT_LEN 0 -+ -+ -+/* MC_CMD_WOL_FILTER_RESET: -+ * Reset (i.e. remove all) WoL filters -+ * -+ * Locks required: None -+ * Returns: 0, ENOSYS -+ */ -+#define MC_CMD_WOL_FILTER_RESET 0x34 -+#define MC_CMD_WOL_FILTER_RESET_IN_LEN 0 -+#define MC_CMD_WOL_FILTER_RESET_OUT_LEN 0 -+ -+/* MC_CMD_SET_MCAST_HASH: -+ * Set the MCASH hash value without otherwise -+ * reconfiguring the MAC -+ */ -+#define MC_CMD_SET_MCAST_HASH 0x35 -+#define MC_CMD_SET_MCAST_HASH_IN_LEN 32 -+#define MC_CMD_SET_MCAST_HASH_IN_HASH0_OFST 0 -+#define MC_CMD_SET_MCAST_HASH_IN_HASH1_OFST 16 -+#define MC_CMD_SET_MCAST_HASH_OUT_LEN 0 -+ -+/* MC_CMD_NVRAM_TYPES: -+ * Return bitfield indicating available types of virtual NVRAM partitions -+ * -+ * Locks required: none -+ * Returns: 0 -+ */ -+#define MC_CMD_NVRAM_TYPES 0x36 -+#define MC_CMD_NVRAM_TYPES_IN_LEN 0 -+#define MC_CMD_NVRAM_TYPES_OUT_LEN 4 -+#define MC_CMD_NVRAM_TYPES_OUT_TYPES_OFST 0 -+ -+/* Supported NVRAM types */ -+#define MC_CMD_NVRAM_TYPE_DISABLED_CALLISTO 0 -+#define MC_CMD_NVRAM_TYPE_MC_FW 1 -+#define MC_CMD_NVRAM_TYPE_MC_FW_BACKUP 2 -+#define MC_CMD_NVRAM_TYPE_STATIC_CFG_PORT0 3 -+#define MC_CMD_NVRAM_TYPE_STATIC_CFG_PORT1 4 -+#define MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT0 5 -+#define MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT1 6 -+#define MC_CMD_NVRAM_TYPE_EXP_ROM 7 -+#define MC_CMD_NVRAM_TYPE_EXP_ROM_CFG_PORT0 8 -+#define MC_CMD_NVRAM_TYPE_EXP_ROM_CFG_PORT1 9 -+#define MC_CMD_NVRAM_TYPE_PHY_PORT0 10 -+#define MC_CMD_NVRAM_TYPE_PHY_PORT1 11 -+#define MC_CMD_NVRAM_TYPE_LOG 12 -+ -+/* MC_CMD_NVRAM_INFO: -+ * Read info about a virtual NVRAM partition -+ * -+ * Locks required: none -+ * Returns: 0, EINVAL (bad type) -+ */ -+#define MC_CMD_NVRAM_INFO 0x37 -+#define MC_CMD_NVRAM_INFO_IN_LEN 4 -+#define MC_CMD_NVRAM_INFO_IN_TYPE_OFST 0 -+#define MC_CMD_NVRAM_INFO_OUT_LEN 24 -+#define MC_CMD_NVRAM_INFO_OUT_TYPE_OFST 0 -+#define MC_CMD_NVRAM_INFO_OUT_SIZE_OFST 4 -+#define MC_CMD_NVRAM_INFO_OUT_ERASESIZE_OFST 8 -+#define MC_CMD_NVRAM_INFO_OUT_FLAGS_OFST 12 -+#define MC_CMD_NVRAM_PROTECTED_LBN 0 -+#define MC_CMD_NVRAM_PROTECTED_WIDTH 1 -+#define MC_CMD_NVRAM_INFO_OUT_PHYSDEV_OFST 16 -+#define MC_CMD_NVRAM_INFO_OUT_PHYSADDR_OFST 20 -+ -+/* MC_CMD_NVRAM_UPDATE_START: -+ * Start a group of update operations on a virtual NVRAM partition -+ * -+ * Locks required: PHY_LOCK if type==*PHY* -+ * Returns: 0, EINVAL (bad type), EACCES (if PHY_LOCK required and not held) -+ */ -+#define MC_CMD_NVRAM_UPDATE_START 0x38 -+#define MC_CMD_NVRAM_UPDATE_START_IN_LEN 4 -+#define MC_CMD_NVRAM_UPDATE_START_IN_TYPE_OFST 0 -+#define MC_CMD_NVRAM_UPDATE_START_OUT_LEN 0 -+ -+/* MC_CMD_NVRAM_READ: -+ * Read data from a virtual NVRAM partition -+ * -+ * Locks required: PHY_LOCK if type==*PHY* -+ * Returns: 0, EINVAL (bad type/offset/length), EACCES (if PHY_LOCK required and not held) -+ */ -+#define MC_CMD_NVRAM_READ 0x39 -+#define MC_CMD_NVRAM_READ_IN_LEN 12 -+#define MC_CMD_NVRAM_READ_IN_TYPE_OFST 0 -+#define MC_CMD_NVRAM_READ_IN_OFFSET_OFST 4 -+#define MC_CMD_NVRAM_READ_IN_LENGTH_OFST 8 -+#define MC_CMD_NVRAM_READ_OUT_LEN(_read_bytes) (_read_bytes) -+#define MC_CMD_NVRAM_READ_OUT_READ_BUFFER_OFST 0 -+ -+/* MC_CMD_NVRAM_WRITE: -+ * Write data to a virtual NVRAM partition -+ * -+ * Locks required: PHY_LOCK if type==*PHY* -+ * Returns: 0, EINVAL (bad type/offset/length), EACCES (if PHY_LOCK required and not held) -+ */ -+#define MC_CMD_NVRAM_WRITE 0x3a -+#define MC_CMD_NVRAM_WRITE_IN_TYPE_OFST 0 -+#define MC_CMD_NVRAM_WRITE_IN_OFFSET_OFST 4 -+#define MC_CMD_NVRAM_WRITE_IN_LENGTH_OFST 8 -+#define MC_CMD_NVRAM_WRITE_IN_WRITE_BUFFER_OFST 12 -+#define MC_CMD_NVRAM_WRITE_IN_LEN(_write_bytes) (12 + _write_bytes) -+#define MC_CMD_NVRAM_WRITE_OUT_LEN 0 -+ -+/* MC_CMD_NVRAM_ERASE: -+ * Erase sector(s) from a virtual NVRAM partition -+ * -+ * Locks required: PHY_LOCK if type==*PHY* -+ * Returns: 0, EINVAL (bad type/offset/length), EACCES (if PHY_LOCK required and not held) -+ */ -+#define MC_CMD_NVRAM_ERASE 0x3b -+#define MC_CMD_NVRAM_ERASE_IN_LEN 12 -+#define MC_CMD_NVRAM_ERASE_IN_TYPE_OFST 0 -+#define MC_CMD_NVRAM_ERASE_IN_OFFSET_OFST 4 -+#define MC_CMD_NVRAM_ERASE_IN_LENGTH_OFST 8 -+#define MC_CMD_NVRAM_ERASE_OUT_LEN 0 -+ -+/* MC_CMD_NVRAM_UPDATE_FINISH: -+ * Finish a group of update operations on a virtual NVRAM partition -+ * -+ * Locks required: PHY_LOCK if type==*PHY* -+ * Returns: 0, EINVAL (bad type/offset/length), EACCES (if PHY_LOCK required and not held) -+ */ -+#define MC_CMD_NVRAM_UPDATE_FINISH 0x3c -+#define MC_CMD_NVRAM_UPDATE_FINISH_IN_LEN 4 -+#define MC_CMD_NVRAM_UPDATE_FINISH_IN_TYPE_OFST 0 -+#define MC_CMD_NVRAM_UPDATE_FINISH_OUT_LEN 0 -+ -+/* MC_CMD_REBOOT: -+ * Reboot the MC. The AFTER_ASSERTION flag is intended to be used -+ * when the driver notices an assertion failure, to allow two ports to -+ * both recover (semi-)gracefully. -+ * -+ * Locks required: NONE -+ * Returns: Nothing. You get back a response with ERR=1, DATALEN=0 -+ */ -+#define MC_CMD_REBOOT 0x3d -+#define MC_CMD_REBOOT_IN_LEN 4 -+#define MC_CMD_REBOOT_IN_FLAGS_OFST 0 -+#define MC_CMD_REBOOT_FLAGS_AFTER_ASSERTION 1 -+#define MC_CMD_REBOOT_OUT_LEN 0 -+ -+/* MC_CMD_SCHEDINFO: -+ * Request scheduler info. from the MC. -+ * -+ * Locks required: NONE -+ * Returns: An array of (timeslice,maximum overrun), one for each thread, -+ * in ascending order of thread address.s -+ */ -+#define MC_CMD_SCHEDINFO 0x3e -+#define MC_CMD_SCHEDINFO_IN_LEN 0 -+ -+ -+/* MC_CMD_SET_REBOOT_MODE: (debug) -+ * Set the mode for the next MC reboot. -+ * -+ * Locks required: NONE -+ * -+ * Sets the reboot mode to the specified value. Returns the old mode. -+ */ -+#define MC_CMD_REBOOT_MODE 0x3f -+#define MC_CMD_REBOOT_MODE_IN_LEN 4 -+#define MC_CMD_REBOOT_MODE_IN_VALUE_OFST 0 -+#define MC_CMD_REBOOT_MODE_OUT_LEN 4 -+#define MC_CMD_REBOOT_MODE_OUT_VALUE_OFST 0 -+#define MC_CMD_REBOOT_MODE_NORMAL 0 -+#define MC_CMD_REBOOT_MODE_SNAPPER 3 -+ -+/* MC_CMD_DEBUG_LOG: -+ * Null request/response command (debug) -+ * - sequence number is always zero -+ * - only supported on the UART interface -+ * (the same set of bytes is delivered as an -+ * event over PCI) -+ */ -+#define MC_CMD_DEBUG_LOG 0x40 -+#define MC_CMD_DEBUG_LOG_IN_LEN 0 -+#define MC_CMD_DEBUG_LOG_OUT_LEN 0 -+ -+/* Generic sensor enumeration. Note that a dual port NIC -+ * will EITHER expose PHY_COMMON_TEMP OR PHY0_TEMP and -+ * PHY1_TEMP depending on whether there is a single sensor -+ * in the vicinity of the two port, or one per port. -+ */ -+#define MC_CMD_SENSOR_CONTROLLER_TEMP 0 /* degC */ -+#define MC_CMD_SENSOR_PHY_COMMON_TEMP 1 /* degC */ -+#define MC_CMD_SENSOR_CONTROLLER_COOLING 2 /* bool */ -+#define MC_CMD_SENSOR_PHY0_TEMP 3 /* degC */ -+#define MC_CMD_SENSOR_PHY0_COOLING 4 /* bool */ -+#define MC_CMD_SENSOR_PHY1_TEMP 5 /* degC */ -+#define MC_CMD_SENSOR_PHY1_COOLING 6 /* bool */ -+#define MC_CMD_SENSOR_IN_1V0 7 /* mV */ -+#define MC_CMD_SENSOR_IN_1V2 8 /* mV */ -+#define MC_CMD_SENSOR_IN_1V8 9 /* mV */ -+#define MC_CMD_SENSOR_IN_2V5 10 /* mV */ -+#define MC_CMD_SENSOR_IN_3V3 11 /* mV */ -+#define MC_CMD_SENSOR_IN_12V0 12 /* mV */ -+ -+ -+/* Sensor state */ -+#define MC_CMD_SENSOR_STATE_OK 0 -+#define MC_CMD_SENSOR_STATE_WARNING 1 -+#define MC_CMD_SENSOR_STATE_FATAL 2 -+#define MC_CMD_SENSOR_STATE_BROKEN 3 -+ -+/* MC_CMD_SENSOR_INFO: -+ * Returns information about every available sensor. -+ * -+ * Each sensor has a single (16bit) value, and a corresponding state. -+ * The mapping between value and sensor is nominally determined by the -+ * MC, but in practise is implemented as zero (BROKEN), one (TEMPERATURE), -+ * or two (VOLTAGE) ranges per sensor per state. -+ * -+ * This call returns a mask (32bit) of the sensors that are supported -+ * by this platform, then an array (indexed by MC_CMD_SENSOR) of byte -+ * offsets to the per-sensor arrays. Each sensor array has four 16bit -+ * numbers, min1, max1, min2, max2. -+ * -+ * Locks required: None -+ * Returns: 0 -+ */ -+#define MC_CMD_SENSOR_INFO 0x41 -+#define MC_CMD_SENSOR_INFO_IN_LEN 0 -+#define MC_CMD_SENSOR_INFO_OUT_MASK_OFST 0 -+#define MC_CMD_SENSOR_INFO_OUT_OFFSET_OFST(_x) \ -+ (4 + (_x)) -+#define MC_CMD_SENSOR_INFO_OUT_MIN1_OFST(_ofst) \ -+ ((_ofst) + 0) -+#define MC_CMD_SENSOR_INFO_OUT_MAX1_OFST(_ofst) \ -+ ((_ofst) + 2) -+#define MC_CMD_SENSOR_INFO_OUT_MIN2_OFST(_ofst) \ -+ ((_ofst) + 4) -+#define MC_CMD_SENSOR_INFO_OUT_MAX2_OFST(_ofst) \ -+ ((_ofst) + 6) -+ -+/* MC_CMD_READ_SENSORS -+ * Returns the current (value, state) for each sensor -+ * -+ * Returns the current (value, state) [each 16bit] of each sensor supported by -+ * this board, by DMA'ing a sparse array (indexed by the sensor type) into host -+ * memory. -+ * -+ * The MC will send a SENSOREVT event every time any sensor changes state. The -+ * driver is responsible for ensuring that it doesn't miss any events. The board -+ * will function normally if all sensors are in STATE_OK or state_WARNING. -+ * Otherwise the board should not be expected to function. -+ */ -+#define MC_CMD_READ_SENSORS 0x42 -+#define MC_CMD_READ_SENSORS_IN_LEN 8 -+#define MC_CMD_READ_SENSORS_IN_DMA_ADDR_LO_OFST 0 -+#define MC_CMD_READ_SENSORS_IN_DMA_ADDR_HI_OFST 4 -+#define MC_CMD_READ_SENSORS_OUT_LEN 0 -+ -+ -+/* MC_CMD_GET_PHY_STATE: -+ * Report current state of PHY. A "zombie" PHY is a PHY that has failed to -+ * boot (e.g. due to missing or corrupted firmware). -+ * -+ * Locks required: None -+ * Return code: 0 -+ */ -+#define MC_CMD_GET_PHY_STATE 0x43 -+ -+#define MC_CMD_GET_PHY_STATE_IN_LEN 0 -+#define MC_CMD_GET_PHY_STATE_OUT_LEN 4 -+#define MC_CMD_GET_PHY_STATE_STATE_OFST 0 -+/* PHY state enumeration: */ -+#define MC_CMD_PHY_STATE_OK 1 -+#define MC_CMD_PHY_STATE_ZOMBIE 2 -+ -+ -+/* 802.1Qbb control. 8 Tx queues that map to priorities 0 - 7. Use all 1s to -+ * disable 802.Qbb for a given priority. */ -+#define MC_CMD_SETUP_8021QBB 0x44 -+#define MC_CMD_SETUP_8021QBB_IN_LEN 32 -+#define MC_CMD_SETUP_8021QBB_OUT_LEN 0 -+#define MC_CMD_SETUP_8021QBB_IN_TXQS_OFFST 0 -+ -+ -+/* MC_CMD_WOL_FILTER_GET: -+ * Retrieve ID of any WoL filters -+ * -+ * Locks required: None -+ * Returns: 0, ENOSYS -+ */ -+#define MC_CMD_WOL_FILTER_GET 0x45 -+#define MC_CMD_WOL_FILTER_GET_IN_LEN 0 -+#define MC_CMD_WOL_FILTER_GET_OUT_LEN 4 -+#define MC_CMD_WOL_FILTER_GET_OUT_FILTER_ID_OFST 0 -+ -+ -+/* MC_CMD_ADD_LIGHTSOUT_OFFLOAD: -+ * Offload a protocol to NIC for lights-out state -+ * -+ * Locks required: None -+ * Returns: 0, ENOSYS -+ */ -+#define MC_CMD_ADD_LIGHTSOUT_OFFLOAD 0x46 -+ -+#define MC_CMD_ADD_LIGHTSOUT_OFFLOAD_IN_LEN 16 -+#define MC_CMD_ADD_LIGHTSOUT_OFFLOAD_IN_PROTOCOL_OFST 0 -+ -+/* There is a union at offset 4, following defines overlap due to -+ * this */ -+#define MC_CMD_ADD_LIGHTSOUT_OFFLOAD_IN_DATA_OFST 4 -+#define MC_CMD_ADD_LIGHTSOUT_OFFLOAD_IN_ARPMAC_OFST 4 -+#define MC_CMD_ADD_LIGHTSOUT_OFFLOAD_IN_ARPIP_OFST 10 -+#define MC_CMD_ADD_LIGHTSOUT_OFFLOAD_IN_NSMAC_OFST 4 -+#define MC_CMD_ADD_LIGHTSOUT_OFFLOAD_IN_NSSNIPV6_OFST 10 -+#define MC_CMD_ADD_LIGHTSOUT_OFFLOAD_IN_NSIPV6_OFST 26 -+ -+#define MC_CMD_ADD_LIGHTSOUT_OFFLOAD_OUT_LEN 4 -+#define MC_CMD_ADD_LIGHTSOUT_OFFLOAD_OUT_FILTER_ID_OFST 0 -+ -+ -+/* MC_CMD_REMOVE_LIGHTSOUT_PROTOCOL_OFFLOAD: -+ * Offload a protocol to NIC for lights-out state -+ * -+ * Locks required: None -+ * Returns: 0, ENOSYS -+ */ -+#define MC_CMD_REMOVE_LIGHTSOUT_OFFLOAD 0x47 -+#define MC_CMD_REMOVE_LIGHTSOUT_OFFLOAD_IN_LEN 8 -+#define MC_CMD_REMOVE_LIGHTSOUT_OFFLOAD_OUT_LEN 0 -+ -+#define MC_CMD_REMOVE_LIGHTSOUT_OFFLOAD_IN_PROTOCOL_OFST 0 -+#define MC_CMD_REMOVE_LIGHTSOUT_OFFLOAD_IN_FILTER_ID_OFST 4 -+ -+/* Lights-out offload protocols enumeration */ -+#define MC_CMD_LIGHTSOUT_OFFLOAD_PROTOCOL_ARP 0x1 -+#define MC_CMD_LIGHTSOUT_OFFLOAD_PROTOCOL_NS 0x2 -+ -+ -+/* MC_CMD_MAC_RESET_RESTORE: -+ * Restore MAC after block reset -+ * -+ * Locks required: None -+ * Returns: 0 -+ */ -+ -+#define MC_CMD_MAC_RESET_RESTORE 0x48 -+#define MC_CMD_MAC_RESET_RESTORE_IN_LEN 0 -+#define MC_CMD_MAC_RESET_RESTORE_OUT_LEN 0 -+ -+#endif /* MCDI_PCOL_H */ -diff --git a/drivers/net/sfc/mcdi_phy.c b/drivers/net/sfc/mcdi_phy.c -new file mode 100644 -index 0000000..0e1bcc5 ---- /dev/null -+++ b/drivers/net/sfc/mcdi_phy.c -@@ -0,0 +1,597 @@ -+/**************************************************************************** -+ * Driver for Solarflare Solarstorm network controllers and boards -+ * Copyright 2009 Solarflare Communications Inc. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License version 2 as published -+ * by the Free Software Foundation, incorporated herein by reference. -+ */ -+ -+/* -+ * Driver for PHY related operations via MCDI. -+ */ -+ -+#include "efx.h" -+#include "phy.h" -+#include "mcdi.h" -+#include "mcdi_pcol.h" -+#include "mdio_10g.h" -+ -+struct efx_mcdi_phy_cfg { -+ u32 flags; -+ u32 type; -+ u32 supported_cap; -+ u32 channel; -+ u32 port; -+ u32 stats_mask; -+ u8 name[20]; -+ u32 media; -+ u32 mmd_mask; -+ u8 revision[20]; -+ u32 forced_cap; -+}; -+ -+static int -+efx_mcdi_get_phy_cfg(struct efx_nic *efx, struct efx_mcdi_phy_cfg *cfg) -+{ -+ u8 outbuf[MC_CMD_GET_PHY_CFG_OUT_LEN]; -+ size_t outlen; -+ int rc; -+ -+ BUILD_BUG_ON(MC_CMD_GET_PHY_CFG_IN_LEN != 0); -+ BUILD_BUG_ON(MC_CMD_GET_PHY_CFG_OUT_NAME_LEN != sizeof(cfg->name)); -+ -+ rc = efx_mcdi_rpc(efx, MC_CMD_GET_PHY_CFG, NULL, 0, -+ outbuf, sizeof(outbuf), &outlen); -+ if (rc) -+ goto fail; -+ -+ if (outlen < MC_CMD_GET_PHY_CFG_OUT_LEN) { -+ rc = -EMSGSIZE; -+ goto fail; -+ } -+ -+ cfg->flags = MCDI_DWORD(outbuf, GET_PHY_CFG_OUT_FLAGS); -+ cfg->type = MCDI_DWORD(outbuf, GET_PHY_CFG_OUT_TYPE); -+ cfg->supported_cap = -+ MCDI_DWORD(outbuf, GET_PHY_CFG_OUT_SUPPORTED_CAP); -+ cfg->channel = MCDI_DWORD(outbuf, GET_PHY_CFG_OUT_CHANNEL); -+ cfg->port = MCDI_DWORD(outbuf, GET_PHY_CFG_OUT_PRT); -+ cfg->stats_mask = MCDI_DWORD(outbuf, GET_PHY_CFG_OUT_STATS_MASK); -+ memcpy(cfg->name, MCDI_PTR(outbuf, GET_PHY_CFG_OUT_NAME), -+ sizeof(cfg->name)); -+ cfg->media = MCDI_DWORD(outbuf, GET_PHY_CFG_OUT_MEDIA_TYPE); -+ cfg->mmd_mask = MCDI_DWORD(outbuf, GET_PHY_CFG_OUT_MMD_MASK); -+ memcpy(cfg->revision, MCDI_PTR(outbuf, GET_PHY_CFG_OUT_REVISION), -+ sizeof(cfg->revision)); -+ -+ return 0; -+ -+fail: -+ EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc); -+ return rc; -+} -+ -+static int efx_mcdi_set_link(struct efx_nic *efx, u32 capabilities, -+ u32 flags, u32 loopback_mode, -+ u32 loopback_speed) -+{ -+ u8 inbuf[MC_CMD_SET_LINK_IN_LEN]; -+ int rc; -+ -+ BUILD_BUG_ON(MC_CMD_SET_LINK_OUT_LEN != 0); -+ -+ MCDI_SET_DWORD(inbuf, SET_LINK_IN_CAP, capabilities); -+ MCDI_SET_DWORD(inbuf, SET_LINK_IN_FLAGS, flags); -+ MCDI_SET_DWORD(inbuf, SET_LINK_IN_LOOPBACK_MODE, loopback_mode); -+ MCDI_SET_DWORD(inbuf, SET_LINK_IN_LOOPBACK_SPEED, loopback_speed); -+ -+ rc = efx_mcdi_rpc(efx, MC_CMD_SET_LINK, inbuf, sizeof(inbuf), -+ NULL, 0, NULL); -+ if (rc) -+ goto fail; -+ -+ return 0; -+ -+fail: -+ EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc); -+ return rc; -+} -+ -+static int efx_mcdi_loopback_modes(struct efx_nic *efx, u64 *loopback_modes) -+{ -+ u8 outbuf[MC_CMD_GET_LOOPBACK_MODES_OUT_LEN]; -+ size_t outlen; -+ int rc; -+ -+ rc = efx_mcdi_rpc(efx, MC_CMD_GET_LOOPBACK_MODES, NULL, 0, -+ outbuf, sizeof(outbuf), &outlen); -+ if (rc) -+ goto fail; -+ -+ if (outlen < MC_CMD_GET_LOOPBACK_MODES_OUT_LEN) { -+ rc = -EMSGSIZE; -+ goto fail; -+ } -+ -+ *loopback_modes = MCDI_QWORD(outbuf, GET_LOOPBACK_MODES_SUGGESTED); -+ -+ return 0; -+ -+fail: -+ EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc); -+ return rc; -+} -+ -+int efx_mcdi_mdio_read(struct efx_nic *efx, unsigned int bus, -+ unsigned int prtad, unsigned int devad, u16 addr, -+ u16 *value_out, u32 *status_out) -+{ -+ u8 inbuf[MC_CMD_MDIO_READ_IN_LEN]; -+ u8 outbuf[MC_CMD_MDIO_READ_OUT_LEN]; -+ size_t outlen; -+ int rc; -+ -+ MCDI_SET_DWORD(inbuf, MDIO_READ_IN_BUS, bus); -+ MCDI_SET_DWORD(inbuf, MDIO_READ_IN_PRTAD, prtad); -+ MCDI_SET_DWORD(inbuf, MDIO_READ_IN_DEVAD, devad); -+ MCDI_SET_DWORD(inbuf, MDIO_READ_IN_ADDR, addr); -+ -+ rc = efx_mcdi_rpc(efx, MC_CMD_MDIO_READ, inbuf, sizeof(inbuf), -+ outbuf, sizeof(outbuf), &outlen); -+ if (rc) -+ goto fail; -+ -+ *value_out = (u16)MCDI_DWORD(outbuf, MDIO_READ_OUT_VALUE); -+ *status_out = MCDI_DWORD(outbuf, MDIO_READ_OUT_STATUS); -+ return 0; -+ -+fail: -+ EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc); -+ return rc; -+} -+ -+int efx_mcdi_mdio_write(struct efx_nic *efx, unsigned int bus, -+ unsigned int prtad, unsigned int devad, u16 addr, -+ u16 value, u32 *status_out) -+{ -+ u8 inbuf[MC_CMD_MDIO_WRITE_IN_LEN]; -+ u8 outbuf[MC_CMD_MDIO_WRITE_OUT_LEN]; -+ size_t outlen; -+ int rc; -+ -+ MCDI_SET_DWORD(inbuf, MDIO_WRITE_IN_BUS, bus); -+ MCDI_SET_DWORD(inbuf, MDIO_WRITE_IN_PRTAD, prtad); -+ MCDI_SET_DWORD(inbuf, MDIO_WRITE_IN_DEVAD, devad); -+ MCDI_SET_DWORD(inbuf, MDIO_WRITE_IN_ADDR, addr); -+ MCDI_SET_DWORD(inbuf, MDIO_WRITE_IN_VALUE, value); -+ -+ rc = efx_mcdi_rpc(efx, MC_CMD_MDIO_WRITE, inbuf, sizeof(inbuf), -+ outbuf, sizeof(outbuf), &outlen); -+ if (rc) -+ goto fail; -+ -+ *status_out = MCDI_DWORD(outbuf, MDIO_WRITE_OUT_STATUS); -+ return 0; -+ -+fail: -+ EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc); -+ return rc; -+} -+ -+static u32 mcdi_to_ethtool_cap(u32 media, u32 cap) -+{ -+ u32 result = 0; -+ -+ switch (media) { -+ case MC_CMD_MEDIA_KX4: -+ result |= SUPPORTED_Backplane; -+ if (cap & (1 << MC_CMD_PHY_CAP_1000FDX_LBN)) -+ result |= SUPPORTED_1000baseKX_Full; -+ if (cap & (1 << MC_CMD_PHY_CAP_10000FDX_LBN)) -+ result |= SUPPORTED_10000baseKX4_Full; -+ break; -+ -+ case MC_CMD_MEDIA_XFP: -+ case MC_CMD_MEDIA_SFP_PLUS: -+ result |= SUPPORTED_FIBRE; -+ break; -+ -+ case MC_CMD_MEDIA_BASE_T: -+ result |= SUPPORTED_TP; -+ if (cap & (1 << MC_CMD_PHY_CAP_10HDX_LBN)) -+ result |= SUPPORTED_10baseT_Half; -+ if (cap & (1 << MC_CMD_PHY_CAP_10FDX_LBN)) -+ result |= SUPPORTED_10baseT_Full; -+ if (cap & (1 << MC_CMD_PHY_CAP_100HDX_LBN)) -+ result |= SUPPORTED_100baseT_Half; -+ if (cap & (1 << MC_CMD_PHY_CAP_100FDX_LBN)) -+ result |= SUPPORTED_100baseT_Full; -+ if (cap & (1 << MC_CMD_PHY_CAP_1000HDX_LBN)) -+ result |= SUPPORTED_1000baseT_Half; -+ if (cap & (1 << MC_CMD_PHY_CAP_1000FDX_LBN)) -+ result |= SUPPORTED_1000baseT_Full; -+ if (cap & (1 << MC_CMD_PHY_CAP_10000FDX_LBN)) -+ result |= SUPPORTED_10000baseT_Full; -+ break; -+ } -+ -+ if (cap & (1 << MC_CMD_PHY_CAP_PAUSE_LBN)) -+ result |= SUPPORTED_Pause; -+ if (cap & (1 << MC_CMD_PHY_CAP_ASYM_LBN)) -+ result |= SUPPORTED_Asym_Pause; -+ if (cap & (1 << MC_CMD_PHY_CAP_AN_LBN)) -+ result |= SUPPORTED_Autoneg; -+ -+ return result; -+} -+ -+static u32 ethtool_to_mcdi_cap(u32 cap) -+{ -+ u32 result = 0; -+ -+ if (cap & SUPPORTED_10baseT_Half) -+ result |= (1 << MC_CMD_PHY_CAP_10HDX_LBN); -+ if (cap & SUPPORTED_10baseT_Full) -+ result |= (1 << MC_CMD_PHY_CAP_10FDX_LBN); -+ if (cap & SUPPORTED_100baseT_Half) -+ result |= (1 << MC_CMD_PHY_CAP_100HDX_LBN); -+ if (cap & SUPPORTED_100baseT_Full) -+ result |= (1 << MC_CMD_PHY_CAP_100FDX_LBN); -+ if (cap & SUPPORTED_1000baseT_Half) -+ result |= (1 << MC_CMD_PHY_CAP_1000HDX_LBN); -+ if (cap & (SUPPORTED_1000baseT_Full | SUPPORTED_1000baseKX_Full)) -+ result |= (1 << MC_CMD_PHY_CAP_1000FDX_LBN); -+ if (cap & (SUPPORTED_10000baseT_Full | SUPPORTED_10000baseKX4_Full)) -+ result |= (1 << MC_CMD_PHY_CAP_10000FDX_LBN); -+ if (cap & SUPPORTED_Pause) -+ result |= (1 << MC_CMD_PHY_CAP_PAUSE_LBN); -+ if (cap & SUPPORTED_Asym_Pause) -+ result |= (1 << MC_CMD_PHY_CAP_ASYM_LBN); -+ if (cap & SUPPORTED_Autoneg) -+ result |= (1 << MC_CMD_PHY_CAP_AN_LBN); -+ -+ return result; -+} -+ -+static u32 efx_get_mcdi_phy_flags(struct efx_nic *efx) -+{ -+ struct efx_mcdi_phy_cfg *phy_cfg = efx->phy_data; -+ enum efx_phy_mode mode, supported; -+ u32 flags; -+ -+ /* TODO: Advertise the capabilities supported by this PHY */ -+ supported = 0; -+ if (phy_cfg->flags & (1 << MC_CMD_GET_PHY_CFG_TXDIS_LBN)) -+ supported |= PHY_MODE_TX_DISABLED; -+ if (phy_cfg->flags & (1 << MC_CMD_GET_PHY_CFG_LOWPOWER_LBN)) -+ supported |= PHY_MODE_LOW_POWER; -+ if (phy_cfg->flags & (1 << MC_CMD_GET_PHY_CFG_POWEROFF_LBN)) -+ supported |= PHY_MODE_OFF; -+ -+ mode = efx->phy_mode & supported; -+ -+ flags = 0; -+ if (mode & PHY_MODE_TX_DISABLED) -+ flags |= (1 << MC_CMD_SET_LINK_TXDIS_LBN); -+ if (mode & PHY_MODE_LOW_POWER) -+ flags |= (1 << MC_CMD_SET_LINK_LOWPOWER_LBN); -+ if (mode & PHY_MODE_OFF) -+ flags |= (1 << MC_CMD_SET_LINK_POWEROFF_LBN); -+ -+ return flags; -+} -+ -+static u32 mcdi_to_ethtool_media(u32 media) -+{ -+ switch (media) { -+ case MC_CMD_MEDIA_XAUI: -+ case MC_CMD_MEDIA_CX4: -+ case MC_CMD_MEDIA_KX4: -+ return PORT_OTHER; -+ -+ case MC_CMD_MEDIA_XFP: -+ case MC_CMD_MEDIA_SFP_PLUS: -+ return PORT_FIBRE; -+ -+ case MC_CMD_MEDIA_BASE_T: -+ return PORT_TP; -+ -+ default: -+ return PORT_OTHER; -+ } -+} -+ -+static int efx_mcdi_phy_probe(struct efx_nic *efx) -+{ -+ struct efx_mcdi_phy_cfg *phy_cfg; -+ int rc; -+ -+ /* TODO: Move phy_data initialisation to -+ * phy_op->probe/remove, rather than init/fini */ -+ phy_cfg = kzalloc(sizeof(*phy_cfg), GFP_KERNEL); -+ if (phy_cfg == NULL) { -+ rc = -ENOMEM; -+ goto fail_alloc; -+ } -+ rc = efx_mcdi_get_phy_cfg(efx, phy_cfg); -+ if (rc != 0) -+ goto fail; -+ -+ efx->phy_type = phy_cfg->type; -+ -+ efx->mdio_bus = phy_cfg->channel; -+ efx->mdio.prtad = phy_cfg->port; -+ efx->mdio.mmds = phy_cfg->mmd_mask & ~(1 << MC_CMD_MMD_CLAUSE22); -+ efx->mdio.mode_support = 0; -+ if (phy_cfg->mmd_mask & (1 << MC_CMD_MMD_CLAUSE22)) -+ efx->mdio.mode_support |= MDIO_SUPPORTS_C22; -+ if (phy_cfg->mmd_mask & ~(1 << MC_CMD_MMD_CLAUSE22)) -+ efx->mdio.mode_support |= MDIO_SUPPORTS_C45 | MDIO_EMULATE_C22; -+ -+ /* Assert that we can map efx -> mcdi loopback modes */ -+ BUILD_BUG_ON(LOOPBACK_NONE != MC_CMD_LOOPBACK_NONE); -+ BUILD_BUG_ON(LOOPBACK_DATA != MC_CMD_LOOPBACK_DATA); -+ BUILD_BUG_ON(LOOPBACK_GMAC != MC_CMD_LOOPBACK_GMAC); -+ BUILD_BUG_ON(LOOPBACK_XGMII != MC_CMD_LOOPBACK_XGMII); -+ BUILD_BUG_ON(LOOPBACK_XGXS != MC_CMD_LOOPBACK_XGXS); -+ BUILD_BUG_ON(LOOPBACK_XAUI != MC_CMD_LOOPBACK_XAUI); -+ BUILD_BUG_ON(LOOPBACK_GMII != MC_CMD_LOOPBACK_GMII); -+ BUILD_BUG_ON(LOOPBACK_SGMII != MC_CMD_LOOPBACK_SGMII); -+ BUILD_BUG_ON(LOOPBACK_XGBR != MC_CMD_LOOPBACK_XGBR); -+ BUILD_BUG_ON(LOOPBACK_XFI != MC_CMD_LOOPBACK_XFI); -+ BUILD_BUG_ON(LOOPBACK_XAUI_FAR != MC_CMD_LOOPBACK_XAUI_FAR); -+ BUILD_BUG_ON(LOOPBACK_GMII_FAR != MC_CMD_LOOPBACK_GMII_FAR); -+ BUILD_BUG_ON(LOOPBACK_SGMII_FAR != MC_CMD_LOOPBACK_SGMII_FAR); -+ BUILD_BUG_ON(LOOPBACK_XFI_FAR != MC_CMD_LOOPBACK_XFI_FAR); -+ BUILD_BUG_ON(LOOPBACK_GPHY != MC_CMD_LOOPBACK_GPHY); -+ BUILD_BUG_ON(LOOPBACK_PHYXS != MC_CMD_LOOPBACK_PHYXS); -+ BUILD_BUG_ON(LOOPBACK_PCS != MC_CMD_LOOPBACK_PCS); -+ BUILD_BUG_ON(LOOPBACK_PMAPMD != MC_CMD_LOOPBACK_PMAPMD); -+ BUILD_BUG_ON(LOOPBACK_XPORT != MC_CMD_LOOPBACK_XPORT); -+ BUILD_BUG_ON(LOOPBACK_XGMII_WS != MC_CMD_LOOPBACK_XGMII_WS); -+ BUILD_BUG_ON(LOOPBACK_XAUI_WS != MC_CMD_LOOPBACK_XAUI_WS); -+ BUILD_BUG_ON(LOOPBACK_XAUI_WS_FAR != MC_CMD_LOOPBACK_XAUI_WS_FAR); -+ BUILD_BUG_ON(LOOPBACK_XAUI_WS_NEAR != MC_CMD_LOOPBACK_XAUI_WS_NEAR); -+ BUILD_BUG_ON(LOOPBACK_GMII_WS != MC_CMD_LOOPBACK_GMII_WS); -+ BUILD_BUG_ON(LOOPBACK_XFI_WS != MC_CMD_LOOPBACK_XFI_WS); -+ BUILD_BUG_ON(LOOPBACK_XFI_WS_FAR != MC_CMD_LOOPBACK_XFI_WS_FAR); -+ BUILD_BUG_ON(LOOPBACK_PHYXS_WS != MC_CMD_LOOPBACK_PHYXS_WS); -+ -+ rc = efx_mcdi_loopback_modes(efx, &efx->loopback_modes); -+ if (rc != 0) -+ goto fail; -+ /* The MC indicates that LOOPBACK_NONE is a valid loopback mode, -+ * but by convention we don't */ -+ efx->loopback_modes &= ~(1 << LOOPBACK_NONE); -+ -+ kfree(phy_cfg); -+ -+ return 0; -+ -+fail: -+ kfree(phy_cfg); -+fail_alloc: -+ return rc; -+} -+ -+static int efx_mcdi_phy_init(struct efx_nic *efx) -+{ -+ struct efx_mcdi_phy_cfg *phy_data; -+ u8 outbuf[MC_CMD_GET_LINK_OUT_LEN]; -+ u32 caps; -+ int rc; -+ -+ phy_data = kzalloc(sizeof(*phy_data), GFP_KERNEL); -+ if (phy_data == NULL) -+ return -ENOMEM; -+ -+ rc = efx_mcdi_get_phy_cfg(efx, phy_data); -+ if (rc != 0) -+ goto fail; -+ -+ efx->phy_data = phy_data; -+ -+ BUILD_BUG_ON(MC_CMD_GET_LINK_IN_LEN != 0); -+ rc = efx_mcdi_rpc(efx, MC_CMD_GET_LINK, NULL, 0, -+ outbuf, sizeof(outbuf), NULL); -+ if (rc) -+ goto fail; -+ -+ caps = MCDI_DWORD(outbuf, GET_LINK_OUT_CAP); -+ if (caps & (1 << MC_CMD_PHY_CAP_AN_LBN)) -+ efx->link_advertising = -+ mcdi_to_ethtool_cap(phy_data->media, caps); -+ else -+ phy_data->forced_cap = caps; -+ -+ return 0; -+ -+fail: -+ kfree(phy_data); -+ return rc; -+} -+ -+int efx_mcdi_phy_reconfigure(struct efx_nic *efx) -+{ -+ struct efx_mcdi_phy_cfg *phy_cfg = efx->phy_data; -+ u32 caps = (efx->link_advertising ? -+ ethtool_to_mcdi_cap(efx->link_advertising) : -+ phy_cfg->forced_cap); -+ -+ return efx_mcdi_set_link(efx, caps, efx_get_mcdi_phy_flags(efx), -+ efx->loopback_mode, 0); -+} -+ -+void efx_mcdi_phy_decode_link(struct efx_nic *efx, -+ struct efx_link_state *link_state, -+ u32 speed, u32 flags, u32 fcntl) -+{ -+ switch (fcntl) { -+ case MC_CMD_FCNTL_AUTO: -+ WARN_ON(1); /* This is not a link mode */ -+ link_state->fc = EFX_FC_AUTO | EFX_FC_TX | EFX_FC_RX; -+ break; -+ case MC_CMD_FCNTL_BIDIR: -+ link_state->fc = EFX_FC_TX | EFX_FC_RX; -+ break; -+ case MC_CMD_FCNTL_RESPOND: -+ link_state->fc = EFX_FC_RX; -+ break; -+ default: -+ WARN_ON(1); -+ case MC_CMD_FCNTL_OFF: -+ link_state->fc = 0; -+ break; -+ } -+ -+ link_state->up = !!(flags & (1 << MC_CMD_GET_LINK_LINK_UP_LBN)); -+ link_state->fd = !!(flags & (1 << MC_CMD_GET_LINK_FULL_DUPLEX_LBN)); -+ link_state->speed = speed; -+} -+ -+/* Verify that the forced flow control settings (!EFX_FC_AUTO) are -+ * supported by the link partner. Warn the user if this isn't the case -+ */ -+void efx_mcdi_phy_check_fcntl(struct efx_nic *efx, u32 lpa) -+{ -+ struct efx_mcdi_phy_cfg *phy_cfg = efx->phy_data; -+ u32 rmtadv; -+ -+ /* The link partner capabilities are only relevent if the -+ * link supports flow control autonegotiation */ -+ if (~phy_cfg->supported_cap & (1 << MC_CMD_PHY_CAP_ASYM_LBN)) -+ return; -+ -+ /* If flow control autoneg is supported and enabled, then fine */ -+ if (efx->wanted_fc & EFX_FC_AUTO) -+ return; -+ -+ rmtadv = 0; -+ if (lpa & (1 << MC_CMD_PHY_CAP_PAUSE_LBN)) -+ rmtadv |= ADVERTISED_Pause; -+ if (lpa & (1 << MC_CMD_PHY_CAP_ASYM_LBN)) -+ rmtadv |= ADVERTISED_Asym_Pause; -+ -+ if ((efx->wanted_fc & EFX_FC_TX) && rmtadv == ADVERTISED_Asym_Pause) -+ EFX_ERR(efx, "warning: link partner doesn't support " -+ "pause frames"); -+} -+ -+static bool efx_mcdi_phy_poll(struct efx_nic *efx) -+{ -+ struct efx_link_state old_state = efx->link_state; -+ u8 outbuf[MC_CMD_GET_LINK_OUT_LEN]; -+ int rc; -+ -+ WARN_ON(!mutex_is_locked(&efx->mac_lock)); -+ -+ BUILD_BUG_ON(MC_CMD_GET_LINK_IN_LEN != 0); -+ -+ rc = efx_mcdi_rpc(efx, MC_CMD_GET_LINK, NULL, 0, -+ outbuf, sizeof(outbuf), NULL); -+ if (rc) { -+ EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc); -+ efx->link_state.up = false; -+ } else { -+ efx_mcdi_phy_decode_link( -+ efx, &efx->link_state, -+ MCDI_DWORD(outbuf, GET_LINK_OUT_LINK_SPEED), -+ MCDI_DWORD(outbuf, GET_LINK_OUT_FLAGS), -+ MCDI_DWORD(outbuf, GET_LINK_OUT_FCNTL)); -+ } -+ -+ return !efx_link_state_equal(&efx->link_state, &old_state); -+} -+ -+static void efx_mcdi_phy_fini(struct efx_nic *efx) -+{ -+ struct efx_mcdi_phy_data *phy_data = efx->phy_data; -+ -+ efx->phy_data = NULL; -+ kfree(phy_data); -+} -+ -+static void efx_mcdi_phy_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) -+{ -+ struct efx_mcdi_phy_cfg *phy_cfg = efx->phy_data; -+ u8 outbuf[MC_CMD_GET_LINK_OUT_LEN]; -+ int rc; -+ -+ ecmd->supported = -+ mcdi_to_ethtool_cap(phy_cfg->media, phy_cfg->supported_cap); -+ ecmd->advertising = efx->link_advertising; -+ ecmd->speed = efx->link_state.speed; -+ ecmd->duplex = efx->link_state.fd; -+ ecmd->port = mcdi_to_ethtool_media(phy_cfg->media); -+ ecmd->phy_address = phy_cfg->port; -+ ecmd->transceiver = XCVR_INTERNAL; -+ ecmd->autoneg = !!(efx->link_advertising & ADVERTISED_Autoneg); -+ ecmd->mdio_support = (efx->mdio.mode_support & -+ (MDIO_SUPPORTS_C45 | MDIO_SUPPORTS_C22)); -+ -+ BUILD_BUG_ON(MC_CMD_GET_LINK_IN_LEN != 0); -+ rc = efx_mcdi_rpc(efx, MC_CMD_GET_LINK, NULL, 0, -+ outbuf, sizeof(outbuf), NULL); -+ if (rc) { -+ EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc); -+ return; -+ } -+ ecmd->lp_advertising = -+ mcdi_to_ethtool_cap(phy_cfg->media, -+ MCDI_DWORD(outbuf, GET_LINK_OUT_LP_CAP)); -+} -+ -+static int efx_mcdi_phy_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) -+{ -+ struct efx_mcdi_phy_cfg *phy_cfg = efx->phy_data; -+ u32 caps; -+ int rc; -+ -+ if (ecmd->autoneg) { -+ caps = (ethtool_to_mcdi_cap(ecmd->advertising) | -+ 1 << MC_CMD_PHY_CAP_AN_LBN); -+ } else if (ecmd->duplex) { -+ switch (ecmd->speed) { -+ case 10: caps = 1 << MC_CMD_PHY_CAP_10FDX_LBN; break; -+ case 100: caps = 1 << MC_CMD_PHY_CAP_100FDX_LBN; break; -+ case 1000: caps = 1 << MC_CMD_PHY_CAP_1000FDX_LBN; break; -+ case 10000: caps = 1 << MC_CMD_PHY_CAP_10000FDX_LBN; break; -+ default: return -EINVAL; -+ } -+ } else { -+ switch (ecmd->speed) { -+ case 10: caps = 1 << MC_CMD_PHY_CAP_10HDX_LBN; break; -+ case 100: caps = 1 << MC_CMD_PHY_CAP_100HDX_LBN; break; -+ case 1000: caps = 1 << MC_CMD_PHY_CAP_1000HDX_LBN; break; -+ default: return -EINVAL; -+ } -+ } -+ -+ rc = efx_mcdi_set_link(efx, caps, efx_get_mcdi_phy_flags(efx), -+ efx->loopback_mode, 0); -+ if (rc) -+ return rc; -+ -+ if (ecmd->autoneg) { -+ efx_link_set_advertising( -+ efx, ecmd->advertising | ADVERTISED_Autoneg); -+ phy_cfg->forced_cap = 0; -+ } else { -+ efx_link_set_advertising(efx, 0); -+ phy_cfg->forced_cap = caps; -+ } -+ return 0; -+} -+ -+struct efx_phy_operations efx_mcdi_phy_ops = { -+ .probe = efx_mcdi_phy_probe, -+ .init = efx_mcdi_phy_init, -+ .reconfigure = efx_mcdi_phy_reconfigure, -+ .poll = efx_mcdi_phy_poll, -+ .fini = efx_mcdi_phy_fini, -+ .get_settings = efx_mcdi_phy_get_settings, -+ .set_settings = efx_mcdi_phy_set_settings, -+ .run_tests = NULL, -+ .test_name = NULL, -+}; -diff --git a/drivers/net/sfc/mdio_10g.c b/drivers/net/sfc/mdio_10g.c -index 6c33459..1574e52 100644 ---- a/drivers/net/sfc/mdio_10g.c -+++ b/drivers/net/sfc/mdio_10g.c -@@ -1,6 +1,6 @@ - /**************************************************************************** - * Driver for Solarflare Solarstorm network controllers and boards -- * Copyright 2006-2008 Solarflare Communications Inc. -+ * Copyright 2006-2009 Solarflare Communications Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published -@@ -14,8 +14,8 @@ - #include - #include "net_driver.h" - #include "mdio_10g.h" --#include "boards.h" - #include "workarounds.h" -+#include "nic.h" - - unsigned efx_mdio_id_oui(u32 id) - { -@@ -174,7 +174,7 @@ bool efx_mdio_links_ok(struct efx_nic *efx, unsigned int mmd_mask) - * of mmd's */ - if (LOOPBACK_INTERNAL(efx)) - return true; -- else if (efx->loopback_mode == LOOPBACK_NETWORK) -+ else if (LOOPBACK_MASK(efx) & LOOPBACKS_WS) - return false; - else if (efx_phy_mode_disabled(efx->phy_mode)) - return false; -@@ -211,7 +211,7 @@ void efx_mdio_phy_reconfigure(struct efx_nic *efx) - efx->loopback_mode == LOOPBACK_PCS); - efx_mdio_set_flag(efx, MDIO_MMD_PHYXS, - MDIO_CTRL1, MDIO_PHYXS_CTRL1_LOOPBACK, -- efx->loopback_mode == LOOPBACK_NETWORK); -+ efx->loopback_mode == LOOPBACK_PHYXS_WS); - } - - static void efx_mdio_set_mmd_lpower(struct efx_nic *efx, -@@ -249,8 +249,6 @@ void efx_mdio_set_mmds_lpower(struct efx_nic *efx, - int efx_mdio_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) - { - struct ethtool_cmd prev; -- u32 required; -- int reg; - - efx->phy_op->get_settings(efx, &prev); - -@@ -266,86 +264,74 @@ int efx_mdio_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) - return -EINVAL; - - /* Check that PHY supports these settings */ -- if (ecmd->autoneg) { -- required = SUPPORTED_Autoneg; -- } else if (ecmd->duplex) { -- switch (ecmd->speed) { -- case SPEED_10: required = SUPPORTED_10baseT_Full; break; -- case SPEED_100: required = SUPPORTED_100baseT_Full; break; -- default: return -EINVAL; -- } -- } else { -- switch (ecmd->speed) { -- case SPEED_10: required = SUPPORTED_10baseT_Half; break; -- case SPEED_100: required = SUPPORTED_100baseT_Half; break; -- default: return -EINVAL; -- } -- } -- required |= ecmd->advertising; -- if (required & ~prev.supported) -+ if (!ecmd->autoneg || -+ (ecmd->advertising | SUPPORTED_Autoneg) & ~prev.supported) - return -EINVAL; - -- if (ecmd->autoneg) { -- bool xnp = (ecmd->advertising & ADVERTISED_10000baseT_Full -- || EFX_WORKAROUND_13204(efx)); -- -- /* Set up the base page */ -- reg = ADVERTISE_CSMA; -- if (ecmd->advertising & ADVERTISED_10baseT_Half) -- reg |= ADVERTISE_10HALF; -- if (ecmd->advertising & ADVERTISED_10baseT_Full) -- reg |= ADVERTISE_10FULL; -- if (ecmd->advertising & ADVERTISED_100baseT_Half) -- reg |= ADVERTISE_100HALF; -- if (ecmd->advertising & ADVERTISED_100baseT_Full) -- reg |= ADVERTISE_100FULL; -- if (xnp) -- reg |= ADVERTISE_RESV; -- else if (ecmd->advertising & (ADVERTISED_1000baseT_Half | -- ADVERTISED_1000baseT_Full)) -- reg |= ADVERTISE_NPAGE; -- reg |= mii_advertise_flowctrl(efx->wanted_fc); -- efx_mdio_write(efx, MDIO_MMD_AN, MDIO_AN_ADVERTISE, reg); -- -- /* Set up the (extended) next page if necessary */ -- if (efx->phy_op->set_npage_adv) -- efx->phy_op->set_npage_adv(efx, ecmd->advertising); -- -- /* Enable and restart AN */ -- reg = efx_mdio_read(efx, MDIO_MMD_AN, MDIO_CTRL1); -- reg |= MDIO_AN_CTRL1_ENABLE; -- if (!(EFX_WORKAROUND_15195(efx) && -- LOOPBACK_MASK(efx) & efx->phy_op->loopbacks)) -- reg |= MDIO_AN_CTRL1_RESTART; -- if (xnp) -- reg |= MDIO_AN_CTRL1_XNP; -- else -- reg &= ~MDIO_AN_CTRL1_XNP; -- efx_mdio_write(efx, MDIO_MMD_AN, MDIO_CTRL1, reg); -- } else { -- /* Disable AN */ -- efx_mdio_set_flag(efx, MDIO_MMD_AN, MDIO_CTRL1, -- MDIO_AN_CTRL1_ENABLE, false); -- -- /* Set the basic control bits */ -- reg = efx_mdio_read(efx, MDIO_MMD_PMAPMD, MDIO_CTRL1); -- reg &= ~(MDIO_CTRL1_SPEEDSEL | MDIO_CTRL1_FULLDPLX); -- if (ecmd->speed == SPEED_100) -- reg |= MDIO_PMA_CTRL1_SPEED100; -- if (ecmd->duplex) -- reg |= MDIO_CTRL1_FULLDPLX; -- efx_mdio_write(efx, MDIO_MMD_PMAPMD, MDIO_CTRL1, reg); -- } -- -+ efx_link_set_advertising(efx, ecmd->advertising | ADVERTISED_Autoneg); -+ efx_mdio_an_reconfigure(efx); - return 0; - } - -+/** -+ * efx_mdio_an_reconfigure - Push advertising flags and restart autonegotiation -+ * @efx: Efx NIC -+ */ -+void efx_mdio_an_reconfigure(struct efx_nic *efx) -+{ -+ bool xnp = (efx->link_advertising & ADVERTISED_10000baseT_Full -+ || EFX_WORKAROUND_13204(efx)); -+ int reg; -+ -+ WARN_ON(!(efx->mdio.mmds & MDIO_DEVS_AN)); -+ -+ /* Set up the base page */ -+ reg = ADVERTISE_CSMA; -+ if (efx->link_advertising & ADVERTISED_10baseT_Half) -+ reg |= ADVERTISE_10HALF; -+ if (efx->link_advertising & ADVERTISED_10baseT_Full) -+ reg |= ADVERTISE_10FULL; -+ if (efx->link_advertising & ADVERTISED_100baseT_Half) -+ reg |= ADVERTISE_100HALF; -+ if (efx->link_advertising & ADVERTISED_100baseT_Full) -+ reg |= ADVERTISE_100FULL; -+ if (xnp) -+ reg |= ADVERTISE_RESV; -+ else if (efx->link_advertising & (ADVERTISED_1000baseT_Half | -+ ADVERTISED_1000baseT_Full)) -+ reg |= ADVERTISE_NPAGE; -+ if (efx->link_advertising & ADVERTISED_Pause) -+ reg |= ADVERTISE_PAUSE_CAP; -+ if (efx->link_advertising & ADVERTISED_Asym_Pause) -+ reg |= ADVERTISE_PAUSE_ASYM; -+ efx_mdio_write(efx, MDIO_MMD_AN, MDIO_AN_ADVERTISE, reg); -+ -+ /* Set up the (extended) next page if necessary */ -+ if (efx->phy_op->set_npage_adv) -+ efx->phy_op->set_npage_adv(efx, efx->link_advertising); -+ -+ /* Enable and restart AN */ -+ reg = efx_mdio_read(efx, MDIO_MMD_AN, MDIO_CTRL1); -+ reg |= MDIO_AN_CTRL1_ENABLE; -+ if (!(EFX_WORKAROUND_15195(efx) && LOOPBACK_EXTERNAL(efx))) -+ reg |= MDIO_AN_CTRL1_RESTART; -+ if (xnp) -+ reg |= MDIO_AN_CTRL1_XNP; -+ else -+ reg &= ~MDIO_AN_CTRL1_XNP; -+ efx_mdio_write(efx, MDIO_MMD_AN, MDIO_CTRL1, reg); -+} -+ - enum efx_fc_type efx_mdio_get_pause(struct efx_nic *efx) - { -- int lpa; -+ BUILD_BUG_ON(EFX_FC_AUTO & (EFX_FC_RX | EFX_FC_TX)); - -- if (!(efx->phy_op->mmds & MDIO_DEVS_AN)) -+ if (!(efx->wanted_fc & EFX_FC_AUTO)) - return efx->wanted_fc; -- lpa = efx_mdio_read(efx, MDIO_MMD_AN, MDIO_AN_LPA); -- return efx_fc_resolve(efx->wanted_fc, lpa); -+ -+ WARN_ON(!(efx->mdio.mmds & MDIO_DEVS_AN)); -+ -+ return mii_resolve_flowctrl_fdx( -+ mii_advertise_flowctrl(efx->wanted_fc), -+ efx_mdio_read(efx, MDIO_MMD_AN, MDIO_AN_LPA)); - } -diff --git a/drivers/net/sfc/mdio_10g.h b/drivers/net/sfc/mdio_10g.h -index 6b14421..f6ac950 100644 ---- a/drivers/net/sfc/mdio_10g.h -+++ b/drivers/net/sfc/mdio_10g.h -@@ -1,6 +1,6 @@ - /**************************************************************************** - * Driver for Solarflare Solarstorm network controllers and boards -- * Copyright 2006-2008 Solarflare Communications Inc. -+ * Copyright 2006-2009 Solarflare Communications Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published -@@ -17,7 +17,6 @@ - */ - - #include "efx.h" --#include "boards.h" - - static inline unsigned efx_mdio_id_rev(u32 id) { return id & 0xf; } - static inline unsigned efx_mdio_id_model(u32 id) { return (id >> 4) & 0x3f; } -@@ -87,6 +86,9 @@ extern void efx_mdio_set_mmds_lpower(struct efx_nic *efx, - /* Set (some of) the PHY settings over MDIO */ - extern int efx_mdio_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd); - -+/* Push advertising flags and restart autonegotiation */ -+extern void efx_mdio_an_reconfigure(struct efx_nic *efx); -+ - /* Get pause parameters from AN if available (otherwise return - * requested pause parameters) - */ -diff --git a/drivers/net/sfc/mtd.c b/drivers/net/sfc/mtd.c -index 820c233..3a46452 100644 ---- a/drivers/net/sfc/mtd.c -+++ b/drivers/net/sfc/mtd.c -@@ -1,36 +1,80 @@ - /**************************************************************************** - * Driver for Solarflare Solarstorm network controllers and boards - * Copyright 2005-2006 Fen Systems Ltd. -- * Copyright 2006-2008 Solarflare Communications Inc. -+ * Copyright 2006-2009 Solarflare Communications Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation, incorporated herein by reference. - */ - -+#include - #include - #include - #include -+#include - - #define EFX_DRIVER_NAME "sfc_mtd" - #include "net_driver.h" - #include "spi.h" - #include "efx.h" -+#include "nic.h" -+#include "mcdi.h" -+#include "mcdi_pcol.h" - - #define EFX_SPI_VERIFY_BUF_LEN 16 -+#define EFX_MCDI_CHUNK_LEN 128 - --struct efx_mtd { -- const struct efx_spi_device *spi; -+struct efx_mtd_partition { - struct mtd_info mtd; -+ union { -+ struct { -+ bool updating; -+ u8 nvram_type; -+ u16 fw_subtype; -+ } mcdi; -+ size_t offset; -+ }; -+ const char *type_name; - char name[IFNAMSIZ + 20]; - }; - -+struct efx_mtd_ops { -+ int (*read)(struct mtd_info *mtd, loff_t start, size_t len, -+ size_t *retlen, u8 *buffer); -+ int (*erase)(struct mtd_info *mtd, loff_t start, size_t len); -+ int (*write)(struct mtd_info *mtd, loff_t start, size_t len, -+ size_t *retlen, const u8 *buffer); -+ int (*sync)(struct mtd_info *mtd); -+}; -+ -+struct efx_mtd { -+ struct list_head node; -+ struct efx_nic *efx; -+ const struct efx_spi_device *spi; -+ const char *name; -+ const struct efx_mtd_ops *ops; -+ size_t n_parts; -+ struct efx_mtd_partition part[0]; -+}; -+ -+#define efx_for_each_partition(part, efx_mtd) \ -+ for ((part) = &(efx_mtd)->part[0]; \ -+ (part) != &(efx_mtd)->part[(efx_mtd)->n_parts]; \ -+ (part)++) -+ -+#define to_efx_mtd_partition(mtd) \ -+ container_of(mtd, struct efx_mtd_partition, mtd) -+ -+static int falcon_mtd_probe(struct efx_nic *efx); -+static int siena_mtd_probe(struct efx_nic *efx); -+ - /* SPI utilities */ - - static int efx_spi_slow_wait(struct efx_mtd *efx_mtd, bool uninterruptible) - { - const struct efx_spi_device *spi = efx_mtd->spi; -- struct efx_nic *efx = spi->efx; -+ struct efx_nic *efx = efx_mtd->efx; - u8 status; - int rc, i; - -@@ -39,7 +83,7 @@ static int efx_spi_slow_wait(struct efx_mtd *efx_mtd, bool uninterruptible) - __set_current_state(uninterruptible ? - TASK_UNINTERRUPTIBLE : TASK_INTERRUPTIBLE); - schedule_timeout(HZ / 10); -- rc = falcon_spi_cmd(spi, SPI_RDSR, -1, NULL, -+ rc = falcon_spi_cmd(efx, spi, SPI_RDSR, -1, NULL, - &status, sizeof(status)); - if (rc) - return rc; -@@ -52,32 +96,35 @@ static int efx_spi_slow_wait(struct efx_mtd *efx_mtd, bool uninterruptible) - return -ETIMEDOUT; - } - --static int efx_spi_unlock(const struct efx_spi_device *spi) -+static int -+efx_spi_unlock(struct efx_nic *efx, const struct efx_spi_device *spi) - { - const u8 unlock_mask = (SPI_STATUS_BP2 | SPI_STATUS_BP1 | - SPI_STATUS_BP0); - u8 status; - int rc; - -- rc = falcon_spi_cmd(spi, SPI_RDSR, -1, NULL, &status, sizeof(status)); -+ rc = falcon_spi_cmd(efx, spi, SPI_RDSR, -1, NULL, -+ &status, sizeof(status)); - if (rc) - return rc; - - if (!(status & unlock_mask)) - return 0; /* already unlocked */ - -- rc = falcon_spi_cmd(spi, SPI_WREN, -1, NULL, NULL, 0); -+ rc = falcon_spi_cmd(efx, spi, SPI_WREN, -1, NULL, NULL, 0); - if (rc) - return rc; -- rc = falcon_spi_cmd(spi, SPI_SST_EWSR, -1, NULL, NULL, 0); -+ rc = falcon_spi_cmd(efx, spi, SPI_SST_EWSR, -1, NULL, NULL, 0); - if (rc) - return rc; - - status &= ~unlock_mask; -- rc = falcon_spi_cmd(spi, SPI_WRSR, -1, &status, NULL, sizeof(status)); -+ rc = falcon_spi_cmd(efx, spi, SPI_WRSR, -1, &status, -+ NULL, sizeof(status)); - if (rc) - return rc; -- rc = falcon_spi_wait_write(spi); -+ rc = falcon_spi_wait_write(efx, spi); - if (rc) - return rc; - -@@ -87,6 +134,7 @@ static int efx_spi_unlock(const struct efx_spi_device *spi) - static int efx_spi_erase(struct efx_mtd *efx_mtd, loff_t start, size_t len) - { - const struct efx_spi_device *spi = efx_mtd->spi; -+ struct efx_nic *efx = efx_mtd->efx; - unsigned pos, block_len; - u8 empty[EFX_SPI_VERIFY_BUF_LEN]; - u8 buffer[EFX_SPI_VERIFY_BUF_LEN]; -@@ -98,13 +146,14 @@ static int efx_spi_erase(struct efx_mtd *efx_mtd, loff_t start, size_t len) - if (spi->erase_command == 0) - return -EOPNOTSUPP; - -- rc = efx_spi_unlock(spi); -+ rc = efx_spi_unlock(efx, spi); - if (rc) - return rc; -- rc = falcon_spi_cmd(spi, SPI_WREN, -1, NULL, NULL, 0); -+ rc = falcon_spi_cmd(efx, spi, SPI_WREN, -1, NULL, NULL, 0); - if (rc) - return rc; -- rc = falcon_spi_cmd(spi, spi->erase_command, start, NULL, NULL, 0); -+ rc = falcon_spi_cmd(efx, spi, spi->erase_command, start, NULL, -+ NULL, 0); - if (rc) - return rc; - rc = efx_spi_slow_wait(efx_mtd, false); -@@ -113,7 +162,8 @@ static int efx_spi_erase(struct efx_mtd *efx_mtd, loff_t start, size_t len) - memset(empty, 0xff, sizeof(empty)); - for (pos = 0; pos < len; pos += block_len) { - block_len = min(len - pos, sizeof(buffer)); -- rc = falcon_spi_read(spi, start + pos, block_len, NULL, buffer); -+ rc = falcon_spi_read(efx, spi, start + pos, block_len, -+ NULL, buffer); - if (rc) - return rc; - if (memcmp(empty, buffer, block_len)) -@@ -130,140 +180,473 @@ static int efx_spi_erase(struct efx_mtd *efx_mtd, loff_t start, size_t len) - - /* MTD interface */ - --static int efx_mtd_read(struct mtd_info *mtd, loff_t start, size_t len, -- size_t *retlen, u8 *buffer) -+static int efx_mtd_erase(struct mtd_info *mtd, struct erase_info *erase) - { - struct efx_mtd *efx_mtd = mtd->priv; -+ int rc; -+ -+ rc = efx_mtd->ops->erase(mtd, erase->addr, erase->len); -+ if (rc == 0) { -+ erase->state = MTD_ERASE_DONE; -+ } else { -+ erase->state = MTD_ERASE_FAILED; -+ erase->fail_addr = 0xffffffff; -+ } -+ mtd_erase_callback(erase); -+ return rc; -+} -+ -+static void efx_mtd_sync(struct mtd_info *mtd) -+{ -+ struct efx_mtd *efx_mtd = mtd->priv; -+ struct efx_nic *efx = efx_mtd->efx; -+ int rc; -+ -+ rc = efx_mtd->ops->sync(mtd); -+ if (rc) -+ EFX_ERR(efx, "%s sync failed (%d)\n", efx_mtd->name, rc); -+} -+ -+static void efx_mtd_remove_partition(struct efx_mtd_partition *part) -+{ -+ int rc; -+ -+ for (;;) { -+ rc = del_mtd_device(&part->mtd); -+ if (rc != -EBUSY) -+ break; -+ ssleep(1); -+ } -+ WARN_ON(rc); -+} -+ -+static void efx_mtd_remove_device(struct efx_mtd *efx_mtd) -+{ -+ struct efx_mtd_partition *part; -+ -+ efx_for_each_partition(part, efx_mtd) -+ efx_mtd_remove_partition(part); -+ list_del(&efx_mtd->node); -+ kfree(efx_mtd); -+} -+ -+static void efx_mtd_rename_device(struct efx_mtd *efx_mtd) -+{ -+ struct efx_mtd_partition *part; -+ -+ efx_for_each_partition(part, efx_mtd) -+ if (efx_nic_rev(efx_mtd->efx) >= EFX_REV_SIENA_A0) -+ snprintf(part->name, sizeof(part->name), -+ "%s %s:%02x", efx_mtd->efx->name, -+ part->type_name, part->mcdi.fw_subtype); -+ else -+ snprintf(part->name, sizeof(part->name), -+ "%s %s", efx_mtd->efx->name, -+ part->type_name); -+} -+ -+static int efx_mtd_probe_device(struct efx_nic *efx, struct efx_mtd *efx_mtd) -+{ -+ struct efx_mtd_partition *part; -+ -+ efx_mtd->efx = efx; -+ -+ efx_mtd_rename_device(efx_mtd); -+ -+ efx_for_each_partition(part, efx_mtd) { -+ part->mtd.writesize = 1; -+ -+ part->mtd.owner = THIS_MODULE; -+ part->mtd.priv = efx_mtd; -+ part->mtd.name = part->name; -+ part->mtd.erase = efx_mtd_erase; -+ part->mtd.read = efx_mtd->ops->read; -+ part->mtd.write = efx_mtd->ops->write; -+ part->mtd.sync = efx_mtd_sync; -+ -+ if (add_mtd_device(&part->mtd)) -+ goto fail; -+ } -+ -+ list_add(&efx_mtd->node, &efx->mtd_list); -+ return 0; -+ -+fail: -+ while (part != &efx_mtd->part[0]) { -+ --part; -+ efx_mtd_remove_partition(part); -+ } -+ /* add_mtd_device() returns 1 if the MTD table is full */ -+ return -ENOMEM; -+} -+ -+void efx_mtd_remove(struct efx_nic *efx) -+{ -+ struct efx_mtd *efx_mtd, *next; -+ -+ WARN_ON(efx_dev_registered(efx)); -+ -+ list_for_each_entry_safe(efx_mtd, next, &efx->mtd_list, node) -+ efx_mtd_remove_device(efx_mtd); -+} -+ -+void efx_mtd_rename(struct efx_nic *efx) -+{ -+ struct efx_mtd *efx_mtd; -+ -+ ASSERT_RTNL(); -+ -+ list_for_each_entry(efx_mtd, &efx->mtd_list, node) -+ efx_mtd_rename_device(efx_mtd); -+} -+ -+int efx_mtd_probe(struct efx_nic *efx) -+{ -+ if (efx_nic_rev(efx) >= EFX_REV_SIENA_A0) -+ return siena_mtd_probe(efx); -+ else -+ return falcon_mtd_probe(efx); -+} -+ -+/* Implementation of MTD operations for Falcon */ -+ -+static int falcon_mtd_read(struct mtd_info *mtd, loff_t start, -+ size_t len, size_t *retlen, u8 *buffer) -+{ -+ struct efx_mtd_partition *part = to_efx_mtd_partition(mtd); -+ struct efx_mtd *efx_mtd = mtd->priv; - const struct efx_spi_device *spi = efx_mtd->spi; -- struct efx_nic *efx = spi->efx; -+ struct efx_nic *efx = efx_mtd->efx; - int rc; - - rc = mutex_lock_interruptible(&efx->spi_lock); - if (rc) - return rc; -- rc = falcon_spi_read(spi, FALCON_FLASH_BOOTCODE_START + start, -- len, retlen, buffer); -+ rc = falcon_spi_read(efx, spi, part->offset + start, len, -+ retlen, buffer); - mutex_unlock(&efx->spi_lock); - return rc; - } - --static int efx_mtd_erase(struct mtd_info *mtd, struct erase_info *erase) -+static int falcon_mtd_erase(struct mtd_info *mtd, loff_t start, size_t len) - { -+ struct efx_mtd_partition *part = to_efx_mtd_partition(mtd); - struct efx_mtd *efx_mtd = mtd->priv; -- struct efx_nic *efx = efx_mtd->spi->efx; -+ struct efx_nic *efx = efx_mtd->efx; - int rc; - - rc = mutex_lock_interruptible(&efx->spi_lock); - if (rc) - return rc; -- rc = efx_spi_erase(efx_mtd, FALCON_FLASH_BOOTCODE_START + erase->addr, -- erase->len); -+ rc = efx_spi_erase(efx_mtd, part->offset + start, len); - mutex_unlock(&efx->spi_lock); -- -- if (rc == 0) { -- erase->state = MTD_ERASE_DONE; -- } else { -- erase->state = MTD_ERASE_FAILED; -- erase->fail_addr = 0xffffffff; -- } -- mtd_erase_callback(erase); - return rc; - } - --static int efx_mtd_write(struct mtd_info *mtd, loff_t start, -- size_t len, size_t *retlen, const u8 *buffer) -+static int falcon_mtd_write(struct mtd_info *mtd, loff_t start, -+ size_t len, size_t *retlen, const u8 *buffer) - { -+ struct efx_mtd_partition *part = to_efx_mtd_partition(mtd); - struct efx_mtd *efx_mtd = mtd->priv; - const struct efx_spi_device *spi = efx_mtd->spi; -- struct efx_nic *efx = spi->efx; -+ struct efx_nic *efx = efx_mtd->efx; - int rc; - - rc = mutex_lock_interruptible(&efx->spi_lock); - if (rc) - return rc; -- rc = falcon_spi_write(spi, FALCON_FLASH_BOOTCODE_START + start, -- len, retlen, buffer); -+ rc = falcon_spi_write(efx, spi, part->offset + start, len, -+ retlen, buffer); - mutex_unlock(&efx->spi_lock); - return rc; - } - --static void efx_mtd_sync(struct mtd_info *mtd) -+static int falcon_mtd_sync(struct mtd_info *mtd) - { - struct efx_mtd *efx_mtd = mtd->priv; -- struct efx_nic *efx = efx_mtd->spi->efx; -+ struct efx_nic *efx = efx_mtd->efx; - int rc; - - mutex_lock(&efx->spi_lock); - rc = efx_spi_slow_wait(efx_mtd, true); - mutex_unlock(&efx->spi_lock); -+ return rc; -+} -+ -+static struct efx_mtd_ops falcon_mtd_ops = { -+ .read = falcon_mtd_read, -+ .erase = falcon_mtd_erase, -+ .write = falcon_mtd_write, -+ .sync = falcon_mtd_sync, -+}; -+ -+static int falcon_mtd_probe(struct efx_nic *efx) -+{ -+ struct efx_spi_device *spi = efx->spi_flash; -+ struct efx_mtd *efx_mtd; -+ int rc; -+ -+ ASSERT_RTNL(); - -+ if (!spi || spi->size <= FALCON_FLASH_BOOTCODE_START) -+ return -ENODEV; -+ -+ efx_mtd = kzalloc(sizeof(*efx_mtd) + sizeof(efx_mtd->part[0]), -+ GFP_KERNEL); -+ if (!efx_mtd) -+ return -ENOMEM; -+ -+ efx_mtd->spi = spi; -+ efx_mtd->name = "flash"; -+ efx_mtd->ops = &falcon_mtd_ops; -+ -+ efx_mtd->n_parts = 1; -+ efx_mtd->part[0].mtd.type = MTD_NORFLASH; -+ efx_mtd->part[0].mtd.flags = MTD_CAP_NORFLASH; -+ efx_mtd->part[0].mtd.size = spi->size - FALCON_FLASH_BOOTCODE_START; -+ efx_mtd->part[0].mtd.erasesize = spi->erase_size; -+ efx_mtd->part[0].offset = FALCON_FLASH_BOOTCODE_START; -+ efx_mtd->part[0].type_name = "sfc_flash_bootrom"; -+ -+ rc = efx_mtd_probe_device(efx, efx_mtd); - if (rc) -- EFX_ERR(efx, "%s sync failed (%d)\n", efx_mtd->name, rc); -- return; -+ kfree(efx_mtd); -+ return rc; - } - --void efx_mtd_remove(struct efx_nic *efx) -+/* Implementation of MTD operations for Siena */ -+ -+static int siena_mtd_read(struct mtd_info *mtd, loff_t start, -+ size_t len, size_t *retlen, u8 *buffer) - { -- if (efx->spi_flash && efx->spi_flash->mtd) { -- struct efx_mtd *efx_mtd = efx->spi_flash->mtd; -- int rc; -- -- for (;;) { -- rc = del_mtd_device(&efx_mtd->mtd); -- if (rc != -EBUSY) -- break; -- ssleep(1); -- } -- WARN_ON(rc); -- kfree(efx_mtd); -+ struct efx_mtd_partition *part = to_efx_mtd_partition(mtd); -+ struct efx_mtd *efx_mtd = mtd->priv; -+ struct efx_nic *efx = efx_mtd->efx; -+ loff_t offset = start; -+ loff_t end = min_t(loff_t, start + len, mtd->size); -+ size_t chunk; -+ int rc = 0; -+ -+ while (offset < end) { -+ chunk = min_t(size_t, end - offset, EFX_MCDI_CHUNK_LEN); -+ rc = efx_mcdi_nvram_read(efx, part->mcdi.nvram_type, offset, -+ buffer, chunk); -+ if (rc) -+ goto out; -+ offset += chunk; -+ buffer += chunk; - } -+out: -+ *retlen = offset - start; -+ return rc; - } - --void efx_mtd_rename(struct efx_nic *efx) -+static int siena_mtd_erase(struct mtd_info *mtd, loff_t start, size_t len) - { -- if (efx->spi_flash && efx->spi_flash->mtd) { -- struct efx_mtd *efx_mtd = efx->spi_flash->mtd; -- snprintf(efx_mtd->name, sizeof(efx_mtd->name), -- "%s sfc_flash_bootrom", efx->name); -+ struct efx_mtd_partition *part = to_efx_mtd_partition(mtd); -+ struct efx_mtd *efx_mtd = mtd->priv; -+ struct efx_nic *efx = efx_mtd->efx; -+ loff_t offset = start & ~((loff_t)(mtd->erasesize - 1)); -+ loff_t end = min_t(loff_t, start + len, mtd->size); -+ size_t chunk = part->mtd.erasesize; -+ int rc = 0; -+ -+ if (!part->mcdi.updating) { -+ rc = efx_mcdi_nvram_update_start(efx, part->mcdi.nvram_type); -+ if (rc) -+ goto out; -+ part->mcdi.updating = 1; -+ } -+ -+ /* The MCDI interface can in fact do multiple erase blocks at once; -+ * but erasing may be slow, so we make multiple calls here to avoid -+ * tripping the MCDI RPC timeout. */ -+ while (offset < end) { -+ rc = efx_mcdi_nvram_erase(efx, part->mcdi.nvram_type, offset, -+ chunk); -+ if (rc) -+ goto out; -+ offset += chunk; - } -+out: -+ return rc; - } - --int efx_mtd_probe(struct efx_nic *efx) -+static int siena_mtd_write(struct mtd_info *mtd, loff_t start, -+ size_t len, size_t *retlen, const u8 *buffer) - { -- struct efx_spi_device *spi = efx->spi_flash; -- struct efx_mtd *efx_mtd; -+ struct efx_mtd_partition *part = to_efx_mtd_partition(mtd); -+ struct efx_mtd *efx_mtd = mtd->priv; -+ struct efx_nic *efx = efx_mtd->efx; -+ loff_t offset = start; -+ loff_t end = min_t(loff_t, start + len, mtd->size); -+ size_t chunk; -+ int rc = 0; -+ -+ if (!part->mcdi.updating) { -+ rc = efx_mcdi_nvram_update_start(efx, part->mcdi.nvram_type); -+ if (rc) -+ goto out; -+ part->mcdi.updating = 1; -+ } - -- if (!spi || spi->size <= FALCON_FLASH_BOOTCODE_START) -+ while (offset < end) { -+ chunk = min_t(size_t, end - offset, EFX_MCDI_CHUNK_LEN); -+ rc = efx_mcdi_nvram_write(efx, part->mcdi.nvram_type, offset, -+ buffer, chunk); -+ if (rc) -+ goto out; -+ offset += chunk; -+ buffer += chunk; -+ } -+out: -+ *retlen = offset - start; -+ return rc; -+} -+ -+static int siena_mtd_sync(struct mtd_info *mtd) -+{ -+ struct efx_mtd_partition *part = to_efx_mtd_partition(mtd); -+ struct efx_mtd *efx_mtd = mtd->priv; -+ struct efx_nic *efx = efx_mtd->efx; -+ int rc = 0; -+ -+ if (part->mcdi.updating) { -+ part->mcdi.updating = 0; -+ rc = efx_mcdi_nvram_update_finish(efx, part->mcdi.nvram_type); -+ } -+ -+ return rc; -+} -+ -+static struct efx_mtd_ops siena_mtd_ops = { -+ .read = siena_mtd_read, -+ .erase = siena_mtd_erase, -+ .write = siena_mtd_write, -+ .sync = siena_mtd_sync, -+}; -+ -+struct siena_nvram_type_info { -+ int port; -+ const char *name; -+}; -+ -+static struct siena_nvram_type_info siena_nvram_types[] = { -+ [MC_CMD_NVRAM_TYPE_DISABLED_CALLISTO] = { 0, "sfc_dummy_phy" }, -+ [MC_CMD_NVRAM_TYPE_MC_FW] = { 0, "sfc_mcfw" }, -+ [MC_CMD_NVRAM_TYPE_MC_FW_BACKUP] = { 0, "sfc_mcfw_backup" }, -+ [MC_CMD_NVRAM_TYPE_STATIC_CFG_PORT0] = { 0, "sfc_static_cfg" }, -+ [MC_CMD_NVRAM_TYPE_STATIC_CFG_PORT1] = { 1, "sfc_static_cfg" }, -+ [MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT0] = { 0, "sfc_dynamic_cfg" }, -+ [MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT1] = { 1, "sfc_dynamic_cfg" }, -+ [MC_CMD_NVRAM_TYPE_EXP_ROM] = { 0, "sfc_exp_rom" }, -+ [MC_CMD_NVRAM_TYPE_EXP_ROM_CFG_PORT0] = { 0, "sfc_exp_rom_cfg" }, -+ [MC_CMD_NVRAM_TYPE_EXP_ROM_CFG_PORT1] = { 1, "sfc_exp_rom_cfg" }, -+ [MC_CMD_NVRAM_TYPE_PHY_PORT0] = { 0, "sfc_phy_fw" }, -+ [MC_CMD_NVRAM_TYPE_PHY_PORT1] = { 1, "sfc_phy_fw" }, -+}; -+ -+static int siena_mtd_probe_partition(struct efx_nic *efx, -+ struct efx_mtd *efx_mtd, -+ unsigned int part_id, -+ unsigned int type) -+{ -+ struct efx_mtd_partition *part = &efx_mtd->part[part_id]; -+ struct siena_nvram_type_info *info; -+ size_t size, erase_size; -+ bool protected; -+ int rc; -+ -+ if (type >= ARRAY_SIZE(siena_nvram_types)) - return -ENODEV; - -- efx_mtd = kzalloc(sizeof(*efx_mtd), GFP_KERNEL); -+ info = &siena_nvram_types[type]; -+ -+ if (info->port != efx_port_num(efx)) -+ return -ENODEV; -+ -+ rc = efx_mcdi_nvram_info(efx, type, &size, &erase_size, &protected); -+ if (rc) -+ return rc; -+ if (protected) -+ return -ENODEV; /* hide it */ -+ -+ part->mcdi.nvram_type = type; -+ part->type_name = info->name; -+ -+ part->mtd.type = MTD_NORFLASH; -+ part->mtd.flags = MTD_CAP_NORFLASH; -+ part->mtd.size = size; -+ part->mtd.erasesize = erase_size; -+ -+ return 0; -+} -+ -+static int siena_mtd_get_fw_subtypes(struct efx_nic *efx, -+ struct efx_mtd *efx_mtd) -+{ -+ struct efx_mtd_partition *part; -+ uint16_t fw_subtype_list[MC_CMD_GET_BOARD_CFG_OUT_FW_SUBTYPE_LIST_LEN / -+ sizeof(uint16_t)]; -+ int rc; -+ -+ rc = efx_mcdi_get_board_cfg(efx, NULL, fw_subtype_list); -+ if (rc) -+ return rc; -+ -+ efx_for_each_partition(part, efx_mtd) -+ part->mcdi.fw_subtype = fw_subtype_list[part->mcdi.nvram_type]; -+ -+ return 0; -+} -+ -+static int siena_mtd_probe(struct efx_nic *efx) -+{ -+ struct efx_mtd *efx_mtd; -+ int rc = -ENODEV; -+ u32 nvram_types; -+ unsigned int type; -+ -+ ASSERT_RTNL(); -+ -+ rc = efx_mcdi_nvram_types(efx, &nvram_types); -+ if (rc) -+ return rc; -+ -+ efx_mtd = kzalloc(sizeof(*efx_mtd) + -+ hweight32(nvram_types) * sizeof(efx_mtd->part[0]), -+ GFP_KERNEL); - if (!efx_mtd) - return -ENOMEM; - -- efx_mtd->spi = spi; -- spi->mtd = efx_mtd; -- -- efx_mtd->mtd.type = MTD_NORFLASH; -- efx_mtd->mtd.flags = MTD_CAP_NORFLASH; -- efx_mtd->mtd.size = spi->size - FALCON_FLASH_BOOTCODE_START; -- efx_mtd->mtd.erasesize = spi->erase_size; -- efx_mtd->mtd.writesize = 1; -- efx_mtd_rename(efx); -- -- efx_mtd->mtd.owner = THIS_MODULE; -- efx_mtd->mtd.priv = efx_mtd; -- efx_mtd->mtd.name = efx_mtd->name; -- efx_mtd->mtd.erase = efx_mtd_erase; -- efx_mtd->mtd.read = efx_mtd_read; -- efx_mtd->mtd.write = efx_mtd_write; -- efx_mtd->mtd.sync = efx_mtd_sync; -- -- if (add_mtd_device(&efx_mtd->mtd)) { -- kfree(efx_mtd); -- spi->mtd = NULL; -- /* add_mtd_device() returns 1 if the MTD table is full */ -- return -ENOMEM; -+ efx_mtd->name = "Siena NVRAM manager"; -+ -+ efx_mtd->ops = &siena_mtd_ops; -+ -+ type = 0; -+ efx_mtd->n_parts = 0; -+ -+ while (nvram_types != 0) { -+ if (nvram_types & 1) { -+ rc = siena_mtd_probe_partition(efx, efx_mtd, -+ efx_mtd->n_parts, type); -+ if (rc == 0) -+ efx_mtd->n_parts++; -+ else if (rc != -ENODEV) -+ goto fail; -+ } -+ type++; -+ nvram_types >>= 1; - } - -- return 0; -+ rc = siena_mtd_get_fw_subtypes(efx, efx_mtd); -+ if (rc) -+ goto fail; -+ -+ rc = efx_mtd_probe_device(efx, efx_mtd); -+fail: -+ if (rc) -+ kfree(efx_mtd); -+ return rc; - } -+ -diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h -index 298566d..34c381f 100644 ---- a/drivers/net/sfc/net_driver.h -+++ b/drivers/net/sfc/net_driver.h -@@ -1,7 +1,7 @@ - /**************************************************************************** - * Driver for Solarflare Solarstorm network controllers and boards - * Copyright 2005-2006 Fen Systems Ltd. -- * Copyright 2005-2008 Solarflare Communications Inc. -+ * Copyright 2005-2009 Solarflare Communications Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published -@@ -38,7 +38,7 @@ - #ifndef EFX_DRIVER_NAME - #define EFX_DRIVER_NAME "sfc" - #endif --#define EFX_DRIVER_VERSION "2.3" -+#define EFX_DRIVER_VERSION "3.0" - - #ifdef EFX_ENABLE_DEBUG - #define EFX_BUG_ON_PARANOID(x) BUG_ON(x) -@@ -113,6 +113,13 @@ struct efx_special_buffer { - int entries; - }; - -+enum efx_flush_state { -+ FLUSH_NONE, -+ FLUSH_PENDING, -+ FLUSH_FAILED, -+ FLUSH_DONE, -+}; -+ - /** - * struct efx_tx_buffer - An Efx TX buffer - * @skb: The associated socket buffer. -@@ -189,7 +196,7 @@ struct efx_tx_queue { - struct efx_nic *nic; - struct efx_tx_buffer *buffer; - struct efx_special_buffer txd; -- bool flushed; -+ enum efx_flush_state flushed; - - /* Members used mainly on the completion path */ - unsigned int read_count ____cacheline_aligned_in_smp; -@@ -284,7 +291,7 @@ struct efx_rx_queue { - struct page *buf_page; - dma_addr_t buf_dma_addr; - char *buf_data; -- bool flushed; -+ enum efx_flush_state flushed; - }; - - /** -@@ -327,7 +334,7 @@ enum efx_rx_alloc_method { - * @used_flags: Channel is used by net driver - * @enabled: Channel enabled indicator - * @irq: IRQ number (MSI and MSI-X only) -- * @irq_moderation: IRQ moderation value (in us) -+ * @irq_moderation: IRQ moderation value (in hardware ticks) - * @napi_dev: Net device used with NAPI - * @napi_str: NAPI control structure - * @reset_work: Scheduled reset work thread -@@ -343,9 +350,9 @@ enum efx_rx_alloc_method { - * @rx_alloc_push_pages: RX allocation method currently in use for pushing - * descriptors - * @n_rx_tobe_disc: Count of RX_TOBE_DISC errors -- * @n_rx_ip_frag_err: Count of RX IP fragment errors - * @n_rx_ip_hdr_chksum_err: Count of RX IP header checksum errors - * @n_rx_tcp_udp_chksum_err: Count of RX TCP and UDP checksum errors -+ * @n_rx_mcast_mismatch: Count of unmatched multicast frames - * @n_rx_frm_trunc: Count of RX_FRM_TRUNC errors - * @n_rx_overlength: Count of RX_OVERLENGTH errors - * @n_skbuff_leaks: Count of skbuffs leaked due to RX overrun -@@ -373,9 +380,9 @@ struct efx_channel { - int rx_alloc_push_pages; - - unsigned n_rx_tobe_disc; -- unsigned n_rx_ip_frag_err; - unsigned n_rx_ip_hdr_chksum_err; - unsigned n_rx_tcp_udp_chksum_err; -+ unsigned n_rx_mcast_mismatch; - unsigned n_rx_frm_trunc; - unsigned n_rx_overlength; - unsigned n_skbuff_leaks; -@@ -388,53 +395,29 @@ struct efx_channel { - - }; - --/** -- * struct efx_blinker - S/W LED blinking context -- * @state: Current state - on or off -- * @resubmit: Timer resubmission flag -- * @timer: Control timer for blinking -- */ --struct efx_blinker { -- bool state; -- bool resubmit; -- struct timer_list timer; -+enum efx_led_mode { -+ EFX_LED_OFF = 0, -+ EFX_LED_ON = 1, -+ EFX_LED_DEFAULT = 2 - }; - -+#define STRING_TABLE_LOOKUP(val, member) \ -+ ((val) < member ## _max) ? member ## _names[val] : "(invalid)" - --/** -- * struct efx_board - board information -- * @type: Board model type -- * @major: Major rev. ('A', 'B' ...) -- * @minor: Minor rev. (0, 1, ...) -- * @init: Initialisation function -- * @init_leds: Sets up board LEDs. May be called repeatedly. -- * @set_id_led: Turns the identification LED on or off -- * @blink: Starts/stops blinking -- * @monitor: Board-specific health check function -- * @fini: Cleanup function -- * @blinker: used to blink LEDs in software -- * @hwmon_client: I2C client for hardware monitor -- * @ioexp_client: I2C client for power/port control -- */ --struct efx_board { -- int type; -- int major; -- int minor; -- int (*init) (struct efx_nic *nic); -- /* As the LEDs are typically attached to the PHY, LEDs -- * have a separate init callback that happens later than -- * board init. */ -- void (*init_leds)(struct efx_nic *efx); -- void (*set_id_led) (struct efx_nic *efx, bool state); -- int (*monitor) (struct efx_nic *nic); -- void (*blink) (struct efx_nic *efx, bool start); -- void (*fini) (struct efx_nic *nic); -- struct efx_blinker blinker; -- struct i2c_client *hwmon_client, *ioexp_client; --}; -+extern const char *efx_loopback_mode_names[]; -+extern const unsigned int efx_loopback_mode_max; -+#define LOOPBACK_MODE(efx) \ -+ STRING_TABLE_LOOKUP((efx)->loopback_mode, efx_loopback_mode) -+ -+extern const char *efx_interrupt_mode_names[]; -+extern const unsigned int efx_interrupt_mode_max; -+#define INT_MODE(efx) \ -+ STRING_TABLE_LOOKUP(efx->interrupt_mode, efx_interrupt_mode) - --#define STRING_TABLE_LOOKUP(val, member) \ -- member ## _names[val] -+extern const char *efx_reset_type_names[]; -+extern const unsigned int efx_reset_type_max; -+#define RESET_TYPE(type) \ -+ STRING_TABLE_LOOKUP(type, efx_reset_type) - - enum efx_int_mode { - /* Be careful if altering to correct macro below */ -@@ -445,20 +428,7 @@ enum efx_int_mode { - }; - #define EFX_INT_MODE_USE_MSI(x) (((x)->interrupt_mode) <= EFX_INT_MODE_MSI) - --enum phy_type { -- PHY_TYPE_NONE = 0, -- PHY_TYPE_TXC43128 = 1, -- PHY_TYPE_88E1111 = 2, -- PHY_TYPE_SFX7101 = 3, -- PHY_TYPE_QT2022C2 = 4, -- PHY_TYPE_PM8358 = 6, -- PHY_TYPE_SFT9001A = 8, -- PHY_TYPE_QT2025C = 9, -- PHY_TYPE_SFT9001B = 10, -- PHY_TYPE_MAX /* Insert any new items before this */ --}; -- --#define EFX_IS10G(efx) ((efx)->link_speed == 10000) -+#define EFX_IS10G(efx) ((efx)->link_state.speed == 10000) - - enum nic_state { - STATE_INIT = 0, -@@ -500,73 +470,69 @@ enum efx_fc_type { - EFX_FC_AUTO = 4, - }; - --/* Supported MAC bit-mask */ --enum efx_mac_type { -- EFX_GMAC = 1, -- EFX_XMAC = 2, -+/** -+ * struct efx_link_state - Current state of the link -+ * @up: Link is up -+ * @fd: Link is full-duplex -+ * @fc: Actual flow control flags -+ * @speed: Link speed (Mbps) -+ */ -+struct efx_link_state { -+ bool up; -+ bool fd; -+ enum efx_fc_type fc; -+ unsigned int speed; - }; - --static inline enum efx_fc_type efx_fc_resolve(enum efx_fc_type wanted_fc, -- unsigned int lpa) -+static inline bool efx_link_state_equal(const struct efx_link_state *left, -+ const struct efx_link_state *right) - { -- BUILD_BUG_ON(EFX_FC_AUTO & (EFX_FC_RX | EFX_FC_TX)); -- -- if (!(wanted_fc & EFX_FC_AUTO)) -- return wanted_fc; -- -- return mii_resolve_flowctrl_fdx(mii_advertise_flowctrl(wanted_fc), lpa); -+ return left->up == right->up && left->fd == right->fd && -+ left->fc == right->fc && left->speed == right->speed; - } - - /** - * struct efx_mac_operations - Efx MAC operations table - * @reconfigure: Reconfigure MAC. Serialised by the mac_lock - * @update_stats: Update statistics -- * @irq: Hardware MAC event callback. Serialised by the mac_lock -- * @poll: Poll for hardware state. Serialised by the mac_lock -+ * @check_fault: Check fault state. True if fault present. - */ - struct efx_mac_operations { -- void (*reconfigure) (struct efx_nic *efx); -+ int (*reconfigure) (struct efx_nic *efx); - void (*update_stats) (struct efx_nic *efx); -- void (*irq) (struct efx_nic *efx); -- void (*poll) (struct efx_nic *efx); -+ bool (*check_fault)(struct efx_nic *efx); - }; - - /** - * struct efx_phy_operations - Efx PHY operations table -+ * @probe: Probe PHY and initialise efx->mdio.mode_support, efx->mdio.mmds, -+ * efx->loopback_modes. - * @init: Initialise PHY - * @fini: Shut down PHY - * @reconfigure: Reconfigure PHY (e.g. for new link parameters) -- * @clear_interrupt: Clear down interrupt -- * @blink: Blink LEDs -- * @poll: Poll for hardware state. Serialised by the mac_lock. -+ * @poll: Update @link_state and report whether it changed. -+ * Serialised by the mac_lock. - * @get_settings: Get ethtool settings. Serialised by the mac_lock. - * @set_settings: Set ethtool settings. Serialised by the mac_lock. - * @set_npage_adv: Set abilities advertised in (Extended) Next Page - * (only needed where AN bit is set in mmds) -- * @num_tests: Number of PHY-specific tests/results -- * @test_names: Names of the tests/results -+ * @test_name: Get the name of a PHY-specific test/result - * @run_tests: Run tests and record results as appropriate. - * Flags are the ethtool tests flags. -- * @mmds: MMD presence mask -- * @loopbacks: Supported loopback modes mask - */ - struct efx_phy_operations { -- enum efx_mac_type macs; -+ int (*probe) (struct efx_nic *efx); - int (*init) (struct efx_nic *efx); - void (*fini) (struct efx_nic *efx); -- void (*reconfigure) (struct efx_nic *efx); -- void (*clear_interrupt) (struct efx_nic *efx); -- void (*poll) (struct efx_nic *efx); -+ int (*reconfigure) (struct efx_nic *efx); -+ bool (*poll) (struct efx_nic *efx); - void (*get_settings) (struct efx_nic *efx, - struct ethtool_cmd *ecmd); - int (*set_settings) (struct efx_nic *efx, - struct ethtool_cmd *ecmd); - void (*set_npage_adv) (struct efx_nic *efx, u32); -- u32 num_tests; -- const char *const *test_names; -+ const char *(*test_name) (struct efx_nic *efx, unsigned int index); - int (*run_tests) (struct efx_nic *efx, int *results, unsigned flags); -- int mmds; -- unsigned loopbacks; - }; - - /** -@@ -690,36 +656,38 @@ union efx_multicast_hash { - * @interrupt_mode: Interrupt mode - * @irq_rx_adaptive: Adaptive IRQ moderation enabled for RX event queues - * @irq_rx_moderation: IRQ moderation time for RX event queues -- * @i2c_adap: I2C adapter -- * @board_info: Board-level information - * @state: Device state flag. Serialised by the rtnl_lock. - * @reset_pending: Pending reset method (normally RESET_TYPE_NONE) - * @tx_queue: TX DMA queues - * @rx_queue: RX DMA queues - * @channel: Channels -+ * @next_buffer_table: First available buffer table id - * @n_rx_queues: Number of RX queues - * @n_channels: Number of channels in use - * @rx_buffer_len: RX buffer length - * @rx_buffer_order: Order (log2) of number of pages for each RX buffer -+ * @int_error_count: Number of internal errors seen recently -+ * @int_error_expire: Time at which error count will be expired - * @irq_status: Interrupt status buffer - * @last_irq_cpu: Last CPU to handle interrupt. - * This register is written with the SMP processor ID whenever an - * interrupt is handled. It is used by falcon_test_interrupt() - * to verify that an interrupt has occurred. - * @spi_flash: SPI flash device -- * This field will be %NULL if no flash device is present. -+ * This field will be %NULL if no flash device is present (or for Siena). - * @spi_eeprom: SPI EEPROM device -- * This field will be %NULL if no EEPROM device is present. -+ * This field will be %NULL if no EEPROM device is present (or for Siena). - * @spi_lock: SPI bus lock -+ * @mtd_list: List of MTDs attached to the NIC - * @n_rx_nodesc_drop_cnt: RX no descriptor drop count - * @nic_data: Hardware dependant state - * @mac_lock: MAC access lock. Protects @port_enabled, @phy_mode, - * @port_inhibited, efx_monitor() and efx_reconfigure_port() - * @port_enabled: Port enabled indicator. -- * Serialises efx_stop_all(), efx_start_all(), efx_monitor(), -- * efx_phy_work(), and efx_mac_work() with kernel interfaces. Safe to read -- * under any one of the rtnl_lock, mac_lock, or netif_tx_lock, but all -- * three must be held to modify it. -+ * Serialises efx_stop_all(), efx_start_all(), efx_monitor() and -+ * efx_mac_work() with kernel interfaces. Safe to read under any -+ * one of the rtnl_lock, mac_lock, or netif_tx_lock, but all three must -+ * be held to modify it. - * @port_inhibited: If set, the netif_carrier is always off. Hold the mac_lock - * @port_initialized: Port initialized? - * @net_dev: Operating system network device. Consider holding the rtnl lock -@@ -731,26 +699,23 @@ union efx_multicast_hash { - * &struct net_device_stats. - * @stats_buffer: DMA buffer for statistics - * @stats_lock: Statistics update lock. Serialises statistics fetches -- * @stats_disable_count: Nest count for disabling statistics fetches - * @mac_op: MAC interface - * @mac_address: Permanent MAC address - * @phy_type: PHY type -- * @phy_lock: PHY access lock -+ * @mdio_lock: MDIO lock - * @phy_op: PHY interface - * @phy_data: PHY private data (including PHY-specific stats) - * @mdio: PHY MDIO interface -+ * @mdio_bus: PHY MDIO bus ID (only used by Siena) - * @phy_mode: PHY operating mode. Serialised by @mac_lock. -- * @mac_up: MAC link state -- * @link_up: Link status -- * @link_fd: Link is full duplex -- * @link_fc: Actualy flow control flags -- * @link_speed: Link speed (Mbps) -+ * @xmac_poll_required: XMAC link state needs polling -+ * @link_advertising: Autonegotiation advertising flags -+ * @link_state: Current state of the link - * @n_link_state_changes: Number of times the link has changed state - * @promiscuous: Promiscuous flag. Protected by netif_tx_lock. - * @multicast_hash: Multicast hash table - * @wanted_fc: Wanted flow control flags -- * @phy_work: work item for dealing with PHY events -- * @mac_work: work item for dealing with MAC events -+ * @mac_work: Work item for changing MAC promiscuity and multicast hash - * @loopback_mode: Loopback status - * @loopback_modes: Supported loopback mode bitmask - * @loopback_selftest: Offline self-test private state -@@ -774,9 +739,6 @@ struct efx_nic { - bool irq_rx_adaptive; - unsigned int irq_rx_moderation; - -- struct i2c_adapter i2c_adap; -- struct efx_board board_info; -- - enum nic_state state; - enum reset_type reset_pending; - -@@ -784,21 +746,29 @@ struct efx_nic { - struct efx_rx_queue rx_queue[EFX_MAX_RX_QUEUES]; - struct efx_channel channel[EFX_MAX_CHANNELS]; - -+ unsigned next_buffer_table; - int n_rx_queues; - int n_channels; - unsigned int rx_buffer_len; - unsigned int rx_buffer_order; - -+ unsigned int_error_count; -+ unsigned long int_error_expire; -+ - struct efx_buffer irq_status; - volatile signed int last_irq_cpu; -+ unsigned long irq_zero_count; - - struct efx_spi_device *spi_flash; - struct efx_spi_device *spi_eeprom; - struct mutex spi_lock; -+#ifdef CONFIG_SFC_MTD -+ struct list_head mtd_list; -+#endif - - unsigned n_rx_nodesc_drop_cnt; - -- struct falcon_nic_data *nic_data; -+ void *nic_data; - - struct mutex mac_lock; - struct work_struct mac_work; -@@ -815,24 +785,21 @@ struct efx_nic { - struct efx_mac_stats mac_stats; - struct efx_buffer stats_buffer; - spinlock_t stats_lock; -- unsigned int stats_disable_count; - - struct efx_mac_operations *mac_op; - unsigned char mac_address[ETH_ALEN]; - -- enum phy_type phy_type; -- spinlock_t phy_lock; -- struct work_struct phy_work; -+ unsigned int phy_type; -+ struct mutex mdio_lock; - struct efx_phy_operations *phy_op; - void *phy_data; - struct mdio_if_info mdio; -+ unsigned int mdio_bus; - enum efx_phy_mode phy_mode; - -- bool mac_up; -- bool link_up; -- bool link_fd; -- enum efx_fc_type link_fc; -- unsigned int link_speed; -+ bool xmac_poll_required; -+ u32 link_advertising; -+ struct efx_link_state link_state; - unsigned int n_link_state_changes; - - bool promiscuous; -@@ -841,7 +808,7 @@ struct efx_nic { - - atomic_t rx_reset; - enum efx_loopback_mode loopback_mode; -- unsigned int loopback_modes; -+ u64 loopback_modes; - - void *loopback_selftest; - }; -@@ -860,50 +827,95 @@ static inline const char *efx_dev_name(struct efx_nic *efx) - return efx_dev_registered(efx) ? efx->name : ""; - } - -+static inline unsigned int efx_port_num(struct efx_nic *efx) -+{ -+ return PCI_FUNC(efx->pci_dev->devfn); -+} -+ - /** - * struct efx_nic_type - Efx device type definition -- * @mem_bar: Memory BAR number -+ * @probe: Probe the controller -+ * @remove: Free resources allocated by probe() -+ * @init: Initialise the controller -+ * @fini: Shut down the controller -+ * @monitor: Periodic function for polling link state and hardware monitor -+ * @reset: Reset the controller hardware and possibly the PHY. This will -+ * be called while the controller is uninitialised. -+ * @probe_port: Probe the MAC and PHY -+ * @remove_port: Free resources allocated by probe_port() -+ * @prepare_flush: Prepare the hardware for flushing the DMA queues -+ * @update_stats: Update statistics not provided by event handling -+ * @start_stats: Start the regular fetching of statistics -+ * @stop_stats: Stop the regular fetching of statistics -+ * @set_id_led: Set state of identifying LED or revert to automatic function -+ * @push_irq_moderation: Apply interrupt moderation value -+ * @push_multicast_hash: Apply multicast hash table -+ * @reconfigure_port: Push loopback/power/txdis changes to the MAC and PHY -+ * @get_wol: Get WoL configuration from driver state -+ * @set_wol: Push WoL configuration to the NIC -+ * @resume_wol: Synchronise WoL state between driver and MC (e.g. after resume) -+ * @test_registers: Test read/write functionality of control registers -+ * @test_nvram: Test validity of NVRAM contents -+ * @default_mac_ops: efx_mac_operations to set at startup -+ * @revision: Hardware architecture revision - * @mem_map_size: Memory BAR mapped size - * @txd_ptr_tbl_base: TX descriptor ring base address - * @rxd_ptr_tbl_base: RX descriptor ring base address - * @buf_tbl_base: Buffer table base address - * @evq_ptr_tbl_base: Event queue pointer table base address - * @evq_rptr_tbl_base: Event queue read-pointer table base address -- * @txd_ring_mask: TX descriptor ring size - 1 (must be a power of two - 1) -- * @rxd_ring_mask: RX descriptor ring size - 1 (must be a power of two - 1) -- * @evq_size: Event queue size (must be a power of two) - * @max_dma_mask: Maximum possible DMA mask -- * @tx_dma_mask: TX DMA mask -- * @bug5391_mask: Address mask for bug 5391 workaround -- * @rx_xoff_thresh: RX FIFO XOFF watermark (bytes) -- * @rx_xon_thresh: RX FIFO XON watermark (bytes) - * @rx_buffer_padding: Padding added to each RX buffer - * @max_interrupt_mode: Highest capability interrupt mode supported - * from &enum efx_init_mode. - * @phys_addr_channels: Number of channels with physically addressed - * descriptors -+ * @tx_dc_base: Base address in SRAM of TX queue descriptor caches -+ * @rx_dc_base: Base address in SRAM of RX queue descriptor caches -+ * @offload_features: net_device feature flags for protocol offload -+ * features implemented in hardware -+ * @reset_world_flags: Flags for additional components covered by -+ * reset method RESET_TYPE_WORLD - */ - struct efx_nic_type { -- unsigned int mem_bar; -+ int (*probe)(struct efx_nic *efx); -+ void (*remove)(struct efx_nic *efx); -+ int (*init)(struct efx_nic *efx); -+ void (*fini)(struct efx_nic *efx); -+ void (*monitor)(struct efx_nic *efx); -+ int (*reset)(struct efx_nic *efx, enum reset_type method); -+ int (*probe_port)(struct efx_nic *efx); -+ void (*remove_port)(struct efx_nic *efx); -+ void (*prepare_flush)(struct efx_nic *efx); -+ void (*update_stats)(struct efx_nic *efx); -+ void (*start_stats)(struct efx_nic *efx); -+ void (*stop_stats)(struct efx_nic *efx); -+ void (*set_id_led)(struct efx_nic *efx, enum efx_led_mode mode); -+ void (*push_irq_moderation)(struct efx_channel *channel); -+ void (*push_multicast_hash)(struct efx_nic *efx); -+ int (*reconfigure_port)(struct efx_nic *efx); -+ void (*get_wol)(struct efx_nic *efx, struct ethtool_wolinfo *wol); -+ int (*set_wol)(struct efx_nic *efx, u32 type); -+ void (*resume_wol)(struct efx_nic *efx); -+ int (*test_registers)(struct efx_nic *efx); -+ int (*test_nvram)(struct efx_nic *efx); -+ struct efx_mac_operations *default_mac_ops; -+ -+ int revision; - unsigned int mem_map_size; - unsigned int txd_ptr_tbl_base; - unsigned int rxd_ptr_tbl_base; - unsigned int buf_tbl_base; - unsigned int evq_ptr_tbl_base; - unsigned int evq_rptr_tbl_base; -- -- unsigned int txd_ring_mask; -- unsigned int rxd_ring_mask; -- unsigned int evq_size; - u64 max_dma_mask; -- unsigned int tx_dma_mask; -- unsigned bug5391_mask; -- -- int rx_xoff_thresh; -- int rx_xon_thresh; - unsigned int rx_buffer_padding; - unsigned int max_interrupt_mode; - unsigned int phys_addr_channels; -+ unsigned int tx_dc_base; -+ unsigned int rx_dc_base; -+ unsigned long offload_features; -+ u32 reset_world_flags; - }; - - /************************************************************************** -diff --git a/drivers/net/sfc/nic.c b/drivers/net/sfc/nic.c -new file mode 100644 -index 0000000..a577be2 ---- /dev/null -+++ b/drivers/net/sfc/nic.c -@@ -0,0 +1,1583 @@ -+/**************************************************************************** -+ * Driver for Solarflare Solarstorm network controllers and boards -+ * Copyright 2005-2006 Fen Systems Ltd. -+ * Copyright 2006-2009 Solarflare Communications Inc. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License version 2 as published -+ * by the Free Software Foundation, incorporated herein by reference. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include "net_driver.h" -+#include "bitfield.h" -+#include "efx.h" -+#include "nic.h" -+#include "regs.h" -+#include "io.h" -+#include "workarounds.h" -+ -+/************************************************************************** -+ * -+ * Configurable values -+ * -+ ************************************************************************** -+ */ -+ -+/* This is set to 16 for a good reason. In summary, if larger than -+ * 16, the descriptor cache holds more than a default socket -+ * buffer's worth of packets (for UDP we can only have at most one -+ * socket buffer's worth outstanding). This combined with the fact -+ * that we only get 1 TX event per descriptor cache means the NIC -+ * goes idle. -+ */ -+#define TX_DC_ENTRIES 16 -+#define TX_DC_ENTRIES_ORDER 1 -+ -+#define RX_DC_ENTRIES 64 -+#define RX_DC_ENTRIES_ORDER 3 -+ -+/* RX FIFO XOFF watermark -+ * -+ * When the amount of the RX FIFO increases used increases past this -+ * watermark send XOFF. Only used if RX flow control is enabled (ethtool -A) -+ * This also has an effect on RX/TX arbitration -+ */ -+int efx_nic_rx_xoff_thresh = -1; -+module_param_named(rx_xoff_thresh_bytes, efx_nic_rx_xoff_thresh, int, 0644); -+MODULE_PARM_DESC(rx_xoff_thresh_bytes, "RX fifo XOFF threshold"); -+ -+/* RX FIFO XON watermark -+ * -+ * When the amount of the RX FIFO used decreases below this -+ * watermark send XON. Only used if TX flow control is enabled (ethtool -A) -+ * This also has an effect on RX/TX arbitration -+ */ -+int efx_nic_rx_xon_thresh = -1; -+module_param_named(rx_xon_thresh_bytes, efx_nic_rx_xon_thresh, int, 0644); -+MODULE_PARM_DESC(rx_xon_thresh_bytes, "RX fifo XON threshold"); -+ -+/* If EFX_MAX_INT_ERRORS internal errors occur within -+ * EFX_INT_ERROR_EXPIRE seconds, we consider the NIC broken and -+ * disable it. -+ */ -+#define EFX_INT_ERROR_EXPIRE 3600 -+#define EFX_MAX_INT_ERRORS 5 -+ -+/* We poll for events every FLUSH_INTERVAL ms, and check FLUSH_POLL_COUNT times -+ */ -+#define EFX_FLUSH_INTERVAL 10 -+#define EFX_FLUSH_POLL_COUNT 100 -+ -+/* Size and alignment of special buffers (4KB) */ -+#define EFX_BUF_SIZE 4096 -+ -+/* Depth of RX flush request fifo */ -+#define EFX_RX_FLUSH_COUNT 4 -+ -+/************************************************************************** -+ * -+ * Solarstorm hardware access -+ * -+ **************************************************************************/ -+ -+static inline void efx_write_buf_tbl(struct efx_nic *efx, efx_qword_t *value, -+ unsigned int index) -+{ -+ efx_sram_writeq(efx, efx->membase + efx->type->buf_tbl_base, -+ value, index); -+} -+ -+/* Read the current event from the event queue */ -+static inline efx_qword_t *efx_event(struct efx_channel *channel, -+ unsigned int index) -+{ -+ return (((efx_qword_t *) (channel->eventq.addr)) + index); -+} -+ -+/* See if an event is present -+ * -+ * We check both the high and low dword of the event for all ones. We -+ * wrote all ones when we cleared the event, and no valid event can -+ * have all ones in either its high or low dwords. This approach is -+ * robust against reordering. -+ * -+ * Note that using a single 64-bit comparison is incorrect; even -+ * though the CPU read will be atomic, the DMA write may not be. -+ */ -+static inline int efx_event_present(efx_qword_t *event) -+{ -+ return (!(EFX_DWORD_IS_ALL_ONES(event->dword[0]) | -+ EFX_DWORD_IS_ALL_ONES(event->dword[1]))); -+} -+ -+static bool efx_masked_compare_oword(const efx_oword_t *a, const efx_oword_t *b, -+ const efx_oword_t *mask) -+{ -+ return ((a->u64[0] ^ b->u64[0]) & mask->u64[0]) || -+ ((a->u64[1] ^ b->u64[1]) & mask->u64[1]); -+} -+ -+int efx_nic_test_registers(struct efx_nic *efx, -+ const struct efx_nic_register_test *regs, -+ size_t n_regs) -+{ -+ unsigned address = 0, i, j; -+ efx_oword_t mask, imask, original, reg, buf; -+ -+ /* Falcon should be in loopback to isolate the XMAC from the PHY */ -+ WARN_ON(!LOOPBACK_INTERNAL(efx)); -+ -+ for (i = 0; i < n_regs; ++i) { -+ address = regs[i].address; -+ mask = imask = regs[i].mask; -+ EFX_INVERT_OWORD(imask); -+ -+ efx_reado(efx, &original, address); -+ -+ /* bit sweep on and off */ -+ for (j = 0; j < 128; j++) { -+ if (!EFX_EXTRACT_OWORD32(mask, j, j)) -+ continue; -+ -+ /* Test this testable bit can be set in isolation */ -+ EFX_AND_OWORD(reg, original, mask); -+ EFX_SET_OWORD32(reg, j, j, 1); -+ -+ efx_writeo(efx, ®, address); -+ efx_reado(efx, &buf, address); -+ -+ if (efx_masked_compare_oword(®, &buf, &mask)) -+ goto fail; -+ -+ /* Test this testable bit can be cleared in isolation */ -+ EFX_OR_OWORD(reg, original, mask); -+ EFX_SET_OWORD32(reg, j, j, 0); -+ -+ efx_writeo(efx, ®, address); -+ efx_reado(efx, &buf, address); -+ -+ if (efx_masked_compare_oword(®, &buf, &mask)) -+ goto fail; -+ } -+ -+ efx_writeo(efx, &original, address); -+ } -+ -+ return 0; -+ -+fail: -+ EFX_ERR(efx, "wrote "EFX_OWORD_FMT" read "EFX_OWORD_FMT -+ " at address 0x%x mask "EFX_OWORD_FMT"\n", EFX_OWORD_VAL(reg), -+ EFX_OWORD_VAL(buf), address, EFX_OWORD_VAL(mask)); -+ return -EIO; -+} -+ -+/************************************************************************** -+ * -+ * Special buffer handling -+ * Special buffers are used for event queues and the TX and RX -+ * descriptor rings. -+ * -+ *************************************************************************/ -+ -+/* -+ * Initialise a special buffer -+ * -+ * This will define a buffer (previously allocated via -+ * efx_alloc_special_buffer()) in the buffer table, allowing -+ * it to be used for event queues, descriptor rings etc. -+ */ -+static void -+efx_init_special_buffer(struct efx_nic *efx, struct efx_special_buffer *buffer) -+{ -+ efx_qword_t buf_desc; -+ int index; -+ dma_addr_t dma_addr; -+ int i; -+ -+ EFX_BUG_ON_PARANOID(!buffer->addr); -+ -+ /* Write buffer descriptors to NIC */ -+ for (i = 0; i < buffer->entries; i++) { -+ index = buffer->index + i; -+ dma_addr = buffer->dma_addr + (i * 4096); -+ EFX_LOG(efx, "mapping special buffer %d at %llx\n", -+ index, (unsigned long long)dma_addr); -+ EFX_POPULATE_QWORD_3(buf_desc, -+ FRF_AZ_BUF_ADR_REGION, 0, -+ FRF_AZ_BUF_ADR_FBUF, dma_addr >> 12, -+ FRF_AZ_BUF_OWNER_ID_FBUF, 0); -+ efx_write_buf_tbl(efx, &buf_desc, index); -+ } -+} -+ -+/* Unmaps a buffer and clears the buffer table entries */ -+static void -+efx_fini_special_buffer(struct efx_nic *efx, struct efx_special_buffer *buffer) -+{ -+ efx_oword_t buf_tbl_upd; -+ unsigned int start = buffer->index; -+ unsigned int end = (buffer->index + buffer->entries - 1); -+ -+ if (!buffer->entries) -+ return; -+ -+ EFX_LOG(efx, "unmapping special buffers %d-%d\n", -+ buffer->index, buffer->index + buffer->entries - 1); -+ -+ EFX_POPULATE_OWORD_4(buf_tbl_upd, -+ FRF_AZ_BUF_UPD_CMD, 0, -+ FRF_AZ_BUF_CLR_CMD, 1, -+ FRF_AZ_BUF_CLR_END_ID, end, -+ FRF_AZ_BUF_CLR_START_ID, start); -+ efx_writeo(efx, &buf_tbl_upd, FR_AZ_BUF_TBL_UPD); -+} -+ -+/* -+ * Allocate a new special buffer -+ * -+ * This allocates memory for a new buffer, clears it and allocates a -+ * new buffer ID range. It does not write into the buffer table. -+ * -+ * This call will allocate 4KB buffers, since 8KB buffers can't be -+ * used for event queues and descriptor rings. -+ */ -+static int efx_alloc_special_buffer(struct efx_nic *efx, -+ struct efx_special_buffer *buffer, -+ unsigned int len) -+{ -+ len = ALIGN(len, EFX_BUF_SIZE); -+ -+ buffer->addr = pci_alloc_consistent(efx->pci_dev, len, -+ &buffer->dma_addr); -+ if (!buffer->addr) -+ return -ENOMEM; -+ buffer->len = len; -+ buffer->entries = len / EFX_BUF_SIZE; -+ BUG_ON(buffer->dma_addr & (EFX_BUF_SIZE - 1)); -+ -+ /* All zeros is a potentially valid event so memset to 0xff */ -+ memset(buffer->addr, 0xff, len); -+ -+ /* Select new buffer ID */ -+ buffer->index = efx->next_buffer_table; -+ efx->next_buffer_table += buffer->entries; -+ -+ EFX_LOG(efx, "allocating special buffers %d-%d at %llx+%x " -+ "(virt %p phys %llx)\n", buffer->index, -+ buffer->index + buffer->entries - 1, -+ (u64)buffer->dma_addr, len, -+ buffer->addr, (u64)virt_to_phys(buffer->addr)); -+ -+ return 0; -+} -+ -+static void -+efx_free_special_buffer(struct efx_nic *efx, struct efx_special_buffer *buffer) -+{ -+ if (!buffer->addr) -+ return; -+ -+ EFX_LOG(efx, "deallocating special buffers %d-%d at %llx+%x " -+ "(virt %p phys %llx)\n", buffer->index, -+ buffer->index + buffer->entries - 1, -+ (u64)buffer->dma_addr, buffer->len, -+ buffer->addr, (u64)virt_to_phys(buffer->addr)); -+ -+ pci_free_consistent(efx->pci_dev, buffer->len, buffer->addr, -+ buffer->dma_addr); -+ buffer->addr = NULL; -+ buffer->entries = 0; -+} -+ -+/************************************************************************** -+ * -+ * Generic buffer handling -+ * These buffers are used for interrupt status and MAC stats -+ * -+ **************************************************************************/ -+ -+int efx_nic_alloc_buffer(struct efx_nic *efx, struct efx_buffer *buffer, -+ unsigned int len) -+{ -+ buffer->addr = pci_alloc_consistent(efx->pci_dev, len, -+ &buffer->dma_addr); -+ if (!buffer->addr) -+ return -ENOMEM; -+ buffer->len = len; -+ memset(buffer->addr, 0, len); -+ return 0; -+} -+ -+void efx_nic_free_buffer(struct efx_nic *efx, struct efx_buffer *buffer) -+{ -+ if (buffer->addr) { -+ pci_free_consistent(efx->pci_dev, buffer->len, -+ buffer->addr, buffer->dma_addr); -+ buffer->addr = NULL; -+ } -+} -+ -+/************************************************************************** -+ * -+ * TX path -+ * -+ **************************************************************************/ -+ -+/* Returns a pointer to the specified transmit descriptor in the TX -+ * descriptor queue belonging to the specified channel. -+ */ -+static inline efx_qword_t * -+efx_tx_desc(struct efx_tx_queue *tx_queue, unsigned int index) -+{ -+ return (((efx_qword_t *) (tx_queue->txd.addr)) + index); -+} -+ -+/* This writes to the TX_DESC_WPTR; write pointer for TX descriptor ring */ -+static inline void efx_notify_tx_desc(struct efx_tx_queue *tx_queue) -+{ -+ unsigned write_ptr; -+ efx_dword_t reg; -+ -+ write_ptr = tx_queue->write_count & EFX_TXQ_MASK; -+ EFX_POPULATE_DWORD_1(reg, FRF_AZ_TX_DESC_WPTR_DWORD, write_ptr); -+ efx_writed_page(tx_queue->efx, ®, -+ FR_AZ_TX_DESC_UPD_DWORD_P0, tx_queue->queue); -+} -+ -+ -+/* For each entry inserted into the software descriptor ring, create a -+ * descriptor in the hardware TX descriptor ring (in host memory), and -+ * write a doorbell. -+ */ -+void efx_nic_push_buffers(struct efx_tx_queue *tx_queue) -+{ -+ -+ struct efx_tx_buffer *buffer; -+ efx_qword_t *txd; -+ unsigned write_ptr; -+ -+ BUG_ON(tx_queue->write_count == tx_queue->insert_count); -+ -+ do { -+ write_ptr = tx_queue->write_count & EFX_TXQ_MASK; -+ buffer = &tx_queue->buffer[write_ptr]; -+ txd = efx_tx_desc(tx_queue, write_ptr); -+ ++tx_queue->write_count; -+ -+ /* Create TX descriptor ring entry */ -+ EFX_POPULATE_QWORD_4(*txd, -+ FSF_AZ_TX_KER_CONT, buffer->continuation, -+ FSF_AZ_TX_KER_BYTE_COUNT, buffer->len, -+ FSF_AZ_TX_KER_BUF_REGION, 0, -+ FSF_AZ_TX_KER_BUF_ADDR, buffer->dma_addr); -+ } while (tx_queue->write_count != tx_queue->insert_count); -+ -+ wmb(); /* Ensure descriptors are written before they are fetched */ -+ efx_notify_tx_desc(tx_queue); -+} -+ -+/* Allocate hardware resources for a TX queue */ -+int efx_nic_probe_tx(struct efx_tx_queue *tx_queue) -+{ -+ struct efx_nic *efx = tx_queue->efx; -+ BUILD_BUG_ON(EFX_TXQ_SIZE < 512 || EFX_TXQ_SIZE > 4096 || -+ EFX_TXQ_SIZE & EFX_TXQ_MASK); -+ return efx_alloc_special_buffer(efx, &tx_queue->txd, -+ EFX_TXQ_SIZE * sizeof(efx_qword_t)); -+} -+ -+void efx_nic_init_tx(struct efx_tx_queue *tx_queue) -+{ -+ efx_oword_t tx_desc_ptr; -+ struct efx_nic *efx = tx_queue->efx; -+ -+ tx_queue->flushed = FLUSH_NONE; -+ -+ /* Pin TX descriptor ring */ -+ efx_init_special_buffer(efx, &tx_queue->txd); -+ -+ /* Push TX descriptor ring to card */ -+ EFX_POPULATE_OWORD_10(tx_desc_ptr, -+ FRF_AZ_TX_DESCQ_EN, 1, -+ FRF_AZ_TX_ISCSI_DDIG_EN, 0, -+ FRF_AZ_TX_ISCSI_HDIG_EN, 0, -+ FRF_AZ_TX_DESCQ_BUF_BASE_ID, tx_queue->txd.index, -+ FRF_AZ_TX_DESCQ_EVQ_ID, -+ tx_queue->channel->channel, -+ FRF_AZ_TX_DESCQ_OWNER_ID, 0, -+ FRF_AZ_TX_DESCQ_LABEL, tx_queue->queue, -+ FRF_AZ_TX_DESCQ_SIZE, -+ __ffs(tx_queue->txd.entries), -+ FRF_AZ_TX_DESCQ_TYPE, 0, -+ FRF_BZ_TX_NON_IP_DROP_DIS, 1); -+ -+ if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0) { -+ int csum = tx_queue->queue == EFX_TX_QUEUE_OFFLOAD_CSUM; -+ EFX_SET_OWORD_FIELD(tx_desc_ptr, FRF_BZ_TX_IP_CHKSM_DIS, !csum); -+ EFX_SET_OWORD_FIELD(tx_desc_ptr, FRF_BZ_TX_TCP_CHKSM_DIS, -+ !csum); -+ } -+ -+ efx_writeo_table(efx, &tx_desc_ptr, efx->type->txd_ptr_tbl_base, -+ tx_queue->queue); -+ -+ if (efx_nic_rev(efx) < EFX_REV_FALCON_B0) { -+ efx_oword_t reg; -+ -+ /* Only 128 bits in this register */ -+ BUILD_BUG_ON(EFX_TX_QUEUE_COUNT >= 128); -+ -+ efx_reado(efx, ®, FR_AA_TX_CHKSM_CFG); -+ if (tx_queue->queue == EFX_TX_QUEUE_OFFLOAD_CSUM) -+ clear_bit_le(tx_queue->queue, (void *)®); -+ else -+ set_bit_le(tx_queue->queue, (void *)®); -+ efx_writeo(efx, ®, FR_AA_TX_CHKSM_CFG); -+ } -+} -+ -+static void efx_flush_tx_queue(struct efx_tx_queue *tx_queue) -+{ -+ struct efx_nic *efx = tx_queue->efx; -+ efx_oword_t tx_flush_descq; -+ -+ tx_queue->flushed = FLUSH_PENDING; -+ -+ /* Post a flush command */ -+ EFX_POPULATE_OWORD_2(tx_flush_descq, -+ FRF_AZ_TX_FLUSH_DESCQ_CMD, 1, -+ FRF_AZ_TX_FLUSH_DESCQ, tx_queue->queue); -+ efx_writeo(efx, &tx_flush_descq, FR_AZ_TX_FLUSH_DESCQ); -+} -+ -+void efx_nic_fini_tx(struct efx_tx_queue *tx_queue) -+{ -+ struct efx_nic *efx = tx_queue->efx; -+ efx_oword_t tx_desc_ptr; -+ -+ /* The queue should have been flushed */ -+ WARN_ON(tx_queue->flushed != FLUSH_DONE); -+ -+ /* Remove TX descriptor ring from card */ -+ EFX_ZERO_OWORD(tx_desc_ptr); -+ efx_writeo_table(efx, &tx_desc_ptr, efx->type->txd_ptr_tbl_base, -+ tx_queue->queue); -+ -+ /* Unpin TX descriptor ring */ -+ efx_fini_special_buffer(efx, &tx_queue->txd); -+} -+ -+/* Free buffers backing TX queue */ -+void efx_nic_remove_tx(struct efx_tx_queue *tx_queue) -+{ -+ efx_free_special_buffer(tx_queue->efx, &tx_queue->txd); -+} -+ -+/************************************************************************** -+ * -+ * RX path -+ * -+ **************************************************************************/ -+ -+/* Returns a pointer to the specified descriptor in the RX descriptor queue */ -+static inline efx_qword_t * -+efx_rx_desc(struct efx_rx_queue *rx_queue, unsigned int index) -+{ -+ return (((efx_qword_t *) (rx_queue->rxd.addr)) + index); -+} -+ -+/* This creates an entry in the RX descriptor queue */ -+static inline void -+efx_build_rx_desc(struct efx_rx_queue *rx_queue, unsigned index) -+{ -+ struct efx_rx_buffer *rx_buf; -+ efx_qword_t *rxd; -+ -+ rxd = efx_rx_desc(rx_queue, index); -+ rx_buf = efx_rx_buffer(rx_queue, index); -+ EFX_POPULATE_QWORD_3(*rxd, -+ FSF_AZ_RX_KER_BUF_SIZE, -+ rx_buf->len - -+ rx_queue->efx->type->rx_buffer_padding, -+ FSF_AZ_RX_KER_BUF_REGION, 0, -+ FSF_AZ_RX_KER_BUF_ADDR, rx_buf->dma_addr); -+} -+ -+/* This writes to the RX_DESC_WPTR register for the specified receive -+ * descriptor ring. -+ */ -+void efx_nic_notify_rx_desc(struct efx_rx_queue *rx_queue) -+{ -+ efx_dword_t reg; -+ unsigned write_ptr; -+ -+ while (rx_queue->notified_count != rx_queue->added_count) { -+ efx_build_rx_desc(rx_queue, -+ rx_queue->notified_count & -+ EFX_RXQ_MASK); -+ ++rx_queue->notified_count; -+ } -+ -+ wmb(); -+ write_ptr = rx_queue->added_count & EFX_RXQ_MASK; -+ EFX_POPULATE_DWORD_1(reg, FRF_AZ_RX_DESC_WPTR_DWORD, write_ptr); -+ efx_writed_page(rx_queue->efx, ®, -+ FR_AZ_RX_DESC_UPD_DWORD_P0, rx_queue->queue); -+} -+ -+int efx_nic_probe_rx(struct efx_rx_queue *rx_queue) -+{ -+ struct efx_nic *efx = rx_queue->efx; -+ BUILD_BUG_ON(EFX_RXQ_SIZE < 512 || EFX_RXQ_SIZE > 4096 || -+ EFX_RXQ_SIZE & EFX_RXQ_MASK); -+ return efx_alloc_special_buffer(efx, &rx_queue->rxd, -+ EFX_RXQ_SIZE * sizeof(efx_qword_t)); -+} -+ -+void efx_nic_init_rx(struct efx_rx_queue *rx_queue) -+{ -+ efx_oword_t rx_desc_ptr; -+ struct efx_nic *efx = rx_queue->efx; -+ bool is_b0 = efx_nic_rev(efx) >= EFX_REV_FALCON_B0; -+ bool iscsi_digest_en = is_b0; -+ -+ EFX_LOG(efx, "RX queue %d ring in special buffers %d-%d\n", -+ rx_queue->queue, rx_queue->rxd.index, -+ rx_queue->rxd.index + rx_queue->rxd.entries - 1); -+ -+ rx_queue->flushed = FLUSH_NONE; -+ -+ /* Pin RX descriptor ring */ -+ efx_init_special_buffer(efx, &rx_queue->rxd); -+ -+ /* Push RX descriptor ring to card */ -+ EFX_POPULATE_OWORD_10(rx_desc_ptr, -+ FRF_AZ_RX_ISCSI_DDIG_EN, iscsi_digest_en, -+ FRF_AZ_RX_ISCSI_HDIG_EN, iscsi_digest_en, -+ FRF_AZ_RX_DESCQ_BUF_BASE_ID, rx_queue->rxd.index, -+ FRF_AZ_RX_DESCQ_EVQ_ID, -+ rx_queue->channel->channel, -+ FRF_AZ_RX_DESCQ_OWNER_ID, 0, -+ FRF_AZ_RX_DESCQ_LABEL, rx_queue->queue, -+ FRF_AZ_RX_DESCQ_SIZE, -+ __ffs(rx_queue->rxd.entries), -+ FRF_AZ_RX_DESCQ_TYPE, 0 /* kernel queue */ , -+ /* For >=B0 this is scatter so disable */ -+ FRF_AZ_RX_DESCQ_JUMBO, !is_b0, -+ FRF_AZ_RX_DESCQ_EN, 1); -+ efx_writeo_table(efx, &rx_desc_ptr, efx->type->rxd_ptr_tbl_base, -+ rx_queue->queue); -+} -+ -+static void efx_flush_rx_queue(struct efx_rx_queue *rx_queue) -+{ -+ struct efx_nic *efx = rx_queue->efx; -+ efx_oword_t rx_flush_descq; -+ -+ rx_queue->flushed = FLUSH_PENDING; -+ -+ /* Post a flush command */ -+ EFX_POPULATE_OWORD_2(rx_flush_descq, -+ FRF_AZ_RX_FLUSH_DESCQ_CMD, 1, -+ FRF_AZ_RX_FLUSH_DESCQ, rx_queue->queue); -+ efx_writeo(efx, &rx_flush_descq, FR_AZ_RX_FLUSH_DESCQ); -+} -+ -+void efx_nic_fini_rx(struct efx_rx_queue *rx_queue) -+{ -+ efx_oword_t rx_desc_ptr; -+ struct efx_nic *efx = rx_queue->efx; -+ -+ /* The queue should already have been flushed */ -+ WARN_ON(rx_queue->flushed != FLUSH_DONE); -+ -+ /* Remove RX descriptor ring from card */ -+ EFX_ZERO_OWORD(rx_desc_ptr); -+ efx_writeo_table(efx, &rx_desc_ptr, efx->type->rxd_ptr_tbl_base, -+ rx_queue->queue); -+ -+ /* Unpin RX descriptor ring */ -+ efx_fini_special_buffer(efx, &rx_queue->rxd); -+} -+ -+/* Free buffers backing RX queue */ -+void efx_nic_remove_rx(struct efx_rx_queue *rx_queue) -+{ -+ efx_free_special_buffer(rx_queue->efx, &rx_queue->rxd); -+} -+ -+/************************************************************************** -+ * -+ * Event queue processing -+ * Event queues are processed by per-channel tasklets. -+ * -+ **************************************************************************/ -+ -+/* Update a channel's event queue's read pointer (RPTR) register -+ * -+ * This writes the EVQ_RPTR_REG register for the specified channel's -+ * event queue. -+ * -+ * Note that EVQ_RPTR_REG contains the index of the "last read" event, -+ * whereas channel->eventq_read_ptr contains the index of the "next to -+ * read" event. -+ */ -+void efx_nic_eventq_read_ack(struct efx_channel *channel) -+{ -+ efx_dword_t reg; -+ struct efx_nic *efx = channel->efx; -+ -+ EFX_POPULATE_DWORD_1(reg, FRF_AZ_EVQ_RPTR, channel->eventq_read_ptr); -+ efx_writed_table(efx, ®, efx->type->evq_rptr_tbl_base, -+ channel->channel); -+} -+ -+/* Use HW to insert a SW defined event */ -+void efx_generate_event(struct efx_channel *channel, efx_qword_t *event) -+{ -+ efx_oword_t drv_ev_reg; -+ -+ BUILD_BUG_ON(FRF_AZ_DRV_EV_DATA_LBN != 0 || -+ FRF_AZ_DRV_EV_DATA_WIDTH != 64); -+ drv_ev_reg.u32[0] = event->u32[0]; -+ drv_ev_reg.u32[1] = event->u32[1]; -+ drv_ev_reg.u32[2] = 0; -+ drv_ev_reg.u32[3] = 0; -+ EFX_SET_OWORD_FIELD(drv_ev_reg, FRF_AZ_DRV_EV_QID, channel->channel); -+ efx_writeo(channel->efx, &drv_ev_reg, FR_AZ_DRV_EV); -+} -+ -+/* Handle a transmit completion event -+ * -+ * The NIC batches TX completion events; the message we receive is of -+ * the form "complete all TX events up to this index". -+ */ -+static void -+efx_handle_tx_event(struct efx_channel *channel, efx_qword_t *event) -+{ -+ unsigned int tx_ev_desc_ptr; -+ unsigned int tx_ev_q_label; -+ struct efx_tx_queue *tx_queue; -+ struct efx_nic *efx = channel->efx; -+ -+ if (likely(EFX_QWORD_FIELD(*event, FSF_AZ_TX_EV_COMP))) { -+ /* Transmit completion */ -+ tx_ev_desc_ptr = EFX_QWORD_FIELD(*event, FSF_AZ_TX_EV_DESC_PTR); -+ tx_ev_q_label = EFX_QWORD_FIELD(*event, FSF_AZ_TX_EV_Q_LABEL); -+ tx_queue = &efx->tx_queue[tx_ev_q_label]; -+ channel->irq_mod_score += -+ (tx_ev_desc_ptr - tx_queue->read_count) & -+ EFX_TXQ_MASK; -+ efx_xmit_done(tx_queue, tx_ev_desc_ptr); -+ } else if (EFX_QWORD_FIELD(*event, FSF_AZ_TX_EV_WQ_FF_FULL)) { -+ /* Rewrite the FIFO write pointer */ -+ tx_ev_q_label = EFX_QWORD_FIELD(*event, FSF_AZ_TX_EV_Q_LABEL); -+ tx_queue = &efx->tx_queue[tx_ev_q_label]; -+ -+ if (efx_dev_registered(efx)) -+ netif_tx_lock(efx->net_dev); -+ efx_notify_tx_desc(tx_queue); -+ if (efx_dev_registered(efx)) -+ netif_tx_unlock(efx->net_dev); -+ } else if (EFX_QWORD_FIELD(*event, FSF_AZ_TX_EV_PKT_ERR) && -+ EFX_WORKAROUND_10727(efx)) { -+ efx_schedule_reset(efx, RESET_TYPE_TX_DESC_FETCH); -+ } else { -+ EFX_ERR(efx, "channel %d unexpected TX event " -+ EFX_QWORD_FMT"\n", channel->channel, -+ EFX_QWORD_VAL(*event)); -+ } -+} -+ -+/* Detect errors included in the rx_evt_pkt_ok bit. */ -+static void efx_handle_rx_not_ok(struct efx_rx_queue *rx_queue, -+ const efx_qword_t *event, -+ bool *rx_ev_pkt_ok, -+ bool *discard) -+{ -+ struct efx_nic *efx = rx_queue->efx; -+ bool rx_ev_buf_owner_id_err, rx_ev_ip_hdr_chksum_err; -+ bool rx_ev_tcp_udp_chksum_err, rx_ev_eth_crc_err; -+ bool rx_ev_frm_trunc, rx_ev_drib_nib, rx_ev_tobe_disc; -+ bool rx_ev_other_err, rx_ev_pause_frm; -+ bool rx_ev_hdr_type, rx_ev_mcast_pkt; -+ unsigned rx_ev_pkt_type; -+ -+ rx_ev_hdr_type = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_HDR_TYPE); -+ rx_ev_mcast_pkt = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_MCAST_PKT); -+ rx_ev_tobe_disc = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_TOBE_DISC); -+ rx_ev_pkt_type = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_PKT_TYPE); -+ rx_ev_buf_owner_id_err = EFX_QWORD_FIELD(*event, -+ FSF_AZ_RX_EV_BUF_OWNER_ID_ERR); -+ rx_ev_ip_hdr_chksum_err = EFX_QWORD_FIELD(*event, -+ FSF_AZ_RX_EV_IP_HDR_CHKSUM_ERR); -+ rx_ev_tcp_udp_chksum_err = EFX_QWORD_FIELD(*event, -+ FSF_AZ_RX_EV_TCP_UDP_CHKSUM_ERR); -+ rx_ev_eth_crc_err = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_ETH_CRC_ERR); -+ rx_ev_frm_trunc = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_FRM_TRUNC); -+ rx_ev_drib_nib = ((efx_nic_rev(efx) >= EFX_REV_FALCON_B0) ? -+ 0 : EFX_QWORD_FIELD(*event, FSF_AA_RX_EV_DRIB_NIB)); -+ rx_ev_pause_frm = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_PAUSE_FRM_ERR); -+ -+ /* Every error apart from tobe_disc and pause_frm */ -+ rx_ev_other_err = (rx_ev_drib_nib | rx_ev_tcp_udp_chksum_err | -+ rx_ev_buf_owner_id_err | rx_ev_eth_crc_err | -+ rx_ev_frm_trunc | rx_ev_ip_hdr_chksum_err); -+ -+ /* Count errors that are not in MAC stats. Ignore expected -+ * checksum errors during self-test. */ -+ if (rx_ev_frm_trunc) -+ ++rx_queue->channel->n_rx_frm_trunc; -+ else if (rx_ev_tobe_disc) -+ ++rx_queue->channel->n_rx_tobe_disc; -+ else if (!efx->loopback_selftest) { -+ if (rx_ev_ip_hdr_chksum_err) -+ ++rx_queue->channel->n_rx_ip_hdr_chksum_err; -+ else if (rx_ev_tcp_udp_chksum_err) -+ ++rx_queue->channel->n_rx_tcp_udp_chksum_err; -+ } -+ -+ /* The frame must be discarded if any of these are true. */ -+ *discard = (rx_ev_eth_crc_err | rx_ev_frm_trunc | rx_ev_drib_nib | -+ rx_ev_tobe_disc | rx_ev_pause_frm); -+ -+ /* TOBE_DISC is expected on unicast mismatches; don't print out an -+ * error message. FRM_TRUNC indicates RXDP dropped the packet due -+ * to a FIFO overflow. -+ */ -+#ifdef EFX_ENABLE_DEBUG -+ if (rx_ev_other_err) { -+ EFX_INFO_RL(efx, " RX queue %d unexpected RX event " -+ EFX_QWORD_FMT "%s%s%s%s%s%s%s%s\n", -+ rx_queue->queue, EFX_QWORD_VAL(*event), -+ rx_ev_buf_owner_id_err ? " [OWNER_ID_ERR]" : "", -+ rx_ev_ip_hdr_chksum_err ? -+ " [IP_HDR_CHKSUM_ERR]" : "", -+ rx_ev_tcp_udp_chksum_err ? -+ " [TCP_UDP_CHKSUM_ERR]" : "", -+ rx_ev_eth_crc_err ? " [ETH_CRC_ERR]" : "", -+ rx_ev_frm_trunc ? " [FRM_TRUNC]" : "", -+ rx_ev_drib_nib ? " [DRIB_NIB]" : "", -+ rx_ev_tobe_disc ? " [TOBE_DISC]" : "", -+ rx_ev_pause_frm ? " [PAUSE]" : ""); -+ } -+#endif -+} -+ -+/* Handle receive events that are not in-order. */ -+static void -+efx_handle_rx_bad_index(struct efx_rx_queue *rx_queue, unsigned index) -+{ -+ struct efx_nic *efx = rx_queue->efx; -+ unsigned expected, dropped; -+ -+ expected = rx_queue->removed_count & EFX_RXQ_MASK; -+ dropped = (index - expected) & EFX_RXQ_MASK; -+ EFX_INFO(efx, "dropped %d events (index=%d expected=%d)\n", -+ dropped, index, expected); -+ -+ efx_schedule_reset(efx, EFX_WORKAROUND_5676(efx) ? -+ RESET_TYPE_RX_RECOVERY : RESET_TYPE_DISABLE); -+} -+ -+/* Handle a packet received event -+ * -+ * The NIC gives a "discard" flag if it's a unicast packet with the -+ * wrong destination address -+ * Also "is multicast" and "matches multicast filter" flags can be used to -+ * discard non-matching multicast packets. -+ */ -+static void -+efx_handle_rx_event(struct efx_channel *channel, const efx_qword_t *event) -+{ -+ unsigned int rx_ev_desc_ptr, rx_ev_byte_cnt; -+ unsigned int rx_ev_hdr_type, rx_ev_mcast_pkt; -+ unsigned expected_ptr; -+ bool rx_ev_pkt_ok, discard = false, checksummed; -+ struct efx_rx_queue *rx_queue; -+ struct efx_nic *efx = channel->efx; -+ -+ /* Basic packet information */ -+ rx_ev_byte_cnt = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_BYTE_CNT); -+ rx_ev_pkt_ok = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_PKT_OK); -+ rx_ev_hdr_type = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_HDR_TYPE); -+ WARN_ON(EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_JUMBO_CONT)); -+ WARN_ON(EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_SOP) != 1); -+ WARN_ON(EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_Q_LABEL) != -+ channel->channel); -+ -+ rx_queue = &efx->rx_queue[channel->channel]; -+ -+ rx_ev_desc_ptr = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_DESC_PTR); -+ expected_ptr = rx_queue->removed_count & EFX_RXQ_MASK; -+ if (unlikely(rx_ev_desc_ptr != expected_ptr)) -+ efx_handle_rx_bad_index(rx_queue, rx_ev_desc_ptr); -+ -+ if (likely(rx_ev_pkt_ok)) { -+ /* If packet is marked as OK and packet type is TCP/IP or -+ * UDP/IP, then we can rely on the hardware checksum. -+ */ -+ checksummed = -+ likely(efx->rx_checksum_enabled) && -+ (rx_ev_hdr_type == FSE_CZ_RX_EV_HDR_TYPE_IPV4V6_TCP || -+ rx_ev_hdr_type == FSE_CZ_RX_EV_HDR_TYPE_IPV4V6_UDP); -+ } else { -+ efx_handle_rx_not_ok(rx_queue, event, &rx_ev_pkt_ok, &discard); -+ checksummed = false; -+ } -+ -+ /* Detect multicast packets that didn't match the filter */ -+ rx_ev_mcast_pkt = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_MCAST_PKT); -+ if (rx_ev_mcast_pkt) { -+ unsigned int rx_ev_mcast_hash_match = -+ EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_MCAST_HASH_MATCH); -+ -+ if (unlikely(!rx_ev_mcast_hash_match)) { -+ ++channel->n_rx_mcast_mismatch; -+ discard = true; -+ } -+ } -+ -+ channel->irq_mod_score += 2; -+ -+ /* Handle received packet */ -+ efx_rx_packet(rx_queue, rx_ev_desc_ptr, rx_ev_byte_cnt, -+ checksummed, discard); -+} -+ -+/* Global events are basically PHY events */ -+static void -+efx_handle_global_event(struct efx_channel *channel, efx_qword_t *event) -+{ -+ struct efx_nic *efx = channel->efx; -+ bool handled = false; -+ -+ if (EFX_QWORD_FIELD(*event, FSF_AB_GLB_EV_G_PHY0_INTR) || -+ EFX_QWORD_FIELD(*event, FSF_AB_GLB_EV_XG_PHY0_INTR) || -+ EFX_QWORD_FIELD(*event, FSF_AB_GLB_EV_XFP_PHY0_INTR)) { -+ /* Ignored */ -+ handled = true; -+ } -+ -+ if ((efx_nic_rev(efx) >= EFX_REV_FALCON_B0) && -+ EFX_QWORD_FIELD(*event, FSF_BB_GLB_EV_XG_MGT_INTR)) { -+ efx->xmac_poll_required = true; -+ handled = true; -+ } -+ -+ if (efx_nic_rev(efx) <= EFX_REV_FALCON_A1 ? -+ EFX_QWORD_FIELD(*event, FSF_AA_GLB_EV_RX_RECOVERY) : -+ EFX_QWORD_FIELD(*event, FSF_BB_GLB_EV_RX_RECOVERY)) { -+ EFX_ERR(efx, "channel %d seen global RX_RESET " -+ "event. Resetting.\n", channel->channel); -+ -+ atomic_inc(&efx->rx_reset); -+ efx_schedule_reset(efx, EFX_WORKAROUND_6555(efx) ? -+ RESET_TYPE_RX_RECOVERY : RESET_TYPE_DISABLE); -+ handled = true; -+ } -+ -+ if (!handled) -+ EFX_ERR(efx, "channel %d unknown global event " -+ EFX_QWORD_FMT "\n", channel->channel, -+ EFX_QWORD_VAL(*event)); -+} -+ -+static void -+efx_handle_driver_event(struct efx_channel *channel, efx_qword_t *event) -+{ -+ struct efx_nic *efx = channel->efx; -+ unsigned int ev_sub_code; -+ unsigned int ev_sub_data; -+ -+ ev_sub_code = EFX_QWORD_FIELD(*event, FSF_AZ_DRIVER_EV_SUBCODE); -+ ev_sub_data = EFX_QWORD_FIELD(*event, FSF_AZ_DRIVER_EV_SUBDATA); -+ -+ switch (ev_sub_code) { -+ case FSE_AZ_TX_DESCQ_FLS_DONE_EV: -+ EFX_TRACE(efx, "channel %d TXQ %d flushed\n", -+ channel->channel, ev_sub_data); -+ break; -+ case FSE_AZ_RX_DESCQ_FLS_DONE_EV: -+ EFX_TRACE(efx, "channel %d RXQ %d flushed\n", -+ channel->channel, ev_sub_data); -+ break; -+ case FSE_AZ_EVQ_INIT_DONE_EV: -+ EFX_LOG(efx, "channel %d EVQ %d initialised\n", -+ channel->channel, ev_sub_data); -+ break; -+ case FSE_AZ_SRM_UPD_DONE_EV: -+ EFX_TRACE(efx, "channel %d SRAM update done\n", -+ channel->channel); -+ break; -+ case FSE_AZ_WAKE_UP_EV: -+ EFX_TRACE(efx, "channel %d RXQ %d wakeup event\n", -+ channel->channel, ev_sub_data); -+ break; -+ case FSE_AZ_TIMER_EV: -+ EFX_TRACE(efx, "channel %d RX queue %d timer expired\n", -+ channel->channel, ev_sub_data); -+ break; -+ case FSE_AA_RX_RECOVER_EV: -+ EFX_ERR(efx, "channel %d seen DRIVER RX_RESET event. " -+ "Resetting.\n", channel->channel); -+ atomic_inc(&efx->rx_reset); -+ efx_schedule_reset(efx, -+ EFX_WORKAROUND_6555(efx) ? -+ RESET_TYPE_RX_RECOVERY : -+ RESET_TYPE_DISABLE); -+ break; -+ case FSE_BZ_RX_DSC_ERROR_EV: -+ EFX_ERR(efx, "RX DMA Q %d reports descriptor fetch error." -+ " RX Q %d is disabled.\n", ev_sub_data, ev_sub_data); -+ efx_schedule_reset(efx, RESET_TYPE_RX_DESC_FETCH); -+ break; -+ case FSE_BZ_TX_DSC_ERROR_EV: -+ EFX_ERR(efx, "TX DMA Q %d reports descriptor fetch error." -+ " TX Q %d is disabled.\n", ev_sub_data, ev_sub_data); -+ efx_schedule_reset(efx, RESET_TYPE_TX_DESC_FETCH); -+ break; -+ default: -+ EFX_TRACE(efx, "channel %d unknown driver event code %d " -+ "data %04x\n", channel->channel, ev_sub_code, -+ ev_sub_data); -+ break; -+ } -+} -+ -+int efx_nic_process_eventq(struct efx_channel *channel, int rx_quota) -+{ -+ unsigned int read_ptr; -+ efx_qword_t event, *p_event; -+ int ev_code; -+ int rx_packets = 0; -+ -+ read_ptr = channel->eventq_read_ptr; -+ -+ do { -+ p_event = efx_event(channel, read_ptr); -+ event = *p_event; -+ -+ if (!efx_event_present(&event)) -+ /* End of events */ -+ break; -+ -+ EFX_TRACE(channel->efx, "channel %d event is "EFX_QWORD_FMT"\n", -+ channel->channel, EFX_QWORD_VAL(event)); -+ -+ /* Clear this event by marking it all ones */ -+ EFX_SET_QWORD(*p_event); -+ -+ ev_code = EFX_QWORD_FIELD(event, FSF_AZ_EV_CODE); -+ -+ switch (ev_code) { -+ case FSE_AZ_EV_CODE_RX_EV: -+ efx_handle_rx_event(channel, &event); -+ ++rx_packets; -+ break; -+ case FSE_AZ_EV_CODE_TX_EV: -+ efx_handle_tx_event(channel, &event); -+ break; -+ case FSE_AZ_EV_CODE_DRV_GEN_EV: -+ channel->eventq_magic = EFX_QWORD_FIELD( -+ event, FSF_AZ_DRV_GEN_EV_MAGIC); -+ EFX_LOG(channel->efx, "channel %d received generated " -+ "event "EFX_QWORD_FMT"\n", channel->channel, -+ EFX_QWORD_VAL(event)); -+ break; -+ case FSE_AZ_EV_CODE_GLOBAL_EV: -+ efx_handle_global_event(channel, &event); -+ break; -+ case FSE_AZ_EV_CODE_DRIVER_EV: -+ efx_handle_driver_event(channel, &event); -+ break; -+ case FSE_CZ_EV_CODE_MCDI_EV: -+ efx_mcdi_process_event(channel, &event); -+ break; -+ default: -+ EFX_ERR(channel->efx, "channel %d unknown event type %d" -+ " (data " EFX_QWORD_FMT ")\n", channel->channel, -+ ev_code, EFX_QWORD_VAL(event)); -+ } -+ -+ /* Increment read pointer */ -+ read_ptr = (read_ptr + 1) & EFX_EVQ_MASK; -+ -+ } while (rx_packets < rx_quota); -+ -+ channel->eventq_read_ptr = read_ptr; -+ return rx_packets; -+} -+ -+ -+/* Allocate buffer table entries for event queue */ -+int efx_nic_probe_eventq(struct efx_channel *channel) -+{ -+ struct efx_nic *efx = channel->efx; -+ BUILD_BUG_ON(EFX_EVQ_SIZE < 512 || EFX_EVQ_SIZE > 32768 || -+ EFX_EVQ_SIZE & EFX_EVQ_MASK); -+ return efx_alloc_special_buffer(efx, &channel->eventq, -+ EFX_EVQ_SIZE * sizeof(efx_qword_t)); -+} -+ -+void efx_nic_init_eventq(struct efx_channel *channel) -+{ -+ efx_oword_t reg; -+ struct efx_nic *efx = channel->efx; -+ -+ EFX_LOG(efx, "channel %d event queue in special buffers %d-%d\n", -+ channel->channel, channel->eventq.index, -+ channel->eventq.index + channel->eventq.entries - 1); -+ -+ if (efx_nic_rev(efx) >= EFX_REV_SIENA_A0) { -+ EFX_POPULATE_OWORD_3(reg, -+ FRF_CZ_TIMER_Q_EN, 1, -+ FRF_CZ_HOST_NOTIFY_MODE, 0, -+ FRF_CZ_TIMER_MODE, FFE_CZ_TIMER_MODE_DIS); -+ efx_writeo_table(efx, ®, FR_BZ_TIMER_TBL, channel->channel); -+ } -+ -+ /* Pin event queue buffer */ -+ efx_init_special_buffer(efx, &channel->eventq); -+ -+ /* Fill event queue with all ones (i.e. empty events) */ -+ memset(channel->eventq.addr, 0xff, channel->eventq.len); -+ -+ /* Push event queue to card */ -+ EFX_POPULATE_OWORD_3(reg, -+ FRF_AZ_EVQ_EN, 1, -+ FRF_AZ_EVQ_SIZE, __ffs(channel->eventq.entries), -+ FRF_AZ_EVQ_BUF_BASE_ID, channel->eventq.index); -+ efx_writeo_table(efx, ®, efx->type->evq_ptr_tbl_base, -+ channel->channel); -+ -+ efx->type->push_irq_moderation(channel); -+} -+ -+void efx_nic_fini_eventq(struct efx_channel *channel) -+{ -+ efx_oword_t reg; -+ struct efx_nic *efx = channel->efx; -+ -+ /* Remove event queue from card */ -+ EFX_ZERO_OWORD(reg); -+ efx_writeo_table(efx, ®, efx->type->evq_ptr_tbl_base, -+ channel->channel); -+ if (efx_nic_rev(efx) >= EFX_REV_SIENA_A0) -+ efx_writeo_table(efx, ®, FR_BZ_TIMER_TBL, channel->channel); -+ -+ /* Unpin event queue */ -+ efx_fini_special_buffer(efx, &channel->eventq); -+} -+ -+/* Free buffers backing event queue */ -+void efx_nic_remove_eventq(struct efx_channel *channel) -+{ -+ efx_free_special_buffer(channel->efx, &channel->eventq); -+} -+ -+ -+/* Generates a test event on the event queue. A subsequent call to -+ * process_eventq() should pick up the event and place the value of -+ * "magic" into channel->eventq_magic; -+ */ -+void efx_nic_generate_test_event(struct efx_channel *channel, unsigned int magic) -+{ -+ efx_qword_t test_event; -+ -+ EFX_POPULATE_QWORD_2(test_event, FSF_AZ_EV_CODE, -+ FSE_AZ_EV_CODE_DRV_GEN_EV, -+ FSF_AZ_DRV_GEN_EV_MAGIC, magic); -+ efx_generate_event(channel, &test_event); -+} -+ -+/************************************************************************** -+ * -+ * Flush handling -+ * -+ **************************************************************************/ -+ -+ -+static void efx_poll_flush_events(struct efx_nic *efx) -+{ -+ struct efx_channel *channel = &efx->channel[0]; -+ struct efx_tx_queue *tx_queue; -+ struct efx_rx_queue *rx_queue; -+ unsigned int read_ptr = channel->eventq_read_ptr; -+ unsigned int end_ptr = (read_ptr - 1) & EFX_EVQ_MASK; -+ -+ do { -+ efx_qword_t *event = efx_event(channel, read_ptr); -+ int ev_code, ev_sub_code, ev_queue; -+ bool ev_failed; -+ -+ if (!efx_event_present(event)) -+ break; -+ -+ ev_code = EFX_QWORD_FIELD(*event, FSF_AZ_EV_CODE); -+ ev_sub_code = EFX_QWORD_FIELD(*event, -+ FSF_AZ_DRIVER_EV_SUBCODE); -+ if (ev_code == FSE_AZ_EV_CODE_DRIVER_EV && -+ ev_sub_code == FSE_AZ_TX_DESCQ_FLS_DONE_EV) { -+ ev_queue = EFX_QWORD_FIELD(*event, -+ FSF_AZ_DRIVER_EV_SUBDATA); -+ if (ev_queue < EFX_TX_QUEUE_COUNT) { -+ tx_queue = efx->tx_queue + ev_queue; -+ tx_queue->flushed = FLUSH_DONE; -+ } -+ } else if (ev_code == FSE_AZ_EV_CODE_DRIVER_EV && -+ ev_sub_code == FSE_AZ_RX_DESCQ_FLS_DONE_EV) { -+ ev_queue = EFX_QWORD_FIELD( -+ *event, FSF_AZ_DRIVER_EV_RX_DESCQ_ID); -+ ev_failed = EFX_QWORD_FIELD( -+ *event, FSF_AZ_DRIVER_EV_RX_FLUSH_FAIL); -+ if (ev_queue < efx->n_rx_queues) { -+ rx_queue = efx->rx_queue + ev_queue; -+ rx_queue->flushed = -+ ev_failed ? FLUSH_FAILED : FLUSH_DONE; -+ } -+ } -+ -+ /* We're about to destroy the queue anyway, so -+ * it's ok to throw away every non-flush event */ -+ EFX_SET_QWORD(*event); -+ -+ read_ptr = (read_ptr + 1) & EFX_EVQ_MASK; -+ } while (read_ptr != end_ptr); -+ -+ channel->eventq_read_ptr = read_ptr; -+} -+ -+/* Handle tx and rx flushes at the same time, since they run in -+ * parallel in the hardware and there's no reason for us to -+ * serialise them */ -+int efx_nic_flush_queues(struct efx_nic *efx) -+{ -+ struct efx_rx_queue *rx_queue; -+ struct efx_tx_queue *tx_queue; -+ int i, tx_pending, rx_pending; -+ -+ /* If necessary prepare the hardware for flushing */ -+ efx->type->prepare_flush(efx); -+ -+ /* Flush all tx queues in parallel */ -+ efx_for_each_tx_queue(tx_queue, efx) -+ efx_flush_tx_queue(tx_queue); -+ -+ /* The hardware supports four concurrent rx flushes, each of which may -+ * need to be retried if there is an outstanding descriptor fetch */ -+ for (i = 0; i < EFX_FLUSH_POLL_COUNT; ++i) { -+ rx_pending = tx_pending = 0; -+ efx_for_each_rx_queue(rx_queue, efx) { -+ if (rx_queue->flushed == FLUSH_PENDING) -+ ++rx_pending; -+ } -+ efx_for_each_rx_queue(rx_queue, efx) { -+ if (rx_pending == EFX_RX_FLUSH_COUNT) -+ break; -+ if (rx_queue->flushed == FLUSH_FAILED || -+ rx_queue->flushed == FLUSH_NONE) { -+ efx_flush_rx_queue(rx_queue); -+ ++rx_pending; -+ } -+ } -+ efx_for_each_tx_queue(tx_queue, efx) { -+ if (tx_queue->flushed != FLUSH_DONE) -+ ++tx_pending; -+ } -+ -+ if (rx_pending == 0 && tx_pending == 0) -+ return 0; -+ -+ msleep(EFX_FLUSH_INTERVAL); -+ efx_poll_flush_events(efx); -+ } -+ -+ /* Mark the queues as all flushed. We're going to return failure -+ * leading to a reset, or fake up success anyway */ -+ efx_for_each_tx_queue(tx_queue, efx) { -+ if (tx_queue->flushed != FLUSH_DONE) -+ EFX_ERR(efx, "tx queue %d flush command timed out\n", -+ tx_queue->queue); -+ tx_queue->flushed = FLUSH_DONE; -+ } -+ efx_for_each_rx_queue(rx_queue, efx) { -+ if (rx_queue->flushed != FLUSH_DONE) -+ EFX_ERR(efx, "rx queue %d flush command timed out\n", -+ rx_queue->queue); -+ rx_queue->flushed = FLUSH_DONE; -+ } -+ -+ if (EFX_WORKAROUND_7803(efx)) -+ return 0; -+ -+ return -ETIMEDOUT; -+} -+ -+/************************************************************************** -+ * -+ * Hardware interrupts -+ * The hardware interrupt handler does very little work; all the event -+ * queue processing is carried out by per-channel tasklets. -+ * -+ **************************************************************************/ -+ -+/* Enable/disable/generate interrupts */ -+static inline void efx_nic_interrupts(struct efx_nic *efx, -+ bool enabled, bool force) -+{ -+ efx_oword_t int_en_reg_ker; -+ unsigned int level = 0; -+ -+ if (EFX_WORKAROUND_17213(efx) && !EFX_INT_MODE_USE_MSI(efx)) -+ /* Set the level always even if we're generating a test -+ * interrupt, because our legacy interrupt handler is safe */ -+ level = 0x1f; -+ -+ EFX_POPULATE_OWORD_3(int_en_reg_ker, -+ FRF_AZ_KER_INT_LEVE_SEL, level, -+ FRF_AZ_KER_INT_KER, force, -+ FRF_AZ_DRV_INT_EN_KER, enabled); -+ efx_writeo(efx, &int_en_reg_ker, FR_AZ_INT_EN_KER); -+} -+ -+void efx_nic_enable_interrupts(struct efx_nic *efx) -+{ -+ struct efx_channel *channel; -+ -+ EFX_ZERO_OWORD(*((efx_oword_t *) efx->irq_status.addr)); -+ wmb(); /* Ensure interrupt vector is clear before interrupts enabled */ -+ -+ /* Enable interrupts */ -+ efx_nic_interrupts(efx, true, false); -+ -+ /* Force processing of all the channels to get the EVQ RPTRs up to -+ date */ -+ efx_for_each_channel(channel, efx) -+ efx_schedule_channel(channel); -+} -+ -+void efx_nic_disable_interrupts(struct efx_nic *efx) -+{ -+ /* Disable interrupts */ -+ efx_nic_interrupts(efx, false, false); -+} -+ -+/* Generate a test interrupt -+ * Interrupt must already have been enabled, otherwise nasty things -+ * may happen. -+ */ -+void efx_nic_generate_interrupt(struct efx_nic *efx) -+{ -+ efx_nic_interrupts(efx, true, true); -+} -+ -+/* Process a fatal interrupt -+ * Disable bus mastering ASAP and schedule a reset -+ */ -+irqreturn_t efx_nic_fatal_interrupt(struct efx_nic *efx) -+{ -+ struct falcon_nic_data *nic_data = efx->nic_data; -+ efx_oword_t *int_ker = efx->irq_status.addr; -+ efx_oword_t fatal_intr; -+ int error, mem_perr; -+ -+ efx_reado(efx, &fatal_intr, FR_AZ_FATAL_INTR_KER); -+ error = EFX_OWORD_FIELD(fatal_intr, FRF_AZ_FATAL_INTR); -+ -+ EFX_ERR(efx, "SYSTEM ERROR " EFX_OWORD_FMT " status " -+ EFX_OWORD_FMT ": %s\n", EFX_OWORD_VAL(*int_ker), -+ EFX_OWORD_VAL(fatal_intr), -+ error ? "disabling bus mastering" : "no recognised error"); -+ if (error == 0) -+ goto out; -+ -+ /* If this is a memory parity error dump which blocks are offending */ -+ mem_perr = EFX_OWORD_FIELD(fatal_intr, FRF_AZ_MEM_PERR_INT_KER); -+ if (mem_perr) { -+ efx_oword_t reg; -+ efx_reado(efx, ®, FR_AZ_MEM_STAT); -+ EFX_ERR(efx, "SYSTEM ERROR: memory parity error " -+ EFX_OWORD_FMT "\n", EFX_OWORD_VAL(reg)); -+ } -+ -+ /* Disable both devices */ -+ pci_clear_master(efx->pci_dev); -+ if (efx_nic_is_dual_func(efx)) -+ pci_clear_master(nic_data->pci_dev2); -+ efx_nic_disable_interrupts(efx); -+ -+ /* Count errors and reset or disable the NIC accordingly */ -+ if (efx->int_error_count == 0 || -+ time_after(jiffies, efx->int_error_expire)) { -+ efx->int_error_count = 0; -+ efx->int_error_expire = -+ jiffies + EFX_INT_ERROR_EXPIRE * HZ; -+ } -+ if (++efx->int_error_count < EFX_MAX_INT_ERRORS) { -+ EFX_ERR(efx, "SYSTEM ERROR - reset scheduled\n"); -+ efx_schedule_reset(efx, RESET_TYPE_INT_ERROR); -+ } else { -+ EFX_ERR(efx, "SYSTEM ERROR - max number of errors seen." -+ "NIC will be disabled\n"); -+ efx_schedule_reset(efx, RESET_TYPE_DISABLE); -+ } -+out: -+ return IRQ_HANDLED; -+} -+ -+/* Handle a legacy interrupt -+ * Acknowledges the interrupt and schedule event queue processing. -+ */ -+static irqreturn_t efx_legacy_interrupt(int irq, void *dev_id) -+{ -+ struct efx_nic *efx = dev_id; -+ efx_oword_t *int_ker = efx->irq_status.addr; -+ irqreturn_t result = IRQ_NONE; -+ struct efx_channel *channel; -+ efx_dword_t reg; -+ u32 queues; -+ int syserr; -+ -+ /* Read the ISR which also ACKs the interrupts */ -+ efx_readd(efx, ®, FR_BZ_INT_ISR0); -+ queues = EFX_EXTRACT_DWORD(reg, 0, 31); -+ -+ /* Check to see if we have a serious error condition */ -+ syserr = EFX_OWORD_FIELD(*int_ker, FSF_AZ_NET_IVEC_FATAL_INT); -+ if (unlikely(syserr)) -+ return efx_nic_fatal_interrupt(efx); -+ -+ if (queues != 0) { -+ if (EFX_WORKAROUND_15783(efx)) -+ efx->irq_zero_count = 0; -+ -+ /* Schedule processing of any interrupting queues */ -+ efx_for_each_channel(channel, efx) { -+ if (queues & 1) -+ efx_schedule_channel(channel); -+ queues >>= 1; -+ } -+ result = IRQ_HANDLED; -+ -+ } else if (EFX_WORKAROUND_15783(efx) && -+ efx->irq_zero_count++ == 0) { -+ efx_qword_t *event; -+ -+ /* Ensure we rearm all event queues */ -+ efx_for_each_channel(channel, efx) { -+ event = efx_event(channel, channel->eventq_read_ptr); -+ if (efx_event_present(event)) -+ efx_schedule_channel(channel); -+ } -+ -+ result = IRQ_HANDLED; -+ } -+ -+ if (result == IRQ_HANDLED) { -+ efx->last_irq_cpu = raw_smp_processor_id(); -+ EFX_TRACE(efx, "IRQ %d on CPU %d status " EFX_DWORD_FMT "\n", -+ irq, raw_smp_processor_id(), EFX_DWORD_VAL(reg)); -+ } -+ -+ return result; -+} -+ -+/* Handle an MSI interrupt -+ * -+ * Handle an MSI hardware interrupt. This routine schedules event -+ * queue processing. No interrupt acknowledgement cycle is necessary. -+ * Also, we never need to check that the interrupt is for us, since -+ * MSI interrupts cannot be shared. -+ */ -+static irqreturn_t efx_msi_interrupt(int irq, void *dev_id) -+{ -+ struct efx_channel *channel = dev_id; -+ struct efx_nic *efx = channel->efx; -+ efx_oword_t *int_ker = efx->irq_status.addr; -+ int syserr; -+ -+ efx->last_irq_cpu = raw_smp_processor_id(); -+ EFX_TRACE(efx, "IRQ %d on CPU %d status " EFX_OWORD_FMT "\n", -+ irq, raw_smp_processor_id(), EFX_OWORD_VAL(*int_ker)); -+ -+ /* Check to see if we have a serious error condition */ -+ syserr = EFX_OWORD_FIELD(*int_ker, FSF_AZ_NET_IVEC_FATAL_INT); -+ if (unlikely(syserr)) -+ return efx_nic_fatal_interrupt(efx); -+ -+ /* Schedule processing of the channel */ -+ efx_schedule_channel(channel); -+ -+ return IRQ_HANDLED; -+} -+ -+ -+/* Setup RSS indirection table. -+ * This maps from the hash value of the packet to RXQ -+ */ -+static void efx_setup_rss_indir_table(struct efx_nic *efx) -+{ -+ int i = 0; -+ unsigned long offset; -+ efx_dword_t dword; -+ -+ if (efx_nic_rev(efx) < EFX_REV_FALCON_B0) -+ return; -+ -+ for (offset = FR_BZ_RX_INDIRECTION_TBL; -+ offset < FR_BZ_RX_INDIRECTION_TBL + 0x800; -+ offset += 0x10) { -+ EFX_POPULATE_DWORD_1(dword, FRF_BZ_IT_QUEUE, -+ i % efx->n_rx_queues); -+ efx_writed(efx, &dword, offset); -+ i++; -+ } -+} -+ -+/* Hook interrupt handler(s) -+ * Try MSI and then legacy interrupts. -+ */ -+int efx_nic_init_interrupt(struct efx_nic *efx) -+{ -+ struct efx_channel *channel; -+ int rc; -+ -+ if (!EFX_INT_MODE_USE_MSI(efx)) { -+ irq_handler_t handler; -+ if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0) -+ handler = efx_legacy_interrupt; -+ else -+ handler = falcon_legacy_interrupt_a1; -+ -+ rc = request_irq(efx->legacy_irq, handler, IRQF_SHARED, -+ efx->name, efx); -+ if (rc) { -+ EFX_ERR(efx, "failed to hook legacy IRQ %d\n", -+ efx->pci_dev->irq); -+ goto fail1; -+ } -+ return 0; -+ } -+ -+ /* Hook MSI or MSI-X interrupt */ -+ efx_for_each_channel(channel, efx) { -+ rc = request_irq(channel->irq, efx_msi_interrupt, -+ IRQF_PROBE_SHARED, /* Not shared */ -+ channel->name, channel); -+ if (rc) { -+ EFX_ERR(efx, "failed to hook IRQ %d\n", channel->irq); -+ goto fail2; -+ } -+ } -+ -+ return 0; -+ -+ fail2: -+ efx_for_each_channel(channel, efx) -+ free_irq(channel->irq, channel); -+ fail1: -+ return rc; -+} -+ -+void efx_nic_fini_interrupt(struct efx_nic *efx) -+{ -+ struct efx_channel *channel; -+ efx_oword_t reg; -+ -+ /* Disable MSI/MSI-X interrupts */ -+ efx_for_each_channel(channel, efx) { -+ if (channel->irq) -+ free_irq(channel->irq, channel); -+ } -+ -+ /* ACK legacy interrupt */ -+ if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0) -+ efx_reado(efx, ®, FR_BZ_INT_ISR0); -+ else -+ falcon_irq_ack_a1(efx); -+ -+ /* Disable legacy interrupt */ -+ if (efx->legacy_irq) -+ free_irq(efx->legacy_irq, efx); -+} -+ -+u32 efx_nic_fpga_ver(struct efx_nic *efx) -+{ -+ efx_oword_t altera_build; -+ efx_reado(efx, &altera_build, FR_AZ_ALTERA_BUILD); -+ return EFX_OWORD_FIELD(altera_build, FRF_AZ_ALTERA_BUILD_VER); -+} -+ -+void efx_nic_init_common(struct efx_nic *efx) -+{ -+ efx_oword_t temp; -+ -+ /* Set positions of descriptor caches in SRAM. */ -+ EFX_POPULATE_OWORD_1(temp, FRF_AZ_SRM_TX_DC_BASE_ADR, -+ efx->type->tx_dc_base / 8); -+ efx_writeo(efx, &temp, FR_AZ_SRM_TX_DC_CFG); -+ EFX_POPULATE_OWORD_1(temp, FRF_AZ_SRM_RX_DC_BASE_ADR, -+ efx->type->rx_dc_base / 8); -+ efx_writeo(efx, &temp, FR_AZ_SRM_RX_DC_CFG); -+ -+ /* Set TX descriptor cache size. */ -+ BUILD_BUG_ON(TX_DC_ENTRIES != (8 << TX_DC_ENTRIES_ORDER)); -+ EFX_POPULATE_OWORD_1(temp, FRF_AZ_TX_DC_SIZE, TX_DC_ENTRIES_ORDER); -+ efx_writeo(efx, &temp, FR_AZ_TX_DC_CFG); -+ -+ /* Set RX descriptor cache size. Set low watermark to size-8, as -+ * this allows most efficient prefetching. -+ */ -+ BUILD_BUG_ON(RX_DC_ENTRIES != (8 << RX_DC_ENTRIES_ORDER)); -+ EFX_POPULATE_OWORD_1(temp, FRF_AZ_RX_DC_SIZE, RX_DC_ENTRIES_ORDER); -+ efx_writeo(efx, &temp, FR_AZ_RX_DC_CFG); -+ EFX_POPULATE_OWORD_1(temp, FRF_AZ_RX_DC_PF_LWM, RX_DC_ENTRIES - 8); -+ efx_writeo(efx, &temp, FR_AZ_RX_DC_PF_WM); -+ -+ /* Program INT_KER address */ -+ EFX_POPULATE_OWORD_2(temp, -+ FRF_AZ_NORM_INT_VEC_DIS_KER, -+ EFX_INT_MODE_USE_MSI(efx), -+ FRF_AZ_INT_ADR_KER, efx->irq_status.dma_addr); -+ efx_writeo(efx, &temp, FR_AZ_INT_ADR_KER); -+ -+ /* Enable all the genuinely fatal interrupts. (They are still -+ * masked by the overall interrupt mask, controlled by -+ * falcon_interrupts()). -+ * -+ * Note: All other fatal interrupts are enabled -+ */ -+ EFX_POPULATE_OWORD_3(temp, -+ FRF_AZ_ILL_ADR_INT_KER_EN, 1, -+ FRF_AZ_RBUF_OWN_INT_KER_EN, 1, -+ FRF_AZ_TBUF_OWN_INT_KER_EN, 1); -+ EFX_INVERT_OWORD(temp); -+ efx_writeo(efx, &temp, FR_AZ_FATAL_INTR_KER); -+ -+ efx_setup_rss_indir_table(efx); -+ -+ /* Disable the ugly timer-based TX DMA backoff and allow TX DMA to be -+ * controlled by the RX FIFO fill level. Set arbitration to one pkt/Q. -+ */ -+ efx_reado(efx, &temp, FR_AZ_TX_RESERVED); -+ EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_RX_SPACER, 0xfe); -+ EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_RX_SPACER_EN, 1); -+ EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_ONE_PKT_PER_Q, 1); -+ EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_PUSH_EN, 0); -+ EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_DIS_NON_IP_EV, 1); -+ /* Enable SW_EV to inherit in char driver - assume harmless here */ -+ EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_SOFT_EVT_EN, 1); -+ /* Prefetch threshold 2 => fetch when descriptor cache half empty */ -+ EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_PREF_THRESHOLD, 2); -+ /* Squash TX of packets of 16 bytes or less */ -+ if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0) -+ EFX_SET_OWORD_FIELD(temp, FRF_BZ_TX_FLUSH_MIN_LEN_EN, 1); -+ efx_writeo(efx, &temp, FR_AZ_TX_RESERVED); -+} -diff --git a/drivers/net/sfc/nic.h b/drivers/net/sfc/nic.h -new file mode 100644 -index 0000000..9351c03 ---- /dev/null -+++ b/drivers/net/sfc/nic.h -@@ -0,0 +1,261 @@ -+/**************************************************************************** -+ * Driver for Solarflare Solarstorm network controllers and boards -+ * Copyright 2005-2006 Fen Systems Ltd. -+ * Copyright 2006-2009 Solarflare Communications Inc. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License version 2 as published -+ * by the Free Software Foundation, incorporated herein by reference. -+ */ -+ -+#ifndef EFX_NIC_H -+#define EFX_NIC_H -+ -+#include -+#include "net_driver.h" -+#include "efx.h" -+#include "mcdi.h" -+ -+/* -+ * Falcon hardware control -+ */ -+ -+enum { -+ EFX_REV_FALCON_A0 = 0, -+ EFX_REV_FALCON_A1 = 1, -+ EFX_REV_FALCON_B0 = 2, -+ EFX_REV_SIENA_A0 = 3, -+}; -+ -+static inline int efx_nic_rev(struct efx_nic *efx) -+{ -+ return efx->type->revision; -+} -+ -+extern u32 efx_nic_fpga_ver(struct efx_nic *efx); -+ -+static inline bool efx_nic_has_mc(struct efx_nic *efx) -+{ -+ return efx_nic_rev(efx) >= EFX_REV_SIENA_A0; -+} -+/* NIC has two interlinked PCI functions for the same port. */ -+static inline bool efx_nic_is_dual_func(struct efx_nic *efx) -+{ -+ return efx_nic_rev(efx) < EFX_REV_FALCON_B0; -+} -+ -+enum { -+ PHY_TYPE_NONE = 0, -+ PHY_TYPE_TXC43128 = 1, -+ PHY_TYPE_88E1111 = 2, -+ PHY_TYPE_SFX7101 = 3, -+ PHY_TYPE_QT2022C2 = 4, -+ PHY_TYPE_PM8358 = 6, -+ PHY_TYPE_SFT9001A = 8, -+ PHY_TYPE_QT2025C = 9, -+ PHY_TYPE_SFT9001B = 10, -+}; -+ -+#define FALCON_XMAC_LOOPBACKS \ -+ ((1 << LOOPBACK_XGMII) | \ -+ (1 << LOOPBACK_XGXS) | \ -+ (1 << LOOPBACK_XAUI)) -+ -+#define FALCON_GMAC_LOOPBACKS \ -+ (1 << LOOPBACK_GMAC) -+ -+/** -+ * struct falcon_board_type - board operations and type information -+ * @id: Board type id, as found in NVRAM -+ * @ref_model: Model number of Solarflare reference design -+ * @gen_type: Generic board type description -+ * @init: Allocate resources and initialise peripheral hardware -+ * @init_phy: Do board-specific PHY initialisation -+ * @fini: Shut down hardware and free resources -+ * @set_id_led: Set state of identifying LED or revert to automatic function -+ * @monitor: Board-specific health check function -+ */ -+struct falcon_board_type { -+ u8 id; -+ const char *ref_model; -+ const char *gen_type; -+ int (*init) (struct efx_nic *nic); -+ void (*init_phy) (struct efx_nic *efx); -+ void (*fini) (struct efx_nic *nic); -+ void (*set_id_led) (struct efx_nic *efx, enum efx_led_mode mode); -+ int (*monitor) (struct efx_nic *nic); -+}; -+ -+/** -+ * struct falcon_board - board information -+ * @type: Type of board -+ * @major: Major rev. ('A', 'B' ...) -+ * @minor: Minor rev. (0, 1, ...) -+ * @i2c_adap: I2C adapter for on-board peripherals -+ * @i2c_data: Data for bit-banging algorithm -+ * @hwmon_client: I2C client for hardware monitor -+ * @ioexp_client: I2C client for power/port control -+ */ -+struct falcon_board { -+ const struct falcon_board_type *type; -+ int major; -+ int minor; -+ struct i2c_adapter i2c_adap; -+ struct i2c_algo_bit_data i2c_data; -+ struct i2c_client *hwmon_client, *ioexp_client; -+}; -+ -+/** -+ * struct falcon_nic_data - Falcon NIC state -+ * @pci_dev2: Secondary function of Falcon A -+ * @board: Board state and functions -+ * @stats_disable_count: Nest count for disabling statistics fetches -+ * @stats_pending: Is there a pending DMA of MAC statistics. -+ * @stats_timer: A timer for regularly fetching MAC statistics. -+ * @stats_dma_done: Pointer to the flag which indicates DMA completion. -+ */ -+struct falcon_nic_data { -+ struct pci_dev *pci_dev2; -+ struct falcon_board board; -+ unsigned int stats_disable_count; -+ bool stats_pending; -+ struct timer_list stats_timer; -+ u32 *stats_dma_done; -+}; -+ -+static inline struct falcon_board *falcon_board(struct efx_nic *efx) -+{ -+ struct falcon_nic_data *data = efx->nic_data; -+ return &data->board; -+} -+ -+/** -+ * struct siena_nic_data - Siena NIC state -+ * @fw_version: Management controller firmware version -+ * @fw_build: Firmware build number -+ * @mcdi: Management-Controller-to-Driver Interface -+ * @wol_filter_id: Wake-on-LAN packet filter id -+ */ -+struct siena_nic_data { -+ u64 fw_version; -+ u32 fw_build; -+ struct efx_mcdi_iface mcdi; -+ int wol_filter_id; -+}; -+ -+extern void siena_print_fwver(struct efx_nic *efx, char *buf, size_t len); -+ -+extern struct efx_nic_type falcon_a1_nic_type; -+extern struct efx_nic_type falcon_b0_nic_type; -+extern struct efx_nic_type siena_a0_nic_type; -+ -+/************************************************************************** -+ * -+ * Externs -+ * -+ ************************************************************************** -+ */ -+ -+extern void falcon_probe_board(struct efx_nic *efx, u16 revision_info); -+ -+/* TX data path */ -+extern int efx_nic_probe_tx(struct efx_tx_queue *tx_queue); -+extern void efx_nic_init_tx(struct efx_tx_queue *tx_queue); -+extern void efx_nic_fini_tx(struct efx_tx_queue *tx_queue); -+extern void efx_nic_remove_tx(struct efx_tx_queue *tx_queue); -+extern void efx_nic_push_buffers(struct efx_tx_queue *tx_queue); -+ -+/* RX data path */ -+extern int efx_nic_probe_rx(struct efx_rx_queue *rx_queue); -+extern void efx_nic_init_rx(struct efx_rx_queue *rx_queue); -+extern void efx_nic_fini_rx(struct efx_rx_queue *rx_queue); -+extern void efx_nic_remove_rx(struct efx_rx_queue *rx_queue); -+extern void efx_nic_notify_rx_desc(struct efx_rx_queue *rx_queue); -+ -+/* Event data path */ -+extern int efx_nic_probe_eventq(struct efx_channel *channel); -+extern void efx_nic_init_eventq(struct efx_channel *channel); -+extern void efx_nic_fini_eventq(struct efx_channel *channel); -+extern void efx_nic_remove_eventq(struct efx_channel *channel); -+extern int efx_nic_process_eventq(struct efx_channel *channel, int rx_quota); -+extern void efx_nic_eventq_read_ack(struct efx_channel *channel); -+ -+/* MAC/PHY */ -+extern void falcon_drain_tx_fifo(struct efx_nic *efx); -+extern void falcon_reconfigure_mac_wrapper(struct efx_nic *efx); -+extern int efx_nic_rx_xoff_thresh, efx_nic_rx_xon_thresh; -+ -+/* Interrupts and test events */ -+extern int efx_nic_init_interrupt(struct efx_nic *efx); -+extern void efx_nic_enable_interrupts(struct efx_nic *efx); -+extern void efx_nic_generate_test_event(struct efx_channel *channel, -+ unsigned int magic); -+extern void efx_nic_generate_interrupt(struct efx_nic *efx); -+extern void efx_nic_disable_interrupts(struct efx_nic *efx); -+extern void efx_nic_fini_interrupt(struct efx_nic *efx); -+extern irqreturn_t efx_nic_fatal_interrupt(struct efx_nic *efx); -+extern irqreturn_t falcon_legacy_interrupt_a1(int irq, void *dev_id); -+extern void falcon_irq_ack_a1(struct efx_nic *efx); -+ -+#define EFX_IRQ_MOD_RESOLUTION 5 -+ -+/* Global Resources */ -+extern int efx_nic_flush_queues(struct efx_nic *efx); -+extern void falcon_start_nic_stats(struct efx_nic *efx); -+extern void falcon_stop_nic_stats(struct efx_nic *efx); -+extern int falcon_reset_xaui(struct efx_nic *efx); -+extern void efx_nic_init_common(struct efx_nic *efx); -+ -+int efx_nic_alloc_buffer(struct efx_nic *efx, struct efx_buffer *buffer, -+ unsigned int len); -+void efx_nic_free_buffer(struct efx_nic *efx, struct efx_buffer *buffer); -+ -+/* Tests */ -+struct efx_nic_register_test { -+ unsigned address; -+ efx_oword_t mask; -+}; -+extern int efx_nic_test_registers(struct efx_nic *efx, -+ const struct efx_nic_register_test *regs, -+ size_t n_regs); -+ -+/************************************************************************** -+ * -+ * Falcon MAC stats -+ * -+ ************************************************************************** -+ */ -+ -+#define FALCON_STAT_OFFSET(falcon_stat) EFX_VAL(falcon_stat, offset) -+#define FALCON_STAT_WIDTH(falcon_stat) EFX_VAL(falcon_stat, WIDTH) -+ -+/* Retrieve statistic from statistics block */ -+#define FALCON_STAT(efx, falcon_stat, efx_stat) do { \ -+ if (FALCON_STAT_WIDTH(falcon_stat) == 16) \ -+ (efx)->mac_stats.efx_stat += le16_to_cpu( \ -+ *((__force __le16 *) \ -+ (efx->stats_buffer.addr + \ -+ FALCON_STAT_OFFSET(falcon_stat)))); \ -+ else if (FALCON_STAT_WIDTH(falcon_stat) == 32) \ -+ (efx)->mac_stats.efx_stat += le32_to_cpu( \ -+ *((__force __le32 *) \ -+ (efx->stats_buffer.addr + \ -+ FALCON_STAT_OFFSET(falcon_stat)))); \ -+ else \ -+ (efx)->mac_stats.efx_stat += le64_to_cpu( \ -+ *((__force __le64 *) \ -+ (efx->stats_buffer.addr + \ -+ FALCON_STAT_OFFSET(falcon_stat)))); \ -+ } while (0) -+ -+#define FALCON_MAC_STATS_SIZE 0x100 -+ -+#define MAC_DATA_LBN 0 -+#define MAC_DATA_WIDTH 32 -+ -+extern void efx_nic_generate_event(struct efx_channel *channel, -+ efx_qword_t *event); -+ -+extern void falcon_poll_xmac(struct efx_nic *efx); -+ -+#endif /* EFX_NIC_H */ -diff --git a/drivers/net/sfc/phy.h b/drivers/net/sfc/phy.h -index c1cff9c..5bc2613 100644 ---- a/drivers/net/sfc/phy.h -+++ b/drivers/net/sfc/phy.h -@@ -1,6 +1,6 @@ - /**************************************************************************** - * Driver for Solarflare Solarstorm network controllers and boards -- * Copyright 2007-2008 Solarflare Communications Inc. -+ * Copyright 2007-2009 Solarflare Communications Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published -@@ -16,16 +16,16 @@ - extern struct efx_phy_operations falcon_sfx7101_phy_ops; - extern struct efx_phy_operations falcon_sft9001_phy_ops; - --extern void tenxpress_phy_blink(struct efx_nic *efx, bool blink); -+extern void tenxpress_set_id_led(struct efx_nic *efx, enum efx_led_mode mode); - - /* Wait for the PHY to boot. Return 0 on success, -EINVAL if the PHY failed - * to boot due to corrupt flash, or some other negative error code. */ - extern int sft9001_wait_boot(struct efx_nic *efx); - - /**************************************************************************** -- * AMCC/Quake QT20xx PHYs -+ * AMCC/Quake QT202x PHYs - */ --extern struct efx_phy_operations falcon_xfp_phy_ops; -+extern struct efx_phy_operations falcon_qt202x_phy_ops; - - /* These PHYs provide various H/W control states for LEDs */ - #define QUAKE_LED_LINK_INVAL (0) -@@ -39,6 +39,23 @@ extern struct efx_phy_operations falcon_xfp_phy_ops; - #define QUAKE_LED_TXLINK (0) - #define QUAKE_LED_RXLINK (8) - --extern void xfp_set_led(struct efx_nic *p, int led, int state); -+extern void falcon_qt202x_set_led(struct efx_nic *p, int led, int state); -+ -+/**************************************************************************** -+ * Siena managed PHYs -+ */ -+extern struct efx_phy_operations efx_mcdi_phy_ops; -+ -+extern int efx_mcdi_mdio_read(struct efx_nic *efx, unsigned int bus, -+ unsigned int prtad, unsigned int devad, -+ u16 addr, u16 *value_out, u32 *status_out); -+extern int efx_mcdi_mdio_write(struct efx_nic *efx, unsigned int bus, -+ unsigned int prtad, unsigned int devad, -+ u16 addr, u16 value, u32 *status_out); -+extern void efx_mcdi_phy_decode_link(struct efx_nic *efx, -+ struct efx_link_state *link_state, -+ u32 speed, u32 flags, u32 fcntl); -+extern int efx_mcdi_phy_reconfigure(struct efx_nic *efx); -+extern void efx_mcdi_phy_check_fcntl(struct efx_nic *efx, u32 lpa); - - #endif -diff --git a/drivers/net/sfc/qt202x_phy.c b/drivers/net/sfc/qt202x_phy.c -new file mode 100644 -index 0000000..3800fc7 ---- /dev/null -+++ b/drivers/net/sfc/qt202x_phy.c -@@ -0,0 +1,242 @@ -+/**************************************************************************** -+ * Driver for Solarflare Solarstorm network controllers and boards -+ * Copyright 2006-2009 Solarflare Communications Inc. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License version 2 as published -+ * by the Free Software Foundation, incorporated herein by reference. -+ */ -+/* -+ * Driver for AMCC QT202x SFP+ and XFP adapters; see www.amcc.com for details -+ */ -+ -+#include -+#include -+#include "efx.h" -+#include "mdio_10g.h" -+#include "phy.h" -+#include "nic.h" -+ -+#define QT202X_REQUIRED_DEVS (MDIO_DEVS_PCS | \ -+ MDIO_DEVS_PMAPMD | \ -+ MDIO_DEVS_PHYXS) -+ -+#define QT202X_LOOPBACKS ((1 << LOOPBACK_PCS) | \ -+ (1 << LOOPBACK_PMAPMD) | \ -+ (1 << LOOPBACK_PHYXS_WS)) -+ -+/****************************************************************************/ -+/* Quake-specific MDIO registers */ -+#define MDIO_QUAKE_LED0_REG (0xD006) -+ -+/* QT2025C only */ -+#define PCS_FW_HEARTBEAT_REG 0xd7ee -+#define PCS_FW_HEARTB_LBN 0 -+#define PCS_FW_HEARTB_WIDTH 8 -+#define PCS_UC8051_STATUS_REG 0xd7fd -+#define PCS_UC_STATUS_LBN 0 -+#define PCS_UC_STATUS_WIDTH 8 -+#define PCS_UC_STATUS_FW_SAVE 0x20 -+#define PMA_PMD_FTX_CTRL2_REG 0xc309 -+#define PMA_PMD_FTX_STATIC_LBN 13 -+#define PMA_PMD_VEND1_REG 0xc001 -+#define PMA_PMD_VEND1_LBTXD_LBN 15 -+#define PCS_VEND1_REG 0xc000 -+#define PCS_VEND1_LBTXD_LBN 5 -+ -+void falcon_qt202x_set_led(struct efx_nic *p, int led, int mode) -+{ -+ int addr = MDIO_QUAKE_LED0_REG + led; -+ efx_mdio_write(p, MDIO_MMD_PMAPMD, addr, mode); -+} -+ -+struct qt202x_phy_data { -+ enum efx_phy_mode phy_mode; -+}; -+ -+#define QT2022C2_MAX_RESET_TIME 500 -+#define QT2022C2_RESET_WAIT 10 -+ -+static int qt2025c_wait_reset(struct efx_nic *efx) -+{ -+ unsigned long timeout = jiffies + 10 * HZ; -+ int reg, old_counter = 0; -+ -+ /* Wait for firmware heartbeat to start */ -+ for (;;) { -+ int counter; -+ reg = efx_mdio_read(efx, MDIO_MMD_PCS, PCS_FW_HEARTBEAT_REG); -+ if (reg < 0) -+ return reg; -+ counter = ((reg >> PCS_FW_HEARTB_LBN) & -+ ((1 << PCS_FW_HEARTB_WIDTH) - 1)); -+ if (old_counter == 0) -+ old_counter = counter; -+ else if (counter != old_counter) -+ break; -+ if (time_after(jiffies, timeout)) -+ return -ETIMEDOUT; -+ msleep(10); -+ } -+ -+ /* Wait for firmware status to look good */ -+ for (;;) { -+ reg = efx_mdio_read(efx, MDIO_MMD_PCS, PCS_UC8051_STATUS_REG); -+ if (reg < 0) -+ return reg; -+ if ((reg & -+ ((1 << PCS_UC_STATUS_WIDTH) - 1) << PCS_UC_STATUS_LBN) >= -+ PCS_UC_STATUS_FW_SAVE) -+ break; -+ if (time_after(jiffies, timeout)) -+ return -ETIMEDOUT; -+ msleep(100); -+ } -+ -+ return 0; -+} -+ -+static int qt202x_reset_phy(struct efx_nic *efx) -+{ -+ int rc; -+ -+ if (efx->phy_type == PHY_TYPE_QT2025C) { -+ /* Wait for the reset triggered by falcon_reset_hw() -+ * to complete */ -+ rc = qt2025c_wait_reset(efx); -+ if (rc < 0) -+ goto fail; -+ } else { -+ /* Reset the PHYXS MMD. This is documented as doing -+ * a complete soft reset. */ -+ rc = efx_mdio_reset_mmd(efx, MDIO_MMD_PHYXS, -+ QT2022C2_MAX_RESET_TIME / -+ QT2022C2_RESET_WAIT, -+ QT2022C2_RESET_WAIT); -+ if (rc < 0) -+ goto fail; -+ } -+ -+ /* Wait 250ms for the PHY to complete bootup */ -+ msleep(250); -+ -+ /* Check that all the MMDs we expect are present and responding. We -+ * expect faults on some if the link is down, but not on the PHY XS */ -+ rc = efx_mdio_check_mmds(efx, QT202X_REQUIRED_DEVS, MDIO_DEVS_PHYXS); -+ if (rc < 0) -+ goto fail; -+ -+ falcon_board(efx)->type->init_phy(efx); -+ -+ return rc; -+ -+ fail: -+ EFX_ERR(efx, "PHY reset timed out\n"); -+ return rc; -+} -+ -+static int qt202x_phy_probe(struct efx_nic *efx) -+{ -+ efx->mdio.mmds = QT202X_REQUIRED_DEVS; -+ efx->mdio.mode_support = MDIO_SUPPORTS_C45 | MDIO_EMULATE_C22; -+ efx->loopback_modes = QT202X_LOOPBACKS | FALCON_XMAC_LOOPBACKS; -+ return 0; -+} -+ -+static int qt202x_phy_init(struct efx_nic *efx) -+{ -+ struct qt202x_phy_data *phy_data; -+ u32 devid; -+ int rc; -+ -+ rc = qt202x_reset_phy(efx); -+ if (rc) { -+ EFX_ERR(efx, "PHY init failed\n"); -+ return rc; -+ } -+ -+ phy_data = kzalloc(sizeof(struct qt202x_phy_data), GFP_KERNEL); -+ if (!phy_data) -+ return -ENOMEM; -+ efx->phy_data = phy_data; -+ -+ devid = efx_mdio_read_id(efx, MDIO_MMD_PHYXS); -+ EFX_INFO(efx, "PHY ID reg %x (OUI %06x model %02x revision %x)\n", -+ devid, efx_mdio_id_oui(devid), efx_mdio_id_model(devid), -+ efx_mdio_id_rev(devid)); -+ -+ phy_data->phy_mode = efx->phy_mode; -+ return 0; -+} -+ -+static int qt202x_link_ok(struct efx_nic *efx) -+{ -+ return efx_mdio_links_ok(efx, QT202X_REQUIRED_DEVS); -+} -+ -+static bool qt202x_phy_poll(struct efx_nic *efx) -+{ -+ bool was_up = efx->link_state.up; -+ -+ efx->link_state.up = qt202x_link_ok(efx); -+ efx->link_state.speed = 10000; -+ efx->link_state.fd = true; -+ efx->link_state.fc = efx->wanted_fc; -+ -+ return efx->link_state.up != was_up; -+} -+ -+static int qt202x_phy_reconfigure(struct efx_nic *efx) -+{ -+ struct qt202x_phy_data *phy_data = efx->phy_data; -+ -+ if (efx->phy_type == PHY_TYPE_QT2025C) { -+ /* There are several different register bits which can -+ * disable TX (and save power) on direct-attach cables -+ * or optical transceivers, varying somewhat between -+ * firmware versions. Only 'static mode' appears to -+ * cover everything. */ -+ mdio_set_flag( -+ &efx->mdio, efx->mdio.prtad, MDIO_MMD_PMAPMD, -+ PMA_PMD_FTX_CTRL2_REG, 1 << PMA_PMD_FTX_STATIC_LBN, -+ efx->phy_mode & PHY_MODE_TX_DISABLED || -+ efx->phy_mode & PHY_MODE_LOW_POWER || -+ efx->loopback_mode == LOOPBACK_PCS || -+ efx->loopback_mode == LOOPBACK_PMAPMD); -+ } else { -+ /* Reset the PHY when moving from tx off to tx on */ -+ if (!(efx->phy_mode & PHY_MODE_TX_DISABLED) && -+ (phy_data->phy_mode & PHY_MODE_TX_DISABLED)) -+ qt202x_reset_phy(efx); -+ -+ efx_mdio_transmit_disable(efx); -+ } -+ -+ efx_mdio_phy_reconfigure(efx); -+ -+ phy_data->phy_mode = efx->phy_mode; -+ -+ return 0; -+} -+ -+static void qt202x_phy_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) -+{ -+ mdio45_ethtool_gset(&efx->mdio, ecmd); -+} -+ -+static void qt202x_phy_fini(struct efx_nic *efx) -+{ -+ /* Free the context block */ -+ kfree(efx->phy_data); -+ efx->phy_data = NULL; -+} -+ -+struct efx_phy_operations falcon_qt202x_phy_ops = { -+ .probe = qt202x_phy_probe, -+ .init = qt202x_phy_init, -+ .reconfigure = qt202x_phy_reconfigure, -+ .poll = qt202x_phy_poll, -+ .fini = qt202x_phy_fini, -+ .get_settings = qt202x_phy_get_settings, -+ .set_settings = efx_mdio_set_settings, -+}; -diff --git a/drivers/net/sfc/regs.h b/drivers/net/sfc/regs.h -new file mode 100644 -index 0000000..89d606f ---- /dev/null -+++ b/drivers/net/sfc/regs.h -@@ -0,0 +1,3168 @@ -+/**************************************************************************** -+ * Driver for Solarflare Solarstorm network controllers and boards -+ * Copyright 2005-2006 Fen Systems Ltd. -+ * Copyright 2006-2009 Solarflare Communications Inc. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License version 2 as published -+ * by the Free Software Foundation, incorporated herein by reference. -+ */ -+ -+#ifndef EFX_REGS_H -+#define EFX_REGS_H -+ -+/* -+ * Falcon hardware architecture definitions have a name prefix following -+ * the format: -+ * -+ * F__ -+ * -+ * The following strings are used: -+ * -+ * MMIO register MC register Host memory structure -+ * ------------------------------------------------------------- -+ * Address R MCR -+ * Bitfield RF MCRF SF -+ * Enumerator FE MCFE SE -+ * -+ * is the first revision to which the definition applies: -+ * -+ * A: Falcon A1 (SFC4000AB) -+ * B: Falcon B0 (SFC4000BA) -+ * C: Siena A0 (SFL9021AA) -+ * -+ * If the definition has been changed or removed in later revisions -+ * then is the last revision to which the definition applies; -+ * otherwise it is "Z". -+ */ -+ -+/************************************************************************** -+ * -+ * Falcon/Siena registers and descriptors -+ * -+ ************************************************************************** -+ */ -+ -+/* ADR_REGION_REG: Address region register */ -+#define FR_AZ_ADR_REGION 0x00000000 -+#define FRF_AZ_ADR_REGION3_LBN 96 -+#define FRF_AZ_ADR_REGION3_WIDTH 18 -+#define FRF_AZ_ADR_REGION2_LBN 64 -+#define FRF_AZ_ADR_REGION2_WIDTH 18 -+#define FRF_AZ_ADR_REGION1_LBN 32 -+#define FRF_AZ_ADR_REGION1_WIDTH 18 -+#define FRF_AZ_ADR_REGION0_LBN 0 -+#define FRF_AZ_ADR_REGION0_WIDTH 18 -+ -+/* INT_EN_REG_KER: Kernel driver Interrupt enable register */ -+#define FR_AZ_INT_EN_KER 0x00000010 -+#define FRF_AZ_KER_INT_LEVE_SEL_LBN 8 -+#define FRF_AZ_KER_INT_LEVE_SEL_WIDTH 6 -+#define FRF_AZ_KER_INT_CHAR_LBN 4 -+#define FRF_AZ_KER_INT_CHAR_WIDTH 1 -+#define FRF_AZ_KER_INT_KER_LBN 3 -+#define FRF_AZ_KER_INT_KER_WIDTH 1 -+#define FRF_AZ_DRV_INT_EN_KER_LBN 0 -+#define FRF_AZ_DRV_INT_EN_KER_WIDTH 1 -+ -+/* INT_EN_REG_CHAR: Char Driver interrupt enable register */ -+#define FR_BZ_INT_EN_CHAR 0x00000020 -+#define FRF_BZ_CHAR_INT_LEVE_SEL_LBN 8 -+#define FRF_BZ_CHAR_INT_LEVE_SEL_WIDTH 6 -+#define FRF_BZ_CHAR_INT_CHAR_LBN 4 -+#define FRF_BZ_CHAR_INT_CHAR_WIDTH 1 -+#define FRF_BZ_CHAR_INT_KER_LBN 3 -+#define FRF_BZ_CHAR_INT_KER_WIDTH 1 -+#define FRF_BZ_DRV_INT_EN_CHAR_LBN 0 -+#define FRF_BZ_DRV_INT_EN_CHAR_WIDTH 1 -+ -+/* INT_ADR_REG_KER: Interrupt host address for Kernel driver */ -+#define FR_AZ_INT_ADR_KER 0x00000030 -+#define FRF_AZ_NORM_INT_VEC_DIS_KER_LBN 64 -+#define FRF_AZ_NORM_INT_VEC_DIS_KER_WIDTH 1 -+#define FRF_AZ_INT_ADR_KER_LBN 0 -+#define FRF_AZ_INT_ADR_KER_WIDTH 64 -+ -+/* INT_ADR_REG_CHAR: Interrupt host address for Char driver */ -+#define FR_BZ_INT_ADR_CHAR 0x00000040 -+#define FRF_BZ_NORM_INT_VEC_DIS_CHAR_LBN 64 -+#define FRF_BZ_NORM_INT_VEC_DIS_CHAR_WIDTH 1 -+#define FRF_BZ_INT_ADR_CHAR_LBN 0 -+#define FRF_BZ_INT_ADR_CHAR_WIDTH 64 -+ -+/* INT_ACK_KER: Kernel interrupt acknowledge register */ -+#define FR_AA_INT_ACK_KER 0x00000050 -+#define FRF_AA_INT_ACK_KER_FIELD_LBN 0 -+#define FRF_AA_INT_ACK_KER_FIELD_WIDTH 32 -+ -+/* INT_ISR0_REG: Function 0 Interrupt Acknowlege Status register */ -+#define FR_BZ_INT_ISR0 0x00000090 -+#define FRF_BZ_INT_ISR_REG_LBN 0 -+#define FRF_BZ_INT_ISR_REG_WIDTH 64 -+ -+/* HW_INIT_REG: Hardware initialization register */ -+#define FR_AZ_HW_INIT 0x000000c0 -+#define FRF_BB_BDMRD_CPLF_FULL_LBN 124 -+#define FRF_BB_BDMRD_CPLF_FULL_WIDTH 1 -+#define FRF_BB_PCIE_CPL_TIMEOUT_CTRL_LBN 121 -+#define FRF_BB_PCIE_CPL_TIMEOUT_CTRL_WIDTH 3 -+#define FRF_CZ_TX_MRG_TAGS_LBN 120 -+#define FRF_CZ_TX_MRG_TAGS_WIDTH 1 -+#define FRF_AB_TRGT_MASK_ALL_LBN 100 -+#define FRF_AB_TRGT_MASK_ALL_WIDTH 1 -+#define FRF_AZ_DOORBELL_DROP_LBN 92 -+#define FRF_AZ_DOORBELL_DROP_WIDTH 8 -+#define FRF_AB_TX_RREQ_MASK_EN_LBN 76 -+#define FRF_AB_TX_RREQ_MASK_EN_WIDTH 1 -+#define FRF_AB_PE_EIDLE_DIS_LBN 75 -+#define FRF_AB_PE_EIDLE_DIS_WIDTH 1 -+#define FRF_AA_FC_BLOCKING_EN_LBN 45 -+#define FRF_AA_FC_BLOCKING_EN_WIDTH 1 -+#define FRF_BZ_B2B_REQ_EN_LBN 45 -+#define FRF_BZ_B2B_REQ_EN_WIDTH 1 -+#define FRF_AA_B2B_REQ_EN_LBN 44 -+#define FRF_AA_B2B_REQ_EN_WIDTH 1 -+#define FRF_BB_FC_BLOCKING_EN_LBN 44 -+#define FRF_BB_FC_BLOCKING_EN_WIDTH 1 -+#define FRF_AZ_POST_WR_MASK_LBN 40 -+#define FRF_AZ_POST_WR_MASK_WIDTH 4 -+#define FRF_AZ_TLP_TC_LBN 34 -+#define FRF_AZ_TLP_TC_WIDTH 3 -+#define FRF_AZ_TLP_ATTR_LBN 32 -+#define FRF_AZ_TLP_ATTR_WIDTH 2 -+#define FRF_AB_INTB_VEC_LBN 24 -+#define FRF_AB_INTB_VEC_WIDTH 5 -+#define FRF_AB_INTA_VEC_LBN 16 -+#define FRF_AB_INTA_VEC_WIDTH 5 -+#define FRF_AZ_WD_TIMER_LBN 8 -+#define FRF_AZ_WD_TIMER_WIDTH 8 -+#define FRF_AZ_US_DISABLE_LBN 5 -+#define FRF_AZ_US_DISABLE_WIDTH 1 -+#define FRF_AZ_TLP_EP_LBN 4 -+#define FRF_AZ_TLP_EP_WIDTH 1 -+#define FRF_AZ_ATTR_SEL_LBN 3 -+#define FRF_AZ_ATTR_SEL_WIDTH 1 -+#define FRF_AZ_TD_SEL_LBN 1 -+#define FRF_AZ_TD_SEL_WIDTH 1 -+#define FRF_AZ_TLP_TD_LBN 0 -+#define FRF_AZ_TLP_TD_WIDTH 1 -+ -+/* EE_SPI_HCMD_REG: SPI host command register */ -+#define FR_AB_EE_SPI_HCMD 0x00000100 -+#define FRF_AB_EE_SPI_HCMD_CMD_EN_LBN 31 -+#define FRF_AB_EE_SPI_HCMD_CMD_EN_WIDTH 1 -+#define FRF_AB_EE_WR_TIMER_ACTIVE_LBN 28 -+#define FRF_AB_EE_WR_TIMER_ACTIVE_WIDTH 1 -+#define FRF_AB_EE_SPI_HCMD_SF_SEL_LBN 24 -+#define FRF_AB_EE_SPI_HCMD_SF_SEL_WIDTH 1 -+#define FRF_AB_EE_SPI_HCMD_DABCNT_LBN 16 -+#define FRF_AB_EE_SPI_HCMD_DABCNT_WIDTH 5 -+#define FRF_AB_EE_SPI_HCMD_READ_LBN 15 -+#define FRF_AB_EE_SPI_HCMD_READ_WIDTH 1 -+#define FRF_AB_EE_SPI_HCMD_DUBCNT_LBN 12 -+#define FRF_AB_EE_SPI_HCMD_DUBCNT_WIDTH 2 -+#define FRF_AB_EE_SPI_HCMD_ADBCNT_LBN 8 -+#define FRF_AB_EE_SPI_HCMD_ADBCNT_WIDTH 2 -+#define FRF_AB_EE_SPI_HCMD_ENC_LBN 0 -+#define FRF_AB_EE_SPI_HCMD_ENC_WIDTH 8 -+ -+/* USR_EV_CFG: User Level Event Configuration register */ -+#define FR_CZ_USR_EV_CFG 0x00000100 -+#define FRF_CZ_USREV_DIS_LBN 16 -+#define FRF_CZ_USREV_DIS_WIDTH 1 -+#define FRF_CZ_DFLT_EVQ_LBN 0 -+#define FRF_CZ_DFLT_EVQ_WIDTH 10 -+ -+/* EE_SPI_HADR_REG: SPI host address register */ -+#define FR_AB_EE_SPI_HADR 0x00000110 -+#define FRF_AB_EE_SPI_HADR_DUBYTE_LBN 24 -+#define FRF_AB_EE_SPI_HADR_DUBYTE_WIDTH 8 -+#define FRF_AB_EE_SPI_HADR_ADR_LBN 0 -+#define FRF_AB_EE_SPI_HADR_ADR_WIDTH 24 -+ -+/* EE_SPI_HDATA_REG: SPI host data register */ -+#define FR_AB_EE_SPI_HDATA 0x00000120 -+#define FRF_AB_EE_SPI_HDATA3_LBN 96 -+#define FRF_AB_EE_SPI_HDATA3_WIDTH 32 -+#define FRF_AB_EE_SPI_HDATA2_LBN 64 -+#define FRF_AB_EE_SPI_HDATA2_WIDTH 32 -+#define FRF_AB_EE_SPI_HDATA1_LBN 32 -+#define FRF_AB_EE_SPI_HDATA1_WIDTH 32 -+#define FRF_AB_EE_SPI_HDATA0_LBN 0 -+#define FRF_AB_EE_SPI_HDATA0_WIDTH 32 -+ -+/* EE_BASE_PAGE_REG: Expansion ROM base mirror register */ -+#define FR_AB_EE_BASE_PAGE 0x00000130 -+#define FRF_AB_EE_EXPROM_MASK_LBN 16 -+#define FRF_AB_EE_EXPROM_MASK_WIDTH 13 -+#define FRF_AB_EE_EXP_ROM_WINDOW_BASE_LBN 0 -+#define FRF_AB_EE_EXP_ROM_WINDOW_BASE_WIDTH 13 -+ -+/* EE_VPD_CFG0_REG: SPI/VPD configuration register 0 */ -+#define FR_AB_EE_VPD_CFG0 0x00000140 -+#define FRF_AB_EE_SF_FASTRD_EN_LBN 127 -+#define FRF_AB_EE_SF_FASTRD_EN_WIDTH 1 -+#define FRF_AB_EE_SF_CLOCK_DIV_LBN 120 -+#define FRF_AB_EE_SF_CLOCK_DIV_WIDTH 7 -+#define FRF_AB_EE_VPD_WIP_POLL_LBN 119 -+#define FRF_AB_EE_VPD_WIP_POLL_WIDTH 1 -+#define FRF_AB_EE_EE_CLOCK_DIV_LBN 112 -+#define FRF_AB_EE_EE_CLOCK_DIV_WIDTH 7 -+#define FRF_AB_EE_EE_WR_TMR_VALUE_LBN 96 -+#define FRF_AB_EE_EE_WR_TMR_VALUE_WIDTH 16 -+#define FRF_AB_EE_VPDW_LENGTH_LBN 80 -+#define FRF_AB_EE_VPDW_LENGTH_WIDTH 15 -+#define FRF_AB_EE_VPDW_BASE_LBN 64 -+#define FRF_AB_EE_VPDW_BASE_WIDTH 15 -+#define FRF_AB_EE_VPD_WR_CMD_EN_LBN 56 -+#define FRF_AB_EE_VPD_WR_CMD_EN_WIDTH 8 -+#define FRF_AB_EE_VPD_BASE_LBN 32 -+#define FRF_AB_EE_VPD_BASE_WIDTH 24 -+#define FRF_AB_EE_VPD_LENGTH_LBN 16 -+#define FRF_AB_EE_VPD_LENGTH_WIDTH 15 -+#define FRF_AB_EE_VPD_AD_SIZE_LBN 8 -+#define FRF_AB_EE_VPD_AD_SIZE_WIDTH 5 -+#define FRF_AB_EE_VPD_ACCESS_ON_LBN 5 -+#define FRF_AB_EE_VPD_ACCESS_ON_WIDTH 1 -+#define FRF_AB_EE_VPD_ACCESS_BLOCK_LBN 4 -+#define FRF_AB_EE_VPD_ACCESS_BLOCK_WIDTH 1 -+#define FRF_AB_EE_VPD_DEV_SF_SEL_LBN 2 -+#define FRF_AB_EE_VPD_DEV_SF_SEL_WIDTH 1 -+#define FRF_AB_EE_VPD_EN_AD9_MODE_LBN 1 -+#define FRF_AB_EE_VPD_EN_AD9_MODE_WIDTH 1 -+#define FRF_AB_EE_VPD_EN_LBN 0 -+#define FRF_AB_EE_VPD_EN_WIDTH 1 -+ -+/* EE_VPD_SW_CNTL_REG: VPD access SW control register */ -+#define FR_AB_EE_VPD_SW_CNTL 0x00000150 -+#define FRF_AB_EE_VPD_CYCLE_PENDING_LBN 31 -+#define FRF_AB_EE_VPD_CYCLE_PENDING_WIDTH 1 -+#define FRF_AB_EE_VPD_CYC_WRITE_LBN 28 -+#define FRF_AB_EE_VPD_CYC_WRITE_WIDTH 1 -+#define FRF_AB_EE_VPD_CYC_ADR_LBN 0 -+#define FRF_AB_EE_VPD_CYC_ADR_WIDTH 15 -+ -+/* EE_VPD_SW_DATA_REG: VPD access SW data register */ -+#define FR_AB_EE_VPD_SW_DATA 0x00000160 -+#define FRF_AB_EE_VPD_CYC_DAT_LBN 0 -+#define FRF_AB_EE_VPD_CYC_DAT_WIDTH 32 -+ -+/* PBMX_DBG_IADDR_REG: Capture Module address register */ -+#define FR_CZ_PBMX_DBG_IADDR 0x000001f0 -+#define FRF_CZ_PBMX_DBG_IADDR_LBN 0 -+#define FRF_CZ_PBMX_DBG_IADDR_WIDTH 32 -+ -+/* PCIE_CORE_INDIRECT_REG: Indirect Access to PCIE Core registers */ -+#define FR_BB_PCIE_CORE_INDIRECT 0x000001f0 -+#define FRF_BB_PCIE_CORE_TARGET_DATA_LBN 32 -+#define FRF_BB_PCIE_CORE_TARGET_DATA_WIDTH 32 -+#define FRF_BB_PCIE_CORE_INDIRECT_ACCESS_DIR_LBN 15 -+#define FRF_BB_PCIE_CORE_INDIRECT_ACCESS_DIR_WIDTH 1 -+#define FRF_BB_PCIE_CORE_TARGET_REG_ADRS_LBN 0 -+#define FRF_BB_PCIE_CORE_TARGET_REG_ADRS_WIDTH 12 -+ -+/* PBMX_DBG_IDATA_REG: Capture Module data register */ -+#define FR_CZ_PBMX_DBG_IDATA 0x000001f8 -+#define FRF_CZ_PBMX_DBG_IDATA_LBN 0 -+#define FRF_CZ_PBMX_DBG_IDATA_WIDTH 64 -+ -+/* NIC_STAT_REG: NIC status register */ -+#define FR_AB_NIC_STAT 0x00000200 -+#define FRF_BB_AER_DIS_LBN 34 -+#define FRF_BB_AER_DIS_WIDTH 1 -+#define FRF_BB_EE_STRAP_EN_LBN 31 -+#define FRF_BB_EE_STRAP_EN_WIDTH 1 -+#define FRF_BB_EE_STRAP_LBN 24 -+#define FRF_BB_EE_STRAP_WIDTH 4 -+#define FRF_BB_REVISION_ID_LBN 17 -+#define FRF_BB_REVISION_ID_WIDTH 7 -+#define FRF_AB_ONCHIP_SRAM_LBN 16 -+#define FRF_AB_ONCHIP_SRAM_WIDTH 1 -+#define FRF_AB_SF_PRST_LBN 9 -+#define FRF_AB_SF_PRST_WIDTH 1 -+#define FRF_AB_EE_PRST_LBN 8 -+#define FRF_AB_EE_PRST_WIDTH 1 -+#define FRF_AB_ATE_MODE_LBN 3 -+#define FRF_AB_ATE_MODE_WIDTH 1 -+#define FRF_AB_STRAP_PINS_LBN 0 -+#define FRF_AB_STRAP_PINS_WIDTH 3 -+ -+/* GPIO_CTL_REG: GPIO control register */ -+#define FR_AB_GPIO_CTL 0x00000210 -+#define FRF_AB_GPIO_OUT3_LBN 112 -+#define FRF_AB_GPIO_OUT3_WIDTH 16 -+#define FRF_AB_GPIO_IN3_LBN 104 -+#define FRF_AB_GPIO_IN3_WIDTH 8 -+#define FRF_AB_GPIO_PWRUP_VALUE3_LBN 96 -+#define FRF_AB_GPIO_PWRUP_VALUE3_WIDTH 8 -+#define FRF_AB_GPIO_OUT2_LBN 80 -+#define FRF_AB_GPIO_OUT2_WIDTH 16 -+#define FRF_AB_GPIO_IN2_LBN 72 -+#define FRF_AB_GPIO_IN2_WIDTH 8 -+#define FRF_AB_GPIO_PWRUP_VALUE2_LBN 64 -+#define FRF_AB_GPIO_PWRUP_VALUE2_WIDTH 8 -+#define FRF_AB_GPIO15_OEN_LBN 63 -+#define FRF_AB_GPIO15_OEN_WIDTH 1 -+#define FRF_AB_GPIO14_OEN_LBN 62 -+#define FRF_AB_GPIO14_OEN_WIDTH 1 -+#define FRF_AB_GPIO13_OEN_LBN 61 -+#define FRF_AB_GPIO13_OEN_WIDTH 1 -+#define FRF_AB_GPIO12_OEN_LBN 60 -+#define FRF_AB_GPIO12_OEN_WIDTH 1 -+#define FRF_AB_GPIO11_OEN_LBN 59 -+#define FRF_AB_GPIO11_OEN_WIDTH 1 -+#define FRF_AB_GPIO10_OEN_LBN 58 -+#define FRF_AB_GPIO10_OEN_WIDTH 1 -+#define FRF_AB_GPIO9_OEN_LBN 57 -+#define FRF_AB_GPIO9_OEN_WIDTH 1 -+#define FRF_AB_GPIO8_OEN_LBN 56 -+#define FRF_AB_GPIO8_OEN_WIDTH 1 -+#define FRF_AB_GPIO15_OUT_LBN 55 -+#define FRF_AB_GPIO15_OUT_WIDTH 1 -+#define FRF_AB_GPIO14_OUT_LBN 54 -+#define FRF_AB_GPIO14_OUT_WIDTH 1 -+#define FRF_AB_GPIO13_OUT_LBN 53 -+#define FRF_AB_GPIO13_OUT_WIDTH 1 -+#define FRF_AB_GPIO12_OUT_LBN 52 -+#define FRF_AB_GPIO12_OUT_WIDTH 1 -+#define FRF_AB_GPIO11_OUT_LBN 51 -+#define FRF_AB_GPIO11_OUT_WIDTH 1 -+#define FRF_AB_GPIO10_OUT_LBN 50 -+#define FRF_AB_GPIO10_OUT_WIDTH 1 -+#define FRF_AB_GPIO9_OUT_LBN 49 -+#define FRF_AB_GPIO9_OUT_WIDTH 1 -+#define FRF_AB_GPIO8_OUT_LBN 48 -+#define FRF_AB_GPIO8_OUT_WIDTH 1 -+#define FRF_AB_GPIO15_IN_LBN 47 -+#define FRF_AB_GPIO15_IN_WIDTH 1 -+#define FRF_AB_GPIO14_IN_LBN 46 -+#define FRF_AB_GPIO14_IN_WIDTH 1 -+#define FRF_AB_GPIO13_IN_LBN 45 -+#define FRF_AB_GPIO13_IN_WIDTH 1 -+#define FRF_AB_GPIO12_IN_LBN 44 -+#define FRF_AB_GPIO12_IN_WIDTH 1 -+#define FRF_AB_GPIO11_IN_LBN 43 -+#define FRF_AB_GPIO11_IN_WIDTH 1 -+#define FRF_AB_GPIO10_IN_LBN 42 -+#define FRF_AB_GPIO10_IN_WIDTH 1 -+#define FRF_AB_GPIO9_IN_LBN 41 -+#define FRF_AB_GPIO9_IN_WIDTH 1 -+#define FRF_AB_GPIO8_IN_LBN 40 -+#define FRF_AB_GPIO8_IN_WIDTH 1 -+#define FRF_AB_GPIO15_PWRUP_VALUE_LBN 39 -+#define FRF_AB_GPIO15_PWRUP_VALUE_WIDTH 1 -+#define FRF_AB_GPIO14_PWRUP_VALUE_LBN 38 -+#define FRF_AB_GPIO14_PWRUP_VALUE_WIDTH 1 -+#define FRF_AB_GPIO13_PWRUP_VALUE_LBN 37 -+#define FRF_AB_GPIO13_PWRUP_VALUE_WIDTH 1 -+#define FRF_AB_GPIO12_PWRUP_VALUE_LBN 36 -+#define FRF_AB_GPIO12_PWRUP_VALUE_WIDTH 1 -+#define FRF_AB_GPIO11_PWRUP_VALUE_LBN 35 -+#define FRF_AB_GPIO11_PWRUP_VALUE_WIDTH 1 -+#define FRF_AB_GPIO10_PWRUP_VALUE_LBN 34 -+#define FRF_AB_GPIO10_PWRUP_VALUE_WIDTH 1 -+#define FRF_AB_GPIO9_PWRUP_VALUE_LBN 33 -+#define FRF_AB_GPIO9_PWRUP_VALUE_WIDTH 1 -+#define FRF_AB_GPIO8_PWRUP_VALUE_LBN 32 -+#define FRF_AB_GPIO8_PWRUP_VALUE_WIDTH 1 -+#define FRF_AB_CLK156_OUT_EN_LBN 31 -+#define FRF_AB_CLK156_OUT_EN_WIDTH 1 -+#define FRF_AB_USE_NIC_CLK_LBN 30 -+#define FRF_AB_USE_NIC_CLK_WIDTH 1 -+#define FRF_AB_GPIO5_OEN_LBN 29 -+#define FRF_AB_GPIO5_OEN_WIDTH 1 -+#define FRF_AB_GPIO4_OEN_LBN 28 -+#define FRF_AB_GPIO4_OEN_WIDTH 1 -+#define FRF_AB_GPIO3_OEN_LBN 27 -+#define FRF_AB_GPIO3_OEN_WIDTH 1 -+#define FRF_AB_GPIO2_OEN_LBN 26 -+#define FRF_AB_GPIO2_OEN_WIDTH 1 -+#define FRF_AB_GPIO1_OEN_LBN 25 -+#define FRF_AB_GPIO1_OEN_WIDTH 1 -+#define FRF_AB_GPIO0_OEN_LBN 24 -+#define FRF_AB_GPIO0_OEN_WIDTH 1 -+#define FRF_AB_GPIO7_OUT_LBN 23 -+#define FRF_AB_GPIO7_OUT_WIDTH 1 -+#define FRF_AB_GPIO6_OUT_LBN 22 -+#define FRF_AB_GPIO6_OUT_WIDTH 1 -+#define FRF_AB_GPIO5_OUT_LBN 21 -+#define FRF_AB_GPIO5_OUT_WIDTH 1 -+#define FRF_AB_GPIO4_OUT_LBN 20 -+#define FRF_AB_GPIO4_OUT_WIDTH 1 -+#define FRF_AB_GPIO3_OUT_LBN 19 -+#define FRF_AB_GPIO3_OUT_WIDTH 1 -+#define FRF_AB_GPIO2_OUT_LBN 18 -+#define FRF_AB_GPIO2_OUT_WIDTH 1 -+#define FRF_AB_GPIO1_OUT_LBN 17 -+#define FRF_AB_GPIO1_OUT_WIDTH 1 -+#define FRF_AB_GPIO0_OUT_LBN 16 -+#define FRF_AB_GPIO0_OUT_WIDTH 1 -+#define FRF_AB_GPIO7_IN_LBN 15 -+#define FRF_AB_GPIO7_IN_WIDTH 1 -+#define FRF_AB_GPIO6_IN_LBN 14 -+#define FRF_AB_GPIO6_IN_WIDTH 1 -+#define FRF_AB_GPIO5_IN_LBN 13 -+#define FRF_AB_GPIO5_IN_WIDTH 1 -+#define FRF_AB_GPIO4_IN_LBN 12 -+#define FRF_AB_GPIO4_IN_WIDTH 1 -+#define FRF_AB_GPIO3_IN_LBN 11 -+#define FRF_AB_GPIO3_IN_WIDTH 1 -+#define FRF_AB_GPIO2_IN_LBN 10 -+#define FRF_AB_GPIO2_IN_WIDTH 1 -+#define FRF_AB_GPIO1_IN_LBN 9 -+#define FRF_AB_GPIO1_IN_WIDTH 1 -+#define FRF_AB_GPIO0_IN_LBN 8 -+#define FRF_AB_GPIO0_IN_WIDTH 1 -+#define FRF_AB_GPIO7_PWRUP_VALUE_LBN 7 -+#define FRF_AB_GPIO7_PWRUP_VALUE_WIDTH 1 -+#define FRF_AB_GPIO6_PWRUP_VALUE_LBN 6 -+#define FRF_AB_GPIO6_PWRUP_VALUE_WIDTH 1 -+#define FRF_AB_GPIO5_PWRUP_VALUE_LBN 5 -+#define FRF_AB_GPIO5_PWRUP_VALUE_WIDTH 1 -+#define FRF_AB_GPIO4_PWRUP_VALUE_LBN 4 -+#define FRF_AB_GPIO4_PWRUP_VALUE_WIDTH 1 -+#define FRF_AB_GPIO3_PWRUP_VALUE_LBN 3 -+#define FRF_AB_GPIO3_PWRUP_VALUE_WIDTH 1 -+#define FRF_AB_GPIO2_PWRUP_VALUE_LBN 2 -+#define FRF_AB_GPIO2_PWRUP_VALUE_WIDTH 1 -+#define FRF_AB_GPIO1_PWRUP_VALUE_LBN 1 -+#define FRF_AB_GPIO1_PWRUP_VALUE_WIDTH 1 -+#define FRF_AB_GPIO0_PWRUP_VALUE_LBN 0 -+#define FRF_AB_GPIO0_PWRUP_VALUE_WIDTH 1 -+ -+/* GLB_CTL_REG: Global control register */ -+#define FR_AB_GLB_CTL 0x00000220 -+#define FRF_AB_EXT_PHY_RST_CTL_LBN 63 -+#define FRF_AB_EXT_PHY_RST_CTL_WIDTH 1 -+#define FRF_AB_XAUI_SD_RST_CTL_LBN 62 -+#define FRF_AB_XAUI_SD_RST_CTL_WIDTH 1 -+#define FRF_AB_PCIE_SD_RST_CTL_LBN 61 -+#define FRF_AB_PCIE_SD_RST_CTL_WIDTH 1 -+#define FRF_AA_PCIX_RST_CTL_LBN 60 -+#define FRF_AA_PCIX_RST_CTL_WIDTH 1 -+#define FRF_BB_BIU_RST_CTL_LBN 60 -+#define FRF_BB_BIU_RST_CTL_WIDTH 1 -+#define FRF_AB_PCIE_STKY_RST_CTL_LBN 59 -+#define FRF_AB_PCIE_STKY_RST_CTL_WIDTH 1 -+#define FRF_AB_PCIE_NSTKY_RST_CTL_LBN 58 -+#define FRF_AB_PCIE_NSTKY_RST_CTL_WIDTH 1 -+#define FRF_AB_PCIE_CORE_RST_CTL_LBN 57 -+#define FRF_AB_PCIE_CORE_RST_CTL_WIDTH 1 -+#define FRF_AB_XGRX_RST_CTL_LBN 56 -+#define FRF_AB_XGRX_RST_CTL_WIDTH 1 -+#define FRF_AB_XGTX_RST_CTL_LBN 55 -+#define FRF_AB_XGTX_RST_CTL_WIDTH 1 -+#define FRF_AB_EM_RST_CTL_LBN 54 -+#define FRF_AB_EM_RST_CTL_WIDTH 1 -+#define FRF_AB_EV_RST_CTL_LBN 53 -+#define FRF_AB_EV_RST_CTL_WIDTH 1 -+#define FRF_AB_SR_RST_CTL_LBN 52 -+#define FRF_AB_SR_RST_CTL_WIDTH 1 -+#define FRF_AB_RX_RST_CTL_LBN 51 -+#define FRF_AB_RX_RST_CTL_WIDTH 1 -+#define FRF_AB_TX_RST_CTL_LBN 50 -+#define FRF_AB_TX_RST_CTL_WIDTH 1 -+#define FRF_AB_EE_RST_CTL_LBN 49 -+#define FRF_AB_EE_RST_CTL_WIDTH 1 -+#define FRF_AB_CS_RST_CTL_LBN 48 -+#define FRF_AB_CS_RST_CTL_WIDTH 1 -+#define FRF_AB_HOT_RST_CTL_LBN 40 -+#define FRF_AB_HOT_RST_CTL_WIDTH 2 -+#define FRF_AB_RST_EXT_PHY_LBN 31 -+#define FRF_AB_RST_EXT_PHY_WIDTH 1 -+#define FRF_AB_RST_XAUI_SD_LBN 30 -+#define FRF_AB_RST_XAUI_SD_WIDTH 1 -+#define FRF_AB_RST_PCIE_SD_LBN 29 -+#define FRF_AB_RST_PCIE_SD_WIDTH 1 -+#define FRF_AA_RST_PCIX_LBN 28 -+#define FRF_AA_RST_PCIX_WIDTH 1 -+#define FRF_BB_RST_BIU_LBN 28 -+#define FRF_BB_RST_BIU_WIDTH 1 -+#define FRF_AB_RST_PCIE_STKY_LBN 27 -+#define FRF_AB_RST_PCIE_STKY_WIDTH 1 -+#define FRF_AB_RST_PCIE_NSTKY_LBN 26 -+#define FRF_AB_RST_PCIE_NSTKY_WIDTH 1 -+#define FRF_AB_RST_PCIE_CORE_LBN 25 -+#define FRF_AB_RST_PCIE_CORE_WIDTH 1 -+#define FRF_AB_RST_XGRX_LBN 24 -+#define FRF_AB_RST_XGRX_WIDTH 1 -+#define FRF_AB_RST_XGTX_LBN 23 -+#define FRF_AB_RST_XGTX_WIDTH 1 -+#define FRF_AB_RST_EM_LBN 22 -+#define FRF_AB_RST_EM_WIDTH 1 -+#define FRF_AB_RST_EV_LBN 21 -+#define FRF_AB_RST_EV_WIDTH 1 -+#define FRF_AB_RST_SR_LBN 20 -+#define FRF_AB_RST_SR_WIDTH 1 -+#define FRF_AB_RST_RX_LBN 19 -+#define FRF_AB_RST_RX_WIDTH 1 -+#define FRF_AB_RST_TX_LBN 18 -+#define FRF_AB_RST_TX_WIDTH 1 -+#define FRF_AB_RST_SF_LBN 17 -+#define FRF_AB_RST_SF_WIDTH 1 -+#define FRF_AB_RST_CS_LBN 16 -+#define FRF_AB_RST_CS_WIDTH 1 -+#define FRF_AB_INT_RST_DUR_LBN 4 -+#define FRF_AB_INT_RST_DUR_WIDTH 3 -+#define FRF_AB_EXT_PHY_RST_DUR_LBN 1 -+#define FRF_AB_EXT_PHY_RST_DUR_WIDTH 3 -+#define FFE_AB_EXT_PHY_RST_DUR_10240US 7 -+#define FFE_AB_EXT_PHY_RST_DUR_5120US 6 -+#define FFE_AB_EXT_PHY_RST_DUR_2560US 5 -+#define FFE_AB_EXT_PHY_RST_DUR_1280US 4 -+#define FFE_AB_EXT_PHY_RST_DUR_640US 3 -+#define FFE_AB_EXT_PHY_RST_DUR_320US 2 -+#define FFE_AB_EXT_PHY_RST_DUR_160US 1 -+#define FFE_AB_EXT_PHY_RST_DUR_80US 0 -+#define FRF_AB_SWRST_LBN 0 -+#define FRF_AB_SWRST_WIDTH 1 -+ -+/* FATAL_INTR_REG_KER: Fatal interrupt register for Kernel */ -+#define FR_AZ_FATAL_INTR_KER 0x00000230 -+#define FRF_CZ_SRAM_PERR_INT_P_KER_EN_LBN 44 -+#define FRF_CZ_SRAM_PERR_INT_P_KER_EN_WIDTH 1 -+#define FRF_AB_PCI_BUSERR_INT_KER_EN_LBN 43 -+#define FRF_AB_PCI_BUSERR_INT_KER_EN_WIDTH 1 -+#define FRF_CZ_MBU_PERR_INT_KER_EN_LBN 43 -+#define FRF_CZ_MBU_PERR_INT_KER_EN_WIDTH 1 -+#define FRF_AZ_SRAM_OOB_INT_KER_EN_LBN 42 -+#define FRF_AZ_SRAM_OOB_INT_KER_EN_WIDTH 1 -+#define FRF_AZ_BUFID_OOB_INT_KER_EN_LBN 41 -+#define FRF_AZ_BUFID_OOB_INT_KER_EN_WIDTH 1 -+#define FRF_AZ_MEM_PERR_INT_KER_EN_LBN 40 -+#define FRF_AZ_MEM_PERR_INT_KER_EN_WIDTH 1 -+#define FRF_AZ_RBUF_OWN_INT_KER_EN_LBN 39 -+#define FRF_AZ_RBUF_OWN_INT_KER_EN_WIDTH 1 -+#define FRF_AZ_TBUF_OWN_INT_KER_EN_LBN 38 -+#define FRF_AZ_TBUF_OWN_INT_KER_EN_WIDTH 1 -+#define FRF_AZ_RDESCQ_OWN_INT_KER_EN_LBN 37 -+#define FRF_AZ_RDESCQ_OWN_INT_KER_EN_WIDTH 1 -+#define FRF_AZ_TDESCQ_OWN_INT_KER_EN_LBN 36 -+#define FRF_AZ_TDESCQ_OWN_INT_KER_EN_WIDTH 1 -+#define FRF_AZ_EVQ_OWN_INT_KER_EN_LBN 35 -+#define FRF_AZ_EVQ_OWN_INT_KER_EN_WIDTH 1 -+#define FRF_AZ_EVF_OFLO_INT_KER_EN_LBN 34 -+#define FRF_AZ_EVF_OFLO_INT_KER_EN_WIDTH 1 -+#define FRF_AZ_ILL_ADR_INT_KER_EN_LBN 33 -+#define FRF_AZ_ILL_ADR_INT_KER_EN_WIDTH 1 -+#define FRF_AZ_SRM_PERR_INT_KER_EN_LBN 32 -+#define FRF_AZ_SRM_PERR_INT_KER_EN_WIDTH 1 -+#define FRF_CZ_SRAM_PERR_INT_P_KER_LBN 12 -+#define FRF_CZ_SRAM_PERR_INT_P_KER_WIDTH 1 -+#define FRF_AB_PCI_BUSERR_INT_KER_LBN 11 -+#define FRF_AB_PCI_BUSERR_INT_KER_WIDTH 1 -+#define FRF_CZ_MBU_PERR_INT_KER_LBN 11 -+#define FRF_CZ_MBU_PERR_INT_KER_WIDTH 1 -+#define FRF_AZ_SRAM_OOB_INT_KER_LBN 10 -+#define FRF_AZ_SRAM_OOB_INT_KER_WIDTH 1 -+#define FRF_AZ_BUFID_DC_OOB_INT_KER_LBN 9 -+#define FRF_AZ_BUFID_DC_OOB_INT_KER_WIDTH 1 -+#define FRF_AZ_MEM_PERR_INT_KER_LBN 8 -+#define FRF_AZ_MEM_PERR_INT_KER_WIDTH 1 -+#define FRF_AZ_RBUF_OWN_INT_KER_LBN 7 -+#define FRF_AZ_RBUF_OWN_INT_KER_WIDTH 1 -+#define FRF_AZ_TBUF_OWN_INT_KER_LBN 6 -+#define FRF_AZ_TBUF_OWN_INT_KER_WIDTH 1 -+#define FRF_AZ_RDESCQ_OWN_INT_KER_LBN 5 -+#define FRF_AZ_RDESCQ_OWN_INT_KER_WIDTH 1 -+#define FRF_AZ_TDESCQ_OWN_INT_KER_LBN 4 -+#define FRF_AZ_TDESCQ_OWN_INT_KER_WIDTH 1 -+#define FRF_AZ_EVQ_OWN_INT_KER_LBN 3 -+#define FRF_AZ_EVQ_OWN_INT_KER_WIDTH 1 -+#define FRF_AZ_EVF_OFLO_INT_KER_LBN 2 -+#define FRF_AZ_EVF_OFLO_INT_KER_WIDTH 1 -+#define FRF_AZ_ILL_ADR_INT_KER_LBN 1 -+#define FRF_AZ_ILL_ADR_INT_KER_WIDTH 1 -+#define FRF_AZ_SRM_PERR_INT_KER_LBN 0 -+#define FRF_AZ_SRM_PERR_INT_KER_WIDTH 1 -+ -+/* FATAL_INTR_REG_CHAR: Fatal interrupt register for Char */ -+#define FR_BZ_FATAL_INTR_CHAR 0x00000240 -+#define FRF_CZ_SRAM_PERR_INT_P_CHAR_EN_LBN 44 -+#define FRF_CZ_SRAM_PERR_INT_P_CHAR_EN_WIDTH 1 -+#define FRF_BB_PCI_BUSERR_INT_CHAR_EN_LBN 43 -+#define FRF_BB_PCI_BUSERR_INT_CHAR_EN_WIDTH 1 -+#define FRF_CZ_MBU_PERR_INT_CHAR_EN_LBN 43 -+#define FRF_CZ_MBU_PERR_INT_CHAR_EN_WIDTH 1 -+#define FRF_BZ_SRAM_OOB_INT_CHAR_EN_LBN 42 -+#define FRF_BZ_SRAM_OOB_INT_CHAR_EN_WIDTH 1 -+#define FRF_BZ_BUFID_OOB_INT_CHAR_EN_LBN 41 -+#define FRF_BZ_BUFID_OOB_INT_CHAR_EN_WIDTH 1 -+#define FRF_BZ_MEM_PERR_INT_CHAR_EN_LBN 40 -+#define FRF_BZ_MEM_PERR_INT_CHAR_EN_WIDTH 1 -+#define FRF_BZ_RBUF_OWN_INT_CHAR_EN_LBN 39 -+#define FRF_BZ_RBUF_OWN_INT_CHAR_EN_WIDTH 1 -+#define FRF_BZ_TBUF_OWN_INT_CHAR_EN_LBN 38 -+#define FRF_BZ_TBUF_OWN_INT_CHAR_EN_WIDTH 1 -+#define FRF_BZ_RDESCQ_OWN_INT_CHAR_EN_LBN 37 -+#define FRF_BZ_RDESCQ_OWN_INT_CHAR_EN_WIDTH 1 -+#define FRF_BZ_TDESCQ_OWN_INT_CHAR_EN_LBN 36 -+#define FRF_BZ_TDESCQ_OWN_INT_CHAR_EN_WIDTH 1 -+#define FRF_BZ_EVQ_OWN_INT_CHAR_EN_LBN 35 -+#define FRF_BZ_EVQ_OWN_INT_CHAR_EN_WIDTH 1 -+#define FRF_BZ_EVF_OFLO_INT_CHAR_EN_LBN 34 -+#define FRF_BZ_EVF_OFLO_INT_CHAR_EN_WIDTH 1 -+#define FRF_BZ_ILL_ADR_INT_CHAR_EN_LBN 33 -+#define FRF_BZ_ILL_ADR_INT_CHAR_EN_WIDTH 1 -+#define FRF_BZ_SRM_PERR_INT_CHAR_EN_LBN 32 -+#define FRF_BZ_SRM_PERR_INT_CHAR_EN_WIDTH 1 -+#define FRF_CZ_SRAM_PERR_INT_P_CHAR_LBN 12 -+#define FRF_CZ_SRAM_PERR_INT_P_CHAR_WIDTH 1 -+#define FRF_BB_PCI_BUSERR_INT_CHAR_LBN 11 -+#define FRF_BB_PCI_BUSERR_INT_CHAR_WIDTH 1 -+#define FRF_CZ_MBU_PERR_INT_CHAR_LBN 11 -+#define FRF_CZ_MBU_PERR_INT_CHAR_WIDTH 1 -+#define FRF_BZ_SRAM_OOB_INT_CHAR_LBN 10 -+#define FRF_BZ_SRAM_OOB_INT_CHAR_WIDTH 1 -+#define FRF_BZ_BUFID_DC_OOB_INT_CHAR_LBN 9 -+#define FRF_BZ_BUFID_DC_OOB_INT_CHAR_WIDTH 1 -+#define FRF_BZ_MEM_PERR_INT_CHAR_LBN 8 -+#define FRF_BZ_MEM_PERR_INT_CHAR_WIDTH 1 -+#define FRF_BZ_RBUF_OWN_INT_CHAR_LBN 7 -+#define FRF_BZ_RBUF_OWN_INT_CHAR_WIDTH 1 -+#define FRF_BZ_TBUF_OWN_INT_CHAR_LBN 6 -+#define FRF_BZ_TBUF_OWN_INT_CHAR_WIDTH 1 -+#define FRF_BZ_RDESCQ_OWN_INT_CHAR_LBN 5 -+#define FRF_BZ_RDESCQ_OWN_INT_CHAR_WIDTH 1 -+#define FRF_BZ_TDESCQ_OWN_INT_CHAR_LBN 4 -+#define FRF_BZ_TDESCQ_OWN_INT_CHAR_WIDTH 1 -+#define FRF_BZ_EVQ_OWN_INT_CHAR_LBN 3 -+#define FRF_BZ_EVQ_OWN_INT_CHAR_WIDTH 1 -+#define FRF_BZ_EVF_OFLO_INT_CHAR_LBN 2 -+#define FRF_BZ_EVF_OFLO_INT_CHAR_WIDTH 1 -+#define FRF_BZ_ILL_ADR_INT_CHAR_LBN 1 -+#define FRF_BZ_ILL_ADR_INT_CHAR_WIDTH 1 -+#define FRF_BZ_SRM_PERR_INT_CHAR_LBN 0 -+#define FRF_BZ_SRM_PERR_INT_CHAR_WIDTH 1 -+ -+/* DP_CTRL_REG: Datapath control register */ -+#define FR_BZ_DP_CTRL 0x00000250 -+#define FRF_BZ_FLS_EVQ_ID_LBN 0 -+#define FRF_BZ_FLS_EVQ_ID_WIDTH 12 -+ -+/* MEM_STAT_REG: Memory status register */ -+#define FR_AZ_MEM_STAT 0x00000260 -+#define FRF_AB_MEM_PERR_VEC_LBN 53 -+#define FRF_AB_MEM_PERR_VEC_WIDTH 38 -+#define FRF_AB_MBIST_CORR_LBN 38 -+#define FRF_AB_MBIST_CORR_WIDTH 15 -+#define FRF_AB_MBIST_ERR_LBN 0 -+#define FRF_AB_MBIST_ERR_WIDTH 40 -+#define FRF_CZ_MEM_PERR_VEC_LBN 0 -+#define FRF_CZ_MEM_PERR_VEC_WIDTH 35 -+ -+/* CS_DEBUG_REG: Debug register */ -+#define FR_AZ_CS_DEBUG 0x00000270 -+#define FRF_AB_GLB_DEBUG2_SEL_LBN 50 -+#define FRF_AB_GLB_DEBUG2_SEL_WIDTH 3 -+#define FRF_AB_DEBUG_BLK_SEL2_LBN 47 -+#define FRF_AB_DEBUG_BLK_SEL2_WIDTH 3 -+#define FRF_AB_DEBUG_BLK_SEL1_LBN 44 -+#define FRF_AB_DEBUG_BLK_SEL1_WIDTH 3 -+#define FRF_AB_DEBUG_BLK_SEL0_LBN 41 -+#define FRF_AB_DEBUG_BLK_SEL0_WIDTH 3 -+#define FRF_CZ_CS_PORT_NUM_LBN 40 -+#define FRF_CZ_CS_PORT_NUM_WIDTH 2 -+#define FRF_AB_MISC_DEBUG_ADDR_LBN 36 -+#define FRF_AB_MISC_DEBUG_ADDR_WIDTH 5 -+#define FRF_AB_SERDES_DEBUG_ADDR_LBN 31 -+#define FRF_AB_SERDES_DEBUG_ADDR_WIDTH 5 -+#define FRF_CZ_CS_PORT_FPE_LBN 1 -+#define FRF_CZ_CS_PORT_FPE_WIDTH 35 -+#define FRF_AB_EM_DEBUG_ADDR_LBN 26 -+#define FRF_AB_EM_DEBUG_ADDR_WIDTH 5 -+#define FRF_AB_SR_DEBUG_ADDR_LBN 21 -+#define FRF_AB_SR_DEBUG_ADDR_WIDTH 5 -+#define FRF_AB_EV_DEBUG_ADDR_LBN 16 -+#define FRF_AB_EV_DEBUG_ADDR_WIDTH 5 -+#define FRF_AB_RX_DEBUG_ADDR_LBN 11 -+#define FRF_AB_RX_DEBUG_ADDR_WIDTH 5 -+#define FRF_AB_TX_DEBUG_ADDR_LBN 6 -+#define FRF_AB_TX_DEBUG_ADDR_WIDTH 5 -+#define FRF_AB_CS_BIU_DEBUG_ADDR_LBN 1 -+#define FRF_AB_CS_BIU_DEBUG_ADDR_WIDTH 5 -+#define FRF_AZ_CS_DEBUG_EN_LBN 0 -+#define FRF_AZ_CS_DEBUG_EN_WIDTH 1 -+ -+/* DRIVER_REG: Driver scratch register [0-7] */ -+#define FR_AZ_DRIVER 0x00000280 -+#define FR_AZ_DRIVER_STEP 16 -+#define FR_AZ_DRIVER_ROWS 8 -+#define FRF_AZ_DRIVER_DW0_LBN 0 -+#define FRF_AZ_DRIVER_DW0_WIDTH 32 -+ -+/* ALTERA_BUILD_REG: Altera build register */ -+#define FR_AZ_ALTERA_BUILD 0x00000300 -+#define FRF_AZ_ALTERA_BUILD_VER_LBN 0 -+#define FRF_AZ_ALTERA_BUILD_VER_WIDTH 32 -+ -+/* CSR_SPARE_REG: Spare register */ -+#define FR_AZ_CSR_SPARE 0x00000310 -+#define FRF_AB_MEM_PERR_EN_LBN 64 -+#define FRF_AB_MEM_PERR_EN_WIDTH 38 -+#define FRF_CZ_MEM_PERR_EN_LBN 64 -+#define FRF_CZ_MEM_PERR_EN_WIDTH 35 -+#define FRF_AB_MEM_PERR_EN_TX_DATA_LBN 72 -+#define FRF_AB_MEM_PERR_EN_TX_DATA_WIDTH 2 -+#define FRF_AZ_CSR_SPARE_BITS_LBN 0 -+#define FRF_AZ_CSR_SPARE_BITS_WIDTH 32 -+ -+/* PCIE_SD_CTL0123_REG: PCIE SerDes control register 0 to 3 */ -+#define FR_AB_PCIE_SD_CTL0123 0x00000320 -+#define FRF_AB_PCIE_TESTSIG_H_LBN 96 -+#define FRF_AB_PCIE_TESTSIG_H_WIDTH 19 -+#define FRF_AB_PCIE_TESTSIG_L_LBN 64 -+#define FRF_AB_PCIE_TESTSIG_L_WIDTH 19 -+#define FRF_AB_PCIE_OFFSET_LBN 56 -+#define FRF_AB_PCIE_OFFSET_WIDTH 8 -+#define FRF_AB_PCIE_OFFSETEN_H_LBN 55 -+#define FRF_AB_PCIE_OFFSETEN_H_WIDTH 1 -+#define FRF_AB_PCIE_OFFSETEN_L_LBN 54 -+#define FRF_AB_PCIE_OFFSETEN_L_WIDTH 1 -+#define FRF_AB_PCIE_HIVMODE_H_LBN 53 -+#define FRF_AB_PCIE_HIVMODE_H_WIDTH 1 -+#define FRF_AB_PCIE_HIVMODE_L_LBN 52 -+#define FRF_AB_PCIE_HIVMODE_L_WIDTH 1 -+#define FRF_AB_PCIE_PARRESET_H_LBN 51 -+#define FRF_AB_PCIE_PARRESET_H_WIDTH 1 -+#define FRF_AB_PCIE_PARRESET_L_LBN 50 -+#define FRF_AB_PCIE_PARRESET_L_WIDTH 1 -+#define FRF_AB_PCIE_LPBKWDRV_H_LBN 49 -+#define FRF_AB_PCIE_LPBKWDRV_H_WIDTH 1 -+#define FRF_AB_PCIE_LPBKWDRV_L_LBN 48 -+#define FRF_AB_PCIE_LPBKWDRV_L_WIDTH 1 -+#define FRF_AB_PCIE_LPBK_LBN 40 -+#define FRF_AB_PCIE_LPBK_WIDTH 8 -+#define FRF_AB_PCIE_PARLPBK_LBN 32 -+#define FRF_AB_PCIE_PARLPBK_WIDTH 8 -+#define FRF_AB_PCIE_RXTERMADJ_H_LBN 30 -+#define FRF_AB_PCIE_RXTERMADJ_H_WIDTH 2 -+#define FRF_AB_PCIE_RXTERMADJ_L_LBN 28 -+#define FRF_AB_PCIE_RXTERMADJ_L_WIDTH 2 -+#define FFE_AB_PCIE_RXTERMADJ_MIN15PCNT 3 -+#define FFE_AB_PCIE_RXTERMADJ_PL10PCNT 2 -+#define FFE_AB_PCIE_RXTERMADJ_MIN17PCNT 1 -+#define FFE_AB_PCIE_RXTERMADJ_NOMNL 0 -+#define FRF_AB_PCIE_TXTERMADJ_H_LBN 26 -+#define FRF_AB_PCIE_TXTERMADJ_H_WIDTH 2 -+#define FRF_AB_PCIE_TXTERMADJ_L_LBN 24 -+#define FRF_AB_PCIE_TXTERMADJ_L_WIDTH 2 -+#define FFE_AB_PCIE_TXTERMADJ_MIN15PCNT 3 -+#define FFE_AB_PCIE_TXTERMADJ_PL10PCNT 2 -+#define FFE_AB_PCIE_TXTERMADJ_MIN17PCNT 1 -+#define FFE_AB_PCIE_TXTERMADJ_NOMNL 0 -+#define FRF_AB_PCIE_RXEQCTL_H_LBN 18 -+#define FRF_AB_PCIE_RXEQCTL_H_WIDTH 2 -+#define FRF_AB_PCIE_RXEQCTL_L_LBN 16 -+#define FRF_AB_PCIE_RXEQCTL_L_WIDTH 2 -+#define FFE_AB_PCIE_RXEQCTL_OFF_ALT 3 -+#define FFE_AB_PCIE_RXEQCTL_OFF 2 -+#define FFE_AB_PCIE_RXEQCTL_MIN 1 -+#define FFE_AB_PCIE_RXEQCTL_MAX 0 -+#define FRF_AB_PCIE_HIDRV_LBN 8 -+#define FRF_AB_PCIE_HIDRV_WIDTH 8 -+#define FRF_AB_PCIE_LODRV_LBN 0 -+#define FRF_AB_PCIE_LODRV_WIDTH 8 -+ -+/* PCIE_SD_CTL45_REG: PCIE SerDes control register 4 and 5 */ -+#define FR_AB_PCIE_SD_CTL45 0x00000330 -+#define FRF_AB_PCIE_DTX7_LBN 60 -+#define FRF_AB_PCIE_DTX7_WIDTH 4 -+#define FRF_AB_PCIE_DTX6_LBN 56 -+#define FRF_AB_PCIE_DTX6_WIDTH 4 -+#define FRF_AB_PCIE_DTX5_LBN 52 -+#define FRF_AB_PCIE_DTX5_WIDTH 4 -+#define FRF_AB_PCIE_DTX4_LBN 48 -+#define FRF_AB_PCIE_DTX4_WIDTH 4 -+#define FRF_AB_PCIE_DTX3_LBN 44 -+#define FRF_AB_PCIE_DTX3_WIDTH 4 -+#define FRF_AB_PCIE_DTX2_LBN 40 -+#define FRF_AB_PCIE_DTX2_WIDTH 4 -+#define FRF_AB_PCIE_DTX1_LBN 36 -+#define FRF_AB_PCIE_DTX1_WIDTH 4 -+#define FRF_AB_PCIE_DTX0_LBN 32 -+#define FRF_AB_PCIE_DTX0_WIDTH 4 -+#define FRF_AB_PCIE_DEQ7_LBN 28 -+#define FRF_AB_PCIE_DEQ7_WIDTH 4 -+#define FRF_AB_PCIE_DEQ6_LBN 24 -+#define FRF_AB_PCIE_DEQ6_WIDTH 4 -+#define FRF_AB_PCIE_DEQ5_LBN 20 -+#define FRF_AB_PCIE_DEQ5_WIDTH 4 -+#define FRF_AB_PCIE_DEQ4_LBN 16 -+#define FRF_AB_PCIE_DEQ4_WIDTH 4 -+#define FRF_AB_PCIE_DEQ3_LBN 12 -+#define FRF_AB_PCIE_DEQ3_WIDTH 4 -+#define FRF_AB_PCIE_DEQ2_LBN 8 -+#define FRF_AB_PCIE_DEQ2_WIDTH 4 -+#define FRF_AB_PCIE_DEQ1_LBN 4 -+#define FRF_AB_PCIE_DEQ1_WIDTH 4 -+#define FRF_AB_PCIE_DEQ0_LBN 0 -+#define FRF_AB_PCIE_DEQ0_WIDTH 4 -+ -+/* PCIE_PCS_CTL_STAT_REG: PCIE PCS control and status register */ -+#define FR_AB_PCIE_PCS_CTL_STAT 0x00000340 -+#define FRF_AB_PCIE_PRBSERRCOUNT0_H_LBN 52 -+#define FRF_AB_PCIE_PRBSERRCOUNT0_H_WIDTH 4 -+#define FRF_AB_PCIE_PRBSERRCOUNT0_L_LBN 48 -+#define FRF_AB_PCIE_PRBSERRCOUNT0_L_WIDTH 4 -+#define FRF_AB_PCIE_PRBSERR_LBN 40 -+#define FRF_AB_PCIE_PRBSERR_WIDTH 8 -+#define FRF_AB_PCIE_PRBSERRH0_LBN 32 -+#define FRF_AB_PCIE_PRBSERRH0_WIDTH 8 -+#define FRF_AB_PCIE_FASTINIT_H_LBN 15 -+#define FRF_AB_PCIE_FASTINIT_H_WIDTH 1 -+#define FRF_AB_PCIE_FASTINIT_L_LBN 14 -+#define FRF_AB_PCIE_FASTINIT_L_WIDTH 1 -+#define FRF_AB_PCIE_CTCDISABLE_H_LBN 13 -+#define FRF_AB_PCIE_CTCDISABLE_H_WIDTH 1 -+#define FRF_AB_PCIE_CTCDISABLE_L_LBN 12 -+#define FRF_AB_PCIE_CTCDISABLE_L_WIDTH 1 -+#define FRF_AB_PCIE_PRBSSYNC_H_LBN 11 -+#define FRF_AB_PCIE_PRBSSYNC_H_WIDTH 1 -+#define FRF_AB_PCIE_PRBSSYNC_L_LBN 10 -+#define FRF_AB_PCIE_PRBSSYNC_L_WIDTH 1 -+#define FRF_AB_PCIE_PRBSERRACK_H_LBN 9 -+#define FRF_AB_PCIE_PRBSERRACK_H_WIDTH 1 -+#define FRF_AB_PCIE_PRBSERRACK_L_LBN 8 -+#define FRF_AB_PCIE_PRBSERRACK_L_WIDTH 1 -+#define FRF_AB_PCIE_PRBSSEL_LBN 0 -+#define FRF_AB_PCIE_PRBSSEL_WIDTH 8 -+ -+/* DEBUG_DATA_OUT_REG: Live Debug and Debug 2 out ports */ -+#define FR_BB_DEBUG_DATA_OUT 0x00000350 -+#define FRF_BB_DEBUG2_PORT_LBN 25 -+#define FRF_BB_DEBUG2_PORT_WIDTH 15 -+#define FRF_BB_DEBUG1_PORT_LBN 0 -+#define FRF_BB_DEBUG1_PORT_WIDTH 25 -+ -+/* EVQ_RPTR_REGP0: Event queue read pointer register */ -+#define FR_BZ_EVQ_RPTR_P0 0x00000400 -+#define FR_BZ_EVQ_RPTR_P0_STEP 8192 -+#define FR_BZ_EVQ_RPTR_P0_ROWS 1024 -+/* EVQ_RPTR_REG_KER: Event queue read pointer register */ -+#define FR_AA_EVQ_RPTR_KER 0x00011b00 -+#define FR_AA_EVQ_RPTR_KER_STEP 4 -+#define FR_AA_EVQ_RPTR_KER_ROWS 4 -+/* EVQ_RPTR_REG: Event queue read pointer register */ -+#define FR_BZ_EVQ_RPTR 0x00fa0000 -+#define FR_BZ_EVQ_RPTR_STEP 16 -+#define FR_BB_EVQ_RPTR_ROWS 4096 -+#define FR_CZ_EVQ_RPTR_ROWS 1024 -+/* EVQ_RPTR_REGP123: Event queue read pointer register */ -+#define FR_BB_EVQ_RPTR_P123 0x01000400 -+#define FR_BB_EVQ_RPTR_P123_STEP 8192 -+#define FR_BB_EVQ_RPTR_P123_ROWS 3072 -+#define FRF_AZ_EVQ_RPTR_VLD_LBN 15 -+#define FRF_AZ_EVQ_RPTR_VLD_WIDTH 1 -+#define FRF_AZ_EVQ_RPTR_LBN 0 -+#define FRF_AZ_EVQ_RPTR_WIDTH 15 -+ -+/* TIMER_COMMAND_REGP0: Timer Command Registers */ -+#define FR_BZ_TIMER_COMMAND_P0 0x00000420 -+#define FR_BZ_TIMER_COMMAND_P0_STEP 8192 -+#define FR_BZ_TIMER_COMMAND_P0_ROWS 1024 -+/* TIMER_COMMAND_REG_KER: Timer Command Registers */ -+#define FR_AA_TIMER_COMMAND_KER 0x00000420 -+#define FR_AA_TIMER_COMMAND_KER_STEP 8192 -+#define FR_AA_TIMER_COMMAND_KER_ROWS 4 -+/* TIMER_COMMAND_REGP123: Timer Command Registers */ -+#define FR_BB_TIMER_COMMAND_P123 0x01000420 -+#define FR_BB_TIMER_COMMAND_P123_STEP 8192 -+#define FR_BB_TIMER_COMMAND_P123_ROWS 3072 -+#define FRF_CZ_TC_TIMER_MODE_LBN 14 -+#define FRF_CZ_TC_TIMER_MODE_WIDTH 2 -+#define FRF_AB_TC_TIMER_MODE_LBN 12 -+#define FRF_AB_TC_TIMER_MODE_WIDTH 2 -+#define FRF_CZ_TC_TIMER_VAL_LBN 0 -+#define FRF_CZ_TC_TIMER_VAL_WIDTH 14 -+#define FRF_AB_TC_TIMER_VAL_LBN 0 -+#define FRF_AB_TC_TIMER_VAL_WIDTH 12 -+ -+/* DRV_EV_REG: Driver generated event register */ -+#define FR_AZ_DRV_EV 0x00000440 -+#define FRF_AZ_DRV_EV_QID_LBN 64 -+#define FRF_AZ_DRV_EV_QID_WIDTH 12 -+#define FRF_AZ_DRV_EV_DATA_LBN 0 -+#define FRF_AZ_DRV_EV_DATA_WIDTH 64 -+ -+/* EVQ_CTL_REG: Event queue control register */ -+#define FR_AZ_EVQ_CTL 0x00000450 -+#define FRF_CZ_RX_EVQ_WAKEUP_MASK_LBN 15 -+#define FRF_CZ_RX_EVQ_WAKEUP_MASK_WIDTH 10 -+#define FRF_BB_RX_EVQ_WAKEUP_MASK_LBN 15 -+#define FRF_BB_RX_EVQ_WAKEUP_MASK_WIDTH 6 -+#define FRF_AZ_EVQ_OWNERR_CTL_LBN 14 -+#define FRF_AZ_EVQ_OWNERR_CTL_WIDTH 1 -+#define FRF_AZ_EVQ_FIFO_AF_TH_LBN 7 -+#define FRF_AZ_EVQ_FIFO_AF_TH_WIDTH 7 -+#define FRF_AZ_EVQ_FIFO_NOTAF_TH_LBN 0 -+#define FRF_AZ_EVQ_FIFO_NOTAF_TH_WIDTH 7 -+ -+/* EVQ_CNT1_REG: Event counter 1 register */ -+#define FR_AZ_EVQ_CNT1 0x00000460 -+#define FRF_AZ_EVQ_CNT_PRE_FIFO_LBN 120 -+#define FRF_AZ_EVQ_CNT_PRE_FIFO_WIDTH 7 -+#define FRF_AZ_EVQ_CNT_TOBIU_LBN 100 -+#define FRF_AZ_EVQ_CNT_TOBIU_WIDTH 20 -+#define FRF_AZ_EVQ_TX_REQ_CNT_LBN 80 -+#define FRF_AZ_EVQ_TX_REQ_CNT_WIDTH 20 -+#define FRF_AZ_EVQ_RX_REQ_CNT_LBN 60 -+#define FRF_AZ_EVQ_RX_REQ_CNT_WIDTH 20 -+#define FRF_AZ_EVQ_EM_REQ_CNT_LBN 40 -+#define FRF_AZ_EVQ_EM_REQ_CNT_WIDTH 20 -+#define FRF_AZ_EVQ_CSR_REQ_CNT_LBN 20 -+#define FRF_AZ_EVQ_CSR_REQ_CNT_WIDTH 20 -+#define FRF_AZ_EVQ_ERR_REQ_CNT_LBN 0 -+#define FRF_AZ_EVQ_ERR_REQ_CNT_WIDTH 20 -+ -+/* EVQ_CNT2_REG: Event counter 2 register */ -+#define FR_AZ_EVQ_CNT2 0x00000470 -+#define FRF_AZ_EVQ_UPD_REQ_CNT_LBN 104 -+#define FRF_AZ_EVQ_UPD_REQ_CNT_WIDTH 20 -+#define FRF_AZ_EVQ_CLR_REQ_CNT_LBN 84 -+#define FRF_AZ_EVQ_CLR_REQ_CNT_WIDTH 20 -+#define FRF_AZ_EVQ_RDY_CNT_LBN 80 -+#define FRF_AZ_EVQ_RDY_CNT_WIDTH 4 -+#define FRF_AZ_EVQ_WU_REQ_CNT_LBN 60 -+#define FRF_AZ_EVQ_WU_REQ_CNT_WIDTH 20 -+#define FRF_AZ_EVQ_WET_REQ_CNT_LBN 40 -+#define FRF_AZ_EVQ_WET_REQ_CNT_WIDTH 20 -+#define FRF_AZ_EVQ_INIT_REQ_CNT_LBN 20 -+#define FRF_AZ_EVQ_INIT_REQ_CNT_WIDTH 20 -+#define FRF_AZ_EVQ_TM_REQ_CNT_LBN 0 -+#define FRF_AZ_EVQ_TM_REQ_CNT_WIDTH 20 -+ -+/* USR_EV_REG: Event mailbox register */ -+#define FR_CZ_USR_EV 0x00000540 -+#define FR_CZ_USR_EV_STEP 8192 -+#define FR_CZ_USR_EV_ROWS 1024 -+#define FRF_CZ_USR_EV_DATA_LBN 0 -+#define FRF_CZ_USR_EV_DATA_WIDTH 32 -+ -+/* BUF_TBL_CFG_REG: Buffer table configuration register */ -+#define FR_AZ_BUF_TBL_CFG 0x00000600 -+#define FRF_AZ_BUF_TBL_MODE_LBN 3 -+#define FRF_AZ_BUF_TBL_MODE_WIDTH 1 -+ -+/* SRM_RX_DC_CFG_REG: SRAM receive descriptor cache configuration register */ -+#define FR_AZ_SRM_RX_DC_CFG 0x00000610 -+#define FRF_AZ_SRM_CLK_TMP_EN_LBN 21 -+#define FRF_AZ_SRM_CLK_TMP_EN_WIDTH 1 -+#define FRF_AZ_SRM_RX_DC_BASE_ADR_LBN 0 -+#define FRF_AZ_SRM_RX_DC_BASE_ADR_WIDTH 21 -+ -+/* SRM_TX_DC_CFG_REG: SRAM transmit descriptor cache configuration register */ -+#define FR_AZ_SRM_TX_DC_CFG 0x00000620 -+#define FRF_AZ_SRM_TX_DC_BASE_ADR_LBN 0 -+#define FRF_AZ_SRM_TX_DC_BASE_ADR_WIDTH 21 -+ -+/* SRM_CFG_REG: SRAM configuration register */ -+#define FR_AZ_SRM_CFG 0x00000630 -+#define FRF_AZ_SRM_OOB_ADR_INTEN_LBN 5 -+#define FRF_AZ_SRM_OOB_ADR_INTEN_WIDTH 1 -+#define FRF_AZ_SRM_OOB_BUF_INTEN_LBN 4 -+#define FRF_AZ_SRM_OOB_BUF_INTEN_WIDTH 1 -+#define FRF_AZ_SRM_INIT_EN_LBN 3 -+#define FRF_AZ_SRM_INIT_EN_WIDTH 1 -+#define FRF_AZ_SRM_NUM_BANK_LBN 2 -+#define FRF_AZ_SRM_NUM_BANK_WIDTH 1 -+#define FRF_AZ_SRM_BANK_SIZE_LBN 0 -+#define FRF_AZ_SRM_BANK_SIZE_WIDTH 2 -+ -+/* BUF_TBL_UPD_REG: Buffer table update register */ -+#define FR_AZ_BUF_TBL_UPD 0x00000650 -+#define FRF_AZ_BUF_UPD_CMD_LBN 63 -+#define FRF_AZ_BUF_UPD_CMD_WIDTH 1 -+#define FRF_AZ_BUF_CLR_CMD_LBN 62 -+#define FRF_AZ_BUF_CLR_CMD_WIDTH 1 -+#define FRF_AZ_BUF_CLR_END_ID_LBN 32 -+#define FRF_AZ_BUF_CLR_END_ID_WIDTH 20 -+#define FRF_AZ_BUF_CLR_START_ID_LBN 0 -+#define FRF_AZ_BUF_CLR_START_ID_WIDTH 20 -+ -+/* SRM_UPD_EVQ_REG: Buffer table update register */ -+#define FR_AZ_SRM_UPD_EVQ 0x00000660 -+#define FRF_AZ_SRM_UPD_EVQ_ID_LBN 0 -+#define FRF_AZ_SRM_UPD_EVQ_ID_WIDTH 12 -+ -+/* SRAM_PARITY_REG: SRAM parity register. */ -+#define FR_AZ_SRAM_PARITY 0x00000670 -+#define FRF_CZ_BYPASS_ECC_LBN 3 -+#define FRF_CZ_BYPASS_ECC_WIDTH 1 -+#define FRF_CZ_SEC_INT_LBN 2 -+#define FRF_CZ_SEC_INT_WIDTH 1 -+#define FRF_CZ_FORCE_SRAM_DOUBLE_ERR_LBN 1 -+#define FRF_CZ_FORCE_SRAM_DOUBLE_ERR_WIDTH 1 -+#define FRF_AB_FORCE_SRAM_PERR_LBN 0 -+#define FRF_AB_FORCE_SRAM_PERR_WIDTH 1 -+#define FRF_CZ_FORCE_SRAM_SINGLE_ERR_LBN 0 -+#define FRF_CZ_FORCE_SRAM_SINGLE_ERR_WIDTH 1 -+ -+/* RX_CFG_REG: Receive configuration register */ -+#define FR_AZ_RX_CFG 0x00000800 -+#define FRF_CZ_RX_MIN_KBUF_SIZE_LBN 72 -+#define FRF_CZ_RX_MIN_KBUF_SIZE_WIDTH 14 -+#define FRF_CZ_RX_HDR_SPLIT_EN_LBN 71 -+#define FRF_CZ_RX_HDR_SPLIT_EN_WIDTH 1 -+#define FRF_CZ_RX_HDR_SPLIT_PLD_BUF_SIZE_LBN 62 -+#define FRF_CZ_RX_HDR_SPLIT_PLD_BUF_SIZE_WIDTH 9 -+#define FRF_CZ_RX_HDR_SPLIT_HDR_BUF_SIZE_LBN 53 -+#define FRF_CZ_RX_HDR_SPLIT_HDR_BUF_SIZE_WIDTH 9 -+#define FRF_CZ_RX_PRE_RFF_IPG_LBN 49 -+#define FRF_CZ_RX_PRE_RFF_IPG_WIDTH 4 -+#define FRF_BZ_RX_TCP_SUP_LBN 48 -+#define FRF_BZ_RX_TCP_SUP_WIDTH 1 -+#define FRF_BZ_RX_INGR_EN_LBN 47 -+#define FRF_BZ_RX_INGR_EN_WIDTH 1 -+#define FRF_BZ_RX_IP_HASH_LBN 46 -+#define FRF_BZ_RX_IP_HASH_WIDTH 1 -+#define FRF_BZ_RX_HASH_ALG_LBN 45 -+#define FRF_BZ_RX_HASH_ALG_WIDTH 1 -+#define FRF_BZ_RX_HASH_INSRT_HDR_LBN 44 -+#define FRF_BZ_RX_HASH_INSRT_HDR_WIDTH 1 -+#define FRF_BZ_RX_DESC_PUSH_EN_LBN 43 -+#define FRF_BZ_RX_DESC_PUSH_EN_WIDTH 1 -+#define FRF_BZ_RX_RDW_PATCH_EN_LBN 42 -+#define FRF_BZ_RX_RDW_PATCH_EN_WIDTH 1 -+#define FRF_BB_RX_PCI_BURST_SIZE_LBN 39 -+#define FRF_BB_RX_PCI_BURST_SIZE_WIDTH 3 -+#define FRF_BZ_RX_OWNERR_CTL_LBN 38 -+#define FRF_BZ_RX_OWNERR_CTL_WIDTH 1 -+#define FRF_BZ_RX_XON_TX_TH_LBN 33 -+#define FRF_BZ_RX_XON_TX_TH_WIDTH 5 -+#define FRF_AA_RX_DESC_PUSH_EN_LBN 35 -+#define FRF_AA_RX_DESC_PUSH_EN_WIDTH 1 -+#define FRF_AA_RX_RDW_PATCH_EN_LBN 34 -+#define FRF_AA_RX_RDW_PATCH_EN_WIDTH 1 -+#define FRF_AA_RX_PCI_BURST_SIZE_LBN 31 -+#define FRF_AA_RX_PCI_BURST_SIZE_WIDTH 3 -+#define FRF_BZ_RX_XOFF_TX_TH_LBN 28 -+#define FRF_BZ_RX_XOFF_TX_TH_WIDTH 5 -+#define FRF_AA_RX_OWNERR_CTL_LBN 30 -+#define FRF_AA_RX_OWNERR_CTL_WIDTH 1 -+#define FRF_AA_RX_XON_TX_TH_LBN 25 -+#define FRF_AA_RX_XON_TX_TH_WIDTH 5 -+#define FRF_BZ_RX_USR_BUF_SIZE_LBN 19 -+#define FRF_BZ_RX_USR_BUF_SIZE_WIDTH 9 -+#define FRF_AA_RX_XOFF_TX_TH_LBN 20 -+#define FRF_AA_RX_XOFF_TX_TH_WIDTH 5 -+#define FRF_AA_RX_USR_BUF_SIZE_LBN 11 -+#define FRF_AA_RX_USR_BUF_SIZE_WIDTH 9 -+#define FRF_BZ_RX_XON_MAC_TH_LBN 10 -+#define FRF_BZ_RX_XON_MAC_TH_WIDTH 9 -+#define FRF_AA_RX_XON_MAC_TH_LBN 6 -+#define FRF_AA_RX_XON_MAC_TH_WIDTH 5 -+#define FRF_BZ_RX_XOFF_MAC_TH_LBN 1 -+#define FRF_BZ_RX_XOFF_MAC_TH_WIDTH 9 -+#define FRF_AA_RX_XOFF_MAC_TH_LBN 1 -+#define FRF_AA_RX_XOFF_MAC_TH_WIDTH 5 -+#define FRF_AZ_RX_XOFF_MAC_EN_LBN 0 -+#define FRF_AZ_RX_XOFF_MAC_EN_WIDTH 1 -+ -+/* RX_FILTER_CTL_REG: Receive filter control registers */ -+#define FR_BZ_RX_FILTER_CTL 0x00000810 -+#define FRF_CZ_ETHERNET_WILDCARD_SEARCH_LIMIT_LBN 94 -+#define FRF_CZ_ETHERNET_WILDCARD_SEARCH_LIMIT_WIDTH 8 -+#define FRF_CZ_ETHERNET_FULL_SEARCH_LIMIT_LBN 86 -+#define FRF_CZ_ETHERNET_FULL_SEARCH_LIMIT_WIDTH 8 -+#define FRF_CZ_RX_FILTER_ALL_VLAN_ETHERTYPES_LBN 85 -+#define FRF_CZ_RX_FILTER_ALL_VLAN_ETHERTYPES_WIDTH 1 -+#define FRF_CZ_RX_VLAN_MATCH_ETHERTYPE_LBN 69 -+#define FRF_CZ_RX_VLAN_MATCH_ETHERTYPE_WIDTH 16 -+#define FRF_CZ_MULTICAST_NOMATCH_Q_ID_LBN 57 -+#define FRF_CZ_MULTICAST_NOMATCH_Q_ID_WIDTH 12 -+#define FRF_CZ_MULTICAST_NOMATCH_RSS_ENABLED_LBN 56 -+#define FRF_CZ_MULTICAST_NOMATCH_RSS_ENABLED_WIDTH 1 -+#define FRF_CZ_MULTICAST_NOMATCH_IP_OVERRIDE_LBN 55 -+#define FRF_CZ_MULTICAST_NOMATCH_IP_OVERRIDE_WIDTH 1 -+#define FRF_CZ_UNICAST_NOMATCH_Q_ID_LBN 43 -+#define FRF_CZ_UNICAST_NOMATCH_Q_ID_WIDTH 12 -+#define FRF_CZ_UNICAST_NOMATCH_RSS_ENABLED_LBN 42 -+#define FRF_CZ_UNICAST_NOMATCH_RSS_ENABLED_WIDTH 1 -+#define FRF_CZ_UNICAST_NOMATCH_IP_OVERRIDE_LBN 41 -+#define FRF_CZ_UNICAST_NOMATCH_IP_OVERRIDE_WIDTH 1 -+#define FRF_BZ_SCATTER_ENBL_NO_MATCH_Q_LBN 40 -+#define FRF_BZ_SCATTER_ENBL_NO_MATCH_Q_WIDTH 1 -+#define FRF_BZ_UDP_FULL_SRCH_LIMIT_LBN 32 -+#define FRF_BZ_UDP_FULL_SRCH_LIMIT_WIDTH 8 -+#define FRF_BZ_NUM_KER_LBN 24 -+#define FRF_BZ_NUM_KER_WIDTH 2 -+#define FRF_BZ_UDP_WILD_SRCH_LIMIT_LBN 16 -+#define FRF_BZ_UDP_WILD_SRCH_LIMIT_WIDTH 8 -+#define FRF_BZ_TCP_WILD_SRCH_LIMIT_LBN 8 -+#define FRF_BZ_TCP_WILD_SRCH_LIMIT_WIDTH 8 -+#define FRF_BZ_TCP_FULL_SRCH_LIMIT_LBN 0 -+#define FRF_BZ_TCP_FULL_SRCH_LIMIT_WIDTH 8 -+ -+/* RX_FLUSH_DESCQ_REG: Receive flush descriptor queue register */ -+#define FR_AZ_RX_FLUSH_DESCQ 0x00000820 -+#define FRF_AZ_RX_FLUSH_DESCQ_CMD_LBN 24 -+#define FRF_AZ_RX_FLUSH_DESCQ_CMD_WIDTH 1 -+#define FRF_AZ_RX_FLUSH_DESCQ_LBN 0 -+#define FRF_AZ_RX_FLUSH_DESCQ_WIDTH 12 -+ -+/* RX_DESC_UPD_REGP0: Receive descriptor update register. */ -+#define FR_BZ_RX_DESC_UPD_P0 0x00000830 -+#define FR_BZ_RX_DESC_UPD_P0_STEP 8192 -+#define FR_BZ_RX_DESC_UPD_P0_ROWS 1024 -+/* RX_DESC_UPD_REG_KER: Receive descriptor update register. */ -+#define FR_AA_RX_DESC_UPD_KER 0x00000830 -+#define FR_AA_RX_DESC_UPD_KER_STEP 8192 -+#define FR_AA_RX_DESC_UPD_KER_ROWS 4 -+/* RX_DESC_UPD_REGP123: Receive descriptor update register. */ -+#define FR_BB_RX_DESC_UPD_P123 0x01000830 -+#define FR_BB_RX_DESC_UPD_P123_STEP 8192 -+#define FR_BB_RX_DESC_UPD_P123_ROWS 3072 -+#define FRF_AZ_RX_DESC_WPTR_LBN 96 -+#define FRF_AZ_RX_DESC_WPTR_WIDTH 12 -+#define FRF_AZ_RX_DESC_PUSH_CMD_LBN 95 -+#define FRF_AZ_RX_DESC_PUSH_CMD_WIDTH 1 -+#define FRF_AZ_RX_DESC_LBN 0 -+#define FRF_AZ_RX_DESC_WIDTH 64 -+ -+/* RX_DC_CFG_REG: Receive descriptor cache configuration register */ -+#define FR_AZ_RX_DC_CFG 0x00000840 -+#define FRF_AB_RX_MAX_PF_LBN 2 -+#define FRF_AB_RX_MAX_PF_WIDTH 2 -+#define FRF_AZ_RX_DC_SIZE_LBN 0 -+#define FRF_AZ_RX_DC_SIZE_WIDTH 2 -+#define FFE_AZ_RX_DC_SIZE_64 3 -+#define FFE_AZ_RX_DC_SIZE_32 2 -+#define FFE_AZ_RX_DC_SIZE_16 1 -+#define FFE_AZ_RX_DC_SIZE_8 0 -+ -+/* RX_DC_PF_WM_REG: Receive descriptor cache pre-fetch watermark register */ -+#define FR_AZ_RX_DC_PF_WM 0x00000850 -+#define FRF_AZ_RX_DC_PF_HWM_LBN 6 -+#define FRF_AZ_RX_DC_PF_HWM_WIDTH 6 -+#define FRF_AZ_RX_DC_PF_LWM_LBN 0 -+#define FRF_AZ_RX_DC_PF_LWM_WIDTH 6 -+ -+/* RX_RSS_TKEY_REG: RSS Toeplitz hash key */ -+#define FR_BZ_RX_RSS_TKEY 0x00000860 -+#define FRF_BZ_RX_RSS_TKEY_HI_LBN 64 -+#define FRF_BZ_RX_RSS_TKEY_HI_WIDTH 64 -+#define FRF_BZ_RX_RSS_TKEY_LO_LBN 0 -+#define FRF_BZ_RX_RSS_TKEY_LO_WIDTH 64 -+ -+/* RX_NODESC_DROP_REG: Receive dropped packet counter register */ -+#define FR_AZ_RX_NODESC_DROP 0x00000880 -+#define FRF_CZ_RX_NODESC_DROP_CNT_LBN 0 -+#define FRF_CZ_RX_NODESC_DROP_CNT_WIDTH 32 -+#define FRF_AB_RX_NODESC_DROP_CNT_LBN 0 -+#define FRF_AB_RX_NODESC_DROP_CNT_WIDTH 16 -+ -+/* RX_SELF_RST_REG: Receive self reset register */ -+#define FR_AA_RX_SELF_RST 0x00000890 -+#define FRF_AA_RX_ISCSI_DIS_LBN 17 -+#define FRF_AA_RX_ISCSI_DIS_WIDTH 1 -+#define FRF_AA_RX_SW_RST_REG_LBN 16 -+#define FRF_AA_RX_SW_RST_REG_WIDTH 1 -+#define FRF_AA_RX_NODESC_WAIT_DIS_LBN 9 -+#define FRF_AA_RX_NODESC_WAIT_DIS_WIDTH 1 -+#define FRF_AA_RX_SELF_RST_EN_LBN 8 -+#define FRF_AA_RX_SELF_RST_EN_WIDTH 1 -+#define FRF_AA_RX_MAX_PF_LAT_LBN 4 -+#define FRF_AA_RX_MAX_PF_LAT_WIDTH 4 -+#define FRF_AA_RX_MAX_LU_LAT_LBN 0 -+#define FRF_AA_RX_MAX_LU_LAT_WIDTH 4 -+ -+/* RX_DEBUG_REG: undocumented register */ -+#define FR_AZ_RX_DEBUG 0x000008a0 -+#define FRF_AZ_RX_DEBUG_LBN 0 -+#define FRF_AZ_RX_DEBUG_WIDTH 64 -+ -+/* RX_PUSH_DROP_REG: Receive descriptor push dropped counter register */ -+#define FR_AZ_RX_PUSH_DROP 0x000008b0 -+#define FRF_AZ_RX_PUSH_DROP_CNT_LBN 0 -+#define FRF_AZ_RX_PUSH_DROP_CNT_WIDTH 32 -+ -+/* RX_RSS_IPV6_REG1: IPv6 RSS Toeplitz hash key low bytes */ -+#define FR_CZ_RX_RSS_IPV6_REG1 0x000008d0 -+#define FRF_CZ_RX_RSS_IPV6_TKEY_LO_LBN 0 -+#define FRF_CZ_RX_RSS_IPV6_TKEY_LO_WIDTH 128 -+ -+/* RX_RSS_IPV6_REG2: IPv6 RSS Toeplitz hash key middle bytes */ -+#define FR_CZ_RX_RSS_IPV6_REG2 0x000008e0 -+#define FRF_CZ_RX_RSS_IPV6_TKEY_MID_LBN 0 -+#define FRF_CZ_RX_RSS_IPV6_TKEY_MID_WIDTH 128 -+ -+/* RX_RSS_IPV6_REG3: IPv6 RSS Toeplitz hash key upper bytes and IPv6 RSS settings */ -+#define FR_CZ_RX_RSS_IPV6_REG3 0x000008f0 -+#define FRF_CZ_RX_RSS_IPV6_THASH_ENABLE_LBN 66 -+#define FRF_CZ_RX_RSS_IPV6_THASH_ENABLE_WIDTH 1 -+#define FRF_CZ_RX_RSS_IPV6_IP_THASH_ENABLE_LBN 65 -+#define FRF_CZ_RX_RSS_IPV6_IP_THASH_ENABLE_WIDTH 1 -+#define FRF_CZ_RX_RSS_IPV6_TCP_SUPPRESS_LBN 64 -+#define FRF_CZ_RX_RSS_IPV6_TCP_SUPPRESS_WIDTH 1 -+#define FRF_CZ_RX_RSS_IPV6_TKEY_HI_LBN 0 -+#define FRF_CZ_RX_RSS_IPV6_TKEY_HI_WIDTH 64 -+ -+/* TX_FLUSH_DESCQ_REG: Transmit flush descriptor queue register */ -+#define FR_AZ_TX_FLUSH_DESCQ 0x00000a00 -+#define FRF_AZ_TX_FLUSH_DESCQ_CMD_LBN 12 -+#define FRF_AZ_TX_FLUSH_DESCQ_CMD_WIDTH 1 -+#define FRF_AZ_TX_FLUSH_DESCQ_LBN 0 -+#define FRF_AZ_TX_FLUSH_DESCQ_WIDTH 12 -+ -+/* TX_DESC_UPD_REGP0: Transmit descriptor update register. */ -+#define FR_BZ_TX_DESC_UPD_P0 0x00000a10 -+#define FR_BZ_TX_DESC_UPD_P0_STEP 8192 -+#define FR_BZ_TX_DESC_UPD_P0_ROWS 1024 -+/* TX_DESC_UPD_REG_KER: Transmit descriptor update register. */ -+#define FR_AA_TX_DESC_UPD_KER 0x00000a10 -+#define FR_AA_TX_DESC_UPD_KER_STEP 8192 -+#define FR_AA_TX_DESC_UPD_KER_ROWS 8 -+/* TX_DESC_UPD_REGP123: Transmit descriptor update register. */ -+#define FR_BB_TX_DESC_UPD_P123 0x01000a10 -+#define FR_BB_TX_DESC_UPD_P123_STEP 8192 -+#define FR_BB_TX_DESC_UPD_P123_ROWS 3072 -+#define FRF_AZ_TX_DESC_WPTR_LBN 96 -+#define FRF_AZ_TX_DESC_WPTR_WIDTH 12 -+#define FRF_AZ_TX_DESC_PUSH_CMD_LBN 95 -+#define FRF_AZ_TX_DESC_PUSH_CMD_WIDTH 1 -+#define FRF_AZ_TX_DESC_LBN 0 -+#define FRF_AZ_TX_DESC_WIDTH 95 -+ -+/* TX_DC_CFG_REG: Transmit descriptor cache configuration register */ -+#define FR_AZ_TX_DC_CFG 0x00000a20 -+#define FRF_AZ_TX_DC_SIZE_LBN 0 -+#define FRF_AZ_TX_DC_SIZE_WIDTH 2 -+#define FFE_AZ_TX_DC_SIZE_32 2 -+#define FFE_AZ_TX_DC_SIZE_16 1 -+#define FFE_AZ_TX_DC_SIZE_8 0 -+ -+/* TX_CHKSM_CFG_REG: Transmit checksum configuration register */ -+#define FR_AA_TX_CHKSM_CFG 0x00000a30 -+#define FRF_AA_TX_Q_CHKSM_DIS_96_127_LBN 96 -+#define FRF_AA_TX_Q_CHKSM_DIS_96_127_WIDTH 32 -+#define FRF_AA_TX_Q_CHKSM_DIS_64_95_LBN 64 -+#define FRF_AA_TX_Q_CHKSM_DIS_64_95_WIDTH 32 -+#define FRF_AA_TX_Q_CHKSM_DIS_32_63_LBN 32 -+#define FRF_AA_TX_Q_CHKSM_DIS_32_63_WIDTH 32 -+#define FRF_AA_TX_Q_CHKSM_DIS_0_31_LBN 0 -+#define FRF_AA_TX_Q_CHKSM_DIS_0_31_WIDTH 32 -+ -+/* TX_CFG_REG: Transmit configuration register */ -+#define FR_AZ_TX_CFG 0x00000a50 -+#define FRF_CZ_TX_CONT_LOOKUP_THRESH_RANGE_LBN 114 -+#define FRF_CZ_TX_CONT_LOOKUP_THRESH_RANGE_WIDTH 8 -+#define FRF_CZ_TX_FILTER_TEST_MODE_BIT_LBN 113 -+#define FRF_CZ_TX_FILTER_TEST_MODE_BIT_WIDTH 1 -+#define FRF_CZ_TX_ETH_FILTER_WILD_SEARCH_RANGE_LBN 105 -+#define FRF_CZ_TX_ETH_FILTER_WILD_SEARCH_RANGE_WIDTH 8 -+#define FRF_CZ_TX_ETH_FILTER_FULL_SEARCH_RANGE_LBN 97 -+#define FRF_CZ_TX_ETH_FILTER_FULL_SEARCH_RANGE_WIDTH 8 -+#define FRF_CZ_TX_UDPIP_FILTER_WILD_SEARCH_RANGE_LBN 89 -+#define FRF_CZ_TX_UDPIP_FILTER_WILD_SEARCH_RANGE_WIDTH 8 -+#define FRF_CZ_TX_UDPIP_FILTER_FULL_SEARCH_RANGE_LBN 81 -+#define FRF_CZ_TX_UDPIP_FILTER_FULL_SEARCH_RANGE_WIDTH 8 -+#define FRF_CZ_TX_TCPIP_FILTER_WILD_SEARCH_RANGE_LBN 73 -+#define FRF_CZ_TX_TCPIP_FILTER_WILD_SEARCH_RANGE_WIDTH 8 -+#define FRF_CZ_TX_TCPIP_FILTER_FULL_SEARCH_RANGE_LBN 65 -+#define FRF_CZ_TX_TCPIP_FILTER_FULL_SEARCH_RANGE_WIDTH 8 -+#define FRF_CZ_TX_FILTER_ALL_VLAN_ETHERTYPES_BIT_LBN 64 -+#define FRF_CZ_TX_FILTER_ALL_VLAN_ETHERTYPES_BIT_WIDTH 1 -+#define FRF_CZ_TX_VLAN_MATCH_ETHERTYPE_RANGE_LBN 48 -+#define FRF_CZ_TX_VLAN_MATCH_ETHERTYPE_RANGE_WIDTH 16 -+#define FRF_CZ_TX_FILTER_EN_BIT_LBN 47 -+#define FRF_CZ_TX_FILTER_EN_BIT_WIDTH 1 -+#define FRF_AZ_TX_IP_ID_P0_OFS_LBN 16 -+#define FRF_AZ_TX_IP_ID_P0_OFS_WIDTH 15 -+#define FRF_AZ_TX_NO_EOP_DISC_EN_LBN 5 -+#define FRF_AZ_TX_NO_EOP_DISC_EN_WIDTH 1 -+#define FRF_AZ_TX_P1_PRI_EN_LBN 4 -+#define FRF_AZ_TX_P1_PRI_EN_WIDTH 1 -+#define FRF_AZ_TX_OWNERR_CTL_LBN 2 -+#define FRF_AZ_TX_OWNERR_CTL_WIDTH 1 -+#define FRF_AA_TX_NON_IP_DROP_DIS_LBN 1 -+#define FRF_AA_TX_NON_IP_DROP_DIS_WIDTH 1 -+#define FRF_AZ_TX_IP_ID_REP_EN_LBN 0 -+#define FRF_AZ_TX_IP_ID_REP_EN_WIDTH 1 -+ -+/* TX_PUSH_DROP_REG: Transmit push dropped register */ -+#define FR_AZ_TX_PUSH_DROP 0x00000a60 -+#define FRF_AZ_TX_PUSH_DROP_CNT_LBN 0 -+#define FRF_AZ_TX_PUSH_DROP_CNT_WIDTH 32 -+ -+/* TX_RESERVED_REG: Transmit configuration register */ -+#define FR_AZ_TX_RESERVED 0x00000a80 -+#define FRF_AZ_TX_EVT_CNT_LBN 121 -+#define FRF_AZ_TX_EVT_CNT_WIDTH 7 -+#define FRF_AZ_TX_PREF_AGE_CNT_LBN 119 -+#define FRF_AZ_TX_PREF_AGE_CNT_WIDTH 2 -+#define FRF_AZ_TX_RD_COMP_TMR_LBN 96 -+#define FRF_AZ_TX_RD_COMP_TMR_WIDTH 23 -+#define FRF_AZ_TX_PUSH_EN_LBN 89 -+#define FRF_AZ_TX_PUSH_EN_WIDTH 1 -+#define FRF_AZ_TX_PUSH_CHK_DIS_LBN 88 -+#define FRF_AZ_TX_PUSH_CHK_DIS_WIDTH 1 -+#define FRF_AZ_TX_D_FF_FULL_P0_LBN 85 -+#define FRF_AZ_TX_D_FF_FULL_P0_WIDTH 1 -+#define FRF_AZ_TX_DMAR_ST_P0_LBN 81 -+#define FRF_AZ_TX_DMAR_ST_P0_WIDTH 1 -+#define FRF_AZ_TX_DMAQ_ST_LBN 78 -+#define FRF_AZ_TX_DMAQ_ST_WIDTH 1 -+#define FRF_AZ_TX_RX_SPACER_LBN 64 -+#define FRF_AZ_TX_RX_SPACER_WIDTH 8 -+#define FRF_AZ_TX_DROP_ABORT_EN_LBN 60 -+#define FRF_AZ_TX_DROP_ABORT_EN_WIDTH 1 -+#define FRF_AZ_TX_SOFT_EVT_EN_LBN 59 -+#define FRF_AZ_TX_SOFT_EVT_EN_WIDTH 1 -+#define FRF_AZ_TX_PS_EVT_DIS_LBN 58 -+#define FRF_AZ_TX_PS_EVT_DIS_WIDTH 1 -+#define FRF_AZ_TX_RX_SPACER_EN_LBN 57 -+#define FRF_AZ_TX_RX_SPACER_EN_WIDTH 1 -+#define FRF_AZ_TX_XP_TIMER_LBN 52 -+#define FRF_AZ_TX_XP_TIMER_WIDTH 5 -+#define FRF_AZ_TX_PREF_SPACER_LBN 44 -+#define FRF_AZ_TX_PREF_SPACER_WIDTH 8 -+#define FRF_AZ_TX_PREF_WD_TMR_LBN 22 -+#define FRF_AZ_TX_PREF_WD_TMR_WIDTH 22 -+#define FRF_AZ_TX_ONLY1TAG_LBN 21 -+#define FRF_AZ_TX_ONLY1TAG_WIDTH 1 -+#define FRF_AZ_TX_PREF_THRESHOLD_LBN 19 -+#define FRF_AZ_TX_PREF_THRESHOLD_WIDTH 2 -+#define FRF_AZ_TX_ONE_PKT_PER_Q_LBN 18 -+#define FRF_AZ_TX_ONE_PKT_PER_Q_WIDTH 1 -+#define FRF_AZ_TX_DIS_NON_IP_EV_LBN 17 -+#define FRF_AZ_TX_DIS_NON_IP_EV_WIDTH 1 -+#define FRF_AA_TX_DMA_FF_THR_LBN 16 -+#define FRF_AA_TX_DMA_FF_THR_WIDTH 1 -+#define FRF_AZ_TX_DMA_SPACER_LBN 8 -+#define FRF_AZ_TX_DMA_SPACER_WIDTH 8 -+#define FRF_AA_TX_TCP_DIS_LBN 7 -+#define FRF_AA_TX_TCP_DIS_WIDTH 1 -+#define FRF_BZ_TX_FLUSH_MIN_LEN_EN_LBN 7 -+#define FRF_BZ_TX_FLUSH_MIN_LEN_EN_WIDTH 1 -+#define FRF_AA_TX_IP_DIS_LBN 6 -+#define FRF_AA_TX_IP_DIS_WIDTH 1 -+#define FRF_AZ_TX_MAX_CPL_LBN 2 -+#define FRF_AZ_TX_MAX_CPL_WIDTH 2 -+#define FFE_AZ_TX_MAX_CPL_16 3 -+#define FFE_AZ_TX_MAX_CPL_8 2 -+#define FFE_AZ_TX_MAX_CPL_4 1 -+#define FFE_AZ_TX_MAX_CPL_NOLIMIT 0 -+#define FRF_AZ_TX_MAX_PREF_LBN 0 -+#define FRF_AZ_TX_MAX_PREF_WIDTH 2 -+#define FFE_AZ_TX_MAX_PREF_32 3 -+#define FFE_AZ_TX_MAX_PREF_16 2 -+#define FFE_AZ_TX_MAX_PREF_8 1 -+#define FFE_AZ_TX_MAX_PREF_OFF 0 -+ -+/* TX_PACE_REG: Transmit pace control register */ -+#define FR_BZ_TX_PACE 0x00000a90 -+#define FRF_BZ_TX_PACE_SB_NOT_AF_LBN 19 -+#define FRF_BZ_TX_PACE_SB_NOT_AF_WIDTH 10 -+#define FRF_BZ_TX_PACE_SB_AF_LBN 9 -+#define FRF_BZ_TX_PACE_SB_AF_WIDTH 10 -+#define FRF_BZ_TX_PACE_FB_BASE_LBN 5 -+#define FRF_BZ_TX_PACE_FB_BASE_WIDTH 4 -+#define FRF_BZ_TX_PACE_BIN_TH_LBN 0 -+#define FRF_BZ_TX_PACE_BIN_TH_WIDTH 5 -+ -+/* TX_PACE_DROP_QID_REG: PACE Drop QID Counter */ -+#define FR_BZ_TX_PACE_DROP_QID 0x00000aa0 -+#define FRF_BZ_TX_PACE_QID_DRP_CNT_LBN 0 -+#define FRF_BZ_TX_PACE_QID_DRP_CNT_WIDTH 16 -+ -+/* TX_VLAN_REG: Transmit VLAN tag register */ -+#define FR_BB_TX_VLAN 0x00000ae0 -+#define FRF_BB_TX_VLAN_EN_LBN 127 -+#define FRF_BB_TX_VLAN_EN_WIDTH 1 -+#define FRF_BB_TX_VLAN7_PORT1_EN_LBN 125 -+#define FRF_BB_TX_VLAN7_PORT1_EN_WIDTH 1 -+#define FRF_BB_TX_VLAN7_PORT0_EN_LBN 124 -+#define FRF_BB_TX_VLAN7_PORT0_EN_WIDTH 1 -+#define FRF_BB_TX_VLAN7_LBN 112 -+#define FRF_BB_TX_VLAN7_WIDTH 12 -+#define FRF_BB_TX_VLAN6_PORT1_EN_LBN 109 -+#define FRF_BB_TX_VLAN6_PORT1_EN_WIDTH 1 -+#define FRF_BB_TX_VLAN6_PORT0_EN_LBN 108 -+#define FRF_BB_TX_VLAN6_PORT0_EN_WIDTH 1 -+#define FRF_BB_TX_VLAN6_LBN 96 -+#define FRF_BB_TX_VLAN6_WIDTH 12 -+#define FRF_BB_TX_VLAN5_PORT1_EN_LBN 93 -+#define FRF_BB_TX_VLAN5_PORT1_EN_WIDTH 1 -+#define FRF_BB_TX_VLAN5_PORT0_EN_LBN 92 -+#define FRF_BB_TX_VLAN5_PORT0_EN_WIDTH 1 -+#define FRF_BB_TX_VLAN5_LBN 80 -+#define FRF_BB_TX_VLAN5_WIDTH 12 -+#define FRF_BB_TX_VLAN4_PORT1_EN_LBN 77 -+#define FRF_BB_TX_VLAN4_PORT1_EN_WIDTH 1 -+#define FRF_BB_TX_VLAN4_PORT0_EN_LBN 76 -+#define FRF_BB_TX_VLAN4_PORT0_EN_WIDTH 1 -+#define FRF_BB_TX_VLAN4_LBN 64 -+#define FRF_BB_TX_VLAN4_WIDTH 12 -+#define FRF_BB_TX_VLAN3_PORT1_EN_LBN 61 -+#define FRF_BB_TX_VLAN3_PORT1_EN_WIDTH 1 -+#define FRF_BB_TX_VLAN3_PORT0_EN_LBN 60 -+#define FRF_BB_TX_VLAN3_PORT0_EN_WIDTH 1 -+#define FRF_BB_TX_VLAN3_LBN 48 -+#define FRF_BB_TX_VLAN3_WIDTH 12 -+#define FRF_BB_TX_VLAN2_PORT1_EN_LBN 45 -+#define FRF_BB_TX_VLAN2_PORT1_EN_WIDTH 1 -+#define FRF_BB_TX_VLAN2_PORT0_EN_LBN 44 -+#define FRF_BB_TX_VLAN2_PORT0_EN_WIDTH 1 -+#define FRF_BB_TX_VLAN2_LBN 32 -+#define FRF_BB_TX_VLAN2_WIDTH 12 -+#define FRF_BB_TX_VLAN1_PORT1_EN_LBN 29 -+#define FRF_BB_TX_VLAN1_PORT1_EN_WIDTH 1 -+#define FRF_BB_TX_VLAN1_PORT0_EN_LBN 28 -+#define FRF_BB_TX_VLAN1_PORT0_EN_WIDTH 1 -+#define FRF_BB_TX_VLAN1_LBN 16 -+#define FRF_BB_TX_VLAN1_WIDTH 12 -+#define FRF_BB_TX_VLAN0_PORT1_EN_LBN 13 -+#define FRF_BB_TX_VLAN0_PORT1_EN_WIDTH 1 -+#define FRF_BB_TX_VLAN0_PORT0_EN_LBN 12 -+#define FRF_BB_TX_VLAN0_PORT0_EN_WIDTH 1 -+#define FRF_BB_TX_VLAN0_LBN 0 -+#define FRF_BB_TX_VLAN0_WIDTH 12 -+ -+/* TX_IPFIL_PORTEN_REG: Transmit filter control register */ -+#define FR_BZ_TX_IPFIL_PORTEN 0x00000af0 -+#define FRF_BZ_TX_MADR0_FIL_EN_LBN 64 -+#define FRF_BZ_TX_MADR0_FIL_EN_WIDTH 1 -+#define FRF_BB_TX_IPFIL31_PORT_EN_LBN 62 -+#define FRF_BB_TX_IPFIL31_PORT_EN_WIDTH 1 -+#define FRF_BB_TX_IPFIL30_PORT_EN_LBN 60 -+#define FRF_BB_TX_IPFIL30_PORT_EN_WIDTH 1 -+#define FRF_BB_TX_IPFIL29_PORT_EN_LBN 58 -+#define FRF_BB_TX_IPFIL29_PORT_EN_WIDTH 1 -+#define FRF_BB_TX_IPFIL28_PORT_EN_LBN 56 -+#define FRF_BB_TX_IPFIL28_PORT_EN_WIDTH 1 -+#define FRF_BB_TX_IPFIL27_PORT_EN_LBN 54 -+#define FRF_BB_TX_IPFIL27_PORT_EN_WIDTH 1 -+#define FRF_BB_TX_IPFIL26_PORT_EN_LBN 52 -+#define FRF_BB_TX_IPFIL26_PORT_EN_WIDTH 1 -+#define FRF_BB_TX_IPFIL25_PORT_EN_LBN 50 -+#define FRF_BB_TX_IPFIL25_PORT_EN_WIDTH 1 -+#define FRF_BB_TX_IPFIL24_PORT_EN_LBN 48 -+#define FRF_BB_TX_IPFIL24_PORT_EN_WIDTH 1 -+#define FRF_BB_TX_IPFIL23_PORT_EN_LBN 46 -+#define FRF_BB_TX_IPFIL23_PORT_EN_WIDTH 1 -+#define FRF_BB_TX_IPFIL22_PORT_EN_LBN 44 -+#define FRF_BB_TX_IPFIL22_PORT_EN_WIDTH 1 -+#define FRF_BB_TX_IPFIL21_PORT_EN_LBN 42 -+#define FRF_BB_TX_IPFIL21_PORT_EN_WIDTH 1 -+#define FRF_BB_TX_IPFIL20_PORT_EN_LBN 40 -+#define FRF_BB_TX_IPFIL20_PORT_EN_WIDTH 1 -+#define FRF_BB_TX_IPFIL19_PORT_EN_LBN 38 -+#define FRF_BB_TX_IPFIL19_PORT_EN_WIDTH 1 -+#define FRF_BB_TX_IPFIL18_PORT_EN_LBN 36 -+#define FRF_BB_TX_IPFIL18_PORT_EN_WIDTH 1 -+#define FRF_BB_TX_IPFIL17_PORT_EN_LBN 34 -+#define FRF_BB_TX_IPFIL17_PORT_EN_WIDTH 1 -+#define FRF_BB_TX_IPFIL16_PORT_EN_LBN 32 -+#define FRF_BB_TX_IPFIL16_PORT_EN_WIDTH 1 -+#define FRF_BB_TX_IPFIL15_PORT_EN_LBN 30 -+#define FRF_BB_TX_IPFIL15_PORT_EN_WIDTH 1 -+#define FRF_BB_TX_IPFIL14_PORT_EN_LBN 28 -+#define FRF_BB_TX_IPFIL14_PORT_EN_WIDTH 1 -+#define FRF_BB_TX_IPFIL13_PORT_EN_LBN 26 -+#define FRF_BB_TX_IPFIL13_PORT_EN_WIDTH 1 -+#define FRF_BB_TX_IPFIL12_PORT_EN_LBN 24 -+#define FRF_BB_TX_IPFIL12_PORT_EN_WIDTH 1 -+#define FRF_BB_TX_IPFIL11_PORT_EN_LBN 22 -+#define FRF_BB_TX_IPFIL11_PORT_EN_WIDTH 1 -+#define FRF_BB_TX_IPFIL10_PORT_EN_LBN 20 -+#define FRF_BB_TX_IPFIL10_PORT_EN_WIDTH 1 -+#define FRF_BB_TX_IPFIL9_PORT_EN_LBN 18 -+#define FRF_BB_TX_IPFIL9_PORT_EN_WIDTH 1 -+#define FRF_BB_TX_IPFIL8_PORT_EN_LBN 16 -+#define FRF_BB_TX_IPFIL8_PORT_EN_WIDTH 1 -+#define FRF_BB_TX_IPFIL7_PORT_EN_LBN 14 -+#define FRF_BB_TX_IPFIL7_PORT_EN_WIDTH 1 -+#define FRF_BB_TX_IPFIL6_PORT_EN_LBN 12 -+#define FRF_BB_TX_IPFIL6_PORT_EN_WIDTH 1 -+#define FRF_BB_TX_IPFIL5_PORT_EN_LBN 10 -+#define FRF_BB_TX_IPFIL5_PORT_EN_WIDTH 1 -+#define FRF_BB_TX_IPFIL4_PORT_EN_LBN 8 -+#define FRF_BB_TX_IPFIL4_PORT_EN_WIDTH 1 -+#define FRF_BB_TX_IPFIL3_PORT_EN_LBN 6 -+#define FRF_BB_TX_IPFIL3_PORT_EN_WIDTH 1 -+#define FRF_BB_TX_IPFIL2_PORT_EN_LBN 4 -+#define FRF_BB_TX_IPFIL2_PORT_EN_WIDTH 1 -+#define FRF_BB_TX_IPFIL1_PORT_EN_LBN 2 -+#define FRF_BB_TX_IPFIL1_PORT_EN_WIDTH 1 -+#define FRF_BB_TX_IPFIL0_PORT_EN_LBN 0 -+#define FRF_BB_TX_IPFIL0_PORT_EN_WIDTH 1 -+ -+/* TX_IPFIL_TBL: Transmit IP source address filter table */ -+#define FR_BB_TX_IPFIL_TBL 0x00000b00 -+#define FR_BB_TX_IPFIL_TBL_STEP 16 -+#define FR_BB_TX_IPFIL_TBL_ROWS 16 -+#define FRF_BB_TX_IPFIL_MASK_1_LBN 96 -+#define FRF_BB_TX_IPFIL_MASK_1_WIDTH 32 -+#define FRF_BB_TX_IP_SRC_ADR_1_LBN 64 -+#define FRF_BB_TX_IP_SRC_ADR_1_WIDTH 32 -+#define FRF_BB_TX_IPFIL_MASK_0_LBN 32 -+#define FRF_BB_TX_IPFIL_MASK_0_WIDTH 32 -+#define FRF_BB_TX_IP_SRC_ADR_0_LBN 0 -+#define FRF_BB_TX_IP_SRC_ADR_0_WIDTH 32 -+ -+/* MD_TXD_REG: PHY management transmit data register */ -+#define FR_AB_MD_TXD 0x00000c00 -+#define FRF_AB_MD_TXD_LBN 0 -+#define FRF_AB_MD_TXD_WIDTH 16 -+ -+/* MD_RXD_REG: PHY management receive data register */ -+#define FR_AB_MD_RXD 0x00000c10 -+#define FRF_AB_MD_RXD_LBN 0 -+#define FRF_AB_MD_RXD_WIDTH 16 -+ -+/* MD_CS_REG: PHY management configuration & status register */ -+#define FR_AB_MD_CS 0x00000c20 -+#define FRF_AB_MD_RD_EN_CMD_LBN 15 -+#define FRF_AB_MD_RD_EN_CMD_WIDTH 1 -+#define FRF_AB_MD_WR_EN_CMD_LBN 14 -+#define FRF_AB_MD_WR_EN_CMD_WIDTH 1 -+#define FRF_AB_MD_ADDR_CMD_LBN 13 -+#define FRF_AB_MD_ADDR_CMD_WIDTH 1 -+#define FRF_AB_MD_PT_LBN 7 -+#define FRF_AB_MD_PT_WIDTH 3 -+#define FRF_AB_MD_PL_LBN 6 -+#define FRF_AB_MD_PL_WIDTH 1 -+#define FRF_AB_MD_INT_CLR_LBN 5 -+#define FRF_AB_MD_INT_CLR_WIDTH 1 -+#define FRF_AB_MD_GC_LBN 4 -+#define FRF_AB_MD_GC_WIDTH 1 -+#define FRF_AB_MD_PRSP_LBN 3 -+#define FRF_AB_MD_PRSP_WIDTH 1 -+#define FRF_AB_MD_RIC_LBN 2 -+#define FRF_AB_MD_RIC_WIDTH 1 -+#define FRF_AB_MD_RDC_LBN 1 -+#define FRF_AB_MD_RDC_WIDTH 1 -+#define FRF_AB_MD_WRC_LBN 0 -+#define FRF_AB_MD_WRC_WIDTH 1 -+ -+/* MD_PHY_ADR_REG: PHY management PHY address register */ -+#define FR_AB_MD_PHY_ADR 0x00000c30 -+#define FRF_AB_MD_PHY_ADR_LBN 0 -+#define FRF_AB_MD_PHY_ADR_WIDTH 16 -+ -+/* MD_ID_REG: PHY management ID register */ -+#define FR_AB_MD_ID 0x00000c40 -+#define FRF_AB_MD_PRT_ADR_LBN 11 -+#define FRF_AB_MD_PRT_ADR_WIDTH 5 -+#define FRF_AB_MD_DEV_ADR_LBN 6 -+#define FRF_AB_MD_DEV_ADR_WIDTH 5 -+ -+/* MD_STAT_REG: PHY management status & mask register */ -+#define FR_AB_MD_STAT 0x00000c50 -+#define FRF_AB_MD_PINT_LBN 4 -+#define FRF_AB_MD_PINT_WIDTH 1 -+#define FRF_AB_MD_DONE_LBN 3 -+#define FRF_AB_MD_DONE_WIDTH 1 -+#define FRF_AB_MD_BSERR_LBN 2 -+#define FRF_AB_MD_BSERR_WIDTH 1 -+#define FRF_AB_MD_LNFL_LBN 1 -+#define FRF_AB_MD_LNFL_WIDTH 1 -+#define FRF_AB_MD_BSY_LBN 0 -+#define FRF_AB_MD_BSY_WIDTH 1 -+ -+/* MAC_STAT_DMA_REG: Port MAC statistical counter DMA register */ -+#define FR_AB_MAC_STAT_DMA 0x00000c60 -+#define FRF_AB_MAC_STAT_DMA_CMD_LBN 48 -+#define FRF_AB_MAC_STAT_DMA_CMD_WIDTH 1 -+#define FRF_AB_MAC_STAT_DMA_ADR_LBN 0 -+#define FRF_AB_MAC_STAT_DMA_ADR_WIDTH 48 -+ -+/* MAC_CTRL_REG: Port MAC control register */ -+#define FR_AB_MAC_CTRL 0x00000c80 -+#define FRF_AB_MAC_XOFF_VAL_LBN 16 -+#define FRF_AB_MAC_XOFF_VAL_WIDTH 16 -+#define FRF_BB_TXFIFO_DRAIN_EN_LBN 7 -+#define FRF_BB_TXFIFO_DRAIN_EN_WIDTH 1 -+#define FRF_AB_MAC_XG_DISTXCRC_LBN 5 -+#define FRF_AB_MAC_XG_DISTXCRC_WIDTH 1 -+#define FRF_AB_MAC_BCAD_ACPT_LBN 4 -+#define FRF_AB_MAC_BCAD_ACPT_WIDTH 1 -+#define FRF_AB_MAC_UC_PROM_LBN 3 -+#define FRF_AB_MAC_UC_PROM_WIDTH 1 -+#define FRF_AB_MAC_LINK_STATUS_LBN 2 -+#define FRF_AB_MAC_LINK_STATUS_WIDTH 1 -+#define FRF_AB_MAC_SPEED_LBN 0 -+#define FRF_AB_MAC_SPEED_WIDTH 2 -+#define FFE_AB_MAC_SPEED_10G 3 -+#define FFE_AB_MAC_SPEED_1G 2 -+#define FFE_AB_MAC_SPEED_100M 1 -+#define FFE_AB_MAC_SPEED_10M 0 -+ -+/* GEN_MODE_REG: General Purpose mode register (external interrupt mask) */ -+#define FR_BB_GEN_MODE 0x00000c90 -+#define FRF_BB_XFP_PHY_INT_POL_SEL_LBN 3 -+#define FRF_BB_XFP_PHY_INT_POL_SEL_WIDTH 1 -+#define FRF_BB_XG_PHY_INT_POL_SEL_LBN 2 -+#define FRF_BB_XG_PHY_INT_POL_SEL_WIDTH 1 -+#define FRF_BB_XFP_PHY_INT_MASK_LBN 1 -+#define FRF_BB_XFP_PHY_INT_MASK_WIDTH 1 -+#define FRF_BB_XG_PHY_INT_MASK_LBN 0 -+#define FRF_BB_XG_PHY_INT_MASK_WIDTH 1 -+ -+/* MAC_MC_HASH_REG0: Multicast address hash table */ -+#define FR_AB_MAC_MC_HASH_REG0 0x00000ca0 -+#define FRF_AB_MAC_MCAST_HASH0_LBN 0 -+#define FRF_AB_MAC_MCAST_HASH0_WIDTH 128 -+ -+/* MAC_MC_HASH_REG1: Multicast address hash table */ -+#define FR_AB_MAC_MC_HASH_REG1 0x00000cb0 -+#define FRF_AB_MAC_MCAST_HASH1_LBN 0 -+#define FRF_AB_MAC_MCAST_HASH1_WIDTH 128 -+ -+/* GM_CFG1_REG: GMAC configuration register 1 */ -+#define FR_AB_GM_CFG1 0x00000e00 -+#define FRF_AB_GM_SW_RST_LBN 31 -+#define FRF_AB_GM_SW_RST_WIDTH 1 -+#define FRF_AB_GM_SIM_RST_LBN 30 -+#define FRF_AB_GM_SIM_RST_WIDTH 1 -+#define FRF_AB_GM_RST_RX_MAC_CTL_LBN 19 -+#define FRF_AB_GM_RST_RX_MAC_CTL_WIDTH 1 -+#define FRF_AB_GM_RST_TX_MAC_CTL_LBN 18 -+#define FRF_AB_GM_RST_TX_MAC_CTL_WIDTH 1 -+#define FRF_AB_GM_RST_RX_FUNC_LBN 17 -+#define FRF_AB_GM_RST_RX_FUNC_WIDTH 1 -+#define FRF_AB_GM_RST_TX_FUNC_LBN 16 -+#define FRF_AB_GM_RST_TX_FUNC_WIDTH 1 -+#define FRF_AB_GM_LOOP_LBN 8 -+#define FRF_AB_GM_LOOP_WIDTH 1 -+#define FRF_AB_GM_RX_FC_EN_LBN 5 -+#define FRF_AB_GM_RX_FC_EN_WIDTH 1 -+#define FRF_AB_GM_TX_FC_EN_LBN 4 -+#define FRF_AB_GM_TX_FC_EN_WIDTH 1 -+#define FRF_AB_GM_SYNC_RXEN_LBN 3 -+#define FRF_AB_GM_SYNC_RXEN_WIDTH 1 -+#define FRF_AB_GM_RX_EN_LBN 2 -+#define FRF_AB_GM_RX_EN_WIDTH 1 -+#define FRF_AB_GM_SYNC_TXEN_LBN 1 -+#define FRF_AB_GM_SYNC_TXEN_WIDTH 1 -+#define FRF_AB_GM_TX_EN_LBN 0 -+#define FRF_AB_GM_TX_EN_WIDTH 1 -+ -+/* GM_CFG2_REG: GMAC configuration register 2 */ -+#define FR_AB_GM_CFG2 0x00000e10 -+#define FRF_AB_GM_PAMBL_LEN_LBN 12 -+#define FRF_AB_GM_PAMBL_LEN_WIDTH 4 -+#define FRF_AB_GM_IF_MODE_LBN 8 -+#define FRF_AB_GM_IF_MODE_WIDTH 2 -+#define FFE_AB_IF_MODE_BYTE_MODE 2 -+#define FFE_AB_IF_MODE_NIBBLE_MODE 1 -+#define FRF_AB_GM_HUGE_FRM_EN_LBN 5 -+#define FRF_AB_GM_HUGE_FRM_EN_WIDTH 1 -+#define FRF_AB_GM_LEN_CHK_LBN 4 -+#define FRF_AB_GM_LEN_CHK_WIDTH 1 -+#define FRF_AB_GM_PAD_CRC_EN_LBN 2 -+#define FRF_AB_GM_PAD_CRC_EN_WIDTH 1 -+#define FRF_AB_GM_CRC_EN_LBN 1 -+#define FRF_AB_GM_CRC_EN_WIDTH 1 -+#define FRF_AB_GM_FD_LBN 0 -+#define FRF_AB_GM_FD_WIDTH 1 -+ -+/* GM_IPG_REG: GMAC IPG register */ -+#define FR_AB_GM_IPG 0x00000e20 -+#define FRF_AB_GM_NONB2B_IPG1_LBN 24 -+#define FRF_AB_GM_NONB2B_IPG1_WIDTH 7 -+#define FRF_AB_GM_NONB2B_IPG2_LBN 16 -+#define FRF_AB_GM_NONB2B_IPG2_WIDTH 7 -+#define FRF_AB_GM_MIN_IPG_ENF_LBN 8 -+#define FRF_AB_GM_MIN_IPG_ENF_WIDTH 8 -+#define FRF_AB_GM_B2B_IPG_LBN 0 -+#define FRF_AB_GM_B2B_IPG_WIDTH 7 -+ -+/* GM_HD_REG: GMAC half duplex register */ -+#define FR_AB_GM_HD 0x00000e30 -+#define FRF_AB_GM_ALT_BOFF_VAL_LBN 20 -+#define FRF_AB_GM_ALT_BOFF_VAL_WIDTH 4 -+#define FRF_AB_GM_ALT_BOFF_EN_LBN 19 -+#define FRF_AB_GM_ALT_BOFF_EN_WIDTH 1 -+#define FRF_AB_GM_BP_NO_BOFF_LBN 18 -+#define FRF_AB_GM_BP_NO_BOFF_WIDTH 1 -+#define FRF_AB_GM_DIS_BOFF_LBN 17 -+#define FRF_AB_GM_DIS_BOFF_WIDTH 1 -+#define FRF_AB_GM_EXDEF_TX_EN_LBN 16 -+#define FRF_AB_GM_EXDEF_TX_EN_WIDTH 1 -+#define FRF_AB_GM_RTRY_LIMIT_LBN 12 -+#define FRF_AB_GM_RTRY_LIMIT_WIDTH 4 -+#define FRF_AB_GM_COL_WIN_LBN 0 -+#define FRF_AB_GM_COL_WIN_WIDTH 10 -+ -+/* GM_MAX_FLEN_REG: GMAC maximum frame length register */ -+#define FR_AB_GM_MAX_FLEN 0x00000e40 -+#define FRF_AB_GM_MAX_FLEN_LBN 0 -+#define FRF_AB_GM_MAX_FLEN_WIDTH 16 -+ -+/* GM_TEST_REG: GMAC test register */ -+#define FR_AB_GM_TEST 0x00000e70 -+#define FRF_AB_GM_MAX_BOFF_LBN 3 -+#define FRF_AB_GM_MAX_BOFF_WIDTH 1 -+#define FRF_AB_GM_REG_TX_FLOW_EN_LBN 2 -+#define FRF_AB_GM_REG_TX_FLOW_EN_WIDTH 1 -+#define FRF_AB_GM_TEST_PAUSE_LBN 1 -+#define FRF_AB_GM_TEST_PAUSE_WIDTH 1 -+#define FRF_AB_GM_SHORT_SLOT_LBN 0 -+#define FRF_AB_GM_SHORT_SLOT_WIDTH 1 -+ -+/* GM_ADR1_REG: GMAC station address register 1 */ -+#define FR_AB_GM_ADR1 0x00000f00 -+#define FRF_AB_GM_ADR_B0_LBN 24 -+#define FRF_AB_GM_ADR_B0_WIDTH 8 -+#define FRF_AB_GM_ADR_B1_LBN 16 -+#define FRF_AB_GM_ADR_B1_WIDTH 8 -+#define FRF_AB_GM_ADR_B2_LBN 8 -+#define FRF_AB_GM_ADR_B2_WIDTH 8 -+#define FRF_AB_GM_ADR_B3_LBN 0 -+#define FRF_AB_GM_ADR_B3_WIDTH 8 -+ -+/* GM_ADR2_REG: GMAC station address register 2 */ -+#define FR_AB_GM_ADR2 0x00000f10 -+#define FRF_AB_GM_ADR_B4_LBN 24 -+#define FRF_AB_GM_ADR_B4_WIDTH 8 -+#define FRF_AB_GM_ADR_B5_LBN 16 -+#define FRF_AB_GM_ADR_B5_WIDTH 8 -+ -+/* GMF_CFG0_REG: GMAC FIFO configuration register 0 */ -+#define FR_AB_GMF_CFG0 0x00000f20 -+#define FRF_AB_GMF_FTFENRPLY_LBN 20 -+#define FRF_AB_GMF_FTFENRPLY_WIDTH 1 -+#define FRF_AB_GMF_STFENRPLY_LBN 19 -+#define FRF_AB_GMF_STFENRPLY_WIDTH 1 -+#define FRF_AB_GMF_FRFENRPLY_LBN 18 -+#define FRF_AB_GMF_FRFENRPLY_WIDTH 1 -+#define FRF_AB_GMF_SRFENRPLY_LBN 17 -+#define FRF_AB_GMF_SRFENRPLY_WIDTH 1 -+#define FRF_AB_GMF_WTMENRPLY_LBN 16 -+#define FRF_AB_GMF_WTMENRPLY_WIDTH 1 -+#define FRF_AB_GMF_FTFENREQ_LBN 12 -+#define FRF_AB_GMF_FTFENREQ_WIDTH 1 -+#define FRF_AB_GMF_STFENREQ_LBN 11 -+#define FRF_AB_GMF_STFENREQ_WIDTH 1 -+#define FRF_AB_GMF_FRFENREQ_LBN 10 -+#define FRF_AB_GMF_FRFENREQ_WIDTH 1 -+#define FRF_AB_GMF_SRFENREQ_LBN 9 -+#define FRF_AB_GMF_SRFENREQ_WIDTH 1 -+#define FRF_AB_GMF_WTMENREQ_LBN 8 -+#define FRF_AB_GMF_WTMENREQ_WIDTH 1 -+#define FRF_AB_GMF_HSTRSTFT_LBN 4 -+#define FRF_AB_GMF_HSTRSTFT_WIDTH 1 -+#define FRF_AB_GMF_HSTRSTST_LBN 3 -+#define FRF_AB_GMF_HSTRSTST_WIDTH 1 -+#define FRF_AB_GMF_HSTRSTFR_LBN 2 -+#define FRF_AB_GMF_HSTRSTFR_WIDTH 1 -+#define FRF_AB_GMF_HSTRSTSR_LBN 1 -+#define FRF_AB_GMF_HSTRSTSR_WIDTH 1 -+#define FRF_AB_GMF_HSTRSTWT_LBN 0 -+#define FRF_AB_GMF_HSTRSTWT_WIDTH 1 -+ -+/* GMF_CFG1_REG: GMAC FIFO configuration register 1 */ -+#define FR_AB_GMF_CFG1 0x00000f30 -+#define FRF_AB_GMF_CFGFRTH_LBN 16 -+#define FRF_AB_GMF_CFGFRTH_WIDTH 5 -+#define FRF_AB_GMF_CFGXOFFRTX_LBN 0 -+#define FRF_AB_GMF_CFGXOFFRTX_WIDTH 16 -+ -+/* GMF_CFG2_REG: GMAC FIFO configuration register 2 */ -+#define FR_AB_GMF_CFG2 0x00000f40 -+#define FRF_AB_GMF_CFGHWM_LBN 16 -+#define FRF_AB_GMF_CFGHWM_WIDTH 6 -+#define FRF_AB_GMF_CFGLWM_LBN 0 -+#define FRF_AB_GMF_CFGLWM_WIDTH 6 -+ -+/* GMF_CFG3_REG: GMAC FIFO configuration register 3 */ -+#define FR_AB_GMF_CFG3 0x00000f50 -+#define FRF_AB_GMF_CFGHWMFT_LBN 16 -+#define FRF_AB_GMF_CFGHWMFT_WIDTH 6 -+#define FRF_AB_GMF_CFGFTTH_LBN 0 -+#define FRF_AB_GMF_CFGFTTH_WIDTH 6 -+ -+/* GMF_CFG4_REG: GMAC FIFO configuration register 4 */ -+#define FR_AB_GMF_CFG4 0x00000f60 -+#define FRF_AB_GMF_HSTFLTRFRM_LBN 0 -+#define FRF_AB_GMF_HSTFLTRFRM_WIDTH 18 -+ -+/* GMF_CFG5_REG: GMAC FIFO configuration register 5 */ -+#define FR_AB_GMF_CFG5 0x00000f70 -+#define FRF_AB_GMF_CFGHDPLX_LBN 22 -+#define FRF_AB_GMF_CFGHDPLX_WIDTH 1 -+#define FRF_AB_GMF_SRFULL_LBN 21 -+#define FRF_AB_GMF_SRFULL_WIDTH 1 -+#define FRF_AB_GMF_HSTSRFULLCLR_LBN 20 -+#define FRF_AB_GMF_HSTSRFULLCLR_WIDTH 1 -+#define FRF_AB_GMF_CFGBYTMODE_LBN 19 -+#define FRF_AB_GMF_CFGBYTMODE_WIDTH 1 -+#define FRF_AB_GMF_HSTDRPLT64_LBN 18 -+#define FRF_AB_GMF_HSTDRPLT64_WIDTH 1 -+#define FRF_AB_GMF_HSTFLTRFRMDC_LBN 0 -+#define FRF_AB_GMF_HSTFLTRFRMDC_WIDTH 18 -+ -+/* TX_SRC_MAC_TBL: Transmit IP source address filter table */ -+#define FR_BB_TX_SRC_MAC_TBL 0x00001000 -+#define FR_BB_TX_SRC_MAC_TBL_STEP 16 -+#define FR_BB_TX_SRC_MAC_TBL_ROWS 16 -+#define FRF_BB_TX_SRC_MAC_ADR_1_LBN 64 -+#define FRF_BB_TX_SRC_MAC_ADR_1_WIDTH 48 -+#define FRF_BB_TX_SRC_MAC_ADR_0_LBN 0 -+#define FRF_BB_TX_SRC_MAC_ADR_0_WIDTH 48 -+ -+/* TX_SRC_MAC_CTL_REG: Transmit MAC source address filter control */ -+#define FR_BB_TX_SRC_MAC_CTL 0x00001100 -+#define FRF_BB_TX_SRC_DROP_CTR_LBN 16 -+#define FRF_BB_TX_SRC_DROP_CTR_WIDTH 16 -+#define FRF_BB_TX_SRC_FLTR_EN_LBN 15 -+#define FRF_BB_TX_SRC_FLTR_EN_WIDTH 1 -+#define FRF_BB_TX_DROP_CTR_CLR_LBN 12 -+#define FRF_BB_TX_DROP_CTR_CLR_WIDTH 1 -+#define FRF_BB_TX_MAC_QID_SEL_LBN 0 -+#define FRF_BB_TX_MAC_QID_SEL_WIDTH 3 -+ -+/* XM_ADR_LO_REG: XGMAC address register low */ -+#define FR_AB_XM_ADR_LO 0x00001200 -+#define FRF_AB_XM_ADR_LO_LBN 0 -+#define FRF_AB_XM_ADR_LO_WIDTH 32 -+ -+/* XM_ADR_HI_REG: XGMAC address register high */ -+#define FR_AB_XM_ADR_HI 0x00001210 -+#define FRF_AB_XM_ADR_HI_LBN 0 -+#define FRF_AB_XM_ADR_HI_WIDTH 16 -+ -+/* XM_GLB_CFG_REG: XGMAC global configuration */ -+#define FR_AB_XM_GLB_CFG 0x00001220 -+#define FRF_AB_XM_RMTFLT_GEN_LBN 17 -+#define FRF_AB_XM_RMTFLT_GEN_WIDTH 1 -+#define FRF_AB_XM_DEBUG_MODE_LBN 16 -+#define FRF_AB_XM_DEBUG_MODE_WIDTH 1 -+#define FRF_AB_XM_RX_STAT_EN_LBN 11 -+#define FRF_AB_XM_RX_STAT_EN_WIDTH 1 -+#define FRF_AB_XM_TX_STAT_EN_LBN 10 -+#define FRF_AB_XM_TX_STAT_EN_WIDTH 1 -+#define FRF_AB_XM_RX_JUMBO_MODE_LBN 6 -+#define FRF_AB_XM_RX_JUMBO_MODE_WIDTH 1 -+#define FRF_AB_XM_WAN_MODE_LBN 5 -+#define FRF_AB_XM_WAN_MODE_WIDTH 1 -+#define FRF_AB_XM_INTCLR_MODE_LBN 3 -+#define FRF_AB_XM_INTCLR_MODE_WIDTH 1 -+#define FRF_AB_XM_CORE_RST_LBN 0 -+#define FRF_AB_XM_CORE_RST_WIDTH 1 -+ -+/* XM_TX_CFG_REG: XGMAC transmit configuration */ -+#define FR_AB_XM_TX_CFG 0x00001230 -+#define FRF_AB_XM_TX_PROG_LBN 24 -+#define FRF_AB_XM_TX_PROG_WIDTH 1 -+#define FRF_AB_XM_IPG_LBN 16 -+#define FRF_AB_XM_IPG_WIDTH 4 -+#define FRF_AB_XM_FCNTL_LBN 10 -+#define FRF_AB_XM_FCNTL_WIDTH 1 -+#define FRF_AB_XM_TXCRC_LBN 8 -+#define FRF_AB_XM_TXCRC_WIDTH 1 -+#define FRF_AB_XM_EDRC_LBN 6 -+#define FRF_AB_XM_EDRC_WIDTH 1 -+#define FRF_AB_XM_AUTO_PAD_LBN 5 -+#define FRF_AB_XM_AUTO_PAD_WIDTH 1 -+#define FRF_AB_XM_TX_PRMBL_LBN 2 -+#define FRF_AB_XM_TX_PRMBL_WIDTH 1 -+#define FRF_AB_XM_TXEN_LBN 1 -+#define FRF_AB_XM_TXEN_WIDTH 1 -+#define FRF_AB_XM_TX_RST_LBN 0 -+#define FRF_AB_XM_TX_RST_WIDTH 1 -+ -+/* XM_RX_CFG_REG: XGMAC receive configuration */ -+#define FR_AB_XM_RX_CFG 0x00001240 -+#define FRF_AB_XM_PASS_LENERR_LBN 26 -+#define FRF_AB_XM_PASS_LENERR_WIDTH 1 -+#define FRF_AB_XM_PASS_CRC_ERR_LBN 25 -+#define FRF_AB_XM_PASS_CRC_ERR_WIDTH 1 -+#define FRF_AB_XM_PASS_PRMBLE_ERR_LBN 24 -+#define FRF_AB_XM_PASS_PRMBLE_ERR_WIDTH 1 -+#define FRF_AB_XM_REJ_BCAST_LBN 20 -+#define FRF_AB_XM_REJ_BCAST_WIDTH 1 -+#define FRF_AB_XM_ACPT_ALL_MCAST_LBN 11 -+#define FRF_AB_XM_ACPT_ALL_MCAST_WIDTH 1 -+#define FRF_AB_XM_ACPT_ALL_UCAST_LBN 9 -+#define FRF_AB_XM_ACPT_ALL_UCAST_WIDTH 1 -+#define FRF_AB_XM_AUTO_DEPAD_LBN 8 -+#define FRF_AB_XM_AUTO_DEPAD_WIDTH 1 -+#define FRF_AB_XM_RXCRC_LBN 3 -+#define FRF_AB_XM_RXCRC_WIDTH 1 -+#define FRF_AB_XM_RX_PRMBL_LBN 2 -+#define FRF_AB_XM_RX_PRMBL_WIDTH 1 -+#define FRF_AB_XM_RXEN_LBN 1 -+#define FRF_AB_XM_RXEN_WIDTH 1 -+#define FRF_AB_XM_RX_RST_LBN 0 -+#define FRF_AB_XM_RX_RST_WIDTH 1 -+ -+/* XM_MGT_INT_MASK: documentation to be written for sum_XM_MGT_INT_MASK */ -+#define FR_AB_XM_MGT_INT_MASK 0x00001250 -+#define FRF_AB_XM_MSK_STA_INTR_LBN 16 -+#define FRF_AB_XM_MSK_STA_INTR_WIDTH 1 -+#define FRF_AB_XM_MSK_STAT_CNTR_HF_LBN 9 -+#define FRF_AB_XM_MSK_STAT_CNTR_HF_WIDTH 1 -+#define FRF_AB_XM_MSK_STAT_CNTR_OF_LBN 8 -+#define FRF_AB_XM_MSK_STAT_CNTR_OF_WIDTH 1 -+#define FRF_AB_XM_MSK_PRMBLE_ERR_LBN 2 -+#define FRF_AB_XM_MSK_PRMBLE_ERR_WIDTH 1 -+#define FRF_AB_XM_MSK_RMTFLT_LBN 1 -+#define FRF_AB_XM_MSK_RMTFLT_WIDTH 1 -+#define FRF_AB_XM_MSK_LCLFLT_LBN 0 -+#define FRF_AB_XM_MSK_LCLFLT_WIDTH 1 -+ -+/* XM_FC_REG: XGMAC flow control register */ -+#define FR_AB_XM_FC 0x00001270 -+#define FRF_AB_XM_PAUSE_TIME_LBN 16 -+#define FRF_AB_XM_PAUSE_TIME_WIDTH 16 -+#define FRF_AB_XM_RX_MAC_STAT_LBN 11 -+#define FRF_AB_XM_RX_MAC_STAT_WIDTH 1 -+#define FRF_AB_XM_TX_MAC_STAT_LBN 10 -+#define FRF_AB_XM_TX_MAC_STAT_WIDTH 1 -+#define FRF_AB_XM_MCNTL_PASS_LBN 8 -+#define FRF_AB_XM_MCNTL_PASS_WIDTH 2 -+#define FRF_AB_XM_REJ_CNTL_UCAST_LBN 6 -+#define FRF_AB_XM_REJ_CNTL_UCAST_WIDTH 1 -+#define FRF_AB_XM_REJ_CNTL_MCAST_LBN 5 -+#define FRF_AB_XM_REJ_CNTL_MCAST_WIDTH 1 -+#define FRF_AB_XM_ZPAUSE_LBN 2 -+#define FRF_AB_XM_ZPAUSE_WIDTH 1 -+#define FRF_AB_XM_XMIT_PAUSE_LBN 1 -+#define FRF_AB_XM_XMIT_PAUSE_WIDTH 1 -+#define FRF_AB_XM_DIS_FCNTL_LBN 0 -+#define FRF_AB_XM_DIS_FCNTL_WIDTH 1 -+ -+/* XM_PAUSE_TIME_REG: XGMAC pause time register */ -+#define FR_AB_XM_PAUSE_TIME 0x00001290 -+#define FRF_AB_XM_TX_PAUSE_CNT_LBN 16 -+#define FRF_AB_XM_TX_PAUSE_CNT_WIDTH 16 -+#define FRF_AB_XM_RX_PAUSE_CNT_LBN 0 -+#define FRF_AB_XM_RX_PAUSE_CNT_WIDTH 16 -+ -+/* XM_TX_PARAM_REG: XGMAC transmit parameter register */ -+#define FR_AB_XM_TX_PARAM 0x000012d0 -+#define FRF_AB_XM_TX_JUMBO_MODE_LBN 31 -+#define FRF_AB_XM_TX_JUMBO_MODE_WIDTH 1 -+#define FRF_AB_XM_MAX_TX_FRM_SIZE_HI_LBN 19 -+#define FRF_AB_XM_MAX_TX_FRM_SIZE_HI_WIDTH 11 -+#define FRF_AB_XM_MAX_TX_FRM_SIZE_LO_LBN 16 -+#define FRF_AB_XM_MAX_TX_FRM_SIZE_LO_WIDTH 3 -+#define FRF_AB_XM_PAD_CHAR_LBN 0 -+#define FRF_AB_XM_PAD_CHAR_WIDTH 8 -+ -+/* XM_RX_PARAM_REG: XGMAC receive parameter register */ -+#define FR_AB_XM_RX_PARAM 0x000012e0 -+#define FRF_AB_XM_MAX_RX_FRM_SIZE_HI_LBN 3 -+#define FRF_AB_XM_MAX_RX_FRM_SIZE_HI_WIDTH 11 -+#define FRF_AB_XM_MAX_RX_FRM_SIZE_LO_LBN 0 -+#define FRF_AB_XM_MAX_RX_FRM_SIZE_LO_WIDTH 3 -+ -+/* XM_MGT_INT_MSK_REG: XGMAC management interrupt mask register */ -+#define FR_AB_XM_MGT_INT_MSK 0x000012f0 -+#define FRF_AB_XM_STAT_CNTR_OF_LBN 9 -+#define FRF_AB_XM_STAT_CNTR_OF_WIDTH 1 -+#define FRF_AB_XM_STAT_CNTR_HF_LBN 8 -+#define FRF_AB_XM_STAT_CNTR_HF_WIDTH 1 -+#define FRF_AB_XM_PRMBLE_ERR_LBN 2 -+#define FRF_AB_XM_PRMBLE_ERR_WIDTH 1 -+#define FRF_AB_XM_RMTFLT_LBN 1 -+#define FRF_AB_XM_RMTFLT_WIDTH 1 -+#define FRF_AB_XM_LCLFLT_LBN 0 -+#define FRF_AB_XM_LCLFLT_WIDTH 1 -+ -+/* XX_PWR_RST_REG: XGXS/XAUI powerdown/reset register */ -+#define FR_AB_XX_PWR_RST 0x00001300 -+#define FRF_AB_XX_PWRDND_SIG_LBN 31 -+#define FRF_AB_XX_PWRDND_SIG_WIDTH 1 -+#define FRF_AB_XX_PWRDNC_SIG_LBN 30 -+#define FRF_AB_XX_PWRDNC_SIG_WIDTH 1 -+#define FRF_AB_XX_PWRDNB_SIG_LBN 29 -+#define FRF_AB_XX_PWRDNB_SIG_WIDTH 1 -+#define FRF_AB_XX_PWRDNA_SIG_LBN 28 -+#define FRF_AB_XX_PWRDNA_SIG_WIDTH 1 -+#define FRF_AB_XX_SIM_MODE_LBN 27 -+#define FRF_AB_XX_SIM_MODE_WIDTH 1 -+#define FRF_AB_XX_RSTPLLCD_SIG_LBN 25 -+#define FRF_AB_XX_RSTPLLCD_SIG_WIDTH 1 -+#define FRF_AB_XX_RSTPLLAB_SIG_LBN 24 -+#define FRF_AB_XX_RSTPLLAB_SIG_WIDTH 1 -+#define FRF_AB_XX_RESETD_SIG_LBN 23 -+#define FRF_AB_XX_RESETD_SIG_WIDTH 1 -+#define FRF_AB_XX_RESETC_SIG_LBN 22 -+#define FRF_AB_XX_RESETC_SIG_WIDTH 1 -+#define FRF_AB_XX_RESETB_SIG_LBN 21 -+#define FRF_AB_XX_RESETB_SIG_WIDTH 1 -+#define FRF_AB_XX_RESETA_SIG_LBN 20 -+#define FRF_AB_XX_RESETA_SIG_WIDTH 1 -+#define FRF_AB_XX_RSTXGXSRX_SIG_LBN 18 -+#define FRF_AB_XX_RSTXGXSRX_SIG_WIDTH 1 -+#define FRF_AB_XX_RSTXGXSTX_SIG_LBN 17 -+#define FRF_AB_XX_RSTXGXSTX_SIG_WIDTH 1 -+#define FRF_AB_XX_SD_RST_ACT_LBN 16 -+#define FRF_AB_XX_SD_RST_ACT_WIDTH 1 -+#define FRF_AB_XX_PWRDND_EN_LBN 15 -+#define FRF_AB_XX_PWRDND_EN_WIDTH 1 -+#define FRF_AB_XX_PWRDNC_EN_LBN 14 -+#define FRF_AB_XX_PWRDNC_EN_WIDTH 1 -+#define FRF_AB_XX_PWRDNB_EN_LBN 13 -+#define FRF_AB_XX_PWRDNB_EN_WIDTH 1 -+#define FRF_AB_XX_PWRDNA_EN_LBN 12 -+#define FRF_AB_XX_PWRDNA_EN_WIDTH 1 -+#define FRF_AB_XX_RSTPLLCD_EN_LBN 9 -+#define FRF_AB_XX_RSTPLLCD_EN_WIDTH 1 -+#define FRF_AB_XX_RSTPLLAB_EN_LBN 8 -+#define FRF_AB_XX_RSTPLLAB_EN_WIDTH 1 -+#define FRF_AB_XX_RESETD_EN_LBN 7 -+#define FRF_AB_XX_RESETD_EN_WIDTH 1 -+#define FRF_AB_XX_RESETC_EN_LBN 6 -+#define FRF_AB_XX_RESETC_EN_WIDTH 1 -+#define FRF_AB_XX_RESETB_EN_LBN 5 -+#define FRF_AB_XX_RESETB_EN_WIDTH 1 -+#define FRF_AB_XX_RESETA_EN_LBN 4 -+#define FRF_AB_XX_RESETA_EN_WIDTH 1 -+#define FRF_AB_XX_RSTXGXSRX_EN_LBN 2 -+#define FRF_AB_XX_RSTXGXSRX_EN_WIDTH 1 -+#define FRF_AB_XX_RSTXGXSTX_EN_LBN 1 -+#define FRF_AB_XX_RSTXGXSTX_EN_WIDTH 1 -+#define FRF_AB_XX_RST_XX_EN_LBN 0 -+#define FRF_AB_XX_RST_XX_EN_WIDTH 1 -+ -+/* XX_SD_CTL_REG: XGXS/XAUI powerdown/reset control register */ -+#define FR_AB_XX_SD_CTL 0x00001310 -+#define FRF_AB_XX_TERMADJ1_LBN 17 -+#define FRF_AB_XX_TERMADJ1_WIDTH 1 -+#define FRF_AB_XX_TERMADJ0_LBN 16 -+#define FRF_AB_XX_TERMADJ0_WIDTH 1 -+#define FRF_AB_XX_HIDRVD_LBN 15 -+#define FRF_AB_XX_HIDRVD_WIDTH 1 -+#define FRF_AB_XX_LODRVD_LBN 14 -+#define FRF_AB_XX_LODRVD_WIDTH 1 -+#define FRF_AB_XX_HIDRVC_LBN 13 -+#define FRF_AB_XX_HIDRVC_WIDTH 1 -+#define FRF_AB_XX_LODRVC_LBN 12 -+#define FRF_AB_XX_LODRVC_WIDTH 1 -+#define FRF_AB_XX_HIDRVB_LBN 11 -+#define FRF_AB_XX_HIDRVB_WIDTH 1 -+#define FRF_AB_XX_LODRVB_LBN 10 -+#define FRF_AB_XX_LODRVB_WIDTH 1 -+#define FRF_AB_XX_HIDRVA_LBN 9 -+#define FRF_AB_XX_HIDRVA_WIDTH 1 -+#define FRF_AB_XX_LODRVA_LBN 8 -+#define FRF_AB_XX_LODRVA_WIDTH 1 -+#define FRF_AB_XX_LPBKD_LBN 3 -+#define FRF_AB_XX_LPBKD_WIDTH 1 -+#define FRF_AB_XX_LPBKC_LBN 2 -+#define FRF_AB_XX_LPBKC_WIDTH 1 -+#define FRF_AB_XX_LPBKB_LBN 1 -+#define FRF_AB_XX_LPBKB_WIDTH 1 -+#define FRF_AB_XX_LPBKA_LBN 0 -+#define FRF_AB_XX_LPBKA_WIDTH 1 -+ -+/* XX_TXDRV_CTL_REG: XAUI SerDes transmit drive control register */ -+#define FR_AB_XX_TXDRV_CTL 0x00001320 -+#define FRF_AB_XX_DEQD_LBN 28 -+#define FRF_AB_XX_DEQD_WIDTH 4 -+#define FRF_AB_XX_DEQC_LBN 24 -+#define FRF_AB_XX_DEQC_WIDTH 4 -+#define FRF_AB_XX_DEQB_LBN 20 -+#define FRF_AB_XX_DEQB_WIDTH 4 -+#define FRF_AB_XX_DEQA_LBN 16 -+#define FRF_AB_XX_DEQA_WIDTH 4 -+#define FRF_AB_XX_DTXD_LBN 12 -+#define FRF_AB_XX_DTXD_WIDTH 4 -+#define FRF_AB_XX_DTXC_LBN 8 -+#define FRF_AB_XX_DTXC_WIDTH 4 -+#define FRF_AB_XX_DTXB_LBN 4 -+#define FRF_AB_XX_DTXB_WIDTH 4 -+#define FRF_AB_XX_DTXA_LBN 0 -+#define FRF_AB_XX_DTXA_WIDTH 4 -+ -+/* XX_PRBS_CTL_REG: documentation to be written for sum_XX_PRBS_CTL_REG */ -+#define FR_AB_XX_PRBS_CTL 0x00001330 -+#define FRF_AB_XX_CH3_RX_PRBS_SEL_LBN 30 -+#define FRF_AB_XX_CH3_RX_PRBS_SEL_WIDTH 2 -+#define FRF_AB_XX_CH3_RX_PRBS_INV_LBN 29 -+#define FRF_AB_XX_CH3_RX_PRBS_INV_WIDTH 1 -+#define FRF_AB_XX_CH3_RX_PRBS_CHKEN_LBN 28 -+#define FRF_AB_XX_CH3_RX_PRBS_CHKEN_WIDTH 1 -+#define FRF_AB_XX_CH2_RX_PRBS_SEL_LBN 26 -+#define FRF_AB_XX_CH2_RX_PRBS_SEL_WIDTH 2 -+#define FRF_AB_XX_CH2_RX_PRBS_INV_LBN 25 -+#define FRF_AB_XX_CH2_RX_PRBS_INV_WIDTH 1 -+#define FRF_AB_XX_CH2_RX_PRBS_CHKEN_LBN 24 -+#define FRF_AB_XX_CH2_RX_PRBS_CHKEN_WIDTH 1 -+#define FRF_AB_XX_CH1_RX_PRBS_SEL_LBN 22 -+#define FRF_AB_XX_CH1_RX_PRBS_SEL_WIDTH 2 -+#define FRF_AB_XX_CH1_RX_PRBS_INV_LBN 21 -+#define FRF_AB_XX_CH1_RX_PRBS_INV_WIDTH 1 -+#define FRF_AB_XX_CH1_RX_PRBS_CHKEN_LBN 20 -+#define FRF_AB_XX_CH1_RX_PRBS_CHKEN_WIDTH 1 -+#define FRF_AB_XX_CH0_RX_PRBS_SEL_LBN 18 -+#define FRF_AB_XX_CH0_RX_PRBS_SEL_WIDTH 2 -+#define FRF_AB_XX_CH0_RX_PRBS_INV_LBN 17 -+#define FRF_AB_XX_CH0_RX_PRBS_INV_WIDTH 1 -+#define FRF_AB_XX_CH0_RX_PRBS_CHKEN_LBN 16 -+#define FRF_AB_XX_CH0_RX_PRBS_CHKEN_WIDTH 1 -+#define FRF_AB_XX_CH3_TX_PRBS_SEL_LBN 14 -+#define FRF_AB_XX_CH3_TX_PRBS_SEL_WIDTH 2 -+#define FRF_AB_XX_CH3_TX_PRBS_INV_LBN 13 -+#define FRF_AB_XX_CH3_TX_PRBS_INV_WIDTH 1 -+#define FRF_AB_XX_CH3_TX_PRBS_CHKEN_LBN 12 -+#define FRF_AB_XX_CH3_TX_PRBS_CHKEN_WIDTH 1 -+#define FRF_AB_XX_CH2_TX_PRBS_SEL_LBN 10 -+#define FRF_AB_XX_CH2_TX_PRBS_SEL_WIDTH 2 -+#define FRF_AB_XX_CH2_TX_PRBS_INV_LBN 9 -+#define FRF_AB_XX_CH2_TX_PRBS_INV_WIDTH 1 -+#define FRF_AB_XX_CH2_TX_PRBS_CHKEN_LBN 8 -+#define FRF_AB_XX_CH2_TX_PRBS_CHKEN_WIDTH 1 -+#define FRF_AB_XX_CH1_TX_PRBS_SEL_LBN 6 -+#define FRF_AB_XX_CH1_TX_PRBS_SEL_WIDTH 2 -+#define FRF_AB_XX_CH1_TX_PRBS_INV_LBN 5 -+#define FRF_AB_XX_CH1_TX_PRBS_INV_WIDTH 1 -+#define FRF_AB_XX_CH1_TX_PRBS_CHKEN_LBN 4 -+#define FRF_AB_XX_CH1_TX_PRBS_CHKEN_WIDTH 1 -+#define FRF_AB_XX_CH0_TX_PRBS_SEL_LBN 2 -+#define FRF_AB_XX_CH0_TX_PRBS_SEL_WIDTH 2 -+#define FRF_AB_XX_CH0_TX_PRBS_INV_LBN 1 -+#define FRF_AB_XX_CH0_TX_PRBS_INV_WIDTH 1 -+#define FRF_AB_XX_CH0_TX_PRBS_CHKEN_LBN 0 -+#define FRF_AB_XX_CH0_TX_PRBS_CHKEN_WIDTH 1 -+ -+/* XX_PRBS_CHK_REG: documentation to be written for sum_XX_PRBS_CHK_REG */ -+#define FR_AB_XX_PRBS_CHK 0x00001340 -+#define FRF_AB_XX_REV_LB_EN_LBN 16 -+#define FRF_AB_XX_REV_LB_EN_WIDTH 1 -+#define FRF_AB_XX_CH3_DEG_DET_LBN 15 -+#define FRF_AB_XX_CH3_DEG_DET_WIDTH 1 -+#define FRF_AB_XX_CH3_LFSR_LOCK_IND_LBN 14 -+#define FRF_AB_XX_CH3_LFSR_LOCK_IND_WIDTH 1 -+#define FRF_AB_XX_CH3_PRBS_FRUN_LBN 13 -+#define FRF_AB_XX_CH3_PRBS_FRUN_WIDTH 1 -+#define FRF_AB_XX_CH3_ERR_CHK_LBN 12 -+#define FRF_AB_XX_CH3_ERR_CHK_WIDTH 1 -+#define FRF_AB_XX_CH2_DEG_DET_LBN 11 -+#define FRF_AB_XX_CH2_DEG_DET_WIDTH 1 -+#define FRF_AB_XX_CH2_LFSR_LOCK_IND_LBN 10 -+#define FRF_AB_XX_CH2_LFSR_LOCK_IND_WIDTH 1 -+#define FRF_AB_XX_CH2_PRBS_FRUN_LBN 9 -+#define FRF_AB_XX_CH2_PRBS_FRUN_WIDTH 1 -+#define FRF_AB_XX_CH2_ERR_CHK_LBN 8 -+#define FRF_AB_XX_CH2_ERR_CHK_WIDTH 1 -+#define FRF_AB_XX_CH1_DEG_DET_LBN 7 -+#define FRF_AB_XX_CH1_DEG_DET_WIDTH 1 -+#define FRF_AB_XX_CH1_LFSR_LOCK_IND_LBN 6 -+#define FRF_AB_XX_CH1_LFSR_LOCK_IND_WIDTH 1 -+#define FRF_AB_XX_CH1_PRBS_FRUN_LBN 5 -+#define FRF_AB_XX_CH1_PRBS_FRUN_WIDTH 1 -+#define FRF_AB_XX_CH1_ERR_CHK_LBN 4 -+#define FRF_AB_XX_CH1_ERR_CHK_WIDTH 1 -+#define FRF_AB_XX_CH0_DEG_DET_LBN 3 -+#define FRF_AB_XX_CH0_DEG_DET_WIDTH 1 -+#define FRF_AB_XX_CH0_LFSR_LOCK_IND_LBN 2 -+#define FRF_AB_XX_CH0_LFSR_LOCK_IND_WIDTH 1 -+#define FRF_AB_XX_CH0_PRBS_FRUN_LBN 1 -+#define FRF_AB_XX_CH0_PRBS_FRUN_WIDTH 1 -+#define FRF_AB_XX_CH0_ERR_CHK_LBN 0 -+#define FRF_AB_XX_CH0_ERR_CHK_WIDTH 1 -+ -+/* XX_PRBS_ERR_REG: documentation to be written for sum_XX_PRBS_ERR_REG */ -+#define FR_AB_XX_PRBS_ERR 0x00001350 -+#define FRF_AB_XX_CH3_PRBS_ERR_CNT_LBN 24 -+#define FRF_AB_XX_CH3_PRBS_ERR_CNT_WIDTH 8 -+#define FRF_AB_XX_CH2_PRBS_ERR_CNT_LBN 16 -+#define FRF_AB_XX_CH2_PRBS_ERR_CNT_WIDTH 8 -+#define FRF_AB_XX_CH1_PRBS_ERR_CNT_LBN 8 -+#define FRF_AB_XX_CH1_PRBS_ERR_CNT_WIDTH 8 -+#define FRF_AB_XX_CH0_PRBS_ERR_CNT_LBN 0 -+#define FRF_AB_XX_CH0_PRBS_ERR_CNT_WIDTH 8 -+ -+/* XX_CORE_STAT_REG: XAUI XGXS core status register */ -+#define FR_AB_XX_CORE_STAT 0x00001360 -+#define FRF_AB_XX_FORCE_SIG3_LBN 31 -+#define FRF_AB_XX_FORCE_SIG3_WIDTH 1 -+#define FRF_AB_XX_FORCE_SIG3_VAL_LBN 30 -+#define FRF_AB_XX_FORCE_SIG3_VAL_WIDTH 1 -+#define FRF_AB_XX_FORCE_SIG2_LBN 29 -+#define FRF_AB_XX_FORCE_SIG2_WIDTH 1 -+#define FRF_AB_XX_FORCE_SIG2_VAL_LBN 28 -+#define FRF_AB_XX_FORCE_SIG2_VAL_WIDTH 1 -+#define FRF_AB_XX_FORCE_SIG1_LBN 27 -+#define FRF_AB_XX_FORCE_SIG1_WIDTH 1 -+#define FRF_AB_XX_FORCE_SIG1_VAL_LBN 26 -+#define FRF_AB_XX_FORCE_SIG1_VAL_WIDTH 1 -+#define FRF_AB_XX_FORCE_SIG0_LBN 25 -+#define FRF_AB_XX_FORCE_SIG0_WIDTH 1 -+#define FRF_AB_XX_FORCE_SIG0_VAL_LBN 24 -+#define FRF_AB_XX_FORCE_SIG0_VAL_WIDTH 1 -+#define FRF_AB_XX_XGXS_LB_EN_LBN 23 -+#define FRF_AB_XX_XGXS_LB_EN_WIDTH 1 -+#define FRF_AB_XX_XGMII_LB_EN_LBN 22 -+#define FRF_AB_XX_XGMII_LB_EN_WIDTH 1 -+#define FRF_AB_XX_MATCH_FAULT_LBN 21 -+#define FRF_AB_XX_MATCH_FAULT_WIDTH 1 -+#define FRF_AB_XX_ALIGN_DONE_LBN 20 -+#define FRF_AB_XX_ALIGN_DONE_WIDTH 1 -+#define FRF_AB_XX_SYNC_STAT3_LBN 19 -+#define FRF_AB_XX_SYNC_STAT3_WIDTH 1 -+#define FRF_AB_XX_SYNC_STAT2_LBN 18 -+#define FRF_AB_XX_SYNC_STAT2_WIDTH 1 -+#define FRF_AB_XX_SYNC_STAT1_LBN 17 -+#define FRF_AB_XX_SYNC_STAT1_WIDTH 1 -+#define FRF_AB_XX_SYNC_STAT0_LBN 16 -+#define FRF_AB_XX_SYNC_STAT0_WIDTH 1 -+#define FRF_AB_XX_COMMA_DET_CH3_LBN 15 -+#define FRF_AB_XX_COMMA_DET_CH3_WIDTH 1 -+#define FRF_AB_XX_COMMA_DET_CH2_LBN 14 -+#define FRF_AB_XX_COMMA_DET_CH2_WIDTH 1 -+#define FRF_AB_XX_COMMA_DET_CH1_LBN 13 -+#define FRF_AB_XX_COMMA_DET_CH1_WIDTH 1 -+#define FRF_AB_XX_COMMA_DET_CH0_LBN 12 -+#define FRF_AB_XX_COMMA_DET_CH0_WIDTH 1 -+#define FRF_AB_XX_CGRP_ALIGN_CH3_LBN 11 -+#define FRF_AB_XX_CGRP_ALIGN_CH3_WIDTH 1 -+#define FRF_AB_XX_CGRP_ALIGN_CH2_LBN 10 -+#define FRF_AB_XX_CGRP_ALIGN_CH2_WIDTH 1 -+#define FRF_AB_XX_CGRP_ALIGN_CH1_LBN 9 -+#define FRF_AB_XX_CGRP_ALIGN_CH1_WIDTH 1 -+#define FRF_AB_XX_CGRP_ALIGN_CH0_LBN 8 -+#define FRF_AB_XX_CGRP_ALIGN_CH0_WIDTH 1 -+#define FRF_AB_XX_CHAR_ERR_CH3_LBN 7 -+#define FRF_AB_XX_CHAR_ERR_CH3_WIDTH 1 -+#define FRF_AB_XX_CHAR_ERR_CH2_LBN 6 -+#define FRF_AB_XX_CHAR_ERR_CH2_WIDTH 1 -+#define FRF_AB_XX_CHAR_ERR_CH1_LBN 5 -+#define FRF_AB_XX_CHAR_ERR_CH1_WIDTH 1 -+#define FRF_AB_XX_CHAR_ERR_CH0_LBN 4 -+#define FRF_AB_XX_CHAR_ERR_CH0_WIDTH 1 -+#define FRF_AB_XX_DISPERR_CH3_LBN 3 -+#define FRF_AB_XX_DISPERR_CH3_WIDTH 1 -+#define FRF_AB_XX_DISPERR_CH2_LBN 2 -+#define FRF_AB_XX_DISPERR_CH2_WIDTH 1 -+#define FRF_AB_XX_DISPERR_CH1_LBN 1 -+#define FRF_AB_XX_DISPERR_CH1_WIDTH 1 -+#define FRF_AB_XX_DISPERR_CH0_LBN 0 -+#define FRF_AB_XX_DISPERR_CH0_WIDTH 1 -+ -+/* RX_DESC_PTR_TBL_KER: Receive descriptor pointer table */ -+#define FR_AA_RX_DESC_PTR_TBL_KER 0x00011800 -+#define FR_AA_RX_DESC_PTR_TBL_KER_STEP 16 -+#define FR_AA_RX_DESC_PTR_TBL_KER_ROWS 4 -+/* RX_DESC_PTR_TBL: Receive descriptor pointer table */ -+#define FR_BZ_RX_DESC_PTR_TBL 0x00f40000 -+#define FR_BZ_RX_DESC_PTR_TBL_STEP 16 -+#define FR_BB_RX_DESC_PTR_TBL_ROWS 4096 -+#define FR_CZ_RX_DESC_PTR_TBL_ROWS 1024 -+#define FRF_CZ_RX_HDR_SPLIT_LBN 90 -+#define FRF_CZ_RX_HDR_SPLIT_WIDTH 1 -+#define FRF_AA_RX_RESET_LBN 89 -+#define FRF_AA_RX_RESET_WIDTH 1 -+#define FRF_AZ_RX_ISCSI_DDIG_EN_LBN 88 -+#define FRF_AZ_RX_ISCSI_DDIG_EN_WIDTH 1 -+#define FRF_AZ_RX_ISCSI_HDIG_EN_LBN 87 -+#define FRF_AZ_RX_ISCSI_HDIG_EN_WIDTH 1 -+#define FRF_AZ_RX_DESC_PREF_ACT_LBN 86 -+#define FRF_AZ_RX_DESC_PREF_ACT_WIDTH 1 -+#define FRF_AZ_RX_DC_HW_RPTR_LBN 80 -+#define FRF_AZ_RX_DC_HW_RPTR_WIDTH 6 -+#define FRF_AZ_RX_DESCQ_HW_RPTR_LBN 68 -+#define FRF_AZ_RX_DESCQ_HW_RPTR_WIDTH 12 -+#define FRF_AZ_RX_DESCQ_SW_WPTR_LBN 56 -+#define FRF_AZ_RX_DESCQ_SW_WPTR_WIDTH 12 -+#define FRF_AZ_RX_DESCQ_BUF_BASE_ID_LBN 36 -+#define FRF_AZ_RX_DESCQ_BUF_BASE_ID_WIDTH 20 -+#define FRF_AZ_RX_DESCQ_EVQ_ID_LBN 24 -+#define FRF_AZ_RX_DESCQ_EVQ_ID_WIDTH 12 -+#define FRF_AZ_RX_DESCQ_OWNER_ID_LBN 10 -+#define FRF_AZ_RX_DESCQ_OWNER_ID_WIDTH 14 -+#define FRF_AZ_RX_DESCQ_LABEL_LBN 5 -+#define FRF_AZ_RX_DESCQ_LABEL_WIDTH 5 -+#define FRF_AZ_RX_DESCQ_SIZE_LBN 3 -+#define FRF_AZ_RX_DESCQ_SIZE_WIDTH 2 -+#define FFE_AZ_RX_DESCQ_SIZE_4K 3 -+#define FFE_AZ_RX_DESCQ_SIZE_2K 2 -+#define FFE_AZ_RX_DESCQ_SIZE_1K 1 -+#define FFE_AZ_RX_DESCQ_SIZE_512 0 -+#define FRF_AZ_RX_DESCQ_TYPE_LBN 2 -+#define FRF_AZ_RX_DESCQ_TYPE_WIDTH 1 -+#define FRF_AZ_RX_DESCQ_JUMBO_LBN 1 -+#define FRF_AZ_RX_DESCQ_JUMBO_WIDTH 1 -+#define FRF_AZ_RX_DESCQ_EN_LBN 0 -+#define FRF_AZ_RX_DESCQ_EN_WIDTH 1 -+ -+/* TX_DESC_PTR_TBL_KER: Transmit descriptor pointer */ -+#define FR_AA_TX_DESC_PTR_TBL_KER 0x00011900 -+#define FR_AA_TX_DESC_PTR_TBL_KER_STEP 16 -+#define FR_AA_TX_DESC_PTR_TBL_KER_ROWS 8 -+/* TX_DESC_PTR_TBL: Transmit descriptor pointer */ -+#define FR_BZ_TX_DESC_PTR_TBL 0x00f50000 -+#define FR_BZ_TX_DESC_PTR_TBL_STEP 16 -+#define FR_BB_TX_DESC_PTR_TBL_ROWS 4096 -+#define FR_CZ_TX_DESC_PTR_TBL_ROWS 1024 -+#define FRF_CZ_TX_DPT_Q_MASK_WIDTH_LBN 94 -+#define FRF_CZ_TX_DPT_Q_MASK_WIDTH_WIDTH 2 -+#define FRF_CZ_TX_DPT_ETH_FILT_EN_LBN 93 -+#define FRF_CZ_TX_DPT_ETH_FILT_EN_WIDTH 1 -+#define FRF_CZ_TX_DPT_IP_FILT_EN_LBN 92 -+#define FRF_CZ_TX_DPT_IP_FILT_EN_WIDTH 1 -+#define FRF_BZ_TX_NON_IP_DROP_DIS_LBN 91 -+#define FRF_BZ_TX_NON_IP_DROP_DIS_WIDTH 1 -+#define FRF_BZ_TX_IP_CHKSM_DIS_LBN 90 -+#define FRF_BZ_TX_IP_CHKSM_DIS_WIDTH 1 -+#define FRF_BZ_TX_TCP_CHKSM_DIS_LBN 89 -+#define FRF_BZ_TX_TCP_CHKSM_DIS_WIDTH 1 -+#define FRF_AZ_TX_DESCQ_EN_LBN 88 -+#define FRF_AZ_TX_DESCQ_EN_WIDTH 1 -+#define FRF_AZ_TX_ISCSI_DDIG_EN_LBN 87 -+#define FRF_AZ_TX_ISCSI_DDIG_EN_WIDTH 1 -+#define FRF_AZ_TX_ISCSI_HDIG_EN_LBN 86 -+#define FRF_AZ_TX_ISCSI_HDIG_EN_WIDTH 1 -+#define FRF_AZ_TX_DC_HW_RPTR_LBN 80 -+#define FRF_AZ_TX_DC_HW_RPTR_WIDTH 6 -+#define FRF_AZ_TX_DESCQ_HW_RPTR_LBN 68 -+#define FRF_AZ_TX_DESCQ_HW_RPTR_WIDTH 12 -+#define FRF_AZ_TX_DESCQ_SW_WPTR_LBN 56 -+#define FRF_AZ_TX_DESCQ_SW_WPTR_WIDTH 12 -+#define FRF_AZ_TX_DESCQ_BUF_BASE_ID_LBN 36 -+#define FRF_AZ_TX_DESCQ_BUF_BASE_ID_WIDTH 20 -+#define FRF_AZ_TX_DESCQ_EVQ_ID_LBN 24 -+#define FRF_AZ_TX_DESCQ_EVQ_ID_WIDTH 12 -+#define FRF_AZ_TX_DESCQ_OWNER_ID_LBN 10 -+#define FRF_AZ_TX_DESCQ_OWNER_ID_WIDTH 14 -+#define FRF_AZ_TX_DESCQ_LABEL_LBN 5 -+#define FRF_AZ_TX_DESCQ_LABEL_WIDTH 5 -+#define FRF_AZ_TX_DESCQ_SIZE_LBN 3 -+#define FRF_AZ_TX_DESCQ_SIZE_WIDTH 2 -+#define FFE_AZ_TX_DESCQ_SIZE_4K 3 -+#define FFE_AZ_TX_DESCQ_SIZE_2K 2 -+#define FFE_AZ_TX_DESCQ_SIZE_1K 1 -+#define FFE_AZ_TX_DESCQ_SIZE_512 0 -+#define FRF_AZ_TX_DESCQ_TYPE_LBN 1 -+#define FRF_AZ_TX_DESCQ_TYPE_WIDTH 2 -+#define FRF_AZ_TX_DESCQ_FLUSH_LBN 0 -+#define FRF_AZ_TX_DESCQ_FLUSH_WIDTH 1 -+ -+/* EVQ_PTR_TBL_KER: Event queue pointer table */ -+#define FR_AA_EVQ_PTR_TBL_KER 0x00011a00 -+#define FR_AA_EVQ_PTR_TBL_KER_STEP 16 -+#define FR_AA_EVQ_PTR_TBL_KER_ROWS 4 -+/* EVQ_PTR_TBL: Event queue pointer table */ -+#define FR_BZ_EVQ_PTR_TBL 0x00f60000 -+#define FR_BZ_EVQ_PTR_TBL_STEP 16 -+#define FR_CZ_EVQ_PTR_TBL_ROWS 1024 -+#define FR_BB_EVQ_PTR_TBL_ROWS 4096 -+#define FRF_BZ_EVQ_RPTR_IGN_LBN 40 -+#define FRF_BZ_EVQ_RPTR_IGN_WIDTH 1 -+#define FRF_AB_EVQ_WKUP_OR_INT_EN_LBN 39 -+#define FRF_AB_EVQ_WKUP_OR_INT_EN_WIDTH 1 -+#define FRF_CZ_EVQ_DOS_PROTECT_EN_LBN 39 -+#define FRF_CZ_EVQ_DOS_PROTECT_EN_WIDTH 1 -+#define FRF_AZ_EVQ_NXT_WPTR_LBN 24 -+#define FRF_AZ_EVQ_NXT_WPTR_WIDTH 15 -+#define FRF_AZ_EVQ_EN_LBN 23 -+#define FRF_AZ_EVQ_EN_WIDTH 1 -+#define FRF_AZ_EVQ_SIZE_LBN 20 -+#define FRF_AZ_EVQ_SIZE_WIDTH 3 -+#define FFE_AZ_EVQ_SIZE_32K 6 -+#define FFE_AZ_EVQ_SIZE_16K 5 -+#define FFE_AZ_EVQ_SIZE_8K 4 -+#define FFE_AZ_EVQ_SIZE_4K 3 -+#define FFE_AZ_EVQ_SIZE_2K 2 -+#define FFE_AZ_EVQ_SIZE_1K 1 -+#define FFE_AZ_EVQ_SIZE_512 0 -+#define FRF_AZ_EVQ_BUF_BASE_ID_LBN 0 -+#define FRF_AZ_EVQ_BUF_BASE_ID_WIDTH 20 -+ -+/* BUF_HALF_TBL_KER: Buffer table in half buffer table mode direct access by driver */ -+#define FR_AA_BUF_HALF_TBL_KER 0x00018000 -+#define FR_AA_BUF_HALF_TBL_KER_STEP 8 -+#define FR_AA_BUF_HALF_TBL_KER_ROWS 4096 -+/* BUF_HALF_TBL: Buffer table in half buffer table mode direct access by driver */ -+#define FR_BZ_BUF_HALF_TBL 0x00800000 -+#define FR_BZ_BUF_HALF_TBL_STEP 8 -+#define FR_CZ_BUF_HALF_TBL_ROWS 147456 -+#define FR_BB_BUF_HALF_TBL_ROWS 524288 -+#define FRF_AZ_BUF_ADR_HBUF_ODD_LBN 44 -+#define FRF_AZ_BUF_ADR_HBUF_ODD_WIDTH 20 -+#define FRF_AZ_BUF_OWNER_ID_HBUF_ODD_LBN 32 -+#define FRF_AZ_BUF_OWNER_ID_HBUF_ODD_WIDTH 12 -+#define FRF_AZ_BUF_ADR_HBUF_EVEN_LBN 12 -+#define FRF_AZ_BUF_ADR_HBUF_EVEN_WIDTH 20 -+#define FRF_AZ_BUF_OWNER_ID_HBUF_EVEN_LBN 0 -+#define FRF_AZ_BUF_OWNER_ID_HBUF_EVEN_WIDTH 12 -+ -+/* BUF_FULL_TBL_KER: Buffer table in full buffer table mode direct access by driver */ -+#define FR_AA_BUF_FULL_TBL_KER 0x00018000 -+#define FR_AA_BUF_FULL_TBL_KER_STEP 8 -+#define FR_AA_BUF_FULL_TBL_KER_ROWS 4096 -+/* BUF_FULL_TBL: Buffer table in full buffer table mode direct access by driver */ -+#define FR_BZ_BUF_FULL_TBL 0x00800000 -+#define FR_BZ_BUF_FULL_TBL_STEP 8 -+#define FR_CZ_BUF_FULL_TBL_ROWS 147456 -+#define FR_BB_BUF_FULL_TBL_ROWS 917504 -+#define FRF_AZ_BUF_FULL_UNUSED_LBN 51 -+#define FRF_AZ_BUF_FULL_UNUSED_WIDTH 13 -+#define FRF_AZ_IP_DAT_BUF_SIZE_LBN 50 -+#define FRF_AZ_IP_DAT_BUF_SIZE_WIDTH 1 -+#define FRF_AZ_BUF_ADR_REGION_LBN 48 -+#define FRF_AZ_BUF_ADR_REGION_WIDTH 2 -+#define FFE_AZ_BUF_ADR_REGN3 3 -+#define FFE_AZ_BUF_ADR_REGN2 2 -+#define FFE_AZ_BUF_ADR_REGN1 1 -+#define FFE_AZ_BUF_ADR_REGN0 0 -+#define FRF_AZ_BUF_ADR_FBUF_LBN 14 -+#define FRF_AZ_BUF_ADR_FBUF_WIDTH 34 -+#define FRF_AZ_BUF_OWNER_ID_FBUF_LBN 0 -+#define FRF_AZ_BUF_OWNER_ID_FBUF_WIDTH 14 -+ -+/* RX_FILTER_TBL0: TCP/IPv4 Receive filter table */ -+#define FR_BZ_RX_FILTER_TBL0 0x00f00000 -+#define FR_BZ_RX_FILTER_TBL0_STEP 32 -+#define FR_BZ_RX_FILTER_TBL0_ROWS 8192 -+/* RX_FILTER_TBL1: TCP/IPv4 Receive filter table */ -+#define FR_BB_RX_FILTER_TBL1 0x00f00010 -+#define FR_BB_RX_FILTER_TBL1_STEP 32 -+#define FR_BB_RX_FILTER_TBL1_ROWS 8192 -+#define FRF_BZ_RSS_EN_LBN 110 -+#define FRF_BZ_RSS_EN_WIDTH 1 -+#define FRF_BZ_SCATTER_EN_LBN 109 -+#define FRF_BZ_SCATTER_EN_WIDTH 1 -+#define FRF_BZ_TCP_UDP_LBN 108 -+#define FRF_BZ_TCP_UDP_WIDTH 1 -+#define FRF_BZ_RXQ_ID_LBN 96 -+#define FRF_BZ_RXQ_ID_WIDTH 12 -+#define FRF_BZ_DEST_IP_LBN 64 -+#define FRF_BZ_DEST_IP_WIDTH 32 -+#define FRF_BZ_DEST_PORT_TCP_LBN 48 -+#define FRF_BZ_DEST_PORT_TCP_WIDTH 16 -+#define FRF_BZ_SRC_IP_LBN 16 -+#define FRF_BZ_SRC_IP_WIDTH 32 -+#define FRF_BZ_SRC_TCP_DEST_UDP_LBN 0 -+#define FRF_BZ_SRC_TCP_DEST_UDP_WIDTH 16 -+ -+/* RX_MAC_FILTER_TBL0: Receive Ethernet filter table */ -+#define FR_CZ_RX_MAC_FILTER_TBL0 0x00f00010 -+#define FR_CZ_RX_MAC_FILTER_TBL0_STEP 32 -+#define FR_CZ_RX_MAC_FILTER_TBL0_ROWS 512 -+#define FRF_CZ_RMFT_RSS_EN_LBN 75 -+#define FRF_CZ_RMFT_RSS_EN_WIDTH 1 -+#define FRF_CZ_RMFT_SCATTER_EN_LBN 74 -+#define FRF_CZ_RMFT_SCATTER_EN_WIDTH 1 -+#define FRF_CZ_RMFT_IP_OVERRIDE_LBN 73 -+#define FRF_CZ_RMFT_IP_OVERRIDE_WIDTH 1 -+#define FRF_CZ_RMFT_RXQ_ID_LBN 61 -+#define FRF_CZ_RMFT_RXQ_ID_WIDTH 12 -+#define FRF_CZ_RMFT_WILDCARD_MATCH_LBN 60 -+#define FRF_CZ_RMFT_WILDCARD_MATCH_WIDTH 1 -+#define FRF_CZ_RMFT_DEST_MAC_LBN 16 -+#define FRF_CZ_RMFT_DEST_MAC_WIDTH 44 -+#define FRF_CZ_RMFT_VLAN_ID_LBN 0 -+#define FRF_CZ_RMFT_VLAN_ID_WIDTH 12 -+ -+/* TIMER_TBL: Timer table */ -+#define FR_BZ_TIMER_TBL 0x00f70000 -+#define FR_BZ_TIMER_TBL_STEP 16 -+#define FR_CZ_TIMER_TBL_ROWS 1024 -+#define FR_BB_TIMER_TBL_ROWS 4096 -+#define FRF_CZ_TIMER_Q_EN_LBN 33 -+#define FRF_CZ_TIMER_Q_EN_WIDTH 1 -+#define FRF_CZ_INT_ARMD_LBN 32 -+#define FRF_CZ_INT_ARMD_WIDTH 1 -+#define FRF_CZ_INT_PEND_LBN 31 -+#define FRF_CZ_INT_PEND_WIDTH 1 -+#define FRF_CZ_HOST_NOTIFY_MODE_LBN 30 -+#define FRF_CZ_HOST_NOTIFY_MODE_WIDTH 1 -+#define FRF_CZ_RELOAD_TIMER_VAL_LBN 16 -+#define FRF_CZ_RELOAD_TIMER_VAL_WIDTH 14 -+#define FRF_CZ_TIMER_MODE_LBN 14 -+#define FRF_CZ_TIMER_MODE_WIDTH 2 -+#define FFE_CZ_TIMER_MODE_INT_HLDOFF 3 -+#define FFE_CZ_TIMER_MODE_TRIG_START 2 -+#define FFE_CZ_TIMER_MODE_IMMED_START 1 -+#define FFE_CZ_TIMER_MODE_DIS 0 -+#define FRF_BB_TIMER_MODE_LBN 12 -+#define FRF_BB_TIMER_MODE_WIDTH 2 -+#define FFE_BB_TIMER_MODE_INT_HLDOFF 2 -+#define FFE_BB_TIMER_MODE_TRIG_START 2 -+#define FFE_BB_TIMER_MODE_IMMED_START 1 -+#define FFE_BB_TIMER_MODE_DIS 0 -+#define FRF_CZ_TIMER_VAL_LBN 0 -+#define FRF_CZ_TIMER_VAL_WIDTH 14 -+#define FRF_BB_TIMER_VAL_LBN 0 -+#define FRF_BB_TIMER_VAL_WIDTH 12 -+ -+/* TX_PACE_TBL: Transmit pacing table */ -+#define FR_BZ_TX_PACE_TBL 0x00f80000 -+#define FR_BZ_TX_PACE_TBL_STEP 16 -+#define FR_CZ_TX_PACE_TBL_ROWS 1024 -+#define FR_BB_TX_PACE_TBL_ROWS 4096 -+#define FRF_BZ_TX_PACE_LBN 0 -+#define FRF_BZ_TX_PACE_WIDTH 5 -+ -+/* RX_INDIRECTION_TBL: RX Indirection Table */ -+#define FR_BZ_RX_INDIRECTION_TBL 0x00fb0000 -+#define FR_BZ_RX_INDIRECTION_TBL_STEP 16 -+#define FR_BZ_RX_INDIRECTION_TBL_ROWS 128 -+#define FRF_BZ_IT_QUEUE_LBN 0 -+#define FRF_BZ_IT_QUEUE_WIDTH 6 -+ -+/* TX_FILTER_TBL0: TCP/IPv4 Transmit filter table */ -+#define FR_CZ_TX_FILTER_TBL0 0x00fc0000 -+#define FR_CZ_TX_FILTER_TBL0_STEP 16 -+#define FR_CZ_TX_FILTER_TBL0_ROWS 8192 -+#define FRF_CZ_TIFT_TCP_UDP_LBN 108 -+#define FRF_CZ_TIFT_TCP_UDP_WIDTH 1 -+#define FRF_CZ_TIFT_TXQ_ID_LBN 96 -+#define FRF_CZ_TIFT_TXQ_ID_WIDTH 12 -+#define FRF_CZ_TIFT_DEST_IP_LBN 64 -+#define FRF_CZ_TIFT_DEST_IP_WIDTH 32 -+#define FRF_CZ_TIFT_DEST_PORT_TCP_LBN 48 -+#define FRF_CZ_TIFT_DEST_PORT_TCP_WIDTH 16 -+#define FRF_CZ_TIFT_SRC_IP_LBN 16 -+#define FRF_CZ_TIFT_SRC_IP_WIDTH 32 -+#define FRF_CZ_TIFT_SRC_TCP_DEST_UDP_LBN 0 -+#define FRF_CZ_TIFT_SRC_TCP_DEST_UDP_WIDTH 16 -+ -+/* TX_MAC_FILTER_TBL0: Transmit Ethernet filter table */ -+#define FR_CZ_TX_MAC_FILTER_TBL0 0x00fe0000 -+#define FR_CZ_TX_MAC_FILTER_TBL0_STEP 16 -+#define FR_CZ_TX_MAC_FILTER_TBL0_ROWS 512 -+#define FRF_CZ_TMFT_TXQ_ID_LBN 61 -+#define FRF_CZ_TMFT_TXQ_ID_WIDTH 12 -+#define FRF_CZ_TMFT_WILDCARD_MATCH_LBN 60 -+#define FRF_CZ_TMFT_WILDCARD_MATCH_WIDTH 1 -+#define FRF_CZ_TMFT_SRC_MAC_LBN 16 -+#define FRF_CZ_TMFT_SRC_MAC_WIDTH 44 -+#define FRF_CZ_TMFT_VLAN_ID_LBN 0 -+#define FRF_CZ_TMFT_VLAN_ID_WIDTH 12 -+ -+/* MC_TREG_SMEM: MC Shared Memory */ -+#define FR_CZ_MC_TREG_SMEM 0x00ff0000 -+#define FR_CZ_MC_TREG_SMEM_STEP 4 -+#define FR_CZ_MC_TREG_SMEM_ROWS 512 -+#define FRF_CZ_MC_TREG_SMEM_ROW_LBN 0 -+#define FRF_CZ_MC_TREG_SMEM_ROW_WIDTH 32 -+ -+/* MSIX_VECTOR_TABLE: MSIX Vector Table */ -+#define FR_BB_MSIX_VECTOR_TABLE 0x00ff0000 -+#define FR_BZ_MSIX_VECTOR_TABLE_STEP 16 -+#define FR_BB_MSIX_VECTOR_TABLE_ROWS 64 -+/* MSIX_VECTOR_TABLE: MSIX Vector Table */ -+#define FR_CZ_MSIX_VECTOR_TABLE 0x00000000 -+/* FR_BZ_MSIX_VECTOR_TABLE_STEP 16 */ -+#define FR_CZ_MSIX_VECTOR_TABLE_ROWS 1024 -+#define FRF_BZ_MSIX_VECTOR_RESERVED_LBN 97 -+#define FRF_BZ_MSIX_VECTOR_RESERVED_WIDTH 31 -+#define FRF_BZ_MSIX_VECTOR_MASK_LBN 96 -+#define FRF_BZ_MSIX_VECTOR_MASK_WIDTH 1 -+#define FRF_BZ_MSIX_MESSAGE_DATA_LBN 64 -+#define FRF_BZ_MSIX_MESSAGE_DATA_WIDTH 32 -+#define FRF_BZ_MSIX_MESSAGE_ADDRESS_HI_LBN 32 -+#define FRF_BZ_MSIX_MESSAGE_ADDRESS_HI_WIDTH 32 -+#define FRF_BZ_MSIX_MESSAGE_ADDRESS_LO_LBN 0 -+#define FRF_BZ_MSIX_MESSAGE_ADDRESS_LO_WIDTH 32 -+ -+/* MSIX_PBA_TABLE: MSIX Pending Bit Array */ -+#define FR_BB_MSIX_PBA_TABLE 0x00ff2000 -+#define FR_BZ_MSIX_PBA_TABLE_STEP 4 -+#define FR_BB_MSIX_PBA_TABLE_ROWS 2 -+/* MSIX_PBA_TABLE: MSIX Pending Bit Array */ -+#define FR_CZ_MSIX_PBA_TABLE 0x00008000 -+/* FR_BZ_MSIX_PBA_TABLE_STEP 4 */ -+#define FR_CZ_MSIX_PBA_TABLE_ROWS 32 -+#define FRF_BZ_MSIX_PBA_PEND_DWORD_LBN 0 -+#define FRF_BZ_MSIX_PBA_PEND_DWORD_WIDTH 32 -+ -+/* SRM_DBG_REG: SRAM debug access */ -+#define FR_BZ_SRM_DBG 0x03000000 -+#define FR_BZ_SRM_DBG_STEP 8 -+#define FR_CZ_SRM_DBG_ROWS 262144 -+#define FR_BB_SRM_DBG_ROWS 2097152 -+#define FRF_BZ_SRM_DBG_LBN 0 -+#define FRF_BZ_SRM_DBG_WIDTH 64 -+ -+/* TB_MSIX_PBA_TABLE: MSIX Pending Bit Array */ -+#define FR_CZ_TB_MSIX_PBA_TABLE 0x00008000 -+#define FR_CZ_TB_MSIX_PBA_TABLE_STEP 4 -+#define FR_CZ_TB_MSIX_PBA_TABLE_ROWS 1024 -+#define FRF_CZ_TB_MSIX_PBA_PEND_DWORD_LBN 0 -+#define FRF_CZ_TB_MSIX_PBA_PEND_DWORD_WIDTH 32 -+ -+/* DRIVER_EV */ -+#define FSF_AZ_DRIVER_EV_SUBCODE_LBN 56 -+#define FSF_AZ_DRIVER_EV_SUBCODE_WIDTH 4 -+#define FSE_BZ_TX_DSC_ERROR_EV 15 -+#define FSE_BZ_RX_DSC_ERROR_EV 14 -+#define FSE_AA_RX_RECOVER_EV 11 -+#define FSE_AZ_TIMER_EV 10 -+#define FSE_AZ_TX_PKT_NON_TCP_UDP 9 -+#define FSE_AZ_WAKE_UP_EV 6 -+#define FSE_AZ_SRM_UPD_DONE_EV 5 -+#define FSE_AB_EVQ_NOT_EN_EV 3 -+#define FSE_AZ_EVQ_INIT_DONE_EV 2 -+#define FSE_AZ_RX_DESCQ_FLS_DONE_EV 1 -+#define FSE_AZ_TX_DESCQ_FLS_DONE_EV 0 -+#define FSF_AZ_DRIVER_EV_SUBDATA_LBN 0 -+#define FSF_AZ_DRIVER_EV_SUBDATA_WIDTH 14 -+ -+/* EVENT_ENTRY */ -+#define FSF_AZ_EV_CODE_LBN 60 -+#define FSF_AZ_EV_CODE_WIDTH 4 -+#define FSE_CZ_EV_CODE_MCDI_EV 12 -+#define FSE_CZ_EV_CODE_USER_EV 8 -+#define FSE_AZ_EV_CODE_DRV_GEN_EV 7 -+#define FSE_AZ_EV_CODE_GLOBAL_EV 6 -+#define FSE_AZ_EV_CODE_DRIVER_EV 5 -+#define FSE_AZ_EV_CODE_TX_EV 2 -+#define FSE_AZ_EV_CODE_RX_EV 0 -+#define FSF_AZ_EV_DATA_LBN 0 -+#define FSF_AZ_EV_DATA_WIDTH 60 -+ -+/* GLOBAL_EV */ -+#define FSF_BB_GLB_EV_RX_RECOVERY_LBN 12 -+#define FSF_BB_GLB_EV_RX_RECOVERY_WIDTH 1 -+#define FSF_AA_GLB_EV_RX_RECOVERY_LBN 11 -+#define FSF_AA_GLB_EV_RX_RECOVERY_WIDTH 1 -+#define FSF_BB_GLB_EV_XG_MGT_INTR_LBN 11 -+#define FSF_BB_GLB_EV_XG_MGT_INTR_WIDTH 1 -+#define FSF_AB_GLB_EV_XFP_PHY0_INTR_LBN 10 -+#define FSF_AB_GLB_EV_XFP_PHY0_INTR_WIDTH 1 -+#define FSF_AB_GLB_EV_XG_PHY0_INTR_LBN 9 -+#define FSF_AB_GLB_EV_XG_PHY0_INTR_WIDTH 1 -+#define FSF_AB_GLB_EV_G_PHY0_INTR_LBN 7 -+#define FSF_AB_GLB_EV_G_PHY0_INTR_WIDTH 1 -+ -+/* LEGACY_INT_VEC */ -+#define FSF_AZ_NET_IVEC_FATAL_INT_LBN 64 -+#define FSF_AZ_NET_IVEC_FATAL_INT_WIDTH 1 -+#define FSF_AZ_NET_IVEC_INT_Q_LBN 40 -+#define FSF_AZ_NET_IVEC_INT_Q_WIDTH 4 -+#define FSF_AZ_NET_IVEC_INT_FLAG_LBN 32 -+#define FSF_AZ_NET_IVEC_INT_FLAG_WIDTH 1 -+#define FSF_AZ_NET_IVEC_EVQ_FIFO_HF_LBN 1 -+#define FSF_AZ_NET_IVEC_EVQ_FIFO_HF_WIDTH 1 -+#define FSF_AZ_NET_IVEC_EVQ_FIFO_AF_LBN 0 -+#define FSF_AZ_NET_IVEC_EVQ_FIFO_AF_WIDTH 1 -+ -+/* MC_XGMAC_FLTR_RULE_DEF */ -+#define FSF_CZ_MC_XFRC_MODE_LBN 416 -+#define FSF_CZ_MC_XFRC_MODE_WIDTH 1 -+#define FSE_CZ_MC_XFRC_MODE_LAYERED 1 -+#define FSE_CZ_MC_XFRC_MODE_SIMPLE 0 -+#define FSF_CZ_MC_XFRC_HASH_LBN 384 -+#define FSF_CZ_MC_XFRC_HASH_WIDTH 32 -+#define FSF_CZ_MC_XFRC_LAYER4_BYTE_MASK_LBN 256 -+#define FSF_CZ_MC_XFRC_LAYER4_BYTE_MASK_WIDTH 128 -+#define FSF_CZ_MC_XFRC_LAYER3_BYTE_MASK_LBN 128 -+#define FSF_CZ_MC_XFRC_LAYER3_BYTE_MASK_WIDTH 128 -+#define FSF_CZ_MC_XFRC_LAYER2_OR_SIMPLE_BYTE_MASK_LBN 0 -+#define FSF_CZ_MC_XFRC_LAYER2_OR_SIMPLE_BYTE_MASK_WIDTH 128 -+ -+/* RX_EV */ -+#define FSF_CZ_RX_EV_PKT_NOT_PARSED_LBN 58 -+#define FSF_CZ_RX_EV_PKT_NOT_PARSED_WIDTH 1 -+#define FSF_CZ_RX_EV_IPV6_PKT_LBN 57 -+#define FSF_CZ_RX_EV_IPV6_PKT_WIDTH 1 -+#define FSF_AZ_RX_EV_PKT_OK_LBN 56 -+#define FSF_AZ_RX_EV_PKT_OK_WIDTH 1 -+#define FSF_AZ_RX_EV_PAUSE_FRM_ERR_LBN 55 -+#define FSF_AZ_RX_EV_PAUSE_FRM_ERR_WIDTH 1 -+#define FSF_AZ_RX_EV_BUF_OWNER_ID_ERR_LBN 54 -+#define FSF_AZ_RX_EV_BUF_OWNER_ID_ERR_WIDTH 1 -+#define FSF_AZ_RX_EV_IP_FRAG_ERR_LBN 53 -+#define FSF_AZ_RX_EV_IP_FRAG_ERR_WIDTH 1 -+#define FSF_AZ_RX_EV_IP_HDR_CHKSUM_ERR_LBN 52 -+#define FSF_AZ_RX_EV_IP_HDR_CHKSUM_ERR_WIDTH 1 -+#define FSF_AZ_RX_EV_TCP_UDP_CHKSUM_ERR_LBN 51 -+#define FSF_AZ_RX_EV_TCP_UDP_CHKSUM_ERR_WIDTH 1 -+#define FSF_AZ_RX_EV_ETH_CRC_ERR_LBN 50 -+#define FSF_AZ_RX_EV_ETH_CRC_ERR_WIDTH 1 -+#define FSF_AZ_RX_EV_FRM_TRUNC_LBN 49 -+#define FSF_AZ_RX_EV_FRM_TRUNC_WIDTH 1 -+#define FSF_AA_RX_EV_DRIB_NIB_LBN 49 -+#define FSF_AA_RX_EV_DRIB_NIB_WIDTH 1 -+#define FSF_AZ_RX_EV_TOBE_DISC_LBN 47 -+#define FSF_AZ_RX_EV_TOBE_DISC_WIDTH 1 -+#define FSF_AZ_RX_EV_PKT_TYPE_LBN 44 -+#define FSF_AZ_RX_EV_PKT_TYPE_WIDTH 3 -+#define FSE_AZ_RX_EV_PKT_TYPE_VLAN_JUMBO 5 -+#define FSE_AZ_RX_EV_PKT_TYPE_VLAN_LLC 4 -+#define FSE_AZ_RX_EV_PKT_TYPE_VLAN 3 -+#define FSE_AZ_RX_EV_PKT_TYPE_JUMBO 2 -+#define FSE_AZ_RX_EV_PKT_TYPE_LLC 1 -+#define FSE_AZ_RX_EV_PKT_TYPE_ETH 0 -+#define FSF_AZ_RX_EV_HDR_TYPE_LBN 42 -+#define FSF_AZ_RX_EV_HDR_TYPE_WIDTH 2 -+#define FSE_AZ_RX_EV_HDR_TYPE_OTHER 3 -+#define FSE_AB_RX_EV_HDR_TYPE_IPV4_OTHER 2 -+#define FSE_CZ_RX_EV_HDR_TYPE_IPV4V6_OTHER 2 -+#define FSE_AB_RX_EV_HDR_TYPE_IPV4_UDP 1 -+#define FSE_CZ_RX_EV_HDR_TYPE_IPV4V6_UDP 1 -+#define FSE_AB_RX_EV_HDR_TYPE_IPV4_TCP 0 -+#define FSE_CZ_RX_EV_HDR_TYPE_IPV4V6_TCP 0 -+#define FSF_AZ_RX_EV_DESC_Q_EMPTY_LBN 41 -+#define FSF_AZ_RX_EV_DESC_Q_EMPTY_WIDTH 1 -+#define FSF_AZ_RX_EV_MCAST_HASH_MATCH_LBN 40 -+#define FSF_AZ_RX_EV_MCAST_HASH_MATCH_WIDTH 1 -+#define FSF_AZ_RX_EV_MCAST_PKT_LBN 39 -+#define FSF_AZ_RX_EV_MCAST_PKT_WIDTH 1 -+#define FSF_AA_RX_EV_RECOVERY_FLAG_LBN 37 -+#define FSF_AA_RX_EV_RECOVERY_FLAG_WIDTH 1 -+#define FSF_AZ_RX_EV_Q_LABEL_LBN 32 -+#define FSF_AZ_RX_EV_Q_LABEL_WIDTH 5 -+#define FSF_AZ_RX_EV_JUMBO_CONT_LBN 31 -+#define FSF_AZ_RX_EV_JUMBO_CONT_WIDTH 1 -+#define FSF_AZ_RX_EV_PORT_LBN 30 -+#define FSF_AZ_RX_EV_PORT_WIDTH 1 -+#define FSF_AZ_RX_EV_BYTE_CNT_LBN 16 -+#define FSF_AZ_RX_EV_BYTE_CNT_WIDTH 14 -+#define FSF_AZ_RX_EV_SOP_LBN 15 -+#define FSF_AZ_RX_EV_SOP_WIDTH 1 -+#define FSF_AZ_RX_EV_ISCSI_PKT_OK_LBN 14 -+#define FSF_AZ_RX_EV_ISCSI_PKT_OK_WIDTH 1 -+#define FSF_AZ_RX_EV_ISCSI_DDIG_ERR_LBN 13 -+#define FSF_AZ_RX_EV_ISCSI_DDIG_ERR_WIDTH 1 -+#define FSF_AZ_RX_EV_ISCSI_HDIG_ERR_LBN 12 -+#define FSF_AZ_RX_EV_ISCSI_HDIG_ERR_WIDTH 1 -+#define FSF_AZ_RX_EV_DESC_PTR_LBN 0 -+#define FSF_AZ_RX_EV_DESC_PTR_WIDTH 12 -+ -+/* RX_KER_DESC */ -+#define FSF_AZ_RX_KER_BUF_SIZE_LBN 48 -+#define FSF_AZ_RX_KER_BUF_SIZE_WIDTH 14 -+#define FSF_AZ_RX_KER_BUF_REGION_LBN 46 -+#define FSF_AZ_RX_KER_BUF_REGION_WIDTH 2 -+#define FSF_AZ_RX_KER_BUF_ADDR_LBN 0 -+#define FSF_AZ_RX_KER_BUF_ADDR_WIDTH 46 -+ -+/* RX_USER_DESC */ -+#define FSF_AZ_RX_USER_2BYTE_OFFSET_LBN 20 -+#define FSF_AZ_RX_USER_2BYTE_OFFSET_WIDTH 12 -+#define FSF_AZ_RX_USER_BUF_ID_LBN 0 -+#define FSF_AZ_RX_USER_BUF_ID_WIDTH 20 -+ -+/* TX_EV */ -+#define FSF_AZ_TX_EV_PKT_ERR_LBN 38 -+#define FSF_AZ_TX_EV_PKT_ERR_WIDTH 1 -+#define FSF_AZ_TX_EV_PKT_TOO_BIG_LBN 37 -+#define FSF_AZ_TX_EV_PKT_TOO_BIG_WIDTH 1 -+#define FSF_AZ_TX_EV_Q_LABEL_LBN 32 -+#define FSF_AZ_TX_EV_Q_LABEL_WIDTH 5 -+#define FSF_AZ_TX_EV_PORT_LBN 16 -+#define FSF_AZ_TX_EV_PORT_WIDTH 1 -+#define FSF_AZ_TX_EV_WQ_FF_FULL_LBN 15 -+#define FSF_AZ_TX_EV_WQ_FF_FULL_WIDTH 1 -+#define FSF_AZ_TX_EV_BUF_OWNER_ID_ERR_LBN 14 -+#define FSF_AZ_TX_EV_BUF_OWNER_ID_ERR_WIDTH 1 -+#define FSF_AZ_TX_EV_COMP_LBN 12 -+#define FSF_AZ_TX_EV_COMP_WIDTH 1 -+#define FSF_AZ_TX_EV_DESC_PTR_LBN 0 -+#define FSF_AZ_TX_EV_DESC_PTR_WIDTH 12 -+ -+/* TX_KER_DESC */ -+#define FSF_AZ_TX_KER_CONT_LBN 62 -+#define FSF_AZ_TX_KER_CONT_WIDTH 1 -+#define FSF_AZ_TX_KER_BYTE_COUNT_LBN 48 -+#define FSF_AZ_TX_KER_BYTE_COUNT_WIDTH 14 -+#define FSF_AZ_TX_KER_BUF_REGION_LBN 46 -+#define FSF_AZ_TX_KER_BUF_REGION_WIDTH 2 -+#define FSF_AZ_TX_KER_BUF_ADDR_LBN 0 -+#define FSF_AZ_TX_KER_BUF_ADDR_WIDTH 46 -+ -+/* TX_USER_DESC */ -+#define FSF_AZ_TX_USER_SW_EV_EN_LBN 48 -+#define FSF_AZ_TX_USER_SW_EV_EN_WIDTH 1 -+#define FSF_AZ_TX_USER_CONT_LBN 46 -+#define FSF_AZ_TX_USER_CONT_WIDTH 1 -+#define FSF_AZ_TX_USER_BYTE_CNT_LBN 33 -+#define FSF_AZ_TX_USER_BYTE_CNT_WIDTH 13 -+#define FSF_AZ_TX_USER_BUF_ID_LBN 13 -+#define FSF_AZ_TX_USER_BUF_ID_WIDTH 20 -+#define FSF_AZ_TX_USER_BYTE_OFS_LBN 0 -+#define FSF_AZ_TX_USER_BYTE_OFS_WIDTH 13 -+ -+/* USER_EV */ -+#define FSF_CZ_USER_QID_LBN 32 -+#define FSF_CZ_USER_QID_WIDTH 10 -+#define FSF_CZ_USER_EV_REG_VALUE_LBN 0 -+#define FSF_CZ_USER_EV_REG_VALUE_WIDTH 32 -+ -+/************************************************************************** -+ * -+ * Falcon B0 PCIe core indirect registers -+ * -+ ************************************************************************** -+ */ -+ -+#define FPCR_BB_PCIE_DEVICE_CTRL_STAT 0x68 -+ -+#define FPCR_BB_PCIE_LINK_CTRL_STAT 0x70 -+ -+#define FPCR_BB_ACK_RPL_TIMER 0x700 -+#define FPCRF_BB_ACK_TL_LBN 0 -+#define FPCRF_BB_ACK_TL_WIDTH 16 -+#define FPCRF_BB_RPL_TL_LBN 16 -+#define FPCRF_BB_RPL_TL_WIDTH 16 -+ -+#define FPCR_BB_ACK_FREQ 0x70C -+#define FPCRF_BB_ACK_FREQ_LBN 0 -+#define FPCRF_BB_ACK_FREQ_WIDTH 7 -+ -+/************************************************************************** -+ * -+ * Pseudo-registers and fields -+ * -+ ************************************************************************** -+ */ -+ -+/* Interrupt acknowledge work-around register (A0/A1 only) */ -+#define FR_AA_WORK_AROUND_BROKEN_PCI_READS 0x0070 -+ -+/* EE_SPI_HCMD_REG: SPI host command register */ -+/* Values for the EE_SPI_HCMD_SF_SEL register field */ -+#define FFE_AB_SPI_DEVICE_EEPROM 0 -+#define FFE_AB_SPI_DEVICE_FLASH 1 -+ -+/* NIC_STAT_REG: NIC status register */ -+#define FRF_AB_STRAP_10G_LBN 2 -+#define FRF_AB_STRAP_10G_WIDTH 1 -+#define FRF_AA_STRAP_PCIE_LBN 0 -+#define FRF_AA_STRAP_PCIE_WIDTH 1 -+ -+/* FATAL_INTR_REG_KER: Fatal interrupt register for Kernel */ -+#define FRF_AZ_FATAL_INTR_LBN 0 -+#define FRF_AZ_FATAL_INTR_WIDTH 12 -+ -+/* SRM_CFG_REG: SRAM configuration register */ -+/* We treat the number of SRAM banks and bank size as a single field */ -+#define FRF_AZ_SRM_NB_SZ_LBN FRF_AZ_SRM_BANK_SIZE_LBN -+#define FRF_AZ_SRM_NB_SZ_WIDTH \ -+ (FRF_AZ_SRM_BANK_SIZE_WIDTH + FRF_AZ_SRM_NUM_BANK_WIDTH) -+#define FFE_AB_SRM_NB1_SZ2M 0 -+#define FFE_AB_SRM_NB1_SZ4M 1 -+#define FFE_AB_SRM_NB1_SZ8M 2 -+#define FFE_AB_SRM_NB_SZ_DEF 3 -+#define FFE_AB_SRM_NB2_SZ4M 4 -+#define FFE_AB_SRM_NB2_SZ8M 5 -+#define FFE_AB_SRM_NB2_SZ16M 6 -+#define FFE_AB_SRM_NB_SZ_RES 7 -+ -+/* RX_DESC_UPD_REGP0: Receive descriptor update register. */ -+/* We write just the last dword of these registers */ -+#define FR_AZ_RX_DESC_UPD_DWORD_P0 \ -+ (BUILD_BUG_ON_ZERO(FR_AA_RX_DESC_UPD_KER != FR_BZ_RX_DESC_UPD_P0) + \ -+ FR_BZ_RX_DESC_UPD_P0 + 3 * 4) -+#define FRF_AZ_RX_DESC_WPTR_DWORD_LBN (FRF_AZ_RX_DESC_WPTR_LBN - 3 * 32) -+#define FRF_AZ_RX_DESC_WPTR_DWORD_WIDTH FRF_AZ_RX_DESC_WPTR_WIDTH -+ -+/* TX_DESC_UPD_REGP0: Transmit descriptor update register. */ -+#define FR_AZ_TX_DESC_UPD_DWORD_P0 \ -+ (BUILD_BUG_ON_ZERO(FR_AA_TX_DESC_UPD_KER != FR_BZ_TX_DESC_UPD_P0) + \ -+ FR_BZ_TX_DESC_UPD_P0 + 3 * 4) -+#define FRF_AZ_TX_DESC_WPTR_DWORD_LBN (FRF_AZ_TX_DESC_WPTR_LBN - 3 * 32) -+#define FRF_AZ_TX_DESC_WPTR_DWORD_WIDTH FRF_AZ_TX_DESC_WPTR_WIDTH -+ -+/* GMF_CFG4_REG: GMAC FIFO configuration register 4 */ -+#define FRF_AB_GMF_HSTFLTRFRM_PAUSE_LBN 12 -+#define FRF_AB_GMF_HSTFLTRFRM_PAUSE_WIDTH 1 -+ -+/* GMF_CFG5_REG: GMAC FIFO configuration register 5 */ -+#define FRF_AB_GMF_HSTFLTRFRMDC_PAUSE_LBN 12 -+#define FRF_AB_GMF_HSTFLTRFRMDC_PAUSE_WIDTH 1 -+ -+/* XM_TX_PARAM_REG: XGMAC transmit parameter register */ -+#define FRF_AB_XM_MAX_TX_FRM_SIZE_LBN FRF_AB_XM_MAX_TX_FRM_SIZE_LO_LBN -+#define FRF_AB_XM_MAX_TX_FRM_SIZE_WIDTH (FRF_AB_XM_MAX_TX_FRM_SIZE_HI_WIDTH + \ -+ FRF_AB_XM_MAX_TX_FRM_SIZE_LO_WIDTH) -+ -+/* XM_RX_PARAM_REG: XGMAC receive parameter register */ -+#define FRF_AB_XM_MAX_RX_FRM_SIZE_LBN FRF_AB_XM_MAX_RX_FRM_SIZE_LO_LBN -+#define FRF_AB_XM_MAX_RX_FRM_SIZE_WIDTH (FRF_AB_XM_MAX_RX_FRM_SIZE_HI_WIDTH + \ -+ FRF_AB_XM_MAX_RX_FRM_SIZE_LO_WIDTH) -+ -+/* XX_TXDRV_CTL_REG: XAUI SerDes transmit drive control register */ -+/* Default values */ -+#define FFE_AB_XX_TXDRV_DEQ_DEF 0xe /* deq=.6 */ -+#define FFE_AB_XX_TXDRV_DTX_DEF 0x5 /* 1.25 */ -+#define FFE_AB_XX_SD_CTL_DRV_DEF 0 /* 20mA */ -+ -+/* XX_CORE_STAT_REG: XAUI XGXS core status register */ -+/* XGXS all-lanes status fields */ -+#define FRF_AB_XX_SYNC_STAT_LBN FRF_AB_XX_SYNC_STAT0_LBN -+#define FRF_AB_XX_SYNC_STAT_WIDTH 4 -+#define FRF_AB_XX_COMMA_DET_LBN FRF_AB_XX_COMMA_DET_CH0_LBN -+#define FRF_AB_XX_COMMA_DET_WIDTH 4 -+#define FRF_AB_XX_CHAR_ERR_LBN FRF_AB_XX_CHAR_ERR_CH0_LBN -+#define FRF_AB_XX_CHAR_ERR_WIDTH 4 -+#define FRF_AB_XX_DISPERR_LBN FRF_AB_XX_DISPERR_CH0_LBN -+#define FRF_AB_XX_DISPERR_WIDTH 4 -+#define FFE_AB_XX_STAT_ALL_LANES 0xf -+#define FRF_AB_XX_FORCE_SIG_LBN FRF_AB_XX_FORCE_SIG0_VAL_LBN -+#define FRF_AB_XX_FORCE_SIG_WIDTH 8 -+#define FFE_AB_XX_FORCE_SIG_ALL_LANES 0xff -+ -+/* DRIVER_EV */ -+/* Sub-fields of an RX flush completion event */ -+#define FSF_AZ_DRIVER_EV_RX_FLUSH_FAIL_LBN 12 -+#define FSF_AZ_DRIVER_EV_RX_FLUSH_FAIL_WIDTH 1 -+#define FSF_AZ_DRIVER_EV_RX_DESCQ_ID_LBN 0 -+#define FSF_AZ_DRIVER_EV_RX_DESCQ_ID_WIDTH 12 -+ -+/* EVENT_ENTRY */ -+/* Magic number field for event test */ -+#define FSF_AZ_DRV_GEN_EV_MAGIC_LBN 0 -+#define FSF_AZ_DRV_GEN_EV_MAGIC_WIDTH 32 -+ -+/************************************************************************** -+ * -+ * Falcon MAC stats -+ * -+ ************************************************************************** -+ * -+ */ -+ -+#define GRxGoodOct_offset 0x0 -+#define GRxGoodOct_WIDTH 48 -+#define GRxBadOct_offset 0x8 -+#define GRxBadOct_WIDTH 48 -+#define GRxMissPkt_offset 0x10 -+#define GRxMissPkt_WIDTH 32 -+#define GRxFalseCRS_offset 0x14 -+#define GRxFalseCRS_WIDTH 32 -+#define GRxPausePkt_offset 0x18 -+#define GRxPausePkt_WIDTH 32 -+#define GRxBadPkt_offset 0x1C -+#define GRxBadPkt_WIDTH 32 -+#define GRxUcastPkt_offset 0x20 -+#define GRxUcastPkt_WIDTH 32 -+#define GRxMcastPkt_offset 0x24 -+#define GRxMcastPkt_WIDTH 32 -+#define GRxBcastPkt_offset 0x28 -+#define GRxBcastPkt_WIDTH 32 -+#define GRxGoodLt64Pkt_offset 0x2C -+#define GRxGoodLt64Pkt_WIDTH 32 -+#define GRxBadLt64Pkt_offset 0x30 -+#define GRxBadLt64Pkt_WIDTH 32 -+#define GRx64Pkt_offset 0x34 -+#define GRx64Pkt_WIDTH 32 -+#define GRx65to127Pkt_offset 0x38 -+#define GRx65to127Pkt_WIDTH 32 -+#define GRx128to255Pkt_offset 0x3C -+#define GRx128to255Pkt_WIDTH 32 -+#define GRx256to511Pkt_offset 0x40 -+#define GRx256to511Pkt_WIDTH 32 -+#define GRx512to1023Pkt_offset 0x44 -+#define GRx512to1023Pkt_WIDTH 32 -+#define GRx1024to15xxPkt_offset 0x48 -+#define GRx1024to15xxPkt_WIDTH 32 -+#define GRx15xxtoJumboPkt_offset 0x4C -+#define GRx15xxtoJumboPkt_WIDTH 32 -+#define GRxGtJumboPkt_offset 0x50 -+#define GRxGtJumboPkt_WIDTH 32 -+#define GRxFcsErr64to15xxPkt_offset 0x54 -+#define GRxFcsErr64to15xxPkt_WIDTH 32 -+#define GRxFcsErr15xxtoJumboPkt_offset 0x58 -+#define GRxFcsErr15xxtoJumboPkt_WIDTH 32 -+#define GRxFcsErrGtJumboPkt_offset 0x5C -+#define GRxFcsErrGtJumboPkt_WIDTH 32 -+#define GTxGoodBadOct_offset 0x80 -+#define GTxGoodBadOct_WIDTH 48 -+#define GTxGoodOct_offset 0x88 -+#define GTxGoodOct_WIDTH 48 -+#define GTxSglColPkt_offset 0x90 -+#define GTxSglColPkt_WIDTH 32 -+#define GTxMultColPkt_offset 0x94 -+#define GTxMultColPkt_WIDTH 32 -+#define GTxExColPkt_offset 0x98 -+#define GTxExColPkt_WIDTH 32 -+#define GTxDefPkt_offset 0x9C -+#define GTxDefPkt_WIDTH 32 -+#define GTxLateCol_offset 0xA0 -+#define GTxLateCol_WIDTH 32 -+#define GTxExDefPkt_offset 0xA4 -+#define GTxExDefPkt_WIDTH 32 -+#define GTxPausePkt_offset 0xA8 -+#define GTxPausePkt_WIDTH 32 -+#define GTxBadPkt_offset 0xAC -+#define GTxBadPkt_WIDTH 32 -+#define GTxUcastPkt_offset 0xB0 -+#define GTxUcastPkt_WIDTH 32 -+#define GTxMcastPkt_offset 0xB4 -+#define GTxMcastPkt_WIDTH 32 -+#define GTxBcastPkt_offset 0xB8 -+#define GTxBcastPkt_WIDTH 32 -+#define GTxLt64Pkt_offset 0xBC -+#define GTxLt64Pkt_WIDTH 32 -+#define GTx64Pkt_offset 0xC0 -+#define GTx64Pkt_WIDTH 32 -+#define GTx65to127Pkt_offset 0xC4 -+#define GTx65to127Pkt_WIDTH 32 -+#define GTx128to255Pkt_offset 0xC8 -+#define GTx128to255Pkt_WIDTH 32 -+#define GTx256to511Pkt_offset 0xCC -+#define GTx256to511Pkt_WIDTH 32 -+#define GTx512to1023Pkt_offset 0xD0 -+#define GTx512to1023Pkt_WIDTH 32 -+#define GTx1024to15xxPkt_offset 0xD4 -+#define GTx1024to15xxPkt_WIDTH 32 -+#define GTx15xxtoJumboPkt_offset 0xD8 -+#define GTx15xxtoJumboPkt_WIDTH 32 -+#define GTxGtJumboPkt_offset 0xDC -+#define GTxGtJumboPkt_WIDTH 32 -+#define GTxNonTcpUdpPkt_offset 0xE0 -+#define GTxNonTcpUdpPkt_WIDTH 16 -+#define GTxMacSrcErrPkt_offset 0xE4 -+#define GTxMacSrcErrPkt_WIDTH 16 -+#define GTxIpSrcErrPkt_offset 0xE8 -+#define GTxIpSrcErrPkt_WIDTH 16 -+#define GDmaDone_offset 0xEC -+#define GDmaDone_WIDTH 32 -+ -+#define XgRxOctets_offset 0x0 -+#define XgRxOctets_WIDTH 48 -+#define XgRxOctetsOK_offset 0x8 -+#define XgRxOctetsOK_WIDTH 48 -+#define XgRxPkts_offset 0x10 -+#define XgRxPkts_WIDTH 32 -+#define XgRxPktsOK_offset 0x14 -+#define XgRxPktsOK_WIDTH 32 -+#define XgRxBroadcastPkts_offset 0x18 -+#define XgRxBroadcastPkts_WIDTH 32 -+#define XgRxMulticastPkts_offset 0x1C -+#define XgRxMulticastPkts_WIDTH 32 -+#define XgRxUnicastPkts_offset 0x20 -+#define XgRxUnicastPkts_WIDTH 32 -+#define XgRxUndersizePkts_offset 0x24 -+#define XgRxUndersizePkts_WIDTH 32 -+#define XgRxOversizePkts_offset 0x28 -+#define XgRxOversizePkts_WIDTH 32 -+#define XgRxJabberPkts_offset 0x2C -+#define XgRxJabberPkts_WIDTH 32 -+#define XgRxUndersizeFCSerrorPkts_offset 0x30 -+#define XgRxUndersizeFCSerrorPkts_WIDTH 32 -+#define XgRxDropEvents_offset 0x34 -+#define XgRxDropEvents_WIDTH 32 -+#define XgRxFCSerrorPkts_offset 0x38 -+#define XgRxFCSerrorPkts_WIDTH 32 -+#define XgRxAlignError_offset 0x3C -+#define XgRxAlignError_WIDTH 32 -+#define XgRxSymbolError_offset 0x40 -+#define XgRxSymbolError_WIDTH 32 -+#define XgRxInternalMACError_offset 0x44 -+#define XgRxInternalMACError_WIDTH 32 -+#define XgRxControlPkts_offset 0x48 -+#define XgRxControlPkts_WIDTH 32 -+#define XgRxPausePkts_offset 0x4C -+#define XgRxPausePkts_WIDTH 32 -+#define XgRxPkts64Octets_offset 0x50 -+#define XgRxPkts64Octets_WIDTH 32 -+#define XgRxPkts65to127Octets_offset 0x54 -+#define XgRxPkts65to127Octets_WIDTH 32 -+#define XgRxPkts128to255Octets_offset 0x58 -+#define XgRxPkts128to255Octets_WIDTH 32 -+#define XgRxPkts256to511Octets_offset 0x5C -+#define XgRxPkts256to511Octets_WIDTH 32 -+#define XgRxPkts512to1023Octets_offset 0x60 -+#define XgRxPkts512to1023Octets_WIDTH 32 -+#define XgRxPkts1024to15xxOctets_offset 0x64 -+#define XgRxPkts1024to15xxOctets_WIDTH 32 -+#define XgRxPkts15xxtoMaxOctets_offset 0x68 -+#define XgRxPkts15xxtoMaxOctets_WIDTH 32 -+#define XgRxLengthError_offset 0x6C -+#define XgRxLengthError_WIDTH 32 -+#define XgTxPkts_offset 0x80 -+#define XgTxPkts_WIDTH 32 -+#define XgTxOctets_offset 0x88 -+#define XgTxOctets_WIDTH 48 -+#define XgTxMulticastPkts_offset 0x90 -+#define XgTxMulticastPkts_WIDTH 32 -+#define XgTxBroadcastPkts_offset 0x94 -+#define XgTxBroadcastPkts_WIDTH 32 -+#define XgTxUnicastPkts_offset 0x98 -+#define XgTxUnicastPkts_WIDTH 32 -+#define XgTxControlPkts_offset 0x9C -+#define XgTxControlPkts_WIDTH 32 -+#define XgTxPausePkts_offset 0xA0 -+#define XgTxPausePkts_WIDTH 32 -+#define XgTxPkts64Octets_offset 0xA4 -+#define XgTxPkts64Octets_WIDTH 32 -+#define XgTxPkts65to127Octets_offset 0xA8 -+#define XgTxPkts65to127Octets_WIDTH 32 -+#define XgTxPkts128to255Octets_offset 0xAC -+#define XgTxPkts128to255Octets_WIDTH 32 -+#define XgTxPkts256to511Octets_offset 0xB0 -+#define XgTxPkts256to511Octets_WIDTH 32 -+#define XgTxPkts512to1023Octets_offset 0xB4 -+#define XgTxPkts512to1023Octets_WIDTH 32 -+#define XgTxPkts1024to15xxOctets_offset 0xB8 -+#define XgTxPkts1024to15xxOctets_WIDTH 32 -+#define XgTxPkts1519toMaxOctets_offset 0xBC -+#define XgTxPkts1519toMaxOctets_WIDTH 32 -+#define XgTxUndersizePkts_offset 0xC0 -+#define XgTxUndersizePkts_WIDTH 32 -+#define XgTxOversizePkts_offset 0xC4 -+#define XgTxOversizePkts_WIDTH 32 -+#define XgTxNonTcpUdpPkt_offset 0xC8 -+#define XgTxNonTcpUdpPkt_WIDTH 16 -+#define XgTxMacSrcErrPkt_offset 0xCC -+#define XgTxMacSrcErrPkt_WIDTH 16 -+#define XgTxIpSrcErrPkt_offset 0xD0 -+#define XgTxIpSrcErrPkt_WIDTH 16 -+#define XgDmaDone_offset 0xD4 -+#define XgDmaDone_WIDTH 32 -+ -+#define FALCON_STATS_NOT_DONE 0x00000000 -+#define FALCON_STATS_DONE 0xffffffff -+ -+/************************************************************************** -+ * -+ * Falcon non-volatile configuration -+ * -+ ************************************************************************** -+ */ -+ -+/* Board configuration v2 (v1 is obsolete; later versions are compatible) */ -+struct falcon_nvconfig_board_v2 { -+ __le16 nports; -+ u8 port0_phy_addr; -+ u8 port0_phy_type; -+ u8 port1_phy_addr; -+ u8 port1_phy_type; -+ __le16 asic_sub_revision; -+ __le16 board_revision; -+} __packed; -+ -+/* Board configuration v3 extra information */ -+struct falcon_nvconfig_board_v3 { -+ __le32 spi_device_type[2]; -+} __packed; -+ -+/* Bit numbers for spi_device_type */ -+#define SPI_DEV_TYPE_SIZE_LBN 0 -+#define SPI_DEV_TYPE_SIZE_WIDTH 5 -+#define SPI_DEV_TYPE_ADDR_LEN_LBN 6 -+#define SPI_DEV_TYPE_ADDR_LEN_WIDTH 2 -+#define SPI_DEV_TYPE_ERASE_CMD_LBN 8 -+#define SPI_DEV_TYPE_ERASE_CMD_WIDTH 8 -+#define SPI_DEV_TYPE_ERASE_SIZE_LBN 16 -+#define SPI_DEV_TYPE_ERASE_SIZE_WIDTH 5 -+#define SPI_DEV_TYPE_BLOCK_SIZE_LBN 24 -+#define SPI_DEV_TYPE_BLOCK_SIZE_WIDTH 5 -+#define SPI_DEV_TYPE_FIELD(type, field) \ -+ (((type) >> EFX_LOW_BIT(field)) & EFX_MASK32(EFX_WIDTH(field))) -+ -+#define FALCON_NVCONFIG_OFFSET 0x300 -+ -+#define FALCON_NVCONFIG_BOARD_MAGIC_NUM 0xFA1C -+struct falcon_nvconfig { -+ efx_oword_t ee_vpd_cfg_reg; /* 0x300 */ -+ u8 mac_address[2][8]; /* 0x310 */ -+ efx_oword_t pcie_sd_ctl0123_reg; /* 0x320 */ -+ efx_oword_t pcie_sd_ctl45_reg; /* 0x330 */ -+ efx_oword_t pcie_pcs_ctl_stat_reg; /* 0x340 */ -+ efx_oword_t hw_init_reg; /* 0x350 */ -+ efx_oword_t nic_stat_reg; /* 0x360 */ -+ efx_oword_t glb_ctl_reg; /* 0x370 */ -+ efx_oword_t srm_cfg_reg; /* 0x380 */ -+ efx_oword_t spare_reg; /* 0x390 */ -+ __le16 board_magic_num; /* 0x3A0 */ -+ __le16 board_struct_ver; -+ __le16 board_checksum; -+ struct falcon_nvconfig_board_v2 board_v2; -+ efx_oword_t ee_base_page_reg; /* 0x3B0 */ -+ struct falcon_nvconfig_board_v3 board_v3; /* 0x3C0 */ -+} __packed; -+ -+#endif /* EFX_REGS_H */ -diff --git a/drivers/net/sfc/rx.c b/drivers/net/sfc/rx.c -index 98bff5a..a97c923 100644 ---- a/drivers/net/sfc/rx.c -+++ b/drivers/net/sfc/rx.c -@@ -1,7 +1,7 @@ - /**************************************************************************** - * Driver for Solarflare Solarstorm network controllers and boards - * Copyright 2005-2006 Fen Systems Ltd. -- * Copyright 2005-2008 Solarflare Communications Inc. -+ * Copyright 2005-2009 Solarflare Communications Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published -@@ -16,9 +16,8 @@ - #include - #include - #include "net_driver.h" --#include "rx.h" - #include "efx.h" --#include "falcon.h" -+#include "nic.h" - #include "selftest.h" - #include "workarounds.h" - -@@ -61,7 +60,7 @@ - * rx_alloc_method = (rx_alloc_level > RX_ALLOC_LEVEL_LRO ? - * RX_ALLOC_METHOD_PAGE : RX_ALLOC_METHOD_SKB) - */ --static int rx_alloc_method = RX_ALLOC_METHOD_PAGE; -+static int rx_alloc_method = RX_ALLOC_METHOD_AUTO; - - #define RX_ALLOC_LEVEL_LRO 0x2000 - #define RX_ALLOC_LEVEL_MAX 0x3000 -@@ -293,8 +292,7 @@ static int __efx_fast_push_rx_descriptors(struct efx_rx_queue *rx_queue, - * fill anyway. - */ - fill_level = (rx_queue->added_count - rx_queue->removed_count); -- EFX_BUG_ON_PARANOID(fill_level > -- rx_queue->efx->type->rxd_ring_mask + 1); -+ EFX_BUG_ON_PARANOID(fill_level > EFX_RXQ_SIZE); - - /* Don't fill if we don't need to */ - if (fill_level >= rx_queue->fast_fill_trigger) -@@ -316,8 +314,7 @@ static int __efx_fast_push_rx_descriptors(struct efx_rx_queue *rx_queue, - retry: - /* Recalculate current fill level now that we have the lock */ - fill_level = (rx_queue->added_count - rx_queue->removed_count); -- EFX_BUG_ON_PARANOID(fill_level > -- rx_queue->efx->type->rxd_ring_mask + 1); -+ EFX_BUG_ON_PARANOID(fill_level > EFX_RXQ_SIZE); - space = rx_queue->fast_fill_limit - fill_level; - if (space < EFX_RX_BATCH) - goto out_unlock; -@@ -329,8 +326,7 @@ static int __efx_fast_push_rx_descriptors(struct efx_rx_queue *rx_queue, - - do { - for (i = 0; i < EFX_RX_BATCH; ++i) { -- index = (rx_queue->added_count & -- rx_queue->efx->type->rxd_ring_mask); -+ index = rx_queue->added_count & EFX_RXQ_MASK; - rx_buf = efx_rx_buffer(rx_queue, index); - rc = efx_init_rx_buffer(rx_queue, rx_buf); - if (unlikely(rc)) -@@ -345,7 +341,7 @@ static int __efx_fast_push_rx_descriptors(struct efx_rx_queue *rx_queue, - - out: - /* Send write pointer to card. */ -- falcon_notify_rx_desc(rx_queue); -+ efx_nic_notify_rx_desc(rx_queue); - - /* If the fast fill is running inside from the refill tasklet, then - * for SMP systems it may be running on a different CPU to -@@ -448,17 +444,23 @@ static void efx_rx_packet_lro(struct efx_channel *channel, - bool checksummed) - { - struct napi_struct *napi = &channel->napi_str; -+ gro_result_t gro_result; - - /* Pass the skb/page into the LRO engine */ - if (rx_buf->page) { -- struct sk_buff *skb = napi_get_frags(napi); -+ struct page *page = rx_buf->page; -+ struct sk_buff *skb; - -+ EFX_BUG_ON_PARANOID(rx_buf->skb); -+ rx_buf->page = NULL; -+ -+ skb = napi_get_frags(napi); - if (!skb) { -- put_page(rx_buf->page); -- goto out; -+ put_page(page); -+ return; - } - -- skb_shinfo(skb)->frags[0].page = rx_buf->page; -+ skb_shinfo(skb)->frags[0].page = page; - skb_shinfo(skb)->frags[0].page_offset = - efx_rx_buf_offset(rx_buf); - skb_shinfo(skb)->frags[0].size = rx_buf->len; -@@ -470,17 +472,24 @@ static void efx_rx_packet_lro(struct efx_channel *channel, - skb->ip_summed = - checksummed ? CHECKSUM_UNNECESSARY : CHECKSUM_NONE; - -- napi_gro_frags(napi); -+ skb_record_rx_queue(skb, channel->channel); - --out: -- EFX_BUG_ON_PARANOID(rx_buf->skb); -- rx_buf->page = NULL; -+ gro_result = napi_gro_frags(napi); - } else { -- EFX_BUG_ON_PARANOID(!rx_buf->skb); -- EFX_BUG_ON_PARANOID(!checksummed); -+ struct sk_buff *skb = rx_buf->skb; - -- napi_gro_receive(napi, rx_buf->skb); -+ EFX_BUG_ON_PARANOID(!skb); -+ EFX_BUG_ON_PARANOID(!checksummed); - rx_buf->skb = NULL; -+ -+ gro_result = napi_gro_receive(napi, skb); -+ } -+ -+ if (gro_result == GRO_NORMAL) { -+ channel->rx_alloc_level += RX_ALLOC_FACTOR_SKB; -+ } else if (gro_result != GRO_DROP) { -+ channel->rx_alloc_level += RX_ALLOC_FACTOR_LRO; -+ channel->irq_mod_score += 2; - } - } - -@@ -558,7 +567,7 @@ void __efx_rx_packet(struct efx_channel *channel, - if (unlikely(efx->loopback_selftest)) { - efx_loopback_rx_packet(efx, rx_buf->data, rx_buf->len); - efx_free_rx_buffer(efx, rx_buf); -- goto done; -+ return; - } - - if (rx_buf->skb) { -@@ -570,34 +579,28 @@ void __efx_rx_packet(struct efx_channel *channel, - * at the ethernet header */ - rx_buf->skb->protocol = eth_type_trans(rx_buf->skb, - efx->net_dev); -+ -+ skb_record_rx_queue(rx_buf->skb, channel->channel); - } - - if (likely(checksummed || rx_buf->page)) { - efx_rx_packet_lro(channel, rx_buf, checksummed); -- goto done; -+ return; - } - - /* We now own the SKB */ - skb = rx_buf->skb; - rx_buf->skb = NULL; -- -- EFX_BUG_ON_PARANOID(rx_buf->page); -- EFX_BUG_ON_PARANOID(rx_buf->skb); - EFX_BUG_ON_PARANOID(!skb); - - /* Set the SKB flags */ - skb->ip_summed = CHECKSUM_NONE; - -- skb_record_rx_queue(skb, channel->channel); -- - /* Pass the packet up */ - netif_receive_skb(skb); - - /* Update allocation strategy method */ - channel->rx_alloc_level += RX_ALLOC_FACTOR_SKB; -- --done: -- ; - } - - void efx_rx_strategy(struct efx_channel *channel) -@@ -632,12 +635,12 @@ int efx_probe_rx_queue(struct efx_rx_queue *rx_queue) - EFX_LOG(efx, "creating RX queue %d\n", rx_queue->queue); - - /* Allocate RX buffers */ -- rxq_size = (efx->type->rxd_ring_mask + 1) * sizeof(*rx_queue->buffer); -+ rxq_size = EFX_RXQ_SIZE * sizeof(*rx_queue->buffer); - rx_queue->buffer = kzalloc(rxq_size, GFP_KERNEL); - if (!rx_queue->buffer) - return -ENOMEM; - -- rc = falcon_probe_rx(rx_queue); -+ rc = efx_nic_probe_rx(rx_queue); - if (rc) { - kfree(rx_queue->buffer); - rx_queue->buffer = NULL; -@@ -647,7 +650,6 @@ int efx_probe_rx_queue(struct efx_rx_queue *rx_queue) - - void efx_init_rx_queue(struct efx_rx_queue *rx_queue) - { -- struct efx_nic *efx = rx_queue->efx; - unsigned int max_fill, trigger, limit; - - EFX_LOG(rx_queue->efx, "initialising RX queue %d\n", rx_queue->queue); -@@ -660,7 +662,7 @@ void efx_init_rx_queue(struct efx_rx_queue *rx_queue) - rx_queue->min_overfill = -1U; - - /* Initialise limit fields */ -- max_fill = efx->type->rxd_ring_mask + 1 - EFX_RXD_HEAD_ROOM; -+ max_fill = EFX_RXQ_SIZE - EFX_RXD_HEAD_ROOM; - trigger = max_fill * min(rx_refill_threshold, 100U) / 100U; - limit = max_fill * min(rx_refill_limit, 100U) / 100U; - -@@ -669,7 +671,7 @@ void efx_init_rx_queue(struct efx_rx_queue *rx_queue) - rx_queue->fast_fill_limit = limit; - - /* Set up RX descriptor ring */ -- falcon_init_rx(rx_queue); -+ efx_nic_init_rx(rx_queue); - } - - void efx_fini_rx_queue(struct efx_rx_queue *rx_queue) -@@ -679,11 +681,11 @@ void efx_fini_rx_queue(struct efx_rx_queue *rx_queue) - - EFX_LOG(rx_queue->efx, "shutting down RX queue %d\n", rx_queue->queue); - -- falcon_fini_rx(rx_queue); -+ efx_nic_fini_rx(rx_queue); - - /* Release RX buffers NB start at index 0 not current HW ptr */ - if (rx_queue->buffer) { -- for (i = 0; i <= rx_queue->efx->type->rxd_ring_mask; i++) { -+ for (i = 0; i <= EFX_RXQ_MASK; i++) { - rx_buf = efx_rx_buffer(rx_queue, i); - efx_fini_rx_buffer(rx_queue, rx_buf); - } -@@ -704,7 +706,7 @@ void efx_remove_rx_queue(struct efx_rx_queue *rx_queue) - { - EFX_LOG(rx_queue->efx, "destroying RX queue %d\n", rx_queue->queue); - -- falcon_remove_rx(rx_queue); -+ efx_nic_remove_rx(rx_queue); - - kfree(rx_queue->buffer); - rx_queue->buffer = NULL; -diff --git a/drivers/net/sfc/rx.h b/drivers/net/sfc/rx.h -deleted file mode 100644 -index 42ee755..0000000 ---- a/drivers/net/sfc/rx.h -+++ /dev/null -@@ -1,26 +0,0 @@ --/**************************************************************************** -- * Driver for Solarflare Solarstorm network controllers and boards -- * Copyright 2006 Solarflare Communications Inc. -- * -- * This program is free software; you can redistribute it and/or modify it -- * under the terms of the GNU General Public License version 2 as published -- * by the Free Software Foundation, incorporated herein by reference. -- */ -- --#ifndef EFX_RX_H --#define EFX_RX_H -- --#include "net_driver.h" -- --int efx_probe_rx_queue(struct efx_rx_queue *rx_queue); --void efx_remove_rx_queue(struct efx_rx_queue *rx_queue); --void efx_init_rx_queue(struct efx_rx_queue *rx_queue); --void efx_fini_rx_queue(struct efx_rx_queue *rx_queue); -- --void efx_rx_strategy(struct efx_channel *channel); --void efx_fast_push_rx_descriptors(struct efx_rx_queue *rx_queue); --void efx_rx_work(struct work_struct *data); --void __efx_rx_packet(struct efx_channel *channel, -- struct efx_rx_buffer *rx_buf, bool checksummed); -- --#endif /* EFX_RX_H */ -diff --git a/drivers/net/sfc/selftest.c b/drivers/net/sfc/selftest.c -index 817c7ef..af39335 100644 ---- a/drivers/net/sfc/selftest.c -+++ b/drivers/net/sfc/selftest.c -@@ -1,7 +1,7 @@ - /**************************************************************************** - * Driver for Solarflare Solarstorm network controllers and boards - * Copyright 2005-2006 Fen Systems Ltd. -- * Copyright 2006-2008 Solarflare Communications Inc. -+ * Copyright 2006-2009 Solarflare Communications Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published -@@ -20,14 +20,12 @@ - #include - #include - #include "net_driver.h" --#include "ethtool.h" - #include "efx.h" --#include "falcon.h" -+#include "nic.h" - #include "selftest.h" --#include "boards.h" - #include "workarounds.h" - #include "spi.h" --#include "falcon_io.h" -+#include "io.h" - #include "mdio_10g.h" - - /* -@@ -49,7 +47,7 @@ static const unsigned char payload_source[ETH_ALEN] = { - 0x00, 0x0f, 0x53, 0x1b, 0x1b, 0x1b, - }; - --static const char *payload_msg = -+static const char payload_msg[] = - "Hello world! This is an Efx loopback test in progress!"; - - /** -@@ -57,6 +55,7 @@ static const char *payload_msg = - * @flush: Drop all packets in efx_loopback_rx_packet - * @packet_count: Number of packets being used in this test - * @skbs: An array of skbs transmitted -+ * @offload_csum: Checksums are being offloaded - * @rx_good: RX good packet count - * @rx_bad: RX bad packet count - * @payload: Payload used in tests -@@ -65,10 +64,7 @@ struct efx_loopback_state { - bool flush; - int packet_count; - struct sk_buff **skbs; -- -- /* Checksums are being offloaded */ - bool offload_csum; -- - atomic_t rx_good; - atomic_t rx_bad; - struct efx_loopback_payload payload; -@@ -104,7 +100,7 @@ static int efx_test_mdio(struct efx_nic *efx, struct efx_self_tests *tests) - } - - if (EFX_IS10G(efx)) { -- rc = efx_mdio_check_mmds(efx, efx->phy_op->mmds, 0); -+ rc = efx_mdio_check_mmds(efx, efx->mdio.mmds, 0); - if (rc) - goto out; - } -@@ -117,23 +113,26 @@ out: - - static int efx_test_nvram(struct efx_nic *efx, struct efx_self_tests *tests) - { -- int rc; -+ int rc = 0; -+ -+ if (efx->type->test_nvram) { -+ rc = efx->type->test_nvram(efx); -+ tests->nvram = rc ? -1 : 1; -+ } - -- rc = falcon_read_nvram(efx, NULL); -- tests->nvram = rc ? -1 : 1; - return rc; - } - - static int efx_test_chip(struct efx_nic *efx, struct efx_self_tests *tests) - { -- int rc; -+ int rc = 0; - -- /* Not supported on A-series silicon */ -- if (falcon_rev(efx) < FALCON_REV_B0) -- return 0; -+ /* Test register access */ -+ if (efx->type->test_registers) { -+ rc = efx->type->test_registers(efx); -+ tests->registers = rc ? -1 : 1; -+ } - -- rc = falcon_test_registers(efx); -- tests->registers = rc ? -1 : 1; - return rc; - } - -@@ -165,7 +164,7 @@ static int efx_test_interrupts(struct efx_nic *efx, - goto success; - } - -- falcon_generate_interrupt(efx); -+ efx_nic_generate_interrupt(efx); - - /* Wait for arrival of test interrupt. */ - EFX_LOG(efx, "waiting for test interrupt\n"); -@@ -177,8 +176,8 @@ static int efx_test_interrupts(struct efx_nic *efx, - return -ETIMEDOUT; - - success: -- EFX_LOG(efx, "test interrupt (mode %d) seen on CPU%d\n", -- efx->interrupt_mode, efx->last_irq_cpu); -+ EFX_LOG(efx, "%s test interrupt seen on CPU%d\n", INT_MODE(efx), -+ efx->last_irq_cpu); - tests->interrupt = 1; - return 0; - } -@@ -203,7 +202,7 @@ static int efx_test_eventq_irq(struct efx_channel *channel, - channel->eventq_magic = 0; - smp_wmb(); - -- falcon_generate_test_event(channel, magic); -+ efx_nic_generate_test_event(channel, magic); - - /* Wait for arrival of interrupt */ - count = 0; -@@ -254,9 +253,6 @@ static int efx_test_phy(struct efx_nic *efx, struct efx_self_tests *tests, - if (!efx->phy_op->run_tests) - return 0; - -- EFX_BUG_ON_PARANOID(efx->phy_op->num_tests == 0 || -- efx->phy_op->num_tests > EFX_MAX_PHY_TESTS); -- - mutex_lock(&efx->mac_lock); - rc = efx->phy_op->run_tests(efx, tests->phy, flags); - mutex_unlock(&efx->mac_lock); -@@ -426,7 +422,7 @@ static int efx_begin_loopback(struct efx_tx_queue *tx_queue) - - if (efx_dev_registered(efx)) - netif_tx_lock_bh(efx->net_dev); -- rc = efx_xmit(efx, tx_queue, skb); -+ rc = efx_enqueue_skb(tx_queue, skb); - if (efx_dev_registered(efx)) - netif_tx_unlock_bh(efx->net_dev); - -@@ -439,7 +435,6 @@ static int efx_begin_loopback(struct efx_tx_queue *tx_queue) - kfree_skb(skb); - return -EPIPE; - } -- efx->net_dev->trans_start = jiffies; - } - - return 0; -@@ -527,7 +522,7 @@ efx_test_loopback(struct efx_tx_queue *tx_queue, - - for (i = 0; i < 3; i++) { - /* Determine how many packets to send */ -- state->packet_count = (efx->type->txd_ring_mask + 1) / 3; -+ state->packet_count = EFX_TXQ_SIZE / 3; - state->packet_count = min(1 << (i << 2), state->packet_count); - state->skbs = kzalloc(sizeof(state->skbs[0]) * - state->packet_count, GFP_KERNEL); -@@ -568,14 +563,49 @@ efx_test_loopback(struct efx_tx_queue *tx_queue, - return 0; - } - -+/* Wait for link up. On Falcon, we would prefer to rely on efx_monitor, but -+ * any contention on the mac lock (via e.g. efx_mac_mcast_work) causes it -+ * to delay and retry. Therefore, it's safer to just poll directly. Wait -+ * for link up and any faults to dissipate. */ -+static int efx_wait_for_link(struct efx_nic *efx) -+{ -+ struct efx_link_state *link_state = &efx->link_state; -+ int count; -+ bool link_up; -+ -+ for (count = 0; count < 40; count++) { -+ schedule_timeout_uninterruptible(HZ / 10); -+ -+ if (efx->type->monitor != NULL) { -+ mutex_lock(&efx->mac_lock); -+ efx->type->monitor(efx); -+ mutex_unlock(&efx->mac_lock); -+ } else { -+ struct efx_channel *channel = &efx->channel[0]; -+ if (channel->work_pending) -+ efx_process_channel_now(channel); -+ } -+ -+ mutex_lock(&efx->mac_lock); -+ link_up = link_state->up; -+ if (link_up) -+ link_up = !efx->mac_op->check_fault(efx); -+ mutex_unlock(&efx->mac_lock); -+ -+ if (link_up) -+ return 0; -+ } -+ -+ return -ETIMEDOUT; -+} -+ - static int efx_test_loopbacks(struct efx_nic *efx, struct efx_self_tests *tests, - unsigned int loopback_modes) - { - enum efx_loopback_mode mode; - struct efx_loopback_state *state; - struct efx_tx_queue *tx_queue; -- bool link_up; -- int count, rc = 0; -+ int rc = 0; - - /* Set the port loopback_selftest member. From this point on - * all received packets will be dropped. Mark the state as -@@ -594,46 +624,23 @@ static int efx_test_loopbacks(struct efx_nic *efx, struct efx_self_tests *tests, - - /* Move the port into the specified loopback mode. */ - state->flush = true; -+ mutex_lock(&efx->mac_lock); - efx->loopback_mode = mode; -- efx_reconfigure_port(efx); -- -- /* Wait for the PHY to signal the link is up. Interrupts -- * are enabled for PHY's using LASI, otherwise we poll() -- * quickly */ -- count = 0; -- do { -- struct efx_channel *channel = &efx->channel[0]; -+ rc = __efx_reconfigure_port(efx); -+ mutex_unlock(&efx->mac_lock); -+ if (rc) { -+ EFX_ERR(efx, "unable to move into %s loopback\n", -+ LOOPBACK_MODE(efx)); -+ goto out; -+ } - -- efx->phy_op->poll(efx); -- schedule_timeout_uninterruptible(HZ / 10); -- if (channel->work_pending) -- efx_process_channel_now(channel); -- /* Wait for PHY events to be processed */ -- flush_workqueue(efx->workqueue); -- rmb(); -- -- /* We need both the phy and xaui links to be ok. -- * rather than relying on the falcon_xmac irq/poll -- * regime, just poll xaui directly */ -- link_up = efx->link_up; -- if (link_up && EFX_IS10G(efx) && -- !falcon_xaui_link_ok(efx)) -- link_up = false; -- -- } while ((++count < 20) && !link_up); -- -- /* The link should now be up. If it isn't, there is no point -- * in attempting a loopback test */ -- if (!link_up) { -+ rc = efx_wait_for_link(efx); -+ if (rc) { - EFX_ERR(efx, "loopback %s never came up\n", - LOOPBACK_MODE(efx)); -- rc = -EIO; - goto out; - } - -- EFX_LOG(efx, "link came up in %s loopback in %d iterations\n", -- LOOPBACK_MODE(efx), count); -- - /* Test every TX queue */ - efx_for_each_tx_queue(tx_queue, efx) { - state->offload_csum = (tx_queue->queue == -@@ -667,7 +674,6 @@ int efx_selftest(struct efx_nic *efx, struct efx_self_tests *tests, - enum efx_loopback_mode loopback_mode = efx->loopback_mode; - int phy_mode = efx->phy_mode; - enum reset_type reset_method = RESET_TYPE_INVISIBLE; -- struct ethtool_cmd ecmd; - struct efx_channel *channel; - int rc_test = 0, rc_reset = 0, rc; - -@@ -720,21 +726,21 @@ int efx_selftest(struct efx_nic *efx, struct efx_self_tests *tests, - mutex_unlock(&efx->mac_lock); - - /* free up all consumers of SRAM (including all the queues) */ -- efx_reset_down(efx, reset_method, &ecmd); -+ efx_reset_down(efx, reset_method); - - rc = efx_test_chip(efx, tests); - if (rc && !rc_test) - rc_test = rc; - - /* reset the chip to recover from the register test */ -- rc_reset = falcon_reset_hw(efx, reset_method); -+ rc_reset = efx->type->reset(efx, reset_method); - - /* Ensure that the phy is powered and out of loopback - * for the bist and loopback tests */ - efx->phy_mode &= ~PHY_MODE_LOW_POWER; - efx->loopback_mode = LOOPBACK_NONE; - -- rc = efx_reset_up(efx, reset_method, &ecmd, rc_reset == 0); -+ rc = efx_reset_up(efx, reset_method, rc_reset == 0); - if (rc && !rc_reset) - rc_reset = rc; - -@@ -753,10 +759,12 @@ int efx_selftest(struct efx_nic *efx, struct efx_self_tests *tests, - rc_test = rc; - - /* restore the PHY to the previous state */ -- efx->loopback_mode = loopback_mode; -+ mutex_lock(&efx->mac_lock); - efx->phy_mode = phy_mode; - efx->port_inhibited = false; -- efx_ethtool_set_settings(efx->net_dev, &ecmd); -+ efx->loopback_mode = loopback_mode; -+ __efx_reconfigure_port(efx); -+ mutex_unlock(&efx->mac_lock); - - return rc_test; - } -diff --git a/drivers/net/sfc/sfe4001.c b/drivers/net/sfc/sfe4001.c -deleted file mode 100644 -index 49eb91b..0000000 ---- a/drivers/net/sfc/sfe4001.c -+++ /dev/null -@@ -1,435 +0,0 @@ --/**************************************************************************** -- * Driver for Solarflare Solarstorm network controllers and boards -- * Copyright 2007-2008 Solarflare Communications Inc. -- * -- * This program is free software; you can redistribute it and/or modify it -- * under the terms of the GNU General Public License version 2 as published -- * by the Free Software Foundation, incorporated herein by reference. -- */ -- --/***************************************************************************** -- * Support for the SFE4001 and SFN4111T NICs. -- * -- * The SFE4001 does not power-up fully at reset due to its high power -- * consumption. We control its power via a PCA9539 I/O expander. -- * Both boards have a MAX6647 temperature monitor which we expose to -- * the lm90 driver. -- * -- * This also provides minimal support for reflashing the PHY, which is -- * initiated by resetting it with the FLASH_CFG_1 pin pulled down. -- * On SFE4001 rev A2 and later this is connected to the 3V3X output of -- * the IO-expander; on the SFN4111T it is connected to Falcon's GPIO3. -- * We represent reflash mode as PHY_MODE_SPECIAL and make it mutually -- * exclusive with the network device being open. -- */ -- --#include --#include --#include "net_driver.h" --#include "efx.h" --#include "phy.h" --#include "boards.h" --#include "falcon.h" --#include "falcon_hwdefs.h" --#include "falcon_io.h" --#include "mac.h" --#include "workarounds.h" -- --/************************************************************************** -- * -- * I2C IO Expander device -- * -- **************************************************************************/ --#define PCA9539 0x74 -- --#define P0_IN 0x00 --#define P0_OUT 0x02 --#define P0_INVERT 0x04 --#define P0_CONFIG 0x06 -- --#define P0_EN_1V0X_LBN 0 --#define P0_EN_1V0X_WIDTH 1 --#define P0_EN_1V2_LBN 1 --#define P0_EN_1V2_WIDTH 1 --#define P0_EN_2V5_LBN 2 --#define P0_EN_2V5_WIDTH 1 --#define P0_EN_3V3X_LBN 3 --#define P0_EN_3V3X_WIDTH 1 --#define P0_EN_5V_LBN 4 --#define P0_EN_5V_WIDTH 1 --#define P0_SHORTEN_JTAG_LBN 5 --#define P0_SHORTEN_JTAG_WIDTH 1 --#define P0_X_TRST_LBN 6 --#define P0_X_TRST_WIDTH 1 --#define P0_DSP_RESET_LBN 7 --#define P0_DSP_RESET_WIDTH 1 -- --#define P1_IN 0x01 --#define P1_OUT 0x03 --#define P1_INVERT 0x05 --#define P1_CONFIG 0x07 -- --#define P1_AFE_PWD_LBN 0 --#define P1_AFE_PWD_WIDTH 1 --#define P1_DSP_PWD25_LBN 1 --#define P1_DSP_PWD25_WIDTH 1 --#define P1_RESERVED_LBN 2 --#define P1_RESERVED_WIDTH 2 --#define P1_SPARE_LBN 4 --#define P1_SPARE_WIDTH 4 -- --/* Temperature Sensor */ --#define MAX664X_REG_RSL 0x02 --#define MAX664X_REG_WLHO 0x0B -- --static void sfe4001_poweroff(struct efx_nic *efx) --{ -- struct i2c_client *ioexp_client = efx->board_info.ioexp_client; -- struct i2c_client *hwmon_client = efx->board_info.hwmon_client; -- -- /* Turn off all power rails and disable outputs */ -- i2c_smbus_write_byte_data(ioexp_client, P0_OUT, 0xff); -- i2c_smbus_write_byte_data(ioexp_client, P1_CONFIG, 0xff); -- i2c_smbus_write_byte_data(ioexp_client, P0_CONFIG, 0xff); -- -- /* Clear any over-temperature alert */ -- i2c_smbus_read_byte_data(hwmon_client, MAX664X_REG_RSL); --} -- --static int sfe4001_poweron(struct efx_nic *efx) --{ -- struct i2c_client *hwmon_client = efx->board_info.hwmon_client; -- struct i2c_client *ioexp_client = efx->board_info.ioexp_client; -- unsigned int i, j; -- int rc; -- u8 out; -- -- /* Clear any previous over-temperature alert */ -- rc = i2c_smbus_read_byte_data(hwmon_client, MAX664X_REG_RSL); -- if (rc < 0) -- return rc; -- -- /* Enable port 0 and port 1 outputs on IO expander */ -- rc = i2c_smbus_write_byte_data(ioexp_client, P0_CONFIG, 0x00); -- if (rc) -- return rc; -- rc = i2c_smbus_write_byte_data(ioexp_client, P1_CONFIG, -- 0xff & ~(1 << P1_SPARE_LBN)); -- if (rc) -- goto fail_on; -- -- /* If PHY power is on, turn it all off and wait 1 second to -- * ensure a full reset. -- */ -- rc = i2c_smbus_read_byte_data(ioexp_client, P0_OUT); -- if (rc < 0) -- goto fail_on; -- out = 0xff & ~((0 << P0_EN_1V2_LBN) | (0 << P0_EN_2V5_LBN) | -- (0 << P0_EN_3V3X_LBN) | (0 << P0_EN_5V_LBN) | -- (0 << P0_EN_1V0X_LBN)); -- if (rc != out) { -- EFX_INFO(efx, "power-cycling PHY\n"); -- rc = i2c_smbus_write_byte_data(ioexp_client, P0_OUT, out); -- if (rc) -- goto fail_on; -- schedule_timeout_uninterruptible(HZ); -- } -- -- for (i = 0; i < 20; ++i) { -- /* Turn on 1.2V, 2.5V, 3.3V and 5V power rails */ -- out = 0xff & ~((1 << P0_EN_1V2_LBN) | (1 << P0_EN_2V5_LBN) | -- (1 << P0_EN_3V3X_LBN) | (1 << P0_EN_5V_LBN) | -- (1 << P0_X_TRST_LBN)); -- if (efx->phy_mode & PHY_MODE_SPECIAL) -- out |= 1 << P0_EN_3V3X_LBN; -- -- rc = i2c_smbus_write_byte_data(ioexp_client, P0_OUT, out); -- if (rc) -- goto fail_on; -- msleep(10); -- -- /* Turn on 1V power rail */ -- out &= ~(1 << P0_EN_1V0X_LBN); -- rc = i2c_smbus_write_byte_data(ioexp_client, P0_OUT, out); -- if (rc) -- goto fail_on; -- -- EFX_INFO(efx, "waiting for DSP boot (attempt %d)...\n", i); -- -- /* In flash config mode, DSP does not turn on AFE, so -- * just wait 1 second. -- */ -- if (efx->phy_mode & PHY_MODE_SPECIAL) { -- schedule_timeout_uninterruptible(HZ); -- return 0; -- } -- -- for (j = 0; j < 10; ++j) { -- msleep(100); -- -- /* Check DSP has asserted AFE power line */ -- rc = i2c_smbus_read_byte_data(ioexp_client, P1_IN); -- if (rc < 0) -- goto fail_on; -- if (rc & (1 << P1_AFE_PWD_LBN)) -- return 0; -- } -- } -- -- EFX_INFO(efx, "timed out waiting for DSP boot\n"); -- rc = -ETIMEDOUT; --fail_on: -- sfe4001_poweroff(efx); -- return rc; --} -- --static int sfn4111t_reset(struct efx_nic *efx) --{ -- efx_oword_t reg; -- -- /* GPIO 3 and the GPIO register are shared with I2C, so block that */ -- i2c_lock_adapter(&efx->i2c_adap); -- -- /* Pull RST_N (GPIO 2) low then let it up again, setting the -- * FLASH_CFG_1 strap (GPIO 3) appropriately. Only change the -- * output enables; the output levels should always be 0 (low) -- * and we rely on external pull-ups. */ -- falcon_read(efx, ®, GPIO_CTL_REG_KER); -- EFX_SET_OWORD_FIELD(reg, GPIO2_OEN, true); -- falcon_write(efx, ®, GPIO_CTL_REG_KER); -- msleep(1000); -- EFX_SET_OWORD_FIELD(reg, GPIO2_OEN, false); -- EFX_SET_OWORD_FIELD(reg, GPIO3_OEN, -- !!(efx->phy_mode & PHY_MODE_SPECIAL)); -- falcon_write(efx, ®, GPIO_CTL_REG_KER); -- msleep(1); -- -- i2c_unlock_adapter(&efx->i2c_adap); -- -- ssleep(1); -- return 0; --} -- --static ssize_t show_phy_flash_cfg(struct device *dev, -- struct device_attribute *attr, char *buf) --{ -- struct efx_nic *efx = pci_get_drvdata(to_pci_dev(dev)); -- return sprintf(buf, "%d\n", !!(efx->phy_mode & PHY_MODE_SPECIAL)); --} -- --static ssize_t set_phy_flash_cfg(struct device *dev, -- struct device_attribute *attr, -- const char *buf, size_t count) --{ -- struct efx_nic *efx = pci_get_drvdata(to_pci_dev(dev)); -- enum efx_phy_mode old_mode, new_mode; -- int err; -- -- rtnl_lock(); -- old_mode = efx->phy_mode; -- if (count == 0 || *buf == '0') -- new_mode = old_mode & ~PHY_MODE_SPECIAL; -- else -- new_mode = PHY_MODE_SPECIAL; -- if (old_mode == new_mode) { -- err = 0; -- } else if (efx->state != STATE_RUNNING || netif_running(efx->net_dev)) { -- err = -EBUSY; -- } else { -- /* Reset the PHY, reconfigure the MAC and enable/disable -- * MAC stats accordingly. */ -- efx->phy_mode = new_mode; -- if (new_mode & PHY_MODE_SPECIAL) -- efx_stats_disable(efx); -- if (efx->board_info.type == EFX_BOARD_SFE4001) -- err = sfe4001_poweron(efx); -- else -- err = sfn4111t_reset(efx); -- efx_reconfigure_port(efx); -- if (!(new_mode & PHY_MODE_SPECIAL)) -- efx_stats_enable(efx); -- } -- rtnl_unlock(); -- -- return err ? err : count; --} -- --static DEVICE_ATTR(phy_flash_cfg, 0644, show_phy_flash_cfg, set_phy_flash_cfg); -- --static void sfe4001_fini(struct efx_nic *efx) --{ -- EFX_INFO(efx, "%s\n", __func__); -- -- device_remove_file(&efx->pci_dev->dev, &dev_attr_phy_flash_cfg); -- sfe4001_poweroff(efx); -- i2c_unregister_device(efx->board_info.ioexp_client); -- i2c_unregister_device(efx->board_info.hwmon_client); --} -- --static int sfe4001_check_hw(struct efx_nic *efx) --{ -- s32 status; -- -- /* If XAUI link is up then do not monitor */ -- if (EFX_WORKAROUND_7884(efx) && efx->mac_up) -- return 0; -- -- /* Check the powered status of the PHY. Lack of power implies that -- * the MAX6647 has shut down power to it, probably due to a temp. -- * alarm. Reading the power status rather than the MAX6647 status -- * directly because the later is read-to-clear and would thus -- * start to power up the PHY again when polled, causing us to blip -- * the power undesirably. -- * We know we can read from the IO expander because we did -- * it during power-on. Assume failure now is bad news. */ -- status = i2c_smbus_read_byte_data(efx->board_info.ioexp_client, P1_IN); -- if (status >= 0 && -- (status & ((1 << P1_AFE_PWD_LBN) | (1 << P1_DSP_PWD25_LBN))) != 0) -- return 0; -- -- /* Use board power control, not PHY power control */ -- sfe4001_poweroff(efx); -- efx->phy_mode = PHY_MODE_OFF; -- -- return (status < 0) ? -EIO : -ERANGE; --} -- --static struct i2c_board_info sfe4001_hwmon_info = { -- I2C_BOARD_INFO("max6647", 0x4e), --}; -- --/* This board uses an I2C expander to provider power to the PHY, which needs to -- * be turned on before the PHY can be used. -- * Context: Process context, rtnl lock held -- */ --int sfe4001_init(struct efx_nic *efx) --{ -- int rc; -- --#if defined(CONFIG_SENSORS_LM90) || defined(CONFIG_SENSORS_LM90_MODULE) -- efx->board_info.hwmon_client = -- i2c_new_device(&efx->i2c_adap, &sfe4001_hwmon_info); --#else -- efx->board_info.hwmon_client = -- i2c_new_dummy(&efx->i2c_adap, sfe4001_hwmon_info.addr); --#endif -- if (!efx->board_info.hwmon_client) -- return -EIO; -- -- /* Raise board/PHY high limit from 85 to 90 degrees Celsius */ -- rc = i2c_smbus_write_byte_data(efx->board_info.hwmon_client, -- MAX664X_REG_WLHO, 90); -- if (rc) -- goto fail_hwmon; -- -- efx->board_info.ioexp_client = i2c_new_dummy(&efx->i2c_adap, PCA9539); -- if (!efx->board_info.ioexp_client) { -- rc = -EIO; -- goto fail_hwmon; -- } -- -- /* 10Xpress has fixed-function LED pins, so there is no board-specific -- * blink code. */ -- efx->board_info.blink = tenxpress_phy_blink; -- -- efx->board_info.monitor = sfe4001_check_hw; -- efx->board_info.fini = sfe4001_fini; -- -- if (efx->phy_mode & PHY_MODE_SPECIAL) { -- /* PHY won't generate a 156.25 MHz clock and MAC stats fetch -- * will fail. */ -- efx_stats_disable(efx); -- } -- rc = sfe4001_poweron(efx); -- if (rc) -- goto fail_ioexp; -- -- rc = device_create_file(&efx->pci_dev->dev, &dev_attr_phy_flash_cfg); -- if (rc) -- goto fail_on; -- -- EFX_INFO(efx, "PHY is powered on\n"); -- return 0; -- --fail_on: -- sfe4001_poweroff(efx); --fail_ioexp: -- i2c_unregister_device(efx->board_info.ioexp_client); --fail_hwmon: -- i2c_unregister_device(efx->board_info.hwmon_client); -- return rc; --} -- --static int sfn4111t_check_hw(struct efx_nic *efx) --{ -- s32 status; -- -- /* If XAUI link is up then do not monitor */ -- if (EFX_WORKAROUND_7884(efx) && efx->mac_up) -- return 0; -- -- /* Test LHIGH, RHIGH, FAULT, EOT and IOT alarms */ -- status = i2c_smbus_read_byte_data(efx->board_info.hwmon_client, -- MAX664X_REG_RSL); -- if (status < 0) -- return -EIO; -- if (status & 0x57) -- return -ERANGE; -- return 0; --} -- --static void sfn4111t_fini(struct efx_nic *efx) --{ -- EFX_INFO(efx, "%s\n", __func__); -- -- device_remove_file(&efx->pci_dev->dev, &dev_attr_phy_flash_cfg); -- i2c_unregister_device(efx->board_info.hwmon_client); --} -- --static struct i2c_board_info sfn4111t_a0_hwmon_info = { -- I2C_BOARD_INFO("max6647", 0x4e), --}; -- --static struct i2c_board_info sfn4111t_r5_hwmon_info = { -- I2C_BOARD_INFO("max6646", 0x4d), --}; -- --int sfn4111t_init(struct efx_nic *efx) --{ -- int i = 0; -- int rc; -- -- efx->board_info.hwmon_client = -- i2c_new_device(&efx->i2c_adap, -- (efx->board_info.minor < 5) ? -- &sfn4111t_a0_hwmon_info : -- &sfn4111t_r5_hwmon_info); -- if (!efx->board_info.hwmon_client) -- return -EIO; -- -- efx->board_info.blink = tenxpress_phy_blink; -- efx->board_info.monitor = sfn4111t_check_hw; -- efx->board_info.fini = sfn4111t_fini; -- -- rc = device_create_file(&efx->pci_dev->dev, &dev_attr_phy_flash_cfg); -- if (rc) -- goto fail_hwmon; -- -- do { -- if (efx->phy_mode & PHY_MODE_SPECIAL) { -- /* PHY may not generate a 156.25 MHz clock and MAC -- * stats fetch will fail. */ -- efx_stats_disable(efx); -- sfn4111t_reset(efx); -- } -- rc = sft9001_wait_boot(efx); -- if (rc == 0) -- return 0; -- efx->phy_mode = PHY_MODE_SPECIAL; -- } while (rc == -EINVAL && ++i < 2); -- -- device_remove_file(&efx->pci_dev->dev, &dev_attr_phy_flash_cfg); --fail_hwmon: -- i2c_unregister_device(efx->board_info.hwmon_client); -- return rc; --} -diff --git a/drivers/net/sfc/siena.c b/drivers/net/sfc/siena.c -new file mode 100644 -index 0000000..de07a4f ---- /dev/null -+++ b/drivers/net/sfc/siena.c -@@ -0,0 +1,604 @@ -+/**************************************************************************** -+ * Driver for Solarflare Solarstorm network controllers and boards -+ * Copyright 2005-2006 Fen Systems Ltd. -+ * Copyright 2006-2009 Solarflare Communications Inc. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License version 2 as published -+ * by the Free Software Foundation, incorporated herein by reference. -+ */ -+ -+#include -+#include -+#include -+#include -+#include "net_driver.h" -+#include "bitfield.h" -+#include "efx.h" -+#include "nic.h" -+#include "mac.h" -+#include "spi.h" -+#include "regs.h" -+#include "io.h" -+#include "phy.h" -+#include "workarounds.h" -+#include "mcdi.h" -+#include "mcdi_pcol.h" -+ -+/* Hardware control for SFC9000 family including SFL9021 (aka Siena). */ -+ -+static void siena_init_wol(struct efx_nic *efx); -+ -+ -+static void siena_push_irq_moderation(struct efx_channel *channel) -+{ -+ efx_dword_t timer_cmd; -+ -+ if (channel->irq_moderation) -+ EFX_POPULATE_DWORD_2(timer_cmd, -+ FRF_CZ_TC_TIMER_MODE, -+ FFE_CZ_TIMER_MODE_INT_HLDOFF, -+ FRF_CZ_TC_TIMER_VAL, -+ channel->irq_moderation - 1); -+ else -+ EFX_POPULATE_DWORD_2(timer_cmd, -+ FRF_CZ_TC_TIMER_MODE, -+ FFE_CZ_TIMER_MODE_DIS, -+ FRF_CZ_TC_TIMER_VAL, 0); -+ efx_writed_page_locked(channel->efx, &timer_cmd, FR_BZ_TIMER_COMMAND_P0, -+ channel->channel); -+} -+ -+static void siena_push_multicast_hash(struct efx_nic *efx) -+{ -+ WARN_ON(!mutex_is_locked(&efx->mac_lock)); -+ -+ efx_mcdi_rpc(efx, MC_CMD_SET_MCAST_HASH, -+ efx->multicast_hash.byte, sizeof(efx->multicast_hash), -+ NULL, 0, NULL); -+} -+ -+static int siena_mdio_write(struct net_device *net_dev, -+ int prtad, int devad, u16 addr, u16 value) -+{ -+ struct efx_nic *efx = netdev_priv(net_dev); -+ uint32_t status; -+ int rc; -+ -+ rc = efx_mcdi_mdio_write(efx, efx->mdio_bus, prtad, devad, -+ addr, value, &status); -+ if (rc) -+ return rc; -+ if (status != MC_CMD_MDIO_STATUS_GOOD) -+ return -EIO; -+ -+ return 0; -+} -+ -+static int siena_mdio_read(struct net_device *net_dev, -+ int prtad, int devad, u16 addr) -+{ -+ struct efx_nic *efx = netdev_priv(net_dev); -+ uint16_t value; -+ uint32_t status; -+ int rc; -+ -+ rc = efx_mcdi_mdio_read(efx, efx->mdio_bus, prtad, devad, -+ addr, &value, &status); -+ if (rc) -+ return rc; -+ if (status != MC_CMD_MDIO_STATUS_GOOD) -+ return -EIO; -+ -+ return (int)value; -+} -+ -+/* This call is responsible for hooking in the MAC and PHY operations */ -+static int siena_probe_port(struct efx_nic *efx) -+{ -+ int rc; -+ -+ /* Hook in PHY operations table */ -+ efx->phy_op = &efx_mcdi_phy_ops; -+ -+ /* Set up MDIO structure for PHY */ -+ efx->mdio.mode_support = MDIO_SUPPORTS_C45 | MDIO_EMULATE_C22; -+ efx->mdio.mdio_read = siena_mdio_read; -+ efx->mdio.mdio_write = siena_mdio_write; -+ -+ /* Fill out MDIO structure and loopback modes */ -+ rc = efx->phy_op->probe(efx); -+ if (rc != 0) -+ return rc; -+ -+ /* Initial assumption */ -+ efx->link_state.speed = 10000; -+ efx->link_state.fd = true; -+ efx->wanted_fc = EFX_FC_RX | EFX_FC_TX; -+ -+ /* Allocate buffer for stats */ -+ rc = efx_nic_alloc_buffer(efx, &efx->stats_buffer, -+ MC_CMD_MAC_NSTATS * sizeof(u64)); -+ if (rc) -+ return rc; -+ EFX_LOG(efx, "stats buffer at %llx (virt %p phys %llx)\n", -+ (u64)efx->stats_buffer.dma_addr, -+ efx->stats_buffer.addr, -+ (u64)virt_to_phys(efx->stats_buffer.addr)); -+ -+ efx_mcdi_mac_stats(efx, efx->stats_buffer.dma_addr, 0, 0, 1); -+ -+ return 0; -+} -+ -+void siena_remove_port(struct efx_nic *efx) -+{ -+ efx_nic_free_buffer(efx, &efx->stats_buffer); -+} -+ -+static const struct efx_nic_register_test siena_register_tests[] = { -+ { FR_AZ_ADR_REGION, -+ EFX_OWORD32(0x0001FFFF, 0x0001FFFF, 0x0001FFFF, 0x0001FFFF) }, -+ { FR_CZ_USR_EV_CFG, -+ EFX_OWORD32(0x000103FF, 0x00000000, 0x00000000, 0x00000000) }, -+ { FR_AZ_RX_CFG, -+ EFX_OWORD32(0xFFFFFFFE, 0xFFFFFFFF, 0x0003FFFF, 0x00000000) }, -+ { FR_AZ_TX_CFG, -+ EFX_OWORD32(0x7FFF0037, 0xFFFF8000, 0xFFFFFFFF, 0x03FFFFFF) }, -+ { FR_AZ_TX_RESERVED, -+ EFX_OWORD32(0xFFFEFE80, 0x1FFFFFFF, 0x020000FE, 0x007FFFFF) }, -+ { FR_AZ_SRM_TX_DC_CFG, -+ EFX_OWORD32(0x001FFFFF, 0x00000000, 0x00000000, 0x00000000) }, -+ { FR_AZ_RX_DC_CFG, -+ EFX_OWORD32(0x00000003, 0x00000000, 0x00000000, 0x00000000) }, -+ { FR_AZ_RX_DC_PF_WM, -+ EFX_OWORD32(0x000003FF, 0x00000000, 0x00000000, 0x00000000) }, -+ { FR_BZ_DP_CTRL, -+ EFX_OWORD32(0x00000FFF, 0x00000000, 0x00000000, 0x00000000) }, -+ { FR_BZ_RX_RSS_TKEY, -+ EFX_OWORD32(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF) }, -+ { FR_CZ_RX_RSS_IPV6_REG1, -+ EFX_OWORD32(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF) }, -+ { FR_CZ_RX_RSS_IPV6_REG2, -+ EFX_OWORD32(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF) }, -+ { FR_CZ_RX_RSS_IPV6_REG3, -+ EFX_OWORD32(0xFFFFFFFF, 0xFFFFFFFF, 0x00000007, 0x00000000) }, -+}; -+ -+static int siena_test_registers(struct efx_nic *efx) -+{ -+ return efx_nic_test_registers(efx, siena_register_tests, -+ ARRAY_SIZE(siena_register_tests)); -+} -+ -+/************************************************************************** -+ * -+ * Device reset -+ * -+ ************************************************************************** -+ */ -+ -+static int siena_reset_hw(struct efx_nic *efx, enum reset_type method) -+{ -+ -+ if (method == RESET_TYPE_WORLD) -+ return efx_mcdi_reset_mc(efx); -+ else -+ return efx_mcdi_reset_port(efx); -+} -+ -+static int siena_probe_nvconfig(struct efx_nic *efx) -+{ -+ int rc; -+ -+ rc = efx_mcdi_get_board_cfg(efx, efx->mac_address, NULL); -+ if (rc) -+ return rc; -+ -+ return 0; -+} -+ -+static int siena_probe_nic(struct efx_nic *efx) -+{ -+ struct siena_nic_data *nic_data; -+ bool already_attached = 0; -+ int rc; -+ -+ /* Allocate storage for hardware specific data */ -+ nic_data = kzalloc(sizeof(struct siena_nic_data), GFP_KERNEL); -+ if (!nic_data) -+ return -ENOMEM; -+ efx->nic_data = nic_data; -+ -+ if (efx_nic_fpga_ver(efx) != 0) { -+ EFX_ERR(efx, "Siena FPGA not supported\n"); -+ rc = -ENODEV; -+ goto fail1; -+ } -+ -+ efx_mcdi_init(efx); -+ -+ /* Recover from a failed assertion before probing */ -+ rc = efx_mcdi_handle_assertion(efx); -+ if (rc) -+ goto fail1; -+ -+ rc = efx_mcdi_fwver(efx, &nic_data->fw_version, &nic_data->fw_build); -+ if (rc) { -+ EFX_ERR(efx, "Failed to read MCPU firmware version - " -+ "rc %d\n", rc); -+ goto fail1; /* MCPU absent? */ -+ } -+ -+ /* Let the BMC know that the driver is now in charge of link and -+ * filter settings. We must do this before we reset the NIC */ -+ rc = efx_mcdi_drv_attach(efx, true, &already_attached); -+ if (rc) { -+ EFX_ERR(efx, "Unable to register driver with MCPU\n"); -+ goto fail2; -+ } -+ if (already_attached) -+ /* Not a fatal error */ -+ EFX_ERR(efx, "Host already registered with MCPU\n"); -+ -+ /* Now we can reset the NIC */ -+ rc = siena_reset_hw(efx, RESET_TYPE_ALL); -+ if (rc) { -+ EFX_ERR(efx, "failed to reset NIC\n"); -+ goto fail3; -+ } -+ -+ siena_init_wol(efx); -+ -+ /* Allocate memory for INT_KER */ -+ rc = efx_nic_alloc_buffer(efx, &efx->irq_status, sizeof(efx_oword_t)); -+ if (rc) -+ goto fail4; -+ BUG_ON(efx->irq_status.dma_addr & 0x0f); -+ -+ EFX_LOG(efx, "INT_KER at %llx (virt %p phys %llx)\n", -+ (unsigned long long)efx->irq_status.dma_addr, -+ efx->irq_status.addr, -+ (unsigned long long)virt_to_phys(efx->irq_status.addr)); -+ -+ /* Read in the non-volatile configuration */ -+ rc = siena_probe_nvconfig(efx); -+ if (rc == -EINVAL) { -+ EFX_ERR(efx, "NVRAM is invalid therefore using defaults\n"); -+ efx->phy_type = PHY_TYPE_NONE; -+ efx->mdio.prtad = MDIO_PRTAD_NONE; -+ } else if (rc) { -+ goto fail5; -+ } -+ -+ return 0; -+ -+fail5: -+ efx_nic_free_buffer(efx, &efx->irq_status); -+fail4: -+fail3: -+ efx_mcdi_drv_attach(efx, false, NULL); -+fail2: -+fail1: -+ kfree(efx->nic_data); -+ return rc; -+} -+ -+/* This call performs hardware-specific global initialisation, such as -+ * defining the descriptor cache sizes and number of RSS channels. -+ * It does not set up any buffers, descriptor rings or event queues. -+ */ -+static int siena_init_nic(struct efx_nic *efx) -+{ -+ efx_oword_t temp; -+ int rc; -+ -+ /* Recover from a failed assertion post-reset */ -+ rc = efx_mcdi_handle_assertion(efx); -+ if (rc) -+ return rc; -+ -+ /* Squash TX of packets of 16 bytes or less */ -+ efx_reado(efx, &temp, FR_AZ_TX_RESERVED); -+ EFX_SET_OWORD_FIELD(temp, FRF_BZ_TX_FLUSH_MIN_LEN_EN, 1); -+ efx_writeo(efx, &temp, FR_AZ_TX_RESERVED); -+ -+ /* Do not enable TX_NO_EOP_DISC_EN, since it limits packets to 16 -+ * descriptors (which is bad). -+ */ -+ efx_reado(efx, &temp, FR_AZ_TX_CFG); -+ EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_NO_EOP_DISC_EN, 0); -+ EFX_SET_OWORD_FIELD(temp, FRF_CZ_TX_FILTER_EN_BIT, 1); -+ efx_writeo(efx, &temp, FR_AZ_TX_CFG); -+ -+ efx_reado(efx, &temp, FR_AZ_RX_CFG); -+ EFX_SET_OWORD_FIELD(temp, FRF_BZ_RX_DESC_PUSH_EN, 0); -+ EFX_SET_OWORD_FIELD(temp, FRF_BZ_RX_INGR_EN, 1); -+ efx_writeo(efx, &temp, FR_AZ_RX_CFG); -+ -+ if (efx_nic_rx_xoff_thresh >= 0 || efx_nic_rx_xon_thresh >= 0) -+ /* No MCDI operation has been defined to set thresholds */ -+ EFX_ERR(efx, "ignoring RX flow control thresholds\n"); -+ -+ /* Enable event logging */ -+ rc = efx_mcdi_log_ctrl(efx, true, false, 0); -+ if (rc) -+ return rc; -+ -+ /* Set destination of both TX and RX Flush events */ -+ EFX_POPULATE_OWORD_1(temp, FRF_BZ_FLS_EVQ_ID, 0); -+ efx_writeo(efx, &temp, FR_BZ_DP_CTRL); -+ -+ EFX_POPULATE_OWORD_1(temp, FRF_CZ_USREV_DIS, 1); -+ efx_writeo(efx, &temp, FR_CZ_USR_EV_CFG); -+ -+ efx_nic_init_common(efx); -+ return 0; -+} -+ -+static void siena_remove_nic(struct efx_nic *efx) -+{ -+ efx_nic_free_buffer(efx, &efx->irq_status); -+ -+ siena_reset_hw(efx, RESET_TYPE_ALL); -+ -+ /* Relinquish the device back to the BMC */ -+ if (efx_nic_has_mc(efx)) -+ efx_mcdi_drv_attach(efx, false, NULL); -+ -+ /* Tear down the private nic state */ -+ kfree(efx->nic_data); -+ efx->nic_data = NULL; -+} -+ -+#define STATS_GENERATION_INVALID ((u64)(-1)) -+ -+static int siena_try_update_nic_stats(struct efx_nic *efx) -+{ -+ u64 *dma_stats; -+ struct efx_mac_stats *mac_stats; -+ u64 generation_start; -+ u64 generation_end; -+ -+ mac_stats = &efx->mac_stats; -+ dma_stats = (u64 *)efx->stats_buffer.addr; -+ -+ generation_end = dma_stats[MC_CMD_MAC_GENERATION_END]; -+ if (generation_end == STATS_GENERATION_INVALID) -+ return 0; -+ rmb(); -+ -+#define MAC_STAT(M, D) \ -+ mac_stats->M = dma_stats[MC_CMD_MAC_ ## D] -+ -+ MAC_STAT(tx_bytes, TX_BYTES); -+ MAC_STAT(tx_bad_bytes, TX_BAD_BYTES); -+ mac_stats->tx_good_bytes = (mac_stats->tx_bytes - -+ mac_stats->tx_bad_bytes); -+ MAC_STAT(tx_packets, TX_PKTS); -+ MAC_STAT(tx_bad, TX_BAD_FCS_PKTS); -+ MAC_STAT(tx_pause, TX_PAUSE_PKTS); -+ MAC_STAT(tx_control, TX_CONTROL_PKTS); -+ MAC_STAT(tx_unicast, TX_UNICAST_PKTS); -+ MAC_STAT(tx_multicast, TX_MULTICAST_PKTS); -+ MAC_STAT(tx_broadcast, TX_BROADCAST_PKTS); -+ MAC_STAT(tx_lt64, TX_LT64_PKTS); -+ MAC_STAT(tx_64, TX_64_PKTS); -+ MAC_STAT(tx_65_to_127, TX_65_TO_127_PKTS); -+ MAC_STAT(tx_128_to_255, TX_128_TO_255_PKTS); -+ MAC_STAT(tx_256_to_511, TX_256_TO_511_PKTS); -+ MAC_STAT(tx_512_to_1023, TX_512_TO_1023_PKTS); -+ MAC_STAT(tx_1024_to_15xx, TX_1024_TO_15XX_PKTS); -+ MAC_STAT(tx_15xx_to_jumbo, TX_15XX_TO_JUMBO_PKTS); -+ MAC_STAT(tx_gtjumbo, TX_GTJUMBO_PKTS); -+ mac_stats->tx_collision = 0; -+ MAC_STAT(tx_single_collision, TX_SINGLE_COLLISION_PKTS); -+ MAC_STAT(tx_multiple_collision, TX_MULTIPLE_COLLISION_PKTS); -+ MAC_STAT(tx_excessive_collision, TX_EXCESSIVE_COLLISION_PKTS); -+ MAC_STAT(tx_deferred, TX_DEFERRED_PKTS); -+ MAC_STAT(tx_late_collision, TX_LATE_COLLISION_PKTS); -+ mac_stats->tx_collision = (mac_stats->tx_single_collision + -+ mac_stats->tx_multiple_collision + -+ mac_stats->tx_excessive_collision + -+ mac_stats->tx_late_collision); -+ MAC_STAT(tx_excessive_deferred, TX_EXCESSIVE_DEFERRED_PKTS); -+ MAC_STAT(tx_non_tcpudp, TX_NON_TCPUDP_PKTS); -+ MAC_STAT(tx_mac_src_error, TX_MAC_SRC_ERR_PKTS); -+ MAC_STAT(tx_ip_src_error, TX_IP_SRC_ERR_PKTS); -+ MAC_STAT(rx_bytes, RX_BYTES); -+ MAC_STAT(rx_bad_bytes, RX_BAD_BYTES); -+ mac_stats->rx_good_bytes = (mac_stats->rx_bytes - -+ mac_stats->rx_bad_bytes); -+ MAC_STAT(rx_packets, RX_PKTS); -+ MAC_STAT(rx_good, RX_GOOD_PKTS); -+ mac_stats->rx_bad = mac_stats->rx_packets - mac_stats->rx_good; -+ MAC_STAT(rx_pause, RX_PAUSE_PKTS); -+ MAC_STAT(rx_control, RX_CONTROL_PKTS); -+ MAC_STAT(rx_unicast, RX_UNICAST_PKTS); -+ MAC_STAT(rx_multicast, RX_MULTICAST_PKTS); -+ MAC_STAT(rx_broadcast, RX_BROADCAST_PKTS); -+ MAC_STAT(rx_lt64, RX_UNDERSIZE_PKTS); -+ MAC_STAT(rx_64, RX_64_PKTS); -+ MAC_STAT(rx_65_to_127, RX_65_TO_127_PKTS); -+ MAC_STAT(rx_128_to_255, RX_128_TO_255_PKTS); -+ MAC_STAT(rx_256_to_511, RX_256_TO_511_PKTS); -+ MAC_STAT(rx_512_to_1023, RX_512_TO_1023_PKTS); -+ MAC_STAT(rx_1024_to_15xx, RX_1024_TO_15XX_PKTS); -+ MAC_STAT(rx_15xx_to_jumbo, RX_15XX_TO_JUMBO_PKTS); -+ MAC_STAT(rx_gtjumbo, RX_GTJUMBO_PKTS); -+ mac_stats->rx_bad_lt64 = 0; -+ mac_stats->rx_bad_64_to_15xx = 0; -+ mac_stats->rx_bad_15xx_to_jumbo = 0; -+ MAC_STAT(rx_bad_gtjumbo, RX_JABBER_PKTS); -+ MAC_STAT(rx_overflow, RX_OVERFLOW_PKTS); -+ mac_stats->rx_missed = 0; -+ MAC_STAT(rx_false_carrier, RX_FALSE_CARRIER_PKTS); -+ MAC_STAT(rx_symbol_error, RX_SYMBOL_ERROR_PKTS); -+ MAC_STAT(rx_align_error, RX_ALIGN_ERROR_PKTS); -+ MAC_STAT(rx_length_error, RX_LENGTH_ERROR_PKTS); -+ MAC_STAT(rx_internal_error, RX_INTERNAL_ERROR_PKTS); -+ mac_stats->rx_good_lt64 = 0; -+ -+ efx->n_rx_nodesc_drop_cnt = dma_stats[MC_CMD_MAC_RX_NODESC_DROPS]; -+ -+#undef MAC_STAT -+ -+ rmb(); -+ generation_start = dma_stats[MC_CMD_MAC_GENERATION_START]; -+ if (generation_end != generation_start) -+ return -EAGAIN; -+ -+ return 0; -+} -+ -+static void siena_update_nic_stats(struct efx_nic *efx) -+{ -+ while (siena_try_update_nic_stats(efx) == -EAGAIN) -+ cpu_relax(); -+} -+ -+static void siena_start_nic_stats(struct efx_nic *efx) -+{ -+ u64 *dma_stats = (u64 *)efx->stats_buffer.addr; -+ -+ dma_stats[MC_CMD_MAC_GENERATION_END] = STATS_GENERATION_INVALID; -+ -+ efx_mcdi_mac_stats(efx, efx->stats_buffer.dma_addr, -+ MC_CMD_MAC_NSTATS * sizeof(u64), 1, 0); -+} -+ -+static void siena_stop_nic_stats(struct efx_nic *efx) -+{ -+ efx_mcdi_mac_stats(efx, efx->stats_buffer.dma_addr, 0, 0, 0); -+} -+ -+void siena_print_fwver(struct efx_nic *efx, char *buf, size_t len) -+{ -+ struct siena_nic_data *nic_data = efx->nic_data; -+ snprintf(buf, len, "%u.%u.%u.%u", -+ (unsigned int)(nic_data->fw_version >> 48), -+ (unsigned int)(nic_data->fw_version >> 32 & 0xffff), -+ (unsigned int)(nic_data->fw_version >> 16 & 0xffff), -+ (unsigned int)(nic_data->fw_version & 0xffff)); -+} -+ -+/************************************************************************** -+ * -+ * Wake on LAN -+ * -+ ************************************************************************** -+ */ -+ -+static void siena_get_wol(struct efx_nic *efx, struct ethtool_wolinfo *wol) -+{ -+ struct siena_nic_data *nic_data = efx->nic_data; -+ -+ wol->supported = WAKE_MAGIC; -+ if (nic_data->wol_filter_id != -1) -+ wol->wolopts = WAKE_MAGIC; -+ else -+ wol->wolopts = 0; -+ memset(&wol->sopass, 0, sizeof(wol->sopass)); -+} -+ -+ -+static int siena_set_wol(struct efx_nic *efx, u32 type) -+{ -+ struct siena_nic_data *nic_data = efx->nic_data; -+ int rc; -+ -+ if (type & ~WAKE_MAGIC) -+ return -EINVAL; -+ -+ if (type & WAKE_MAGIC) { -+ if (nic_data->wol_filter_id != -1) -+ efx_mcdi_wol_filter_remove(efx, -+ nic_data->wol_filter_id); -+ rc = efx_mcdi_wol_filter_set_magic(efx, efx->mac_address, -+ &nic_data->wol_filter_id); -+ if (rc) -+ goto fail; -+ -+ pci_wake_from_d3(efx->pci_dev, true); -+ } else { -+ rc = efx_mcdi_wol_filter_reset(efx); -+ nic_data->wol_filter_id = -1; -+ pci_wake_from_d3(efx->pci_dev, false); -+ if (rc) -+ goto fail; -+ } -+ -+ return 0; -+ fail: -+ EFX_ERR(efx, "%s failed: type=%d rc=%d\n", __func__, type, rc); -+ return rc; -+} -+ -+ -+static void siena_init_wol(struct efx_nic *efx) -+{ -+ struct siena_nic_data *nic_data = efx->nic_data; -+ int rc; -+ -+ rc = efx_mcdi_wol_filter_get_magic(efx, &nic_data->wol_filter_id); -+ -+ if (rc != 0) { -+ /* If it failed, attempt to get into a synchronised -+ * state with MC by resetting any set WoL filters */ -+ efx_mcdi_wol_filter_reset(efx); -+ nic_data->wol_filter_id = -1; -+ } else if (nic_data->wol_filter_id != -1) { -+ pci_wake_from_d3(efx->pci_dev, true); -+ } -+} -+ -+ -+/************************************************************************** -+ * -+ * Revision-dependent attributes used by efx.c and nic.c -+ * -+ ************************************************************************** -+ */ -+ -+struct efx_nic_type siena_a0_nic_type = { -+ .probe = siena_probe_nic, -+ .remove = siena_remove_nic, -+ .init = siena_init_nic, -+ .fini = efx_port_dummy_op_void, -+ .monitor = NULL, -+ .reset = siena_reset_hw, -+ .probe_port = siena_probe_port, -+ .remove_port = siena_remove_port, -+ .prepare_flush = efx_port_dummy_op_void, -+ .update_stats = siena_update_nic_stats, -+ .start_stats = siena_start_nic_stats, -+ .stop_stats = siena_stop_nic_stats, -+ .set_id_led = efx_mcdi_set_id_led, -+ .push_irq_moderation = siena_push_irq_moderation, -+ .push_multicast_hash = siena_push_multicast_hash, -+ .reconfigure_port = efx_mcdi_phy_reconfigure, -+ .get_wol = siena_get_wol, -+ .set_wol = siena_set_wol, -+ .resume_wol = siena_init_wol, -+ .test_registers = siena_test_registers, -+ .default_mac_ops = &efx_mcdi_mac_operations, -+ -+ .revision = EFX_REV_SIENA_A0, -+ .mem_map_size = (FR_CZ_MC_TREG_SMEM + -+ FR_CZ_MC_TREG_SMEM_STEP * FR_CZ_MC_TREG_SMEM_ROWS), -+ .txd_ptr_tbl_base = FR_BZ_TX_DESC_PTR_TBL, -+ .rxd_ptr_tbl_base = FR_BZ_RX_DESC_PTR_TBL, -+ .buf_tbl_base = FR_BZ_BUF_FULL_TBL, -+ .evq_ptr_tbl_base = FR_BZ_EVQ_PTR_TBL, -+ .evq_rptr_tbl_base = FR_BZ_EVQ_RPTR, -+ .max_dma_mask = DMA_BIT_MASK(FSF_AZ_TX_KER_BUF_ADDR_WIDTH), -+ .rx_buffer_padding = 0, -+ .max_interrupt_mode = EFX_INT_MODE_MSIX, -+ .phys_addr_channels = 32, /* Hardware limit is 64, but the legacy -+ * interrupt handler only supports 32 -+ * channels */ -+ .tx_dc_base = 0x88000, -+ .rx_dc_base = 0x68000, -+ .offload_features = NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM, -+ .reset_world_flags = ETH_RESET_MGMT << ETH_RESET_SHARED_SHIFT, -+}; -diff --git a/drivers/net/sfc/spi.h b/drivers/net/sfc/spi.h -index 1b1ceb4..8bf4fce 100644 ---- a/drivers/net/sfc/spi.h -+++ b/drivers/net/sfc/spi.h -@@ -36,8 +36,6 @@ - - /** - * struct efx_spi_device - an Efx SPI (Serial Peripheral Interface) device -- * @efx: The Efx controller that owns this device -- * @mtd: MTD state - * @device_id: Controller's id for the device - * @size: Size (in bytes) - * @addr_len: Number of address bytes in read/write commands -@@ -54,10 +52,6 @@ - * Write commands are limited to blocks with this size and alignment. - */ - struct efx_spi_device { -- struct efx_nic *efx; --#ifdef CONFIG_SFC_MTD -- void *mtd; --#endif - int device_id; - unsigned int size; - unsigned int addr_len; -@@ -67,12 +61,16 @@ struct efx_spi_device { - unsigned int block_size; - }; - --int falcon_spi_cmd(const struct efx_spi_device *spi, unsigned int command, -+int falcon_spi_cmd(struct efx_nic *efx, -+ const struct efx_spi_device *spi, unsigned int command, - int address, const void* in, void *out, size_t len); --int falcon_spi_wait_write(const struct efx_spi_device *spi); --int falcon_spi_read(const struct efx_spi_device *spi, loff_t start, -+int falcon_spi_wait_write(struct efx_nic *efx, -+ const struct efx_spi_device *spi); -+int falcon_spi_read(struct efx_nic *efx, -+ const struct efx_spi_device *spi, loff_t start, - size_t len, size_t *retlen, u8 *buffer); --int falcon_spi_write(const struct efx_spi_device *spi, loff_t start, -+int falcon_spi_write(struct efx_nic *efx, -+ const struct efx_spi_device *spi, loff_t start, - size_t len, size_t *retlen, const u8 *buffer); - - /* -diff --git a/drivers/net/sfc/tenxpress.c b/drivers/net/sfc/tenxpress.c -index f4d5090..ca11572 100644 ---- a/drivers/net/sfc/tenxpress.c -+++ b/drivers/net/sfc/tenxpress.c -@@ -1,6 +1,6 @@ - /**************************************************************************** - * Driver for Solarflare Solarstorm network controllers and boards -- * Copyright 2007-2008 Solarflare Communications Inc. -+ * Copyright 2007-2009 Solarflare Communications Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published -@@ -12,10 +12,9 @@ - #include - #include "efx.h" - #include "mdio_10g.h" --#include "falcon.h" -+#include "nic.h" - #include "phy.h" --#include "falcon_hwdefs.h" --#include "boards.h" -+#include "regs.h" - #include "workarounds.h" - #include "selftest.h" - -@@ -31,13 +30,13 @@ - #define SFX7101_LOOPBACKS ((1 << LOOPBACK_PHYXS) | \ - (1 << LOOPBACK_PCS) | \ - (1 << LOOPBACK_PMAPMD) | \ -- (1 << LOOPBACK_NETWORK)) -+ (1 << LOOPBACK_PHYXS_WS)) - - #define SFT9001_LOOPBACKS ((1 << LOOPBACK_GPHY) | \ - (1 << LOOPBACK_PHYXS) | \ - (1 << LOOPBACK_PCS) | \ - (1 << LOOPBACK_PMAPMD) | \ -- (1 << LOOPBACK_NETWORK)) -+ (1 << LOOPBACK_PHYXS_WS)) - - /* We complain if we fail to see the link partner as 10G capable this many - * times in a row (must be > 1 as sampling the autoneg. registers is racy) -@@ -84,9 +83,9 @@ - #define PMA_PMD_LED_FLASH (3) - #define PMA_PMD_LED_MASK 3 - /* All LEDs under hardware control */ --#define PMA_PMD_LED_FULL_AUTO (0) -+#define SFT9001_PMA_PMD_LED_DEFAULT 0 - /* Green and Amber under hardware control, Red off */ --#define PMA_PMD_LED_DEFAULT (PMA_PMD_LED_OFF << PMA_PMD_LED_RX_LBN) -+#define SFX7101_PMA_PMD_LED_DEFAULT (PMA_PMD_LED_OFF << PMA_PMD_LED_RX_LBN) - - #define PMA_PMD_SPEED_ENABLE_REG 49192 - #define PMA_PMD_100TX_ADV_LBN 1 -@@ -200,15 +199,16 @@ static ssize_t set_phy_short_reach(struct device *dev, - const char *buf, size_t count) - { - struct efx_nic *efx = pci_get_drvdata(to_pci_dev(dev)); -+ int rc; - - rtnl_lock(); - efx_mdio_set_flag(efx, MDIO_MMD_PMAPMD, MDIO_PMA_10GBT_TXPWR, - MDIO_PMA_10GBT_TXPWR_SHORT, - count != 0 && *buf != '0'); -- efx_reconfigure_port(efx); -+ rc = efx_reconfigure_port(efx); - rtnl_unlock(); - -- return count; -+ return rc < 0 ? rc : (ssize_t)count; - } - - static DEVICE_ATTR(phy_short_reach, 0644, show_phy_short_reach, -@@ -292,17 +292,36 @@ static int tenxpress_init(struct efx_nic *efx) - efx_mdio_set_flag(efx, MDIO_MMD_PMAPMD, PMA_PMD_LED_CTRL_REG, - 1 << PMA_PMA_LED_ACTIVITY_LBN, true); - efx_mdio_write(efx, MDIO_MMD_PMAPMD, PMA_PMD_LED_OVERR_REG, -- PMA_PMD_LED_DEFAULT); -+ SFX7101_PMA_PMD_LED_DEFAULT); - } - - return 0; - } - -+static int sfx7101_phy_probe(struct efx_nic *efx) -+{ -+ efx->mdio.mmds = TENXPRESS_REQUIRED_DEVS; -+ efx->mdio.mode_support = MDIO_SUPPORTS_C45 | MDIO_EMULATE_C22; -+ efx->loopback_modes = SFX7101_LOOPBACKS | FALCON_XMAC_LOOPBACKS; -+ return 0; -+} -+ -+static int sft9001_phy_probe(struct efx_nic *efx) -+{ -+ efx->mdio.mmds = TENXPRESS_REQUIRED_DEVS; -+ efx->mdio.mode_support = MDIO_SUPPORTS_C45 | MDIO_EMULATE_C22; -+ efx->loopback_modes = (SFT9001_LOOPBACKS | FALCON_XMAC_LOOPBACKS | -+ FALCON_GMAC_LOOPBACKS); -+ return 0; -+} -+ - static int tenxpress_phy_init(struct efx_nic *efx) - { - struct tenxpress_phy_data *phy_data; - int rc = 0; - -+ falcon_board(efx)->type->init_phy(efx); -+ - phy_data = kzalloc(sizeof(*phy_data), GFP_KERNEL); - if (!phy_data) - return -ENOMEM; -@@ -333,6 +352,15 @@ static int tenxpress_phy_init(struct efx_nic *efx) - if (rc < 0) - goto fail; - -+ /* Initialise advertising flags */ -+ efx->link_advertising = (ADVERTISED_TP | ADVERTISED_Autoneg | -+ ADVERTISED_10000baseT_Full); -+ if (efx->phy_type != PHY_TYPE_SFX7101) -+ efx->link_advertising |= (ADVERTISED_1000baseT_Full | -+ ADVERTISED_100baseT_Full); -+ efx_link_set_wanted_fc(efx, efx->wanted_fc); -+ efx_mdio_an_reconfigure(efx); -+ - if (efx->phy_type == PHY_TYPE_SFT9001B) { - rc = device_create_file(&efx->pci_dev->dev, - &dev_attr_phy_short_reach); -@@ -363,7 +391,7 @@ static int tenxpress_special_reset(struct efx_nic *efx) - /* The XGMAC clock is driven from the SFC7101/SFT9001 312MHz clock, so - * a special software reset can glitch the XGMAC sufficiently for stats - * requests to fail. */ -- efx_stats_disable(efx); -+ falcon_stop_nic_stats(efx); - - /* Initiate reset */ - reg = efx_mdio_read(efx, MDIO_MMD_PMAPMD, PMA_PMD_XCONTROL_REG); -@@ -385,7 +413,7 @@ static int tenxpress_special_reset(struct efx_nic *efx) - /* Wait for the XGXS state machine to churn */ - mdelay(10); - out: -- efx_stats_enable(efx); -+ falcon_start_nic_stats(efx); - return rc; - } - -@@ -489,95 +517,76 @@ static void tenxpress_low_power(struct efx_nic *efx) - !!(efx->phy_mode & PHY_MODE_LOW_POWER)); - } - --static void tenxpress_phy_reconfigure(struct efx_nic *efx) -+static int tenxpress_phy_reconfigure(struct efx_nic *efx) - { - struct tenxpress_phy_data *phy_data = efx->phy_data; -- struct ethtool_cmd ecmd; - bool phy_mode_change, loop_reset; - - if (efx->phy_mode & (PHY_MODE_OFF | PHY_MODE_SPECIAL)) { - phy_data->phy_mode = efx->phy_mode; -- return; -+ return 0; - } - -- tenxpress_low_power(efx); -- - phy_mode_change = (efx->phy_mode == PHY_MODE_NORMAL && - phy_data->phy_mode != PHY_MODE_NORMAL); -- loop_reset = (LOOPBACK_OUT_OF(phy_data, efx, efx->phy_op->loopbacks) || -+ loop_reset = (LOOPBACK_OUT_OF(phy_data, efx, LOOPBACKS_EXTERNAL(efx)) || - LOOPBACK_CHANGED(phy_data, efx, 1 << LOOPBACK_GPHY)); - - if (loop_reset || phy_mode_change) { -- int rc; -- -- efx->phy_op->get_settings(efx, &ecmd); -- -- if (loop_reset || phy_mode_change) { -- tenxpress_special_reset(efx); -- -- /* Reset XAUI if we were in 10G, and are staying -- * in 10G. If we're moving into and out of 10G -- * then xaui will be reset anyway */ -- if (EFX_IS10G(efx)) -- falcon_reset_xaui(efx); -- } -+ tenxpress_special_reset(efx); - -- rc = efx->phy_op->set_settings(efx, &ecmd); -- WARN_ON(rc); -+ /* Reset XAUI if we were in 10G, and are staying -+ * in 10G. If we're moving into and out of 10G -+ * then xaui will be reset anyway */ -+ if (EFX_IS10G(efx)) -+ falcon_reset_xaui(efx); - } - -+ tenxpress_low_power(efx); - efx_mdio_transmit_disable(efx); - efx_mdio_phy_reconfigure(efx); - tenxpress_ext_loopback(efx); -+ efx_mdio_an_reconfigure(efx); - - phy_data->loopback_mode = efx->loopback_mode; - phy_data->phy_mode = efx->phy_mode; - -- if (efx->phy_type == PHY_TYPE_SFX7101) { -- efx->link_speed = 10000; -- efx->link_fd = true; -- efx->link_up = sfx7101_link_ok(efx); -- } else { -- efx->phy_op->get_settings(efx, &ecmd); -- efx->link_speed = ecmd.speed; -- efx->link_fd = ecmd.duplex == DUPLEX_FULL; -- efx->link_up = sft9001_link_ok(efx, &ecmd); -- } -- efx->link_fc = efx_mdio_get_pause(efx); -+ return 0; - } - --/* Poll PHY for interrupt */ --static void tenxpress_phy_poll(struct efx_nic *efx) -+static void -+tenxpress_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd); -+ -+/* Poll for link state changes */ -+static bool tenxpress_phy_poll(struct efx_nic *efx) - { -- struct tenxpress_phy_data *phy_data = efx->phy_data; -- bool change = false; -+ struct efx_link_state old_state = efx->link_state; - - if (efx->phy_type == PHY_TYPE_SFX7101) { -- bool link_ok = sfx7101_link_ok(efx); -- if (link_ok != efx->link_up) { -- change = true; -- } else { -- unsigned int link_fc = efx_mdio_get_pause(efx); -- if (link_fc != efx->link_fc) -- change = true; -- } -- sfx7101_check_bad_lp(efx, link_ok); -- } else if (efx->loopback_mode) { -- bool link_ok = sft9001_link_ok(efx, NULL); -- if (link_ok != efx->link_up) -- change = true; -+ efx->link_state.up = sfx7101_link_ok(efx); -+ efx->link_state.speed = 10000; -+ efx->link_state.fd = true; -+ efx->link_state.fc = efx_mdio_get_pause(efx); -+ -+ sfx7101_check_bad_lp(efx, efx->link_state.up); - } else { -- int status = efx_mdio_read(efx, MDIO_MMD_PMAPMD, -- MDIO_PMA_LASI_STAT); -- if (status & MDIO_PMA_LASI_LSALARM) -- change = true; -- } -+ struct ethtool_cmd ecmd; - -- if (change) -- falcon_sim_phy_event(efx); -+ /* Check the LASI alarm first */ -+ if (efx->loopback_mode == LOOPBACK_NONE && -+ !(efx_mdio_read(efx, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_STAT) & -+ MDIO_PMA_LASI_LSALARM)) -+ return false; - -- if (phy_data->phy_mode != PHY_MODE_NORMAL) -- return; -+ tenxpress_get_settings(efx, &ecmd); -+ -+ efx->link_state.up = sft9001_link_ok(efx, &ecmd); -+ efx->link_state.speed = ecmd.speed; -+ efx->link_state.fd = (ecmd.duplex == DUPLEX_FULL); -+ efx->link_state.fc = efx_mdio_get_pause(efx); -+ } -+ -+ return !efx_link_state_equal(&efx->link_state, &old_state); - } - - static void tenxpress_phy_fini(struct efx_nic *efx) -@@ -604,18 +613,29 @@ static void tenxpress_phy_fini(struct efx_nic *efx) - } - - --/* Set the RX and TX LEDs and Link LED flashing. The other LEDs -- * (which probably aren't wired anyway) are left in AUTO mode */ --void tenxpress_phy_blink(struct efx_nic *efx, bool blink) -+/* Override the RX, TX and link LEDs */ -+void tenxpress_set_id_led(struct efx_nic *efx, enum efx_led_mode mode) - { - int reg; - -- if (blink) -- reg = (PMA_PMD_LED_FLASH << PMA_PMD_LED_TX_LBN) | -- (PMA_PMD_LED_FLASH << PMA_PMD_LED_RX_LBN) | -- (PMA_PMD_LED_FLASH << PMA_PMD_LED_LINK_LBN); -- else -- reg = PMA_PMD_LED_DEFAULT; -+ switch (mode) { -+ case EFX_LED_OFF: -+ reg = (PMA_PMD_LED_OFF << PMA_PMD_LED_TX_LBN) | -+ (PMA_PMD_LED_OFF << PMA_PMD_LED_RX_LBN) | -+ (PMA_PMD_LED_OFF << PMA_PMD_LED_LINK_LBN); -+ break; -+ case EFX_LED_ON: -+ reg = (PMA_PMD_LED_ON << PMA_PMD_LED_TX_LBN) | -+ (PMA_PMD_LED_ON << PMA_PMD_LED_RX_LBN) | -+ (PMA_PMD_LED_ON << PMA_PMD_LED_LINK_LBN); -+ break; -+ default: -+ if (efx->phy_type == PHY_TYPE_SFX7101) -+ reg = SFX7101_PMA_PMD_LED_DEFAULT; -+ else -+ reg = SFT9001_PMA_PMD_LED_DEFAULT; -+ break; -+ } - - efx_mdio_write(efx, MDIO_MMD_PMAPMD, PMA_PMD_LED_OVERR_REG, reg); - } -@@ -624,6 +644,13 @@ static const char *const sfx7101_test_names[] = { - "bist" - }; - -+static const char *sfx7101_test_name(struct efx_nic *efx, unsigned int index) -+{ -+ if (index < ARRAY_SIZE(sfx7101_test_names)) -+ return sfx7101_test_names[index]; -+ return NULL; -+} -+ - static int - sfx7101_run_tests(struct efx_nic *efx, int *results, unsigned flags) - { -@@ -635,6 +662,9 @@ sfx7101_run_tests(struct efx_nic *efx, int *results, unsigned flags) - /* BIST is automatically run after a special software reset */ - rc = tenxpress_special_reset(efx); - results[0] = rc ? -1 : 1; -+ -+ efx_mdio_an_reconfigure(efx); -+ - return rc; - } - -@@ -650,14 +680,17 @@ static const char *const sft9001_test_names[] = { - "cable.pairD.length", - }; - -+static const char *sft9001_test_name(struct efx_nic *efx, unsigned int index) -+{ -+ if (index < ARRAY_SIZE(sft9001_test_names)) -+ return sft9001_test_names[index]; -+ return NULL; -+} -+ - static int sft9001_run_tests(struct efx_nic *efx, int *results, unsigned flags) - { -- struct ethtool_cmd ecmd; - int rc = 0, rc2, i, ctrl_reg, res_reg; - -- if (flags & ETH_TEST_FL_OFFLINE) -- efx->phy_op->get_settings(efx, &ecmd); -- - /* Initialise cable diagnostic results to unknown failure */ - for (i = 1; i < 9; ++i) - results[i] = -1; -@@ -709,9 +742,7 @@ out: - if (!rc) - rc = rc2; - -- rc2 = efx->phy_op->set_settings(efx, &ecmd); -- if (!rc) -- rc = rc2; -+ efx_mdio_an_reconfigure(efx); - } - - return rc; -@@ -758,7 +789,7 @@ tenxpress_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) - * but doesn't advertise the correct speed. So override it */ - if (efx->loopback_mode == LOOPBACK_GPHY) - ecmd->speed = SPEED_1000; -- else if (LOOPBACK_MASK(efx) & efx->phy_op->loopbacks) -+ else if (LOOPBACK_EXTERNAL(efx)) - ecmd->speed = SPEED_10000; - } - -@@ -788,35 +819,27 @@ static void sft9001_set_npage_adv(struct efx_nic *efx, u32 advertising) - } - - struct efx_phy_operations falcon_sfx7101_phy_ops = { -- .macs = EFX_XMAC, -+ .probe = sfx7101_phy_probe, - .init = tenxpress_phy_init, - .reconfigure = tenxpress_phy_reconfigure, - .poll = tenxpress_phy_poll, - .fini = tenxpress_phy_fini, -- .clear_interrupt = efx_port_dummy_op_void, - .get_settings = tenxpress_get_settings, - .set_settings = tenxpress_set_settings, - .set_npage_adv = sfx7101_set_npage_adv, -- .num_tests = ARRAY_SIZE(sfx7101_test_names), -- .test_names = sfx7101_test_names, -+ .test_name = sfx7101_test_name, - .run_tests = sfx7101_run_tests, -- .mmds = TENXPRESS_REQUIRED_DEVS, -- .loopbacks = SFX7101_LOOPBACKS, - }; - - struct efx_phy_operations falcon_sft9001_phy_ops = { -- .macs = EFX_GMAC | EFX_XMAC, -+ .probe = sft9001_phy_probe, - .init = tenxpress_phy_init, - .reconfigure = tenxpress_phy_reconfigure, - .poll = tenxpress_phy_poll, - .fini = tenxpress_phy_fini, -- .clear_interrupt = efx_port_dummy_op_void, - .get_settings = tenxpress_get_settings, - .set_settings = tenxpress_set_settings, - .set_npage_adv = sft9001_set_npage_adv, -- .num_tests = ARRAY_SIZE(sft9001_test_names), -- .test_names = sft9001_test_names, -+ .test_name = sft9001_test_name, - .run_tests = sft9001_run_tests, -- .mmds = TENXPRESS_REQUIRED_DEVS, -- .loopbacks = SFT9001_LOOPBACKS, - }; -diff --git a/drivers/net/sfc/tx.c b/drivers/net/sfc/tx.c -index 489c4de..e669f94 100644 ---- a/drivers/net/sfc/tx.c -+++ b/drivers/net/sfc/tx.c -@@ -1,7 +1,7 @@ - /**************************************************************************** - * Driver for Solarflare Solarstorm network controllers and boards - * Copyright 2005-2006 Fen Systems Ltd. -- * Copyright 2005-2008 Solarflare Communications Inc. -+ * Copyright 2005-2009 Solarflare Communications Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published -@@ -12,12 +12,13 @@ - #include - #include - #include -+#include -+#include - #include - #include - #include "net_driver.h" --#include "tx.h" - #include "efx.h" --#include "falcon.h" -+#include "nic.h" - #include "workarounds.h" - - /* -@@ -26,8 +27,7 @@ - * The tx_queue descriptor ring fill-level must fall below this value - * before we restart the netif queue - */ --#define EFX_NETDEV_TX_THRESHOLD(_tx_queue) \ -- (_tx_queue->efx->type->txd_ring_mask / 2u) -+#define EFX_TXQ_THRESHOLD (EFX_TXQ_MASK / 2u) - - /* We want to be able to nest calls to netif_stop_queue(), since each - * channel can have an individual stop on the queue. -@@ -125,6 +125,24 @@ static void efx_tsoh_free(struct efx_tx_queue *tx_queue, - } - - -+static inline unsigned -+efx_max_tx_len(struct efx_nic *efx, dma_addr_t dma_addr) -+{ -+ /* Depending on the NIC revision, we can use descriptor -+ * lengths up to 8K or 8K-1. However, since PCI Express -+ * devices must split read requests at 4K boundaries, there is -+ * little benefit from using descriptors that cross those -+ * boundaries and we keep things simple by not doing so. -+ */ -+ unsigned len = (~dma_addr & 0xfff) + 1; -+ -+ /* Work around hardware bug for unaligned buffers. */ -+ if (EFX_WORKAROUND_5391(efx) && (dma_addr & 0xf)) -+ len = min_t(unsigned, len, 512 - (dma_addr & 0xf)); -+ -+ return len; -+} -+ - /* - * Add a socket buffer to a TX queue - * -@@ -135,11 +153,13 @@ static void efx_tsoh_free(struct efx_tx_queue *tx_queue, - * If any DMA mapping fails, any mapped fragments will be unmapped, - * the queue's insert pointer will be restored to its original value. - * -+ * This function is split out from efx_hard_start_xmit to allow the -+ * loopback test to direct packets via specific TX queues. -+ * - * Returns NETDEV_TX_OK or NETDEV_TX_BUSY - * You must hold netif_tx_lock() to call this function. - */ --static netdev_tx_t efx_enqueue_skb(struct efx_tx_queue *tx_queue, -- struct sk_buff *skb) -+netdev_tx_t efx_enqueue_skb(struct efx_tx_queue *tx_queue, struct sk_buff *skb) - { - struct efx_nic *efx = tx_queue->efx; - struct pci_dev *pci_dev = efx->pci_dev; -@@ -147,7 +167,7 @@ static netdev_tx_t efx_enqueue_skb(struct efx_tx_queue *tx_queue, - skb_frag_t *fragment; - struct page *page; - int page_offset; -- unsigned int len, unmap_len = 0, fill_level, insert_ptr, misalign; -+ unsigned int len, unmap_len = 0, fill_level, insert_ptr; - dma_addr_t dma_addr, unmap_addr = 0; - unsigned int dma_len; - bool unmap_single; -@@ -156,7 +176,7 @@ static netdev_tx_t efx_enqueue_skb(struct efx_tx_queue *tx_queue, - - EFX_BUG_ON_PARANOID(tx_queue->write_count != tx_queue->insert_count); - -- if (skb_shinfo((struct sk_buff *)skb)->gso_size) -+ if (skb_shinfo(skb)->gso_size) - return efx_enqueue_skb_tso(tx_queue, skb); - - /* Get size of the initial fragment */ -@@ -171,7 +191,7 @@ static netdev_tx_t efx_enqueue_skb(struct efx_tx_queue *tx_queue, - } - - fill_level = tx_queue->insert_count - tx_queue->old_read_count; -- q_space = efx->type->txd_ring_mask - 1 - fill_level; -+ q_space = EFX_TXQ_MASK - 1 - fill_level; - - /* Map for DMA. Use pci_map_single rather than pci_map_page - * since this is more efficient on machines with sparse -@@ -208,16 +228,14 @@ static netdev_tx_t efx_enqueue_skb(struct efx_tx_queue *tx_queue, - &tx_queue->read_count; - fill_level = (tx_queue->insert_count - - tx_queue->old_read_count); -- q_space = (efx->type->txd_ring_mask - 1 - -- fill_level); -+ q_space = EFX_TXQ_MASK - 1 - fill_level; - if (unlikely(q_space-- <= 0)) - goto stop; - smp_mb(); - --tx_queue->stopped; - } - -- insert_ptr = (tx_queue->insert_count & -- efx->type->txd_ring_mask); -+ insert_ptr = tx_queue->insert_count & EFX_TXQ_MASK; - buffer = &tx_queue->buffer[insert_ptr]; - efx_tsoh_free(tx_queue, buffer); - EFX_BUG_ON_PARANOID(buffer->tsoh); -@@ -226,14 +244,10 @@ static netdev_tx_t efx_enqueue_skb(struct efx_tx_queue *tx_queue, - EFX_BUG_ON_PARANOID(!buffer->continuation); - EFX_BUG_ON_PARANOID(buffer->unmap_len); - -- dma_len = (((~dma_addr) & efx->type->tx_dma_mask) + 1); -- if (likely(dma_len > len)) -+ dma_len = efx_max_tx_len(efx, dma_addr); -+ if (likely(dma_len >= len)) - dma_len = len; - -- misalign = (unsigned)dma_addr & efx->type->bug5391_mask; -- if (misalign && dma_len + misalign > 512) -- dma_len = 512 - misalign; -- - /* Fill out per descriptor fields */ - buffer->len = dma_len; - buffer->dma_addr = dma_addr; -@@ -266,7 +280,7 @@ static netdev_tx_t efx_enqueue_skb(struct efx_tx_queue *tx_queue, - buffer->continuation = false; - - /* Pass off to hardware */ -- falcon_push_buffers(tx_queue); -+ efx_nic_push_buffers(tx_queue); - - return NETDEV_TX_OK; - -@@ -276,7 +290,7 @@ static netdev_tx_t efx_enqueue_skb(struct efx_tx_queue *tx_queue, - skb_shinfo(skb)->nr_frags + 1); - - /* Mark the packet as transmitted, and free the SKB ourselves */ -- dev_kfree_skb_any((struct sk_buff *)skb); -+ dev_kfree_skb_any(skb); - goto unwind; - - stop: -@@ -289,7 +303,7 @@ static netdev_tx_t efx_enqueue_skb(struct efx_tx_queue *tx_queue, - /* Work backwards until we hit the original insert pointer value */ - while (tx_queue->insert_count != tx_queue->write_count) { - --tx_queue->insert_count; -- insert_ptr = tx_queue->insert_count & efx->type->txd_ring_mask; -+ insert_ptr = tx_queue->insert_count & EFX_TXQ_MASK; - buffer = &tx_queue->buffer[insert_ptr]; - efx_dequeue_buffer(tx_queue, buffer); - buffer->len = 0; -@@ -318,10 +332,9 @@ static void efx_dequeue_buffers(struct efx_tx_queue *tx_queue, - { - struct efx_nic *efx = tx_queue->efx; - unsigned int stop_index, read_ptr; -- unsigned int mask = tx_queue->efx->type->txd_ring_mask; - -- stop_index = (index + 1) & mask; -- read_ptr = tx_queue->read_count & mask; -+ stop_index = (index + 1) & EFX_TXQ_MASK; -+ read_ptr = tx_queue->read_count & EFX_TXQ_MASK; - - while (read_ptr != stop_index) { - struct efx_tx_buffer *buffer = &tx_queue->buffer[read_ptr]; -@@ -338,28 +351,10 @@ static void efx_dequeue_buffers(struct efx_tx_queue *tx_queue, - buffer->len = 0; - - ++tx_queue->read_count; -- read_ptr = tx_queue->read_count & mask; -+ read_ptr = tx_queue->read_count & EFX_TXQ_MASK; - } - } - --/* Initiate a packet transmission on the specified TX queue. -- * Note that returning anything other than NETDEV_TX_OK will cause the -- * OS to free the skb. -- * -- * This function is split out from efx_hard_start_xmit to allow the -- * loopback test to direct packets via specific TX queues. It is -- * therefore a non-static inline, so as not to penalise performance -- * for non-loopback transmissions. -- * -- * Context: netif_tx_lock held -- */ --inline netdev_tx_t efx_xmit(struct efx_nic *efx, -- struct efx_tx_queue *tx_queue, struct sk_buff *skb) --{ -- /* Map fragments for DMA and add to TX queue */ -- return efx_enqueue_skb(tx_queue, skb); --} -- - /* Initiate a packet transmission. We use one channel per CPU - * (sharing when we have more CPUs than channels). On Falcon, the TX - * completion events will be directed back to the CPU that transmitted -@@ -383,7 +378,7 @@ netdev_tx_t efx_hard_start_xmit(struct sk_buff *skb, - else - tx_queue = &efx->tx_queue[EFX_TX_QUEUE_NO_CSUM]; - -- return efx_xmit(efx, tx_queue, skb); -+ return efx_enqueue_skb(tx_queue, skb); - } - - void efx_xmit_done(struct efx_tx_queue *tx_queue, unsigned int index) -@@ -391,7 +386,7 @@ void efx_xmit_done(struct efx_tx_queue *tx_queue, unsigned int index) - unsigned fill_level; - struct efx_nic *efx = tx_queue->efx; - -- EFX_BUG_ON_PARANOID(index > efx->type->txd_ring_mask); -+ EFX_BUG_ON_PARANOID(index > EFX_TXQ_MASK); - - efx_dequeue_buffers(tx_queue, index); - -@@ -401,7 +396,7 @@ void efx_xmit_done(struct efx_tx_queue *tx_queue, unsigned int index) - smp_mb(); - if (unlikely(tx_queue->stopped) && likely(efx->port_enabled)) { - fill_level = tx_queue->insert_count - tx_queue->read_count; -- if (fill_level < EFX_NETDEV_TX_THRESHOLD(tx_queue)) { -+ if (fill_level < EFX_TXQ_THRESHOLD) { - EFX_BUG_ON_PARANOID(!efx_dev_registered(efx)); - - /* Do this under netif_tx_lock(), to avoid racing -@@ -425,15 +420,15 @@ int efx_probe_tx_queue(struct efx_tx_queue *tx_queue) - EFX_LOG(efx, "creating TX queue %d\n", tx_queue->queue); - - /* Allocate software ring */ -- txq_size = (efx->type->txd_ring_mask + 1) * sizeof(*tx_queue->buffer); -+ txq_size = EFX_TXQ_SIZE * sizeof(*tx_queue->buffer); - tx_queue->buffer = kzalloc(txq_size, GFP_KERNEL); - if (!tx_queue->buffer) - return -ENOMEM; -- for (i = 0; i <= efx->type->txd_ring_mask; ++i) -+ for (i = 0; i <= EFX_TXQ_MASK; ++i) - tx_queue->buffer[i].continuation = true; - - /* Allocate hardware ring */ -- rc = falcon_probe_tx(tx_queue); -+ rc = efx_nic_probe_tx(tx_queue); - if (rc) - goto fail; - -@@ -456,7 +451,7 @@ void efx_init_tx_queue(struct efx_tx_queue *tx_queue) - BUG_ON(tx_queue->stopped); - - /* Set up TX descriptor ring */ -- falcon_init_tx(tx_queue); -+ efx_nic_init_tx(tx_queue); - } - - void efx_release_tx_buffers(struct efx_tx_queue *tx_queue) -@@ -468,8 +463,7 @@ void efx_release_tx_buffers(struct efx_tx_queue *tx_queue) - - /* Free any buffers left in the ring */ - while (tx_queue->read_count != tx_queue->write_count) { -- buffer = &tx_queue->buffer[tx_queue->read_count & -- tx_queue->efx->type->txd_ring_mask]; -+ buffer = &tx_queue->buffer[tx_queue->read_count & EFX_TXQ_MASK]; - efx_dequeue_buffer(tx_queue, buffer); - buffer->continuation = true; - buffer->len = 0; -@@ -483,7 +477,7 @@ void efx_fini_tx_queue(struct efx_tx_queue *tx_queue) - EFX_LOG(tx_queue->efx, "shutting down TX queue %d\n", tx_queue->queue); - - /* Flush TX queue, remove descriptor ring */ -- falcon_fini_tx(tx_queue); -+ efx_nic_fini_tx(tx_queue); - - efx_release_tx_buffers(tx_queue); - -@@ -500,7 +494,7 @@ void efx_fini_tx_queue(struct efx_tx_queue *tx_queue) - void efx_remove_tx_queue(struct efx_tx_queue *tx_queue) - { - EFX_LOG(tx_queue->efx, "destroying TX queue %d\n", tx_queue->queue); -- falcon_remove_tx(tx_queue); -+ efx_nic_remove_tx(tx_queue); - - kfree(tx_queue->buffer); - tx_queue->buffer = NULL; -@@ -539,6 +533,7 @@ void efx_remove_tx_queue(struct efx_tx_queue *tx_queue) - #define ETH_HDR_LEN(skb) (skb_network_header(skb) - (skb)->data) - #define SKB_TCP_OFF(skb) PTR_DIFF(tcp_hdr(skb), (skb)->data) - #define SKB_IPV4_OFF(skb) PTR_DIFF(ip_hdr(skb), (skb)->data) -+#define SKB_IPV6_OFF(skb) PTR_DIFF(ipv6_hdr(skb), (skb)->data) - - /** - * struct tso_state - TSO state for an SKB -@@ -551,6 +546,7 @@ void efx_remove_tx_queue(struct efx_tx_queue *tx_queue) - * @unmap_len: Length of SKB fragment - * @unmap_addr: DMA address of SKB fragment - * @unmap_single: DMA single vs page mapping flag -+ * @protocol: Network protocol (after any VLAN header) - * @header_len: Number of bytes of header - * @full_packet_size: Number of bytes to put in each outgoing segment - * -@@ -571,6 +567,7 @@ struct tso_state { - dma_addr_t unmap_addr; - bool unmap_single; - -+ __be16 protocol; - unsigned header_len; - int full_packet_size; - }; -@@ -578,9 +575,9 @@ struct tso_state { - - /* - * Verify that our various assumptions about sk_buffs and the conditions -- * under which TSO will be attempted hold true. -+ * under which TSO will be attempted hold true. Return the protocol number. - */ --static void efx_tso_check_safe(struct sk_buff *skb) -+static __be16 efx_tso_check_protocol(struct sk_buff *skb) - { - __be16 protocol = skb->protocol; - -@@ -595,13 +592,22 @@ static void efx_tso_check_safe(struct sk_buff *skb) - if (protocol == htons(ETH_P_IP)) - skb_set_transport_header(skb, sizeof(*veh) + - 4 * ip_hdr(skb)->ihl); -+ else if (protocol == htons(ETH_P_IPV6)) -+ skb_set_transport_header(skb, sizeof(*veh) + -+ sizeof(struct ipv6hdr)); - } - -- EFX_BUG_ON_PARANOID(protocol != htons(ETH_P_IP)); -- EFX_BUG_ON_PARANOID(ip_hdr(skb)->protocol != IPPROTO_TCP); -+ if (protocol == htons(ETH_P_IP)) { -+ EFX_BUG_ON_PARANOID(ip_hdr(skb)->protocol != IPPROTO_TCP); -+ } else { -+ EFX_BUG_ON_PARANOID(protocol != htons(ETH_P_IPV6)); -+ EFX_BUG_ON_PARANOID(ipv6_hdr(skb)->nexthdr != NEXTHDR_TCP); -+ } - EFX_BUG_ON_PARANOID((PTR_DIFF(tcp_hdr(skb), skb->data) - + (tcp_hdr(skb)->doff << 2u)) > - skb_headlen(skb)); -+ -+ return protocol; - } - - -@@ -708,14 +714,14 @@ static int efx_tx_queue_insert(struct efx_tx_queue *tx_queue, - { - struct efx_tx_buffer *buffer; - struct efx_nic *efx = tx_queue->efx; -- unsigned dma_len, fill_level, insert_ptr, misalign; -+ unsigned dma_len, fill_level, insert_ptr; - int q_space; - - EFX_BUG_ON_PARANOID(len <= 0); - - fill_level = tx_queue->insert_count - tx_queue->old_read_count; - /* -1 as there is no way to represent all descriptors used */ -- q_space = efx->type->txd_ring_mask - 1 - fill_level; -+ q_space = EFX_TXQ_MASK - 1 - fill_level; - - while (1) { - if (unlikely(q_space-- <= 0)) { -@@ -731,7 +737,7 @@ static int efx_tx_queue_insert(struct efx_tx_queue *tx_queue, - *(volatile unsigned *)&tx_queue->read_count; - fill_level = (tx_queue->insert_count - - tx_queue->old_read_count); -- q_space = efx->type->txd_ring_mask - 1 - fill_level; -+ q_space = EFX_TXQ_MASK - 1 - fill_level; - if (unlikely(q_space-- <= 0)) { - *final_buffer = NULL; - return 1; -@@ -740,13 +746,13 @@ static int efx_tx_queue_insert(struct efx_tx_queue *tx_queue, - --tx_queue->stopped; - } - -- insert_ptr = tx_queue->insert_count & efx->type->txd_ring_mask; -+ insert_ptr = tx_queue->insert_count & EFX_TXQ_MASK; - buffer = &tx_queue->buffer[insert_ptr]; - ++tx_queue->insert_count; - - EFX_BUG_ON_PARANOID(tx_queue->insert_count - - tx_queue->read_count > -- efx->type->txd_ring_mask); -+ EFX_TXQ_MASK); - - efx_tsoh_free(tx_queue, buffer); - EFX_BUG_ON_PARANOID(buffer->len); -@@ -757,12 +763,7 @@ static int efx_tx_queue_insert(struct efx_tx_queue *tx_queue, - - buffer->dma_addr = dma_addr; - -- /* Ensure we do not cross a boundary unsupported by H/W */ -- dma_len = (~dma_addr & efx->type->tx_dma_mask) + 1; -- -- misalign = (unsigned)dma_addr & efx->type->bug5391_mask; -- if (misalign && dma_len + misalign > 512) -- dma_len = 512 - misalign; -+ dma_len = efx_max_tx_len(efx, dma_addr); - - /* If there is enough space to send then do so */ - if (dma_len >= len) -@@ -792,8 +793,7 @@ static void efx_tso_put_header(struct efx_tx_queue *tx_queue, - { - struct efx_tx_buffer *buffer; - -- buffer = &tx_queue->buffer[tx_queue->insert_count & -- tx_queue->efx->type->txd_ring_mask]; -+ buffer = &tx_queue->buffer[tx_queue->insert_count & EFX_TXQ_MASK]; - efx_tsoh_free(tx_queue, buffer); - EFX_BUG_ON_PARANOID(buffer->len); - EFX_BUG_ON_PARANOID(buffer->unmap_len); -@@ -818,7 +818,7 @@ static void efx_enqueue_unwind(struct efx_tx_queue *tx_queue) - while (tx_queue->insert_count != tx_queue->write_count) { - --tx_queue->insert_count; - buffer = &tx_queue->buffer[tx_queue->insert_count & -- tx_queue->efx->type->txd_ring_mask]; -+ EFX_TXQ_MASK]; - efx_tsoh_free(tx_queue, buffer); - EFX_BUG_ON_PARANOID(buffer->skb); - buffer->len = 0; -@@ -850,7 +850,10 @@ static void tso_start(struct tso_state *st, const struct sk_buff *skb) - + PTR_DIFF(tcp_hdr(skb), skb->data)); - st->full_packet_size = st->header_len + skb_shinfo(skb)->gso_size; - -- st->ipv4_id = ntohs(ip_hdr(skb)->id); -+ if (st->protocol == htons(ETH_P_IP)) -+ st->ipv4_id = ntohs(ip_hdr(skb)->id); -+ else -+ st->ipv4_id = 0; - st->seqnum = ntohl(tcp_hdr(skb)->seq); - - EFX_BUG_ON_PARANOID(tcp_hdr(skb)->urg); -@@ -965,7 +968,6 @@ static int tso_start_new_packet(struct efx_tx_queue *tx_queue, - struct tso_state *st) - { - struct efx_tso_header *tsoh; -- struct iphdr *tsoh_iph; - struct tcphdr *tsoh_th; - unsigned ip_length; - u8 *header; -@@ -989,7 +991,6 @@ static int tso_start_new_packet(struct efx_tx_queue *tx_queue, - - header = TSOH_BUFFER(tsoh); - tsoh_th = (struct tcphdr *)(header + SKB_TCP_OFF(skb)); -- tsoh_iph = (struct iphdr *)(header + SKB_IPV4_OFF(skb)); - - /* Copy and update the headers. */ - memcpy(header, skb->data, st->header_len); -@@ -1007,11 +1008,22 @@ static int tso_start_new_packet(struct efx_tx_queue *tx_queue, - tsoh_th->fin = tcp_hdr(skb)->fin; - tsoh_th->psh = tcp_hdr(skb)->psh; - } -- tsoh_iph->tot_len = htons(ip_length); - -- /* Linux leaves suitable gaps in the IP ID space for us to fill. */ -- tsoh_iph->id = htons(st->ipv4_id); -- st->ipv4_id++; -+ if (st->protocol == htons(ETH_P_IP)) { -+ struct iphdr *tsoh_iph = -+ (struct iphdr *)(header + SKB_IPV4_OFF(skb)); -+ -+ tsoh_iph->tot_len = htons(ip_length); -+ -+ /* Linux leaves suitable gaps in the IP ID space for us to fill. */ -+ tsoh_iph->id = htons(st->ipv4_id); -+ st->ipv4_id++; -+ } else { -+ struct ipv6hdr *tsoh_iph = -+ (struct ipv6hdr *)(header + SKB_IPV6_OFF(skb)); -+ -+ tsoh_iph->payload_len = htons(ip_length - sizeof(*tsoh_iph)); -+ } - - st->packet_space = skb_shinfo(skb)->gso_size; - ++tx_queue->tso_packets; -@@ -1041,8 +1053,8 @@ static int efx_enqueue_skb_tso(struct efx_tx_queue *tx_queue, - int frag_i, rc, rc2 = NETDEV_TX_OK; - struct tso_state state; - -- /* Verify TSO is safe - these checks should never fail. */ -- efx_tso_check_safe(skb); -+ /* Find the packet protocol and sanity-check it */ -+ state.protocol = efx_tso_check_protocol(skb); - - EFX_BUG_ON_PARANOID(tx_queue->write_count != tx_queue->insert_count); - -@@ -1092,14 +1104,14 @@ static int efx_enqueue_skb_tso(struct efx_tx_queue *tx_queue, - } - - /* Pass off to hardware */ -- falcon_push_buffers(tx_queue); -+ efx_nic_push_buffers(tx_queue); - - tx_queue->tso_bursts++; - return NETDEV_TX_OK; - - mem_err: - EFX_ERR(efx, "Out of memory for TSO headers, or PCI mapping error\n"); -- dev_kfree_skb_any((struct sk_buff *)skb); -+ dev_kfree_skb_any(skb); - goto unwind; - - stop: -@@ -1135,7 +1147,7 @@ static void efx_fini_tso(struct efx_tx_queue *tx_queue) - unsigned i; - - if (tx_queue->buffer) { -- for (i = 0; i <= tx_queue->efx->type->txd_ring_mask; ++i) -+ for (i = 0; i <= EFX_TXQ_MASK; ++i) - efx_tsoh_free(tx_queue, &tx_queue->buffer[i]); - } - -diff --git a/drivers/net/sfc/tx.h b/drivers/net/sfc/tx.h -deleted file mode 100644 -index e367896..0000000 ---- a/drivers/net/sfc/tx.h -+++ /dev/null -@@ -1,25 +0,0 @@ --/**************************************************************************** -- * Driver for Solarflare Solarstorm network controllers and boards -- * Copyright 2006 Fen Systems Ltd. -- * Copyright 2006-2008 Solarflare Communications Inc. -- * -- * This program is free software; you can redistribute it and/or modify it -- * under the terms of the GNU General Public License version 2 as published -- * by the Free Software Foundation, incorporated herein by reference. -- */ -- --#ifndef EFX_TX_H --#define EFX_TX_H -- --#include "net_driver.h" -- --int efx_probe_tx_queue(struct efx_tx_queue *tx_queue); --void efx_remove_tx_queue(struct efx_tx_queue *tx_queue); --void efx_init_tx_queue(struct efx_tx_queue *tx_queue); --void efx_fini_tx_queue(struct efx_tx_queue *tx_queue); -- --netdev_tx_t efx_hard_start_xmit(struct sk_buff *skb, -- struct net_device *net_dev); --void efx_release_tx_buffers(struct efx_tx_queue *tx_queue); -- --#endif /* EFX_TX_H */ -diff --git a/drivers/net/sfc/workarounds.h b/drivers/net/sfc/workarounds.h -index c821c15..acd9c73 100644 ---- a/drivers/net/sfc/workarounds.h -+++ b/drivers/net/sfc/workarounds.h -@@ -1,6 +1,6 @@ - /**************************************************************************** - * Driver for Solarflare Solarstorm network controllers and boards -- * Copyright 2006-2008 Solarflare Communications Inc. -+ * Copyright 2006-2009 Solarflare Communications Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published -@@ -16,7 +16,9 @@ - */ - - #define EFX_WORKAROUND_ALWAYS(efx) 1 --#define EFX_WORKAROUND_FALCON_A(efx) (falcon_rev(efx) <= FALCON_REV_A1) -+#define EFX_WORKAROUND_FALCON_A(efx) (efx_nic_rev(efx) <= EFX_REV_FALCON_A1) -+#define EFX_WORKAROUND_FALCON_AB(efx) (efx_nic_rev(efx) <= EFX_REV_FALCON_B0) -+#define EFX_WORKAROUND_SIENA(efx) (efx_nic_rev(efx) == EFX_REV_SIENA_A0) - #define EFX_WORKAROUND_10G(efx) EFX_IS10G(efx) - #define EFX_WORKAROUND_SFT9001(efx) ((efx)->phy_type == PHY_TYPE_SFT9001A || \ - (efx)->phy_type == PHY_TYPE_SFT9001B) -@@ -27,20 +29,22 @@ - #define EFX_WORKAROUND_7575 EFX_WORKAROUND_ALWAYS - /* Bit-bashed I2C reads cause performance drop */ - #define EFX_WORKAROUND_7884 EFX_WORKAROUND_10G --/* TX pkt parser problem with <= 16 byte TXes */ --#define EFX_WORKAROUND_9141 EFX_WORKAROUND_ALWAYS - /* TX_EV_PKT_ERR can be caused by a dangling TX descriptor - * or a PCIe error (bug 11028) */ - #define EFX_WORKAROUND_10727 EFX_WORKAROUND_ALWAYS - /* Transmit flow control may get disabled */ --#define EFX_WORKAROUND_11482 EFX_WORKAROUND_ALWAYS --/* Flush events can take a very long time to appear */ --#define EFX_WORKAROUND_11557 EFX_WORKAROUND_ALWAYS -+#define EFX_WORKAROUND_11482 EFX_WORKAROUND_FALCON_AB - /* Truncated IPv4 packets can confuse the TX packet parser */ --#define EFX_WORKAROUND_15592 EFX_WORKAROUND_ALWAYS -+#define EFX_WORKAROUND_15592 EFX_WORKAROUND_FALCON_AB -+/* Legacy ISR read can return zero once */ -+#define EFX_WORKAROUND_15783 EFX_WORKAROUND_SIENA -+/* Legacy interrupt storm when interrupt fifo fills */ -+#define EFX_WORKAROUND_17213 EFX_WORKAROUND_SIENA - - /* Spurious parity errors in TSORT buffers */ - #define EFX_WORKAROUND_5129 EFX_WORKAROUND_FALCON_A -+/* Unaligned read request >512 bytes after aligning may break TSORT */ -+#define EFX_WORKAROUND_5391 EFX_WORKAROUND_FALCON_A - /* iSCSI parsing errors */ - #define EFX_WORKAROUND_5583 EFX_WORKAROUND_FALCON_A - /* RX events go missing */ -diff --git a/drivers/net/sfc/xfp_phy.c b/drivers/net/sfc/xfp_phy.c -deleted file mode 100644 -index e6b3d5e..0000000 ---- a/drivers/net/sfc/xfp_phy.c -+++ /dev/null -@@ -1,250 +0,0 @@ --/**************************************************************************** -- * Driver for Solarflare Solarstorm network controllers and boards -- * Copyright 2006-2008 Solarflare Communications Inc. -- * -- * This program is free software; you can redistribute it and/or modify it -- * under the terms of the GNU General Public License version 2 as published -- * by the Free Software Foundation, incorporated herein by reference. -- */ --/* -- * Driver for SFP+ and XFP optical PHYs plus some support specific to the -- * AMCC QT20xx adapters; see www.amcc.com for details -- */ -- --#include --#include --#include "efx.h" --#include "mdio_10g.h" --#include "phy.h" --#include "falcon.h" -- --#define XFP_REQUIRED_DEVS (MDIO_DEVS_PCS | \ -- MDIO_DEVS_PMAPMD | \ -- MDIO_DEVS_PHYXS) -- --#define XFP_LOOPBACKS ((1 << LOOPBACK_PCS) | \ -- (1 << LOOPBACK_PMAPMD) | \ -- (1 << LOOPBACK_NETWORK)) -- --/****************************************************************************/ --/* Quake-specific MDIO registers */ --#define MDIO_QUAKE_LED0_REG (0xD006) -- --/* QT2025C only */ --#define PCS_FW_HEARTBEAT_REG 0xd7ee --#define PCS_FW_HEARTB_LBN 0 --#define PCS_FW_HEARTB_WIDTH 8 --#define PCS_UC8051_STATUS_REG 0xd7fd --#define PCS_UC_STATUS_LBN 0 --#define PCS_UC_STATUS_WIDTH 8 --#define PCS_UC_STATUS_FW_SAVE 0x20 --#define PMA_PMD_FTX_CTRL2_REG 0xc309 --#define PMA_PMD_FTX_STATIC_LBN 13 --#define PMA_PMD_VEND1_REG 0xc001 --#define PMA_PMD_VEND1_LBTXD_LBN 15 --#define PCS_VEND1_REG 0xc000 --#define PCS_VEND1_LBTXD_LBN 5 -- --void xfp_set_led(struct efx_nic *p, int led, int mode) --{ -- int addr = MDIO_QUAKE_LED0_REG + led; -- efx_mdio_write(p, MDIO_MMD_PMAPMD, addr, mode); --} -- --struct xfp_phy_data { -- enum efx_phy_mode phy_mode; --}; -- --#define XFP_MAX_RESET_TIME 500 --#define XFP_RESET_WAIT 10 -- --static int qt2025c_wait_reset(struct efx_nic *efx) --{ -- unsigned long timeout = jiffies + 10 * HZ; -- int reg, old_counter = 0; -- -- /* Wait for firmware heartbeat to start */ -- for (;;) { -- int counter; -- reg = efx_mdio_read(efx, MDIO_MMD_PCS, PCS_FW_HEARTBEAT_REG); -- if (reg < 0) -- return reg; -- counter = ((reg >> PCS_FW_HEARTB_LBN) & -- ((1 << PCS_FW_HEARTB_WIDTH) - 1)); -- if (old_counter == 0) -- old_counter = counter; -- else if (counter != old_counter) -- break; -- if (time_after(jiffies, timeout)) -- return -ETIMEDOUT; -- msleep(10); -- } -- -- /* Wait for firmware status to look good */ -- for (;;) { -- reg = efx_mdio_read(efx, MDIO_MMD_PCS, PCS_UC8051_STATUS_REG); -- if (reg < 0) -- return reg; -- if ((reg & -- ((1 << PCS_UC_STATUS_WIDTH) - 1) << PCS_UC_STATUS_LBN) >= -- PCS_UC_STATUS_FW_SAVE) -- break; -- if (time_after(jiffies, timeout)) -- return -ETIMEDOUT; -- msleep(100); -- } -- -- return 0; --} -- --static int xfp_reset_phy(struct efx_nic *efx) --{ -- int rc; -- -- if (efx->phy_type == PHY_TYPE_QT2025C) { -- /* Wait for the reset triggered by falcon_reset_hw() -- * to complete */ -- rc = qt2025c_wait_reset(efx); -- if (rc < 0) -- goto fail; -- } else { -- /* Reset the PHYXS MMD. This is documented as doing -- * a complete soft reset. */ -- rc = efx_mdio_reset_mmd(efx, MDIO_MMD_PHYXS, -- XFP_MAX_RESET_TIME / XFP_RESET_WAIT, -- XFP_RESET_WAIT); -- if (rc < 0) -- goto fail; -- } -- -- /* Wait 250ms for the PHY to complete bootup */ -- msleep(250); -- -- /* Check that all the MMDs we expect are present and responding. We -- * expect faults on some if the link is down, but not on the PHY XS */ -- rc = efx_mdio_check_mmds(efx, XFP_REQUIRED_DEVS, MDIO_DEVS_PHYXS); -- if (rc < 0) -- goto fail; -- -- efx->board_info.init_leds(efx); -- -- return rc; -- -- fail: -- EFX_ERR(efx, "PHY reset timed out\n"); -- return rc; --} -- --static int xfp_phy_init(struct efx_nic *efx) --{ -- struct xfp_phy_data *phy_data; -- u32 devid = efx_mdio_read_id(efx, MDIO_MMD_PHYXS); -- int rc; -- -- phy_data = kzalloc(sizeof(struct xfp_phy_data), GFP_KERNEL); -- if (!phy_data) -- return -ENOMEM; -- efx->phy_data = phy_data; -- -- EFX_INFO(efx, "PHY ID reg %x (OUI %06x model %02x revision %x)\n", -- devid, efx_mdio_id_oui(devid), efx_mdio_id_model(devid), -- efx_mdio_id_rev(devid)); -- -- phy_data->phy_mode = efx->phy_mode; -- -- rc = xfp_reset_phy(efx); -- -- EFX_INFO(efx, "PHY init %s.\n", -- rc ? "failed" : "successful"); -- if (rc < 0) -- goto fail; -- -- return 0; -- -- fail: -- kfree(efx->phy_data); -- efx->phy_data = NULL; -- return rc; --} -- --static void xfp_phy_clear_interrupt(struct efx_nic *efx) --{ -- /* Read to clear link status alarm */ -- efx_mdio_read(efx, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_STAT); --} -- --static int xfp_link_ok(struct efx_nic *efx) --{ -- return efx_mdio_links_ok(efx, XFP_REQUIRED_DEVS); --} -- --static void xfp_phy_poll(struct efx_nic *efx) --{ -- int link_up = xfp_link_ok(efx); -- /* Simulate a PHY event if link state has changed */ -- if (link_up != efx->link_up) -- falcon_sim_phy_event(efx); --} -- --static void xfp_phy_reconfigure(struct efx_nic *efx) --{ -- struct xfp_phy_data *phy_data = efx->phy_data; -- -- if (efx->phy_type == PHY_TYPE_QT2025C) { -- /* There are several different register bits which can -- * disable TX (and save power) on direct-attach cables -- * or optical transceivers, varying somewhat between -- * firmware versions. Only 'static mode' appears to -- * cover everything. */ -- mdio_set_flag( -- &efx->mdio, efx->mdio.prtad, MDIO_MMD_PMAPMD, -- PMA_PMD_FTX_CTRL2_REG, 1 << PMA_PMD_FTX_STATIC_LBN, -- efx->phy_mode & PHY_MODE_TX_DISABLED || -- efx->phy_mode & PHY_MODE_LOW_POWER || -- efx->loopback_mode == LOOPBACK_PCS || -- efx->loopback_mode == LOOPBACK_PMAPMD); -- } else { -- /* Reset the PHY when moving from tx off to tx on */ -- if (!(efx->phy_mode & PHY_MODE_TX_DISABLED) && -- (phy_data->phy_mode & PHY_MODE_TX_DISABLED)) -- xfp_reset_phy(efx); -- -- efx_mdio_transmit_disable(efx); -- } -- -- efx_mdio_phy_reconfigure(efx); -- -- phy_data->phy_mode = efx->phy_mode; -- efx->link_up = xfp_link_ok(efx); -- efx->link_speed = 10000; -- efx->link_fd = true; -- efx->link_fc = efx->wanted_fc; --} -- --static void xfp_phy_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) --{ -- mdio45_ethtool_gset(&efx->mdio, ecmd); --} -- --static void xfp_phy_fini(struct efx_nic *efx) --{ -- /* Clobber the LED if it was blinking */ -- efx->board_info.blink(efx, false); -- -- /* Free the context block */ -- kfree(efx->phy_data); -- efx->phy_data = NULL; --} -- --struct efx_phy_operations falcon_xfp_phy_ops = { -- .macs = EFX_XMAC, -- .init = xfp_phy_init, -- .reconfigure = xfp_phy_reconfigure, -- .poll = xfp_phy_poll, -- .fini = xfp_phy_fini, -- .clear_interrupt = xfp_phy_clear_interrupt, -- .get_settings = xfp_phy_get_settings, -- .set_settings = efx_mdio_set_settings, -- .mmds = XFP_REQUIRED_DEVS, -- .loopbacks = XFP_LOOPBACKS, --}; diff --git a/debian/patches/features/all/speakup/speakup-kbuild.patch b/debian/patches/features/all/speakup/speakup-kbuild.patch index 993be4b09..aec7a485a 100644 --- a/debian/patches/features/all/speakup/speakup-kbuild.patch +++ b/debian/patches/features/all/speakup/speakup-kbuild.patch @@ -4,9 +4,9 @@ Subject: [PATCH] speakup: integrate into kbuild --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig @@ -126,6 +126,8 @@ - source "drivers/staging/sep/Kconfig" + source "drivers/staging/netwave/Kconfig" - source "drivers/staging/iio/Kconfig" + source "drivers/staging/sm7xx/Kconfig" + +source "drivers/staging/speakup/Kconfig" @@ -15,9 +15,9 @@ Subject: [PATCH] speakup: integrate into kbuild --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile @@ -45,3 +45,4 @@ - obj-$(CONFIG_RAR_REGISTER) += rar/ - obj-$(CONFIG_DX_SEP) += sep/ - obj-$(CONFIG_IIO) += iio/ + obj-$(CONFIG_PCMCIA_WAVELAN) += wavelan/ + obj-$(CONFIG_PCMCIA_NETWAVE) += netwave/ + obj-$(CONFIG_FB_SM7XX) += sm7xx/ +obj-$(CONFIG_SPEAKUP) += speakup/ --- a/drivers/staging/speakup/Kbuild +++ b/drivers/staging/speakup/Kbuild diff --git a/debian/patches/features/all/vserver/bindmount-dev.patch b/debian/patches/features/all/vserver/bindmount-dev.patch deleted file mode 100644 index 2cb270691..000000000 --- a/debian/patches/features/all/vserver/bindmount-dev.patch +++ /dev/null @@ -1,41 +0,0 @@ ---- a/fs/namespace.c 2007-02-07 14:15:28.000000000 +0100 -+++ b/fs/namespace.c 2007-02-08 10:57:40.000000000 +0100 -@@ -988,6 +988,9 @@ static int do_loopback(struct nameidata - if (!mnt) - goto out; - -+ if (!capable(CAP_SYS_ADMIN) && (old_nd.path.mnt->mnt_flags & MNT_NODEV)) -+ mnt_flags |= MNT_NODEV; -+ - err = graft_tree(mnt, &nd->path); - if (err) { - LIST_HEAD(umount_list); -@@ -1030,6 +1033,9 @@ static int do_remount(struct nameidata * - if (nd->path.dentry != nd->path.mnt->mnt_root) - return -EINVAL; - -+ if (!capable(CAP_SYS_ADMIN)) -+ mnt_flags |= MNT_NODEV; -+ - down_write(&sb->s_umount); - if (flags & MS_BIND) - err = change_mount_flags(nd->path.mnt, flags); -@@ -1138,6 +1144,9 @@ static int do_new_mount(struct nameidata - if (!vx_capable(CAP_SYS_ADMIN, VXC_SECURE_MOUNT)) - return -EPERM; - -+ if (!capable(CAP_SYS_ADMIN)) -+ mnt_flags |= MNT_NODEV; -+ - mnt = do_kern_mount(type, flags, name, data); - if (IS_ERR(mnt)) - return PTR_ERR(mnt); -@@ -1489,8 +1498,6 @@ long do_mount(char *dev_name, char *dir_ - if (flags & MS_RDONLY) - mnt_flags |= MNT_READONLY; - -- if (!capable(CAP_SYS_ADMIN)) -- mnt_flags |= MNT_NODEV; - flags &= ~(MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_ACTIVE | - MS_NOATIME | MS_NODIRATIME | MS_RELATIME| MS_KERNMOUNT); - diff --git a/debian/patches/features/all/vserver/ia64-buildfix.patch b/debian/patches/features/all/vserver/ia64-buildfix.patch deleted file mode 100644 index 415e0f417..000000000 --- a/debian/patches/features/all/vserver/ia64-buildfix.patch +++ /dev/null @@ -1,11 +0,0 @@ -diff -urpN a/arch/ia64/include/asm/tlb.h b/arch/ia64/include/asm/tlb.h ---- a/arch/ia64/include/asm/tlb.h 2009-12-02 20:51:21.000000000 -0700 -+++ b/arch/ia64/include/asm/tlb.h 2009-12-30 01:46:05.000000000 -0700 -@@ -40,6 +40,7 @@ - #include - #include - #include -+#include - - #include - #include diff --git a/debian/patches/features/all/vserver/s390-buildfix.patch b/debian/patches/features/all/vserver/s390-buildfix.patch deleted file mode 100644 index 0705df61d..000000000 --- a/debian/patches/features/all/vserver/s390-buildfix.patch +++ /dev/null @@ -1,23 +0,0 @@ -diff -urpN a/arch/s390/include/asm/tlb.h b/arch/s390/include/asm/tlb.h ---- a/arch/s390/include/asm/tlb.h 2009-12-02 20:51:21.000000000 -0700 -+++ b/arch/s390/include/asm/tlb.h 2009-12-30 01:46:05.000000000 -0700 -@@ -23,6 +23,7 @@ - - #include - #include -+#include - #include - #include - #include -diff -urpN a/arch/s390/include/asm/unistd.h b/arch/s390/include/asm/unistd.h ---- a/arch/s390/include/asm/unistd.h 2009-12-02 20:51:21.000000000 -0700 -+++ b/arch/s390/include/asm/unistd.h 2009-12-30 01:42:52.000000000 -0700 -@@ -202,7 +202,7 @@ - #define __NR_clock_gettime (__NR_timer_create+6) - #define __NR_clock_getres (__NR_timer_create+7) - #define __NR_clock_nanosleep (__NR_timer_create+8) --/* Number 263 is reserved for vserver */ -+#define __NR_vserver 263 - #define __NR_statfs64 265 - #define __NR_fstatfs64 266 - #define __NR_remap_file_pages 267 diff --git a/debian/patches/features/all/vserver/vs2.3.0.36.27.patch b/debian/patches/features/all/vserver/vs2.3.0.36.27.patch deleted file mode 100644 index 4cb9ace35..000000000 --- a/debian/patches/features/all/vserver/vs2.3.0.36.27.patch +++ /dev/null @@ -1,28738 +0,0 @@ -diff -NurpP --minimal linux-2.6.32.1/arch/alpha/Kconfig linux-2.6.32.1-vs2.3.0.36.27/arch/alpha/Kconfig ---- linux-2.6.32.1/arch/alpha/Kconfig 2009-12-03 20:01:49.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/arch/alpha/Kconfig 2009-12-03 20:04:56.000000000 +0100 -@@ -674,6 +674,8 @@ config DUMMY_CONSOLE - depends on VGA_HOSE - default y - -+source "kernel/vserver/Kconfig" -+ - source "security/Kconfig" - - source "crypto/Kconfig" -diff -NurpP --minimal linux-2.6.32.1/arch/alpha/kernel/entry.S linux-2.6.32.1-vs2.3.0.36.27/arch/alpha/kernel/entry.S ---- linux-2.6.32.1/arch/alpha/kernel/entry.S 2009-06-11 17:11:46.000000000 +0200 -+++ linux-2.6.32.1-vs2.3.0.36.27/arch/alpha/kernel/entry.S 2009-12-03 20:04:56.000000000 +0100 -@@ -874,24 +874,15 @@ sys_getxgid: - .globl sys_getxpid - .ent sys_getxpid - sys_getxpid: -+ lda $sp, -16($sp) -+ stq $26, 0($sp) - .prologue 0 -- ldq $2, TI_TASK($8) - -- /* See linux/kernel/timer.c sys_getppid for discussion -- about this loop. */ -- ldq $3, TASK_GROUP_LEADER($2) -- ldq $4, TASK_REAL_PARENT($3) -- ldl $0, TASK_TGID($2) --1: ldl $1, TASK_TGID($4) --#ifdef CONFIG_SMP -- mov $4, $5 -- mb -- ldq $3, TASK_GROUP_LEADER($2) -- ldq $4, TASK_REAL_PARENT($3) -- cmpeq $4, $5, $5 -- beq $5, 1b --#endif -- stq $1, 80($sp) -+ lda $16, 96($sp) -+ jsr $26, do_getxpid -+ ldq $26, 0($sp) -+ -+ lda $sp, 16($sp) - ret - .end sys_getxpid - -diff -NurpP --minimal linux-2.6.32.1/arch/alpha/kernel/osf_sys.c linux-2.6.32.1-vs2.3.0.36.27/arch/alpha/kernel/osf_sys.c ---- linux-2.6.32.1/arch/alpha/kernel/osf_sys.c 2009-09-10 15:25:14.000000000 +0200 -+++ linux-2.6.32.1-vs2.3.0.36.27/arch/alpha/kernel/osf_sys.c 2009-12-03 20:04:56.000000000 +0100 -@@ -872,7 +872,7 @@ SYSCALL_DEFINE2(osf_gettimeofday, struct - { - if (tv) { - struct timeval ktv; -- do_gettimeofday(&ktv); -+ vx_gettimeofday(&ktv); - if (put_tv32(tv, &ktv)) - return -EFAULT; - } -diff -NurpP --minimal linux-2.6.32.1/arch/alpha/kernel/ptrace.c linux-2.6.32.1-vs2.3.0.36.27/arch/alpha/kernel/ptrace.c ---- linux-2.6.32.1/arch/alpha/kernel/ptrace.c 2009-09-10 15:25:14.000000000 +0200 -+++ linux-2.6.32.1-vs2.3.0.36.27/arch/alpha/kernel/ptrace.c 2009-12-03 20:04:56.000000000 +0100 -@@ -14,6 +14,7 @@ - #include - #include - #include -+#include - - #include - #include -diff -NurpP --minimal linux-2.6.32.1/arch/alpha/kernel/systbls.S linux-2.6.32.1-vs2.3.0.36.27/arch/alpha/kernel/systbls.S ---- linux-2.6.32.1/arch/alpha/kernel/systbls.S 2009-03-24 14:18:08.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/arch/alpha/kernel/systbls.S 2009-12-03 20:04:56.000000000 +0100 -@@ -446,7 +446,7 @@ sys_call_table: - .quad sys_stat64 /* 425 */ - .quad sys_lstat64 - .quad sys_fstat64 -- .quad sys_ni_syscall /* sys_vserver */ -+ .quad sys_vserver /* sys_vserver */ - .quad sys_ni_syscall /* sys_mbind */ - .quad sys_ni_syscall /* sys_get_mempolicy */ - .quad sys_ni_syscall /* sys_set_mempolicy */ -diff -NurpP --minimal linux-2.6.32.1/arch/alpha/kernel/traps.c linux-2.6.32.1-vs2.3.0.36.27/arch/alpha/kernel/traps.c ---- linux-2.6.32.1/arch/alpha/kernel/traps.c 2009-06-11 17:11:46.000000000 +0200 -+++ linux-2.6.32.1-vs2.3.0.36.27/arch/alpha/kernel/traps.c 2009-12-03 20:04:56.000000000 +0100 -@@ -183,7 +183,8 @@ die_if_kernel(char * str, struct pt_regs - #ifdef CONFIG_SMP - printk("CPU %d ", hard_smp_processor_id()); - #endif -- printk("%s(%d): %s %ld\n", current->comm, task_pid_nr(current), str, err); -+ printk("%s(%d[#%u]): %s %ld\n", current->comm, -+ task_pid_nr(current), current->xid, str, err); - dik_show_regs(regs, r9_15); - add_taint(TAINT_DIE); - dik_show_trace((unsigned long *)(regs+1)); -diff -NurpP --minimal linux-2.6.32.1/arch/alpha/mm/fault.c linux-2.6.32.1-vs2.3.0.36.27/arch/alpha/mm/fault.c ---- linux-2.6.32.1/arch/alpha/mm/fault.c 2009-09-10 15:25:14.000000000 +0200 -+++ linux-2.6.32.1-vs2.3.0.36.27/arch/alpha/mm/fault.c 2009-12-03 20:04:56.000000000 +0100 -@@ -193,8 +193,8 @@ do_page_fault(unsigned long address, uns - down_read(&mm->mmap_sem); - goto survive; - } -- printk(KERN_ALERT "VM: killing process %s(%d)\n", -- current->comm, task_pid_nr(current)); -+ printk(KERN_ALERT "VM: killing process %s(%d:#%u)\n", -+ current->comm, task_pid_nr(current), current->xid); - if (!user_mode(regs)) - goto no_context; - do_group_exit(SIGKILL); -diff -NurpP --minimal linux-2.6.32.1/arch/arm/Kconfig linux-2.6.32.1-vs2.3.0.36.27/arch/arm/Kconfig ---- linux-2.6.32.1/arch/arm/Kconfig 2009-12-03 20:01:49.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/arch/arm/Kconfig 2009-12-03 20:04:56.000000000 +0100 -@@ -1512,6 +1512,8 @@ source "fs/Kconfig" - - source "arch/arm/Kconfig.debug" - -+source "kernel/vserver/Kconfig" -+ - source "security/Kconfig" - - source "crypto/Kconfig" -diff -NurpP --minimal linux-2.6.32.1/arch/arm/kernel/calls.S linux-2.6.32.1-vs2.3.0.36.27/arch/arm/kernel/calls.S ---- linux-2.6.32.1/arch/arm/kernel/calls.S 2009-12-03 20:01:50.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/arch/arm/kernel/calls.S 2009-12-03 20:04:56.000000000 +0100 -@@ -322,7 +322,7 @@ - /* 310 */ CALL(sys_request_key) - CALL(sys_keyctl) - CALL(ABI(sys_semtimedop, sys_oabi_semtimedop)) --/* vserver */ CALL(sys_ni_syscall) -+ CALL(sys_vserver) - CALL(sys_ioprio_set) - /* 315 */ CALL(sys_ioprio_get) - CALL(sys_inotify_init) -diff -NurpP --minimal linux-2.6.32.1/arch/arm/kernel/process.c linux-2.6.32.1-vs2.3.0.36.27/arch/arm/kernel/process.c ---- linux-2.6.32.1/arch/arm/kernel/process.c 2009-12-03 20:01:50.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/arch/arm/kernel/process.c 2009-12-03 20:04:56.000000000 +0100 -@@ -269,7 +269,8 @@ void __show_regs(struct pt_regs *regs) - void show_regs(struct pt_regs * regs) - { - printk("\n"); -- printk("Pid: %d, comm: %20s\n", task_pid_nr(current), current->comm); -+ printk("Pid: %d[#%u], comm: %20s\n", -+ task_pid_nr(current), current->xid, current->comm); - __show_regs(regs); - __backtrace(); - } -diff -NurpP --minimal linux-2.6.32.1/arch/arm/kernel/traps.c linux-2.6.32.1-vs2.3.0.36.27/arch/arm/kernel/traps.c ---- linux-2.6.32.1/arch/arm/kernel/traps.c 2009-12-03 20:01:50.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/arch/arm/kernel/traps.c 2009-12-03 20:04:56.000000000 +0100 -@@ -234,8 +234,8 @@ static void __die(const char *str, int e - sysfs_printk_last_file(); - print_modules(); - __show_regs(regs); -- printk(KERN_EMERG "Process %.*s (pid: %d, stack limit = 0x%p)\n", -- TASK_COMM_LEN, tsk->comm, task_pid_nr(tsk), thread + 1); -+ printk(KERN_EMERG "Process %.*s (pid: %d:#%u, stack limit = 0x%p)\n", -+ TASK_COMM_LEN, tsk->comm, task_pid_nr(tsk), tsk->xid, thread + 1); - - if (!user_mode(regs) || in_interrupt()) { - dump_mem(KERN_EMERG, "Stack: ", regs->ARM_sp, -diff -NurpP --minimal linux-2.6.32.1/arch/avr32/mm/fault.c linux-2.6.32.1-vs2.3.0.36.27/arch/avr32/mm/fault.c ---- linux-2.6.32.1/arch/avr32/mm/fault.c 2009-09-10 15:25:20.000000000 +0200 -+++ linux-2.6.32.1-vs2.3.0.36.27/arch/avr32/mm/fault.c 2009-12-03 20:04:56.000000000 +0100 -@@ -216,7 +216,8 @@ out_of_memory: - down_read(&mm->mmap_sem); - goto survive; - } -- printk("VM: Killing process %s\n", tsk->comm); -+ printk("VM: Killing process %s(%d:#%u)\n", -+ tsk->comm, task_pid_nr(tsk), tsk->xid); - if (user_mode(regs)) - do_group_exit(SIGKILL); - goto no_context; -diff -NurpP --minimal linux-2.6.32.1/arch/cris/Kconfig linux-2.6.32.1-vs2.3.0.36.27/arch/cris/Kconfig ---- linux-2.6.32.1/arch/cris/Kconfig 2009-06-11 17:11:56.000000000 +0200 -+++ linux-2.6.32.1-vs2.3.0.36.27/arch/cris/Kconfig 2009-12-03 20:04:56.000000000 +0100 -@@ -685,6 +685,8 @@ source "drivers/staging/Kconfig" - - source "arch/cris/Kconfig.debug" - -+source "kernel/vserver/Kconfig" -+ - source "security/Kconfig" - - source "crypto/Kconfig" -diff -NurpP --minimal linux-2.6.32.1/arch/cris/mm/fault.c linux-2.6.32.1-vs2.3.0.36.27/arch/cris/mm/fault.c ---- linux-2.6.32.1/arch/cris/mm/fault.c 2009-12-03 20:01:56.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/arch/cris/mm/fault.c 2009-12-03 20:04:56.000000000 +0100 -@@ -245,7 +245,8 @@ do_page_fault(unsigned long address, str - - out_of_memory: - up_read(&mm->mmap_sem); -- printk("VM: killing process %s\n", tsk->comm); -+ printk("VM: killing process %s(%d:#%u)\n", -+ tsk->comm, task_pid_nr(tsk), tsk->xid); - if (user_mode(regs)) - do_exit(SIGKILL); - goto no_context; -diff -NurpP --minimal linux-2.6.32.1/arch/frv/kernel/kernel_thread.S linux-2.6.32.1-vs2.3.0.36.27/arch/frv/kernel/kernel_thread.S ---- linux-2.6.32.1/arch/frv/kernel/kernel_thread.S 2008-12-25 00:26:37.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/arch/frv/kernel/kernel_thread.S 2009-12-03 20:04:56.000000000 +0100 -@@ -37,7 +37,7 @@ kernel_thread: - - # start by forking the current process, but with shared VM - setlos.p #__NR_clone,gr7 ; syscall number -- ori gr10,#CLONE_VM,gr8 ; first syscall arg [clone_flags] -+ ori gr10,#CLONE_KT,gr8 ; first syscall arg [clone_flags] - sethi.p #0xe4e4,gr9 ; second syscall arg [newsp] - setlo #0xe4e4,gr9 - setlos.p #0,gr10 ; third syscall arg [parent_tidptr] -diff -NurpP --minimal linux-2.6.32.1/arch/frv/mm/fault.c linux-2.6.32.1-vs2.3.0.36.27/arch/frv/mm/fault.c ---- linux-2.6.32.1/arch/frv/mm/fault.c 2009-09-10 15:25:22.000000000 +0200 -+++ linux-2.6.32.1-vs2.3.0.36.27/arch/frv/mm/fault.c 2009-12-03 20:04:56.000000000 +0100 -@@ -257,7 +257,8 @@ asmlinkage void do_page_fault(int datamm - */ - out_of_memory: - up_read(&mm->mmap_sem); -- printk("VM: killing process %s\n", current->comm); -+ printk("VM: killing process %s(%d:#%u)\n", -+ current->comm, task_pid_nr(current), current->xid); - if (user_mode(__frame)) - do_group_exit(SIGKILL); - goto no_context; -diff -NurpP --minimal linux-2.6.32.1/arch/h8300/Kconfig linux-2.6.32.1-vs2.3.0.36.27/arch/h8300/Kconfig ---- linux-2.6.32.1/arch/h8300/Kconfig 2009-03-24 14:18:24.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/arch/h8300/Kconfig 2009-12-03 20:04:56.000000000 +0100 -@@ -226,6 +226,8 @@ source "fs/Kconfig" - - source "arch/h8300/Kconfig.debug" - -+source "kernel/vserver/Kconfig" -+ - source "security/Kconfig" - - source "crypto/Kconfig" -diff -NurpP --minimal linux-2.6.32.1/arch/ia64/ia32/ia32_entry.S linux-2.6.32.1-vs2.3.0.36.27/arch/ia64/ia32/ia32_entry.S ---- linux-2.6.32.1/arch/ia64/ia32/ia32_entry.S 2009-06-11 17:11:57.000000000 +0200 -+++ linux-2.6.32.1-vs2.3.0.36.27/arch/ia64/ia32/ia32_entry.S 2009-12-03 20:04:56.000000000 +0100 -@@ -451,7 +451,7 @@ ia32_syscall_table: - data8 sys_tgkill /* 270 */ - data8 compat_sys_utimes - data8 sys32_fadvise64_64 -- data8 sys_ni_syscall -+ data8 sys32_vserver - data8 sys_ni_syscall - data8 sys_ni_syscall /* 275 */ - data8 sys_ni_syscall -diff -NurpP --minimal linux-2.6.32.1/arch/ia64/Kconfig linux-2.6.32.1-vs2.3.0.36.27/arch/ia64/Kconfig ---- linux-2.6.32.1/arch/ia64/Kconfig 2009-12-03 20:01:56.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/arch/ia64/Kconfig 2009-12-03 20:04:56.000000000 +0100 -@@ -685,6 +685,8 @@ source "fs/Kconfig" - - source "arch/ia64/Kconfig.debug" - -+source "kernel/vserver/Kconfig" -+ - source "security/Kconfig" - - source "crypto/Kconfig" -diff -NurpP --minimal linux-2.6.32.1/arch/ia64/kernel/entry.S linux-2.6.32.1-vs2.3.0.36.27/arch/ia64/kernel/entry.S ---- linux-2.6.32.1/arch/ia64/kernel/entry.S 2009-09-10 15:25:22.000000000 +0200 -+++ linux-2.6.32.1-vs2.3.0.36.27/arch/ia64/kernel/entry.S 2009-12-03 20:04:56.000000000 +0100 -@@ -1753,7 +1753,7 @@ sys_call_table: - data8 sys_mq_notify - data8 sys_mq_getsetattr - data8 sys_kexec_load -- data8 sys_ni_syscall // reserved for vserver -+ data8 sys_vserver - data8 sys_waitid // 1270 - data8 sys_add_key - data8 sys_request_key -diff -NurpP --minimal linux-2.6.32.1/arch/ia64/kernel/perfmon.c linux-2.6.32.1-vs2.3.0.36.27/arch/ia64/kernel/perfmon.c ---- linux-2.6.32.1/arch/ia64/kernel/perfmon.c 2009-09-10 15:25:22.000000000 +0200 -+++ linux-2.6.32.1-vs2.3.0.36.27/arch/ia64/kernel/perfmon.c 2009-12-03 20:04:56.000000000 +0100 -@@ -41,6 +41,7 @@ - #include - #include - #include -+#include - - #include - #include -@@ -2372,7 +2373,7 @@ pfm_smpl_buffer_alloc(struct task_struct - */ - insert_vm_struct(mm, vma); - -- mm->total_vm += size >> PAGE_SHIFT; -+ vx_vmpages_add(mm, size >> PAGE_SHIFT); - vm_stat_account(vma->vm_mm, vma->vm_flags, vma->vm_file, - vma_pages(vma)); - up_write(&task->mm->mmap_sem); -diff -NurpP --minimal linux-2.6.32.1/arch/ia64/kernel/process.c linux-2.6.32.1-vs2.3.0.36.27/arch/ia64/kernel/process.c ---- linux-2.6.32.1/arch/ia64/kernel/process.c 2009-12-03 20:01:56.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/arch/ia64/kernel/process.c 2009-12-03 20:04:56.000000000 +0100 -@@ -110,8 +110,8 @@ show_regs (struct pt_regs *regs) - unsigned long ip = regs->cr_iip + ia64_psr(regs)->ri; - - print_modules(); -- printk("\nPid: %d, CPU %d, comm: %20s\n", task_pid_nr(current), -- smp_processor_id(), current->comm); -+ printk("\nPid: %d[#%u], CPU %d, comm: %20s\n", task_pid_nr(current), -+ current->xid, smp_processor_id(), current->comm); - printk("psr : %016lx ifs : %016lx ip : [<%016lx>] %s (%s)\n", - regs->cr_ipsr, regs->cr_ifs, ip, print_tainted(), - init_utsname()->release); -diff -NurpP --minimal linux-2.6.32.1/arch/ia64/kernel/ptrace.c linux-2.6.32.1-vs2.3.0.36.27/arch/ia64/kernel/ptrace.c ---- linux-2.6.32.1/arch/ia64/kernel/ptrace.c 2009-09-10 15:25:22.000000000 +0200 -+++ linux-2.6.32.1-vs2.3.0.36.27/arch/ia64/kernel/ptrace.c 2009-12-03 20:04:56.000000000 +0100 -@@ -22,6 +22,7 @@ - #include - #include - #include -+#include - - #include - #include -diff -NurpP --minimal linux-2.6.32.1/arch/ia64/kernel/traps.c linux-2.6.32.1-vs2.3.0.36.27/arch/ia64/kernel/traps.c ---- linux-2.6.32.1/arch/ia64/kernel/traps.c 2008-12-25 00:26:37.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/arch/ia64/kernel/traps.c 2009-12-03 20:04:56.000000000 +0100 -@@ -60,8 +60,9 @@ die (const char *str, struct pt_regs *re - put_cpu(); - - if (++die.lock_owner_depth < 3) { -- printk("%s[%d]: %s %ld [%d]\n", -- current->comm, task_pid_nr(current), str, err, ++die_counter); -+ printk("%s[%d[#%u]]: %s %ld [%d]\n", -+ current->comm, task_pid_nr(current), current->xid, -+ str, err, ++die_counter); - if (notify_die(DIE_OOPS, str, regs, err, 255, SIGSEGV) - != NOTIFY_STOP) - show_regs(regs); -@@ -324,8 +325,9 @@ handle_fpu_swa (int fp_fault, struct pt_ - if ((last.count & 15) < 5 && (ia64_fetchadd(1, &last.count, acq) & 15) < 5) { - last.time = current_jiffies + 5 * HZ; - printk(KERN_WARNING -- "%s(%d): floating-point assist fault at ip %016lx, isr %016lx\n", -- current->comm, task_pid_nr(current), regs->cr_iip + ia64_psr(regs)->ri, isr); -+ "%s(%d[#%u]): floating-point assist fault at ip %016lx, isr %016lx\n", -+ current->comm, task_pid_nr(current), current->xid, -+ regs->cr_iip + ia64_psr(regs)->ri, isr); - } - } - } -diff -NurpP --minimal linux-2.6.32.1/arch/ia64/mm/fault.c linux-2.6.32.1-vs2.3.0.36.27/arch/ia64/mm/fault.c ---- linux-2.6.32.1/arch/ia64/mm/fault.c 2009-09-10 15:25:23.000000000 +0200 -+++ linux-2.6.32.1-vs2.3.0.36.27/arch/ia64/mm/fault.c 2009-12-03 20:04:56.000000000 +0100 -@@ -10,6 +10,7 @@ - #include - #include - #include -+#include - - #include - #include -@@ -281,7 +282,8 @@ ia64_do_page_fault (unsigned long addres - down_read(&mm->mmap_sem); - goto survive; - } -- printk(KERN_CRIT "VM: killing process %s\n", current->comm); -+ printk(KERN_CRIT "VM: killing process %s(%d:#%u)\n", -+ current->comm, task_pid_nr(current), current->xid); - if (user_mode(regs)) - do_group_exit(SIGKILL); - goto no_context; -diff -NurpP --minimal linux-2.6.32.1/arch/m32r/kernel/traps.c linux-2.6.32.1-vs2.3.0.36.27/arch/m32r/kernel/traps.c ---- linux-2.6.32.1/arch/m32r/kernel/traps.c 2009-12-03 20:01:57.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/arch/m32r/kernel/traps.c 2009-12-03 20:04:56.000000000 +0100 -@@ -196,8 +196,9 @@ static void show_registers(struct pt_reg - } else { - printk("SPI: %08lx\n", sp); - } -- printk("Process %s (pid: %d, process nr: %d, stackpage=%08lx)", -- current->comm, task_pid_nr(current), 0xffff & i, 4096+(unsigned long)current); -+ printk("Process %s (pid: %d[#%u], process nr: %d, stackpage=%08lx)", -+ current->comm, task_pid_nr(current), current->xid, -+ 0xffff & i, 4096+(unsigned long)current); - - /* - * When in-kernel, we also print out the stack and code at the -diff -NurpP --minimal linux-2.6.32.1/arch/m32r/mm/fault.c linux-2.6.32.1-vs2.3.0.36.27/arch/m32r/mm/fault.c ---- linux-2.6.32.1/arch/m32r/mm/fault.c 2009-09-10 15:25:23.000000000 +0200 -+++ linux-2.6.32.1-vs2.3.0.36.27/arch/m32r/mm/fault.c 2009-12-03 20:04:56.000000000 +0100 -@@ -276,7 +276,8 @@ out_of_memory: - down_read(&mm->mmap_sem); - goto survive; - } -- printk("VM: killing process %s\n", tsk->comm); -+ printk("VM: killing process %s(%d:#%u)\n", -+ tsk->comm, task_pid_nr(tsk), tsk->xid); - if (error_code & ACE_USERMODE) - do_group_exit(SIGKILL); - goto no_context; -diff -NurpP --minimal linux-2.6.32.1/arch/m68k/Kconfig linux-2.6.32.1-vs2.3.0.36.27/arch/m68k/Kconfig ---- linux-2.6.32.1/arch/m68k/Kconfig 2009-12-03 20:01:57.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/arch/m68k/Kconfig 2009-12-03 20:04:56.000000000 +0100 -@@ -622,6 +622,8 @@ source "fs/Kconfig" - - source "arch/m68k/Kconfig.debug" - -+source "kernel/vserver/Kconfig" -+ - source "security/Kconfig" - - source "crypto/Kconfig" -diff -NurpP --minimal linux-2.6.32.1/arch/m68k/kernel/ptrace.c linux-2.6.32.1-vs2.3.0.36.27/arch/m68k/kernel/ptrace.c ---- linux-2.6.32.1/arch/m68k/kernel/ptrace.c 2008-12-25 00:26:37.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/arch/m68k/kernel/ptrace.c 2009-12-03 20:04:56.000000000 +0100 -@@ -18,6 +18,7 @@ - #include - #include - #include -+#include - - #include - #include -@@ -269,6 +270,8 @@ long arch_ptrace(struct task_struct *chi - ret = ptrace_request(child, request, addr, data); - break; - } -+ if (!vx_check(vx_task_xid(child), VS_WATCH_P | VS_IDENT)) -+ goto out_tsk; - - return ret; - out_eio: -diff -NurpP --minimal linux-2.6.32.1/arch/m68k/kernel/traps.c linux-2.6.32.1-vs2.3.0.36.27/arch/m68k/kernel/traps.c ---- linux-2.6.32.1/arch/m68k/kernel/traps.c 2009-09-10 15:25:23.000000000 +0200 -+++ linux-2.6.32.1-vs2.3.0.36.27/arch/m68k/kernel/traps.c 2009-12-03 20:04:56.000000000 +0100 -@@ -906,8 +906,8 @@ void show_registers(struct pt_regs *regs - printk("d4: %08lx d5: %08lx a0: %08lx a1: %08lx\n", - regs->d4, regs->d5, regs->a0, regs->a1); - -- printk("Process %s (pid: %d, task=%p)\n", -- current->comm, task_pid_nr(current), current); -+ printk("Process %s (pid: %d[#%u], task=%p)\n", -+ current->comm, task_pid_nr(current), current->xid, current); - addr = (unsigned long)&fp->un; - printk("Frame format=%X ", regs->format); - switch (regs->format) { -diff -NurpP --minimal linux-2.6.32.1/arch/m68k/mm/fault.c linux-2.6.32.1-vs2.3.0.36.27/arch/m68k/mm/fault.c ---- linux-2.6.32.1/arch/m68k/mm/fault.c 2009-09-10 15:25:23.000000000 +0200 -+++ linux-2.6.32.1-vs2.3.0.36.27/arch/m68k/mm/fault.c 2009-12-03 20:04:56.000000000 +0100 -@@ -186,7 +186,8 @@ out_of_memory: - goto survive; - } - -- printk("VM: killing process %s\n", current->comm); -+ printk("VM: killing process %s(%d:#%u)\n", -+ current->comm, task_pid_nr(current), current->xid); - if (user_mode(regs)) - do_group_exit(SIGKILL); - -diff -NurpP --minimal linux-2.6.32.1/arch/m68knommu/Kconfig linux-2.6.32.1-vs2.3.0.36.27/arch/m68knommu/Kconfig ---- linux-2.6.32.1/arch/m68knommu/Kconfig 2009-12-03 20:01:57.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/arch/m68knommu/Kconfig 2009-12-03 20:04:56.000000000 +0100 -@@ -727,6 +727,8 @@ source "fs/Kconfig" - - source "arch/m68knommu/Kconfig.debug" - -+source "kernel/vserver/Kconfig" -+ - source "security/Kconfig" - - source "crypto/Kconfig" -diff -NurpP --minimal linux-2.6.32.1/arch/m68knommu/kernel/traps.c linux-2.6.32.1-vs2.3.0.36.27/arch/m68knommu/kernel/traps.c ---- linux-2.6.32.1/arch/m68knommu/kernel/traps.c 2009-09-10 15:25:23.000000000 +0200 -+++ linux-2.6.32.1-vs2.3.0.36.27/arch/m68knommu/kernel/traps.c 2009-12-03 20:04:56.000000000 +0100 -@@ -78,8 +78,9 @@ void die_if_kernel(char *str, struct pt_ - printk(KERN_EMERG "d4: %08lx d5: %08lx a0: %08lx a1: %08lx\n", - fp->d4, fp->d5, fp->a0, fp->a1); - -- printk(KERN_EMERG "Process %s (pid: %d, stackpage=%08lx)\n", -- current->comm, current->pid, PAGE_SIZE+(unsigned long)current); -+ printk(KERN_EMERG "Process %s (pid: %d[#%u], stackpage=%08lx)\n", -+ current->comm, task_pid_nr(current), current->xid, -+ PAGE_SIZE+(unsigned long)current); - show_stack(NULL, (unsigned long *)(fp + 1)); - add_taint(TAINT_DIE); - do_exit(SIGSEGV); -diff -NurpP --minimal linux-2.6.32.1/arch/microblaze/mm/fault.c linux-2.6.32.1-vs2.3.0.36.27/arch/microblaze/mm/fault.c ---- linux-2.6.32.1/arch/microblaze/mm/fault.c 2009-09-10 15:25:24.000000000 +0200 -+++ linux-2.6.32.1-vs2.3.0.36.27/arch/microblaze/mm/fault.c 2009-12-03 20:04:56.000000000 +0100 -@@ -279,7 +279,8 @@ out_of_memory: - goto survive; - } - up_read(&mm->mmap_sem); -- printk(KERN_WARNING "VM: killing process %s\n", current->comm); -+ printk(KERN_WARNING "VM: killing process %s(%d:#%u)\n", -+ current->comm, task_pid_nr(current), current->xid); - if (user_mode(regs)) - do_exit(SIGKILL); - bad_page_fault(regs, address, SIGKILL); -diff -NurpP --minimal linux-2.6.32.1/arch/mips/Kconfig linux-2.6.32.1-vs2.3.0.36.27/arch/mips/Kconfig ---- linux-2.6.32.1/arch/mips/Kconfig 2009-12-03 20:01:58.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/arch/mips/Kconfig 2009-12-03 20:04:56.000000000 +0100 -@@ -2188,6 +2188,8 @@ source "fs/Kconfig" - - source "arch/mips/Kconfig.debug" - -+source "kernel/vserver/Kconfig" -+ - source "security/Kconfig" - - source "crypto/Kconfig" -diff -NurpP --minimal linux-2.6.32.1/arch/mips/kernel/ptrace.c linux-2.6.32.1-vs2.3.0.36.27/arch/mips/kernel/ptrace.c ---- linux-2.6.32.1/arch/mips/kernel/ptrace.c 2008-12-25 00:26:37.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/arch/mips/kernel/ptrace.c 2009-12-03 20:04:56.000000000 +0100 -@@ -25,6 +25,7 @@ - #include - #include - #include -+#include - - #include - #include -@@ -259,6 +260,9 @@ long arch_ptrace(struct task_struct *chi - { - int ret; - -+ if (!vx_check(vx_task_xid(child), VS_WATCH_P | VS_IDENT)) -+ goto out; -+ - switch (request) { - /* when I and D space are separate, these will need to be fixed. */ - case PTRACE_PEEKTEXT: /* read word at location addr. */ -diff -NurpP --minimal linux-2.6.32.1/arch/mips/kernel/scall32-o32.S linux-2.6.32.1-vs2.3.0.36.27/arch/mips/kernel/scall32-o32.S ---- linux-2.6.32.1/arch/mips/kernel/scall32-o32.S 2009-12-03 20:01:59.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/arch/mips/kernel/scall32-o32.S 2009-12-03 20:04:56.000000000 +0100 -@@ -525,7 +525,7 @@ einval: li v0, -ENOSYS - sys sys_mq_timedreceive 5 - sys sys_mq_notify 2 /* 4275 */ - sys sys_mq_getsetattr 3 -- sys sys_ni_syscall 0 /* sys_vserver */ -+ sys sys_vserver 3 - sys sys_waitid 5 - sys sys_ni_syscall 0 /* available, was setaltroot */ - sys sys_add_key 5 /* 4280 */ -diff -NurpP --minimal linux-2.6.32.1/arch/mips/kernel/scall64-64.S linux-2.6.32.1-vs2.3.0.36.27/arch/mips/kernel/scall64-64.S ---- linux-2.6.32.1/arch/mips/kernel/scall64-64.S 2009-12-03 20:01:59.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/arch/mips/kernel/scall64-64.S 2009-12-03 20:04:56.000000000 +0100 -@@ -362,7 +362,7 @@ sys_call_table: - PTR sys_mq_timedreceive - PTR sys_mq_notify - PTR sys_mq_getsetattr /* 5235 */ -- PTR sys_ni_syscall /* sys_vserver */ -+ PTR sys_vserver - PTR sys_waitid - PTR sys_ni_syscall /* available, was setaltroot */ - PTR sys_add_key -diff -NurpP --minimal linux-2.6.32.1/arch/mips/kernel/scall64-n32.S linux-2.6.32.1-vs2.3.0.36.27/arch/mips/kernel/scall64-n32.S ---- linux-2.6.32.1/arch/mips/kernel/scall64-n32.S 2009-12-03 20:01:59.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/arch/mips/kernel/scall64-n32.S 2009-12-03 20:04:56.000000000 +0100 -@@ -360,7 +360,7 @@ EXPORT(sysn32_call_table) - PTR compat_sys_mq_timedreceive - PTR compat_sys_mq_notify - PTR compat_sys_mq_getsetattr -- PTR sys_ni_syscall /* 6240, sys_vserver */ -+ PTR sys32_vserver /* 6240 */ - PTR compat_sys_waitid - PTR sys_ni_syscall /* available, was setaltroot */ - PTR sys_add_key -diff -NurpP --minimal linux-2.6.32.1/arch/mips/kernel/scall64-o32.S linux-2.6.32.1-vs2.3.0.36.27/arch/mips/kernel/scall64-o32.S ---- linux-2.6.32.1/arch/mips/kernel/scall64-o32.S 2009-12-03 20:01:59.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/arch/mips/kernel/scall64-o32.S 2009-12-03 20:04:56.000000000 +0100 -@@ -480,7 +480,7 @@ sys_call_table: - PTR compat_sys_mq_timedreceive - PTR compat_sys_mq_notify /* 4275 */ - PTR compat_sys_mq_getsetattr -- PTR sys_ni_syscall /* sys_vserver */ -+ PTR sys32_vserver - PTR sys_32_waitid - PTR sys_ni_syscall /* available, was setaltroot */ - PTR sys_add_key /* 4280 */ -diff -NurpP --minimal linux-2.6.32.1/arch/mips/kernel/traps.c linux-2.6.32.1-vs2.3.0.36.27/arch/mips/kernel/traps.c ---- linux-2.6.32.1/arch/mips/kernel/traps.c 2009-12-03 20:01:59.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/arch/mips/kernel/traps.c 2009-12-03 20:04:56.000000000 +0100 -@@ -335,9 +335,10 @@ void show_registers(const struct pt_regs - - __show_regs(regs); - print_modules(); -- printk("Process %s (pid: %d, threadinfo=%p, task=%p, tls=%0*lx)\n", -- current->comm, current->pid, current_thread_info(), current, -- field, current_thread_info()->tp_value); -+ printk("Process %s (pid: %d:#%u, threadinfo=%p, task=%p, tls=%0*lx)\n", -+ current->comm, task_pid_nr(current), current->xid, -+ current_thread_info(), current, -+ field, current_thread_info()->tp_value); - if (cpu_has_userlocal) { - unsigned long tls; - -diff -NurpP --minimal linux-2.6.32.1/arch/mn10300/mm/fault.c linux-2.6.32.1-vs2.3.0.36.27/arch/mn10300/mm/fault.c ---- linux-2.6.32.1/arch/mn10300/mm/fault.c 2009-09-10 15:25:39.000000000 +0200 -+++ linux-2.6.32.1-vs2.3.0.36.27/arch/mn10300/mm/fault.c 2009-12-03 20:04:56.000000000 +0100 -@@ -339,7 +339,8 @@ no_context: - out_of_memory: - up_read(&mm->mmap_sem); - monitor_signal(regs); -- printk(KERN_ALERT "VM: killing process %s\n", tsk->comm); -+ printk(KERN_ALERT "VM: killing process %s(%d:#%u)\n", -+ tsk->comm, task_pid_nr(tsk), tsk->xid); - if ((fault_code & MMUFCR_xFC_ACCESS) == MMUFCR_xFC_ACCESS_USR) - do_exit(SIGKILL); - goto no_context; -diff -NurpP --minimal linux-2.6.32.1/arch/parisc/Kconfig linux-2.6.32.1-vs2.3.0.36.27/arch/parisc/Kconfig ---- linux-2.6.32.1/arch/parisc/Kconfig 2009-12-03 20:02:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/arch/parisc/Kconfig 2009-12-03 20:04:56.000000000 +0100 -@@ -294,6 +294,8 @@ source "fs/Kconfig" - - source "arch/parisc/Kconfig.debug" - -+source "kernel/vserver/Kconfig" -+ - source "security/Kconfig" - - source "crypto/Kconfig" -diff -NurpP --minimal linux-2.6.32.1/arch/parisc/kernel/syscall_table.S linux-2.6.32.1-vs2.3.0.36.27/arch/parisc/kernel/syscall_table.S ---- linux-2.6.32.1/arch/parisc/kernel/syscall_table.S 2009-12-03 20:02:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/arch/parisc/kernel/syscall_table.S 2009-12-03 20:04:56.000000000 +0100 -@@ -361,7 +361,7 @@ - ENTRY_COMP(mbind) /* 260 */ - ENTRY_COMP(get_mempolicy) - ENTRY_COMP(set_mempolicy) -- ENTRY_SAME(ni_syscall) /* 263: reserved for vserver */ -+ ENTRY_DIFF(vserver) - ENTRY_SAME(add_key) - ENTRY_SAME(request_key) /* 265 */ - ENTRY_SAME(keyctl) -diff -NurpP --minimal linux-2.6.32.1/arch/parisc/kernel/traps.c linux-2.6.32.1-vs2.3.0.36.27/arch/parisc/kernel/traps.c ---- linux-2.6.32.1/arch/parisc/kernel/traps.c 2009-09-10 15:25:40.000000000 +0200 -+++ linux-2.6.32.1-vs2.3.0.36.27/arch/parisc/kernel/traps.c 2009-12-03 20:04:56.000000000 +0100 -@@ -236,8 +236,9 @@ void die_if_kernel(char *str, struct pt_ - if (err == 0) - return; /* STFU */ - -- printk(KERN_CRIT "%s (pid %d): %s (code %ld) at " RFMT "\n", -- current->comm, task_pid_nr(current), str, err, regs->iaoq[0]); -+ printk(KERN_CRIT "%s (pid %d:#%u): %s (code %ld) at " RFMT "\n", -+ current->comm, task_pid_nr(current), current->xid, -+ str, err, regs->iaoq[0]); - #ifdef PRINT_USER_FAULTS - /* XXX for debugging only */ - show_regs(regs); -@@ -270,8 +271,8 @@ void die_if_kernel(char *str, struct pt_ - pdc_console_restart(); - - if (err) -- printk(KERN_CRIT "%s (pid %d): %s (code %ld)\n", -- current->comm, task_pid_nr(current), str, err); -+ printk(KERN_CRIT "%s (pid %d:#%u): %s (code %ld)\n", -+ current->comm, task_pid_nr(current), current->xid, str, err); - - /* Wot's wrong wif bein' racy? */ - if (current->thread.flags & PARISC_KERNEL_DEATH) { -diff -NurpP --minimal linux-2.6.32.1/arch/parisc/mm/fault.c linux-2.6.32.1-vs2.3.0.36.27/arch/parisc/mm/fault.c ---- linux-2.6.32.1/arch/parisc/mm/fault.c 2009-09-10 15:25:40.000000000 +0200 -+++ linux-2.6.32.1-vs2.3.0.36.27/arch/parisc/mm/fault.c 2009-12-03 20:04:56.000000000 +0100 -@@ -237,8 +237,9 @@ bad_area: - - #ifdef PRINT_USER_FAULTS - printk(KERN_DEBUG "\n"); -- printk(KERN_DEBUG "do_page_fault() pid=%d command='%s' type=%lu address=0x%08lx\n", -- task_pid_nr(tsk), tsk->comm, code, address); -+ printk(KERN_DEBUG "do_page_fault() pid=%d:#%u " -+ "command='%s' type=%lu address=0x%08lx\n", -+ task_pid_nr(tsk), tsk->xid, tsk->comm, code, address); - if (vma) { - printk(KERN_DEBUG "vm_start = 0x%08lx, vm_end = 0x%08lx\n", - vma->vm_start, vma->vm_end); -@@ -264,7 +265,8 @@ no_context: - - out_of_memory: - up_read(&mm->mmap_sem); -- printk(KERN_CRIT "VM: killing process %s\n", current->comm); -+ printk(KERN_CRIT "VM: killing process %s(%d:#%u)\n", -+ current->comm, current->pid, current->xid); - if (user_mode(regs)) - do_group_exit(SIGKILL); - goto no_context; -diff -NurpP --minimal linux-2.6.32.1/arch/powerpc/include/asm/unistd.h linux-2.6.32.1-vs2.3.0.36.27/arch/powerpc/include/asm/unistd.h ---- linux-2.6.32.1/arch/powerpc/include/asm/unistd.h 2009-12-03 20:02:01.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/arch/powerpc/include/asm/unistd.h 2009-12-03 20:04:56.000000000 +0100 -@@ -275,7 +275,7 @@ - #endif - #define __NR_rtas 255 - #define __NR_sys_debug_setcontext 256 --/* Number 257 is reserved for vserver */ -+#define __NR_vserver 257 - #define __NR_migrate_pages 258 - #define __NR_mbind 259 - #define __NR_get_mempolicy 260 -diff -NurpP --minimal linux-2.6.32.1/arch/powerpc/Kconfig linux-2.6.32.1-vs2.3.0.36.27/arch/powerpc/Kconfig ---- linux-2.6.32.1/arch/powerpc/Kconfig 2009-12-03 20:02:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/arch/powerpc/Kconfig 2009-12-03 20:04:56.000000000 +0100 -@@ -943,6 +943,8 @@ source "lib/Kconfig" - - source "arch/powerpc/Kconfig.debug" - -+source "kernel/vserver/Kconfig" -+ - source "security/Kconfig" - - config KEYS_COMPAT -diff -NurpP --minimal linux-2.6.32.1/arch/powerpc/kernel/irq.c linux-2.6.32.1-vs2.3.0.36.27/arch/powerpc/kernel/irq.c ---- linux-2.6.32.1/arch/powerpc/kernel/irq.c 2009-12-03 20:02:01.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/arch/powerpc/kernel/irq.c 2009-12-03 20:04:56.000000000 +0100 -@@ -54,6 +54,7 @@ - #include - #include - #include -+// #include - - #include - #include -diff -NurpP --minimal linux-2.6.32.1/arch/powerpc/kernel/process.c linux-2.6.32.1-vs2.3.0.36.27/arch/powerpc/kernel/process.c ---- linux-2.6.32.1/arch/powerpc/kernel/process.c 2009-12-03 20:02:02.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/arch/powerpc/kernel/process.c 2009-12-03 20:04:56.000000000 +0100 -@@ -519,8 +519,9 @@ void show_regs(struct pt_regs * regs) - #else - printk("DAR: "REG", DSISR: "REG"\n", regs->dar, regs->dsisr); - #endif -- printk("TASK = %p[%d] '%s' THREAD: %p", -- current, task_pid_nr(current), current->comm, task_thread_info(current)); -+ printk("TASK = %p[%d,#%u] '%s' THREAD: %p", -+ current, task_pid_nr(current), current->xid, -+ current->comm, task_thread_info(current)); - - #ifdef CONFIG_SMP - printk(" CPU: %d", raw_smp_processor_id()); -diff -NurpP --minimal linux-2.6.32.1/arch/powerpc/kernel/traps.c linux-2.6.32.1-vs2.3.0.36.27/arch/powerpc/kernel/traps.c ---- linux-2.6.32.1/arch/powerpc/kernel/traps.c 2009-09-10 15:25:41.000000000 +0200 -+++ linux-2.6.32.1-vs2.3.0.36.27/arch/powerpc/kernel/traps.c 2009-12-03 20:04:56.000000000 +0100 -@@ -931,8 +931,9 @@ void nonrecoverable_exception(struct pt_ - - void trace_syscall(struct pt_regs *regs) - { -- printk("Task: %p(%d), PC: %08lX/%08lX, Syscall: %3ld, Result: %s%ld %s\n", -- current, task_pid_nr(current), regs->nip, regs->link, regs->gpr[0], -+ printk("Task: %p(%d[#%u]), PC: %08lX/%08lX, Syscall: %3ld, Result: %s%ld %s\n", -+ current, task_pid_nr(current), current->xid, -+ regs->nip, regs->link, regs->gpr[0], - regs->ccr&0x10000000?"Error=":"", regs->gpr[3], print_tainted()); - } - -diff -NurpP --minimal linux-2.6.32.1/arch/powerpc/kernel/vdso.c linux-2.6.32.1-vs2.3.0.36.27/arch/powerpc/kernel/vdso.c ---- linux-2.6.32.1/arch/powerpc/kernel/vdso.c 2009-12-03 20:02:02.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/arch/powerpc/kernel/vdso.c 2009-12-03 20:04:56.000000000 +0100 -@@ -23,6 +23,7 @@ - #include - #include - #include -+#include - - #include - #include -diff -NurpP --minimal linux-2.6.32.1/arch/powerpc/mm/fault.c linux-2.6.32.1-vs2.3.0.36.27/arch/powerpc/mm/fault.c ---- linux-2.6.32.1/arch/powerpc/mm/fault.c 2009-12-03 20:02:02.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/arch/powerpc/mm/fault.c 2009-12-03 20:04:56.000000000 +0100 -@@ -358,7 +358,8 @@ out_of_memory: - down_read(&mm->mmap_sem); - goto survive; - } -- printk("VM: killing process %s\n", current->comm); -+ printk("VM: killing process %s(%d:#%u)\n", -+ current->comm, current->pid, current->xid); - if (user_mode(regs)) - do_group_exit(SIGKILL); - return SIGKILL; -diff -NurpP --minimal linux-2.6.32.1/arch/s390/Kconfig linux-2.6.32.1-vs2.3.0.36.27/arch/s390/Kconfig ---- linux-2.6.32.1/arch/s390/Kconfig 2009-12-03 20:02:03.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/arch/s390/Kconfig 2009-12-03 20:04:56.000000000 +0100 -@@ -616,6 +616,8 @@ source "fs/Kconfig" - - source "arch/s390/Kconfig.debug" - -+source "kernel/vserver/Kconfig" -+ - source "security/Kconfig" - - source "crypto/Kconfig" -diff -NurpP --minimal linux-2.6.32.1/arch/s390/kernel/ptrace.c linux-2.6.32.1-vs2.3.0.36.27/arch/s390/kernel/ptrace.c ---- linux-2.6.32.1/arch/s390/kernel/ptrace.c 2009-12-03 20:02:03.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/arch/s390/kernel/ptrace.c 2009-12-03 20:04:56.000000000 +0100 -@@ -36,6 +36,7 @@ - #include - #include - #include -+#include - #include - #include - #include -diff -NurpP --minimal linux-2.6.32.1/arch/s390/kernel/syscalls.S linux-2.6.32.1-vs2.3.0.36.27/arch/s390/kernel/syscalls.S ---- linux-2.6.32.1/arch/s390/kernel/syscalls.S 2009-12-03 20:02:03.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/arch/s390/kernel/syscalls.S 2009-12-03 20:04:56.000000000 +0100 -@@ -271,7 +271,7 @@ SYSCALL(sys_clock_settime,sys_clock_sett - SYSCALL(sys_clock_gettime,sys_clock_gettime,sys32_clock_gettime_wrapper) /* 260 */ - SYSCALL(sys_clock_getres,sys_clock_getres,sys32_clock_getres_wrapper) - SYSCALL(sys_clock_nanosleep,sys_clock_nanosleep,sys32_clock_nanosleep_wrapper) --NI_SYSCALL /* reserved for vserver */ -+SYSCALL(sys_vserver,sys_vserver,sys32_vserver) - SYSCALL(sys_s390_fadvise64_64,sys_ni_syscall,sys32_fadvise64_64_wrapper) - SYSCALL(sys_statfs64,sys_statfs64,compat_sys_statfs64_wrapper) - SYSCALL(sys_fstatfs64,sys_fstatfs64,compat_sys_fstatfs64_wrapper) -diff -NurpP --minimal linux-2.6.32.1/arch/s390/lib/uaccess_pt.c linux-2.6.32.1-vs2.3.0.36.27/arch/s390/lib/uaccess_pt.c ---- linux-2.6.32.1/arch/s390/lib/uaccess_pt.c 2009-09-10 15:25:43.000000000 +0200 -+++ linux-2.6.32.1-vs2.3.0.36.27/arch/s390/lib/uaccess_pt.c 2009-12-03 20:04:56.000000000 +0100 -@@ -90,7 +90,8 @@ out_of_memory: - down_read(&mm->mmap_sem); - goto survive; - } -- printk("VM: killing process %s\n", current->comm); -+ printk("VM: killing process %s(%d:#%u)\n", -+ current->comm, task_pid_nr(current), current->xid); - return ret; - - out_sigbus: -diff -NurpP --minimal linux-2.6.32.1/arch/sh/Kconfig linux-2.6.32.1-vs2.3.0.36.27/arch/sh/Kconfig ---- linux-2.6.32.1/arch/sh/Kconfig 2009-12-03 20:02:03.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/arch/sh/Kconfig 2009-12-03 20:04:56.000000000 +0100 -@@ -853,6 +853,8 @@ source "fs/Kconfig" - - source "arch/sh/Kconfig.debug" - -+source "kernel/vserver/Kconfig" -+ - source "security/Kconfig" - - source "crypto/Kconfig" -diff -NurpP --minimal linux-2.6.32.1/arch/sh/kernel/irq.c linux-2.6.32.1-vs2.3.0.36.27/arch/sh/kernel/irq.c ---- linux-2.6.32.1/arch/sh/kernel/irq.c 2009-12-03 20:02:10.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/arch/sh/kernel/irq.c 2009-12-03 20:04:56.000000000 +0100 -@@ -12,6 +12,7 @@ - #include - #include - #include -+// #include - #include - #include - #include -diff -NurpP --minimal linux-2.6.32.1/arch/sh/kernel/vsyscall/vsyscall.c linux-2.6.32.1-vs2.3.0.36.27/arch/sh/kernel/vsyscall/vsyscall.c ---- linux-2.6.32.1/arch/sh/kernel/vsyscall/vsyscall.c 2009-03-24 14:18:42.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/arch/sh/kernel/vsyscall/vsyscall.c 2009-12-03 20:04:56.000000000 +0100 -@@ -19,6 +19,7 @@ - #include - #include - #include -+#include - - /* - * Should the kernel map a VDSO page into processes and pass its -diff -NurpP --minimal linux-2.6.32.1/arch/sh/mm/fault_32.c linux-2.6.32.1-vs2.3.0.36.27/arch/sh/mm/fault_32.c ---- linux-2.6.32.1/arch/sh/mm/fault_32.c 2009-12-03 20:02:14.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/arch/sh/mm/fault_32.c 2009-12-03 20:04:56.000000000 +0100 -@@ -292,7 +292,8 @@ out_of_memory: - down_read(&mm->mmap_sem); - goto survive; - } -- printk("VM: killing process %s\n", tsk->comm); -+ printk("VM: killing process %s(%d:#%u)\n", -+ tsk->comm, task_pid_nr(tsk), tsk->xid); - if (user_mode(regs)) - do_group_exit(SIGKILL); - goto no_context; -diff -NurpP --minimal linux-2.6.32.1/arch/sh/mm/tlbflush_64.c linux-2.6.32.1-vs2.3.0.36.27/arch/sh/mm/tlbflush_64.c ---- linux-2.6.32.1/arch/sh/mm/tlbflush_64.c 2009-12-03 20:02:14.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/arch/sh/mm/tlbflush_64.c 2009-12-03 20:04:56.000000000 +0100 -@@ -306,7 +306,8 @@ out_of_memory: - down_read(&mm->mmap_sem); - goto survive; - } -- printk("VM: killing process %s\n", tsk->comm); -+ printk("VM: killing process %s(%d:#%u)\n", -+ tsk->comm, task_pid_nr(tsk), tsk->xid); - if (user_mode(regs)) - do_group_exit(SIGKILL); - goto no_context; -diff -NurpP --minimal linux-2.6.32.1/arch/sparc/include/asm/tlb_64.h linux-2.6.32.1-vs2.3.0.36.27/arch/sparc/include/asm/tlb_64.h ---- linux-2.6.32.1/arch/sparc/include/asm/tlb_64.h 2009-09-10 15:25:45.000000000 +0200 -+++ linux-2.6.32.1-vs2.3.0.36.27/arch/sparc/include/asm/tlb_64.h 2009-12-03 20:04:56.000000000 +0100 -@@ -3,6 +3,7 @@ - - #include - #include -+#include - #include - #include - #include -diff -NurpP --minimal linux-2.6.32.1/arch/sparc/include/asm/unistd.h linux-2.6.32.1-vs2.3.0.36.27/arch/sparc/include/asm/unistd.h ---- linux-2.6.32.1/arch/sparc/include/asm/unistd.h 2009-12-03 20:02:15.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/arch/sparc/include/asm/unistd.h 2009-12-03 20:04:56.000000000 +0100 -@@ -335,7 +335,7 @@ - #define __NR_timer_getoverrun 264 - #define __NR_timer_delete 265 - #define __NR_timer_create 266 --/* #define __NR_vserver 267 Reserved for VSERVER */ -+#define __NR_vserver 267 - #define __NR_io_setup 268 - #define __NR_io_destroy 269 - #define __NR_io_submit 270 -diff -NurpP --minimal linux-2.6.32.1/arch/sparc/Kconfig linux-2.6.32.1-vs2.3.0.36.27/arch/sparc/Kconfig ---- linux-2.6.32.1/arch/sparc/Kconfig 2009-12-03 20:02:14.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/arch/sparc/Kconfig 2009-12-03 20:04:56.000000000 +0100 -@@ -550,6 +550,8 @@ source "fs/Kconfig" - - source "arch/sparc/Kconfig.debug" - -+source "kernel/vserver/Kconfig" -+ - source "security/Kconfig" - - source "crypto/Kconfig" -diff -NurpP --minimal linux-2.6.32.1/arch/sparc/kernel/systbls_32.S linux-2.6.32.1-vs2.3.0.36.27/arch/sparc/kernel/systbls_32.S ---- linux-2.6.32.1/arch/sparc/kernel/systbls_32.S 2009-12-03 20:02:15.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/arch/sparc/kernel/systbls_32.S 2009-12-03 20:04:56.000000000 +0100 -@@ -70,7 +70,7 @@ sys_call_table: - /*250*/ .long sparc_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys_nfsservctl - /*255*/ .long sys_sync_file_range, sys_clock_settime, sys_clock_gettime, sys_clock_getres, sys_clock_nanosleep - /*260*/ .long sys_sched_getaffinity, sys_sched_setaffinity, sys_timer_settime, sys_timer_gettime, sys_timer_getoverrun --/*265*/ .long sys_timer_delete, sys_timer_create, sys_nis_syscall, sys_io_setup, sys_io_destroy -+/*265*/ .long sys_timer_delete, sys_timer_create, sys_vserver, sys_io_setup, sys_io_destroy - /*270*/ .long sys_io_submit, sys_io_cancel, sys_io_getevents, sys_mq_open, sys_mq_unlink - /*275*/ .long sys_mq_timedsend, sys_mq_timedreceive, sys_mq_notify, sys_mq_getsetattr, sys_waitid - /*280*/ .long sys_tee, sys_add_key, sys_request_key, sys_keyctl, sys_openat -diff -NurpP --minimal linux-2.6.32.1/arch/sparc/kernel/systbls_64.S linux-2.6.32.1-vs2.3.0.36.27/arch/sparc/kernel/systbls_64.S ---- linux-2.6.32.1/arch/sparc/kernel/systbls_64.S 2009-12-03 20:02:15.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/arch/sparc/kernel/systbls_64.S 2009-12-03 20:04:56.000000000 +0100 -@@ -71,7 +71,7 @@ sys_call_table32: - /*250*/ .word sys32_mremap, sys32_sysctl, sys32_getsid, sys_fdatasync, sys32_nfsservctl - .word sys32_sync_file_range, compat_sys_clock_settime, compat_sys_clock_gettime, compat_sys_clock_getres, sys32_clock_nanosleep - /*260*/ .word compat_sys_sched_getaffinity, compat_sys_sched_setaffinity, sys32_timer_settime, compat_sys_timer_gettime, sys_timer_getoverrun -- .word sys_timer_delete, compat_sys_timer_create, sys_ni_syscall, compat_sys_io_setup, sys_io_destroy -+ .word sys_timer_delete, compat_sys_timer_create, sys32_vserver, compat_sys_io_setup, sys_io_destroy - /*270*/ .word sys32_io_submit, sys_io_cancel, compat_sys_io_getevents, sys32_mq_open, sys_mq_unlink - .word compat_sys_mq_timedsend, compat_sys_mq_timedreceive, compat_sys_mq_notify, compat_sys_mq_getsetattr, compat_sys_waitid - /*280*/ .word sys32_tee, sys_add_key, sys_request_key, sys_keyctl, compat_sys_openat -@@ -146,7 +146,7 @@ sys_call_table: - /*250*/ .word sys_64_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys_nfsservctl - .word sys_sync_file_range, sys_clock_settime, sys_clock_gettime, sys_clock_getres, sys_clock_nanosleep - /*260*/ .word sys_sched_getaffinity, sys_sched_setaffinity, sys_timer_settime, sys_timer_gettime, sys_timer_getoverrun -- .word sys_timer_delete, sys_timer_create, sys_ni_syscall, sys_io_setup, sys_io_destroy -+ .word sys_timer_delete, sys_timer_create, sys_vserver, sys_io_setup, sys_io_destroy - /*270*/ .word sys_io_submit, sys_io_cancel, sys_io_getevents, sys_mq_open, sys_mq_unlink - .word sys_mq_timedsend, sys_mq_timedreceive, sys_mq_notify, sys_mq_getsetattr, sys_waitid - /*280*/ .word sys_tee, sys_add_key, sys_request_key, sys_keyctl, sys_openat -diff -NurpP --minimal linux-2.6.32.1/arch/x86/ia32/ia32entry.S linux-2.6.32.1-vs2.3.0.36.27/arch/x86/ia32/ia32entry.S ---- linux-2.6.32.1/arch/x86/ia32/ia32entry.S 2009-12-03 20:02:15.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/arch/x86/ia32/ia32entry.S 2009-12-03 20:04:56.000000000 +0100 -@@ -777,7 +777,7 @@ ia32_sys_call_table: - .quad sys_tgkill /* 270 */ - .quad compat_sys_utimes - .quad sys32_fadvise64_64 -- .quad quiet_ni_syscall /* sys_vserver */ -+ .quad sys32_vserver - .quad sys_mbind - .quad compat_sys_get_mempolicy /* 275 */ - .quad sys_set_mempolicy -diff -NurpP --minimal linux-2.6.32.1/arch/x86/include/asm/unistd_64.h linux-2.6.32.1-vs2.3.0.36.27/arch/x86/include/asm/unistd_64.h ---- linux-2.6.32.1/arch/x86/include/asm/unistd_64.h 2009-12-03 20:02:16.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/arch/x86/include/asm/unistd_64.h 2009-12-03 20:04:56.000000000 +0100 -@@ -535,7 +535,7 @@ __SYSCALL(__NR_tgkill, sys_tgkill) - #define __NR_utimes 235 - __SYSCALL(__NR_utimes, sys_utimes) - #define __NR_vserver 236 --__SYSCALL(__NR_vserver, sys_ni_syscall) -+__SYSCALL(__NR_vserver, sys_vserver) - #define __NR_mbind 237 - __SYSCALL(__NR_mbind, sys_mbind) - #define __NR_set_mempolicy 238 -diff -NurpP --minimal linux-2.6.32.1/arch/x86/Kconfig linux-2.6.32.1-vs2.3.0.36.27/arch/x86/Kconfig ---- linux-2.6.32.1/arch/x86/Kconfig 2009-12-03 20:02:15.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/arch/x86/Kconfig 2009-12-03 20:04:56.000000000 +0100 -@@ -2085,6 +2085,8 @@ source "fs/Kconfig" - - source "arch/x86/Kconfig.debug" - -+source "kernel/vserver/Kconfig" -+ - source "security/Kconfig" - - source "crypto/Kconfig" -diff -NurpP --minimal linux-2.6.32.1/arch/x86/kernel/syscall_table_32.S linux-2.6.32.1-vs2.3.0.36.27/arch/x86/kernel/syscall_table_32.S ---- linux-2.6.32.1/arch/x86/kernel/syscall_table_32.S 2009-12-03 20:02:16.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/arch/x86/kernel/syscall_table_32.S 2009-12-03 20:04:56.000000000 +0100 -@@ -272,7 +272,7 @@ ENTRY(sys_call_table) - .long sys_tgkill /* 270 */ - .long sys_utimes - .long sys_fadvise64_64 -- .long sys_ni_syscall /* sys_vserver */ -+ .long sys_vserver - .long sys_mbind - .long sys_get_mempolicy - .long sys_set_mempolicy -diff -NurpP --minimal linux-2.6.32.1/arch/xtensa/mm/fault.c linux-2.6.32.1-vs2.3.0.36.27/arch/xtensa/mm/fault.c ---- linux-2.6.32.1/arch/xtensa/mm/fault.c 2009-09-10 15:25:48.000000000 +0200 -+++ linux-2.6.32.1-vs2.3.0.36.27/arch/xtensa/mm/fault.c 2009-12-03 20:04:56.000000000 +0100 -@@ -151,7 +151,8 @@ out_of_memory: - down_read(&mm->mmap_sem); - goto survive; - } -- printk("VM: killing process %s\n", current->comm); -+ printk("VM: killing process %s(%d:#%u)\n", -+ current->comm, task_pid_nr(current), current->xid); - if (user_mode(regs)) - do_group_exit(SIGKILL); - bad_page_fault(regs, address, SIGKILL); -diff -NurpP --minimal linux-2.6.32.1/Documentation/scheduler/sched-cfs-hard-limits.txt linux-2.6.32.1-vs2.3.0.36.27/Documentation/scheduler/sched-cfs-hard-limits.txt ---- linux-2.6.32.1/Documentation/scheduler/sched-cfs-hard-limits.txt 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/Documentation/scheduler/sched-cfs-hard-limits.txt 2009-12-03 20:04:56.000000000 +0100 -@@ -0,0 +1,48 @@ -+CPU HARD LIMITS FOR CFS GROUPS -+============================== -+ -+1. Overview -+2. Interface -+3. Examples -+ -+1. Overview -+----------- -+ -+CFS is a proportional share scheduler which tries to divide the CPU time -+proportionately between tasks or groups of tasks (task group/cgroup) depending -+on the priority/weight of the task or shares assigned to groups of tasks. -+In CFS, a task/task group can get more than its share of CPU if there are -+enough idle CPU cycles available in the system, due to the work conserving -+nature of the scheduler. However in certain scenarios (like pay-per-use), -+it is desirable not to provide extra time to a group even in the presence -+of idle CPU cycles. This is where hard limiting can be of use. -+ -+Hard limits for task groups can be set by specifying how much CPU runtime a -+group can consume within a given period. If the group consumes more CPU time -+than the runtime in a given period, it gets throttled. None of the tasks of -+the throttled group gets to run until the runtime of the group gets refreshed -+at the beginning of the next period. -+ -+2. Interface -+------------ -+ -+Hard limit feature adds 2 cgroup files for CFS group scheduler: -+ -+cfs_runtime_us: Hard limit for the group in microseconds. -+ -+cfs_period_us: Time period in microseconds within which hard limits is -+enforced. -+ -+A group gets created with default values for runtime (infinite runtime which -+means hard limits disabled) and period (0.5s). Each group can set its own -+values for runtime and period independent of other groups in the system. -+ -+3. Examples -+----------- -+ -+# mount -t cgroup -ocpu none /cgroups/ -+# cd /cgroups -+# mkdir 1 -+# cd 1/ -+# echo 250000 > cfs_runtime_us /* set a 250ms runtime or limit */ -+# echo 500000 > cfs_period_us /* set a 500ms period */ -diff -NurpP --minimal linux-2.6.32.1/Documentation/vserver/debug.txt linux-2.6.32.1-vs2.3.0.36.27/Documentation/vserver/debug.txt ---- linux-2.6.32.1/Documentation/vserver/debug.txt 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/Documentation/vserver/debug.txt 2009-12-03 20:04:56.000000000 +0100 -@@ -0,0 +1,154 @@ -+ -+debug_cvirt: -+ -+ 2 4 "vx_map_tgid: %p/%llx: %d -> %d" -+ "vx_rmap_tgid: %p/%llx: %d -> %d" -+ -+debug_dlim: -+ -+ 0 1 "ALLOC (%p,#%d)%c inode (%d)" -+ "FREE (%p,#%d)%c inode" -+ 1 2 "ALLOC (%p,#%d)%c %lld bytes (%d)" -+ "FREE (%p,#%d)%c %lld bytes" -+ 2 4 "ADJUST: %lld,%lld on %ld,%ld [mult=%d]" -+ 3 8 "ext3_has_free_blocks(%p): %lu<%lu+1, %c, %u!=%u r=%d" -+ "ext3_has_free_blocks(%p): free=%lu, root=%lu" -+ "rcu_free_dl_info(%p)" -+ 4 10 "alloc_dl_info(%p,%d) = %p" -+ "dealloc_dl_info(%p)" -+ "get_dl_info(%p[#%d.%d])" -+ "put_dl_info(%p[#%d.%d])" -+ 5 20 "alloc_dl_info(%p,%d)*" -+ 6 40 "__hash_dl_info: %p[#%d]" -+ "__unhash_dl_info: %p[#%d]" -+ 7 80 "locate_dl_info(%p,#%d) = %p" -+ -+debug_misc: -+ -+ 0 1 "destroy_dqhash: %p [#0x%08x] c=%d" -+ "new_dqhash: %p [#0x%08x]" -+ "vroot[%d]_clr_dev: dev=%p[%lu,%d:%d]" -+ "vroot[%d]_get_real_bdev: dev=%p[%lu,%d:%d]" -+ "vroot[%d]_set_dev: dev=%p[%lu,%d:%d]" -+ "vroot_get_real_bdev not set" -+ 1 2 "cow_break_link(»%s«)" -+ "temp copy »%s«" -+ 2 4 "dentry_open(new): %p" -+ "dentry_open(old): %p" -+ "lookup_create(new): %p" -+ "old path »%s«" -+ "path_lookup(old): %d" -+ "vfs_create(new): %d" -+ "vfs_rename: %d" -+ "vfs_sendfile: %d" -+ 3 8 "fput(new_file=%p[#%d])" -+ "fput(old_file=%p[#%d])" -+ 4 10 "vx_info_kill(%p[#%d],%d,%d) = %d" -+ "vx_info_kill(%p[#%d],%d,%d)*" -+ 5 20 "vs_reboot(%p[#%d],%d)" -+ 6 40 "dropping task %p[#%u,%u] for %p[#%u,%u]" -+ -+debug_net: -+ -+ 2 4 "nx_addr_conflict(%p,%p) %d.%d,%d.%d" -+ 3 8 "inet_bind(%p) %d.%d.%d.%d, %d.%d.%d.%d, %d.%d.%d.%d" -+ "inet_bind(%p)* %p,%p;%lx %d.%d.%d.%d" -+ 4 10 "ip_route_connect(%p) %p,%p;%lx" -+ 5 20 "__addr_in_socket(%p,%d.%d.%d.%d) %p:%d.%d.%d.%d %p;%lx" -+ 6 40 "sk,egf: %p [#%d] (from %d)" -+ "sk,egn: %p [#%d] (from %d)" -+ "sk,req: %p [#%d] (from %d)" -+ "sk: %p [#%d] (from %d)" -+ "tw: %p [#%d] (from %d)" -+ 7 80 "__sock_recvmsg: %p[%p,%p,%p;%d]:%d/%d" -+ "__sock_sendmsg: %p[%p,%p,%p;%d]:%d/%d" -+ -+debug_nid: -+ -+ 0 1 "__lookup_nx_info(#%u): %p[#%u]" -+ "alloc_nx_info(%d) = %p" -+ "create_nx_info(%d) (dynamic rejected)" -+ "create_nx_info(%d) = %p (already there)" -+ "create_nx_info(%d) = %p (new)" -+ "dealloc_nx_info(%p)" -+ 1 2 "alloc_nx_info(%d)*" -+ "create_nx_info(%d)*" -+ 2 4 "get_nx_info(%p[#%d.%d])" -+ "put_nx_info(%p[#%d.%d])" -+ 3 8 "claim_nx_info(%p[#%d.%d.%d]) %p" -+ "clr_nx_info(%p[#%d.%d])" -+ "init_nx_info(%p[#%d.%d])" -+ "release_nx_info(%p[#%d.%d.%d]) %p" -+ "set_nx_info(%p[#%d.%d])" -+ 4 10 "__hash_nx_info: %p[#%d]" -+ "__nx_dynamic_id: [#%d]" -+ "__unhash_nx_info: %p[#%d.%d.%d]" -+ 5 20 "moved task %p into nxi:%p[#%d]" -+ "nx_migrate_task(%p,%p[#%d.%d.%d])" -+ "task_get_nx_info(%p)" -+ 6 40 "nx_clear_persistent(%p[#%d])" -+ -+debug_quota: -+ -+ 0 1 "quota_sync_dqh(%p,%d) discard inode %p" -+ 1 2 "quota_sync_dqh(%p,%d)" -+ "sync_dquots(%p,%d)" -+ "sync_dquots_dqh(%p,%d)" -+ 3 8 "do_quotactl(%p,%d,cmd=%d,id=%d,%p)" -+ -+debug_switch: -+ -+ 0 1 "vc: VCMD_%02d_%d[%d], %d,%p [%d,%d,%x,%x]" -+ 1 2 "vc: VCMD_%02d_%d[%d] = %08lx(%ld) [%d,%d]" -+ 4 10 "%s: (%s %s) returned %s with %d" -+ -+debug_tag: -+ -+ 7 80 "dx_parse_tag(»%s«): %d:#%d" -+ "dx_propagate_tag(%p[#%lu.%d]): %d,%d" -+ -+debug_xid: -+ -+ 0 1 "__lookup_vx_info(#%u): %p[#%u]" -+ "alloc_vx_info(%d) = %p" -+ "alloc_vx_info(%d)*" -+ "create_vx_info(%d) (dynamic rejected)" -+ "create_vx_info(%d) = %p (already there)" -+ "create_vx_info(%d) = %p (new)" -+ "dealloc_vx_info(%p)" -+ "loc_vx_info(%d) = %p (found)" -+ "loc_vx_info(%d) = %p (new)" -+ "loc_vx_info(%d) = %p (not available)" -+ 1 2 "create_vx_info(%d)*" -+ "loc_vx_info(%d)*" -+ 2 4 "get_vx_info(%p[#%d.%d])" -+ "put_vx_info(%p[#%d.%d])" -+ 3 8 "claim_vx_info(%p[#%d.%d.%d]) %p" -+ "clr_vx_info(%p[#%d.%d])" -+ "init_vx_info(%p[#%d.%d])" -+ "release_vx_info(%p[#%d.%d.%d]) %p" -+ "set_vx_info(%p[#%d.%d])" -+ 4 10 "__hash_vx_info: %p[#%d]" -+ "__unhash_vx_info: %p[#%d.%d.%d]" -+ "__vx_dynamic_id: [#%d]" -+ 5 20 "enter_vx_info(%p[#%d],%p) %p[#%d,%p]" -+ "leave_vx_info(%p[#%d,%p]) %p[#%d,%p]" -+ "moved task %p into vxi:%p[#%d]" -+ "task_get_vx_info(%p)" -+ "vx_migrate_task(%p,%p[#%d.%d])" -+ 6 40 "vx_clear_persistent(%p[#%d])" -+ "vx_exit_init(%p[#%d],%p[#%d,%d,%d])" -+ "vx_set_init(%p[#%d],%p[#%d,%d,%d])" -+ "vx_set_persistent(%p[#%d])" -+ "vx_set_reaper(%p[#%d],%p[#%d,%d])" -+ 7 80 "vx_child_reaper(%p[#%u,%u]) = %p[#%u,%u]" -+ -+ -+debug_limit: -+ -+ n 2^n "vx_acc_cres[%5d,%s,%2d]: %5d%s" -+ "vx_cres_avail[%5d,%s,%2d]: %5ld > %5d + %5d" -+ -+ m 2^m "vx_acc_page[%5d,%s,%2d]: %5d%s" -+ "vx_acc_pages[%5d,%s,%2d]: %5d += %5d" -+ "vx_pages_avail[%5d,%s,%2d]: %5ld > %5d + %5d" -diff -NurpP --minimal linux-2.6.32.1/drivers/block/Kconfig linux-2.6.32.1-vs2.3.0.36.27/drivers/block/Kconfig ---- linux-2.6.32.1/drivers/block/Kconfig 2009-09-10 15:25:49.000000000 +0200 -+++ linux-2.6.32.1-vs2.3.0.36.27/drivers/block/Kconfig 2009-12-03 20:04:56.000000000 +0100 -@@ -271,6 +271,13 @@ config BLK_DEV_CRYPTOLOOP - instead, which can be configured to be on-disk compatible with the - cryptoloop device. - -+config BLK_DEV_VROOT -+ tristate "Virtual Root device support" -+ depends on QUOTACTL -+ ---help--- -+ Saying Y here will allow you to use quota/fs ioctls on a shared -+ partition within a virtual server without compromising security. -+ - config BLK_DEV_NBD - tristate "Network block device support" - depends on NET -diff -NurpP --minimal linux-2.6.32.1/drivers/block/loop.c linux-2.6.32.1-vs2.3.0.36.27/drivers/block/loop.c ---- linux-2.6.32.1/drivers/block/loop.c 2009-12-03 20:02:19.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/drivers/block/loop.c 2009-12-03 20:04:56.000000000 +0100 -@@ -74,6 +74,7 @@ - #include - #include - #include -+#include - - #include - -@@ -812,6 +813,7 @@ static int loop_set_fd(struct loop_devic - lo->lo_blocksize = lo_blocksize; - lo->lo_device = bdev; - lo->lo_flags = lo_flags; -+ lo->lo_xid = vx_current_xid(); - lo->lo_backing_file = file; - lo->transfer = transfer_none; - lo->ioctl = NULL; -@@ -937,6 +939,7 @@ static int loop_clr_fd(struct loop_devic - lo->lo_encrypt_key_size = 0; - lo->lo_flags = 0; - lo->lo_thread = NULL; -+ lo->lo_xid = 0; - memset(lo->lo_encrypt_key, 0, LO_KEY_SIZE); - memset(lo->lo_crypt_name, 0, LO_NAME_SIZE); - memset(lo->lo_file_name, 0, LO_NAME_SIZE); -@@ -971,7 +974,7 @@ loop_set_status(struct loop_device *lo, - - if (lo->lo_encrypt_key_size && - lo->lo_key_owner != uid && -- !capable(CAP_SYS_ADMIN)) -+ !vx_capable(CAP_SYS_ADMIN, VXC_ADMIN_CLOOP)) - return -EPERM; - if (lo->lo_state != Lo_bound) - return -ENXIO; -@@ -1055,7 +1058,8 @@ loop_get_status(struct loop_device *lo, - memcpy(info->lo_crypt_name, lo->lo_crypt_name, LO_NAME_SIZE); - info->lo_encrypt_type = - lo->lo_encryption ? lo->lo_encryption->number : 0; -- if (lo->lo_encrypt_key_size && capable(CAP_SYS_ADMIN)) { -+ if (lo->lo_encrypt_key_size && -+ vx_capable(CAP_SYS_ADMIN, VXC_ADMIN_CLOOP)) { - info->lo_encrypt_key_size = lo->lo_encrypt_key_size; - memcpy(info->lo_encrypt_key, lo->lo_encrypt_key, - lo->lo_encrypt_key_size); -@@ -1399,6 +1403,9 @@ static int lo_open(struct block_device * - { - struct loop_device *lo = bdev->bd_disk->private_data; - -+ if (!vx_check(lo->lo_xid, VS_IDENT|VS_HOSTID|VS_ADMIN_P)) -+ return -EACCES; -+ - mutex_lock(&lo->lo_ctl_mutex); - lo->lo_refcnt++; - mutex_unlock(&lo->lo_ctl_mutex); -diff -NurpP --minimal linux-2.6.32.1/drivers/block/Makefile linux-2.6.32.1-vs2.3.0.36.27/drivers/block/Makefile ---- linux-2.6.32.1/drivers/block/Makefile 2009-09-10 15:25:49.000000000 +0200 -+++ linux-2.6.32.1-vs2.3.0.36.27/drivers/block/Makefile 2009-12-03 20:04:56.000000000 +0100 -@@ -34,6 +34,7 @@ obj-$(CONFIG_VIODASD) += viodasd.o - obj-$(CONFIG_BLK_DEV_SX8) += sx8.o - obj-$(CONFIG_BLK_DEV_UB) += ub.o - obj-$(CONFIG_BLK_DEV_HD) += hd.o -+obj-$(CONFIG_BLK_DEV_VROOT) += vroot.o - - obj-$(CONFIG_XEN_BLKDEV_FRONTEND) += xen-blkfront.o - -diff -NurpP --minimal linux-2.6.32.1/drivers/block/vroot.c linux-2.6.32.1-vs2.3.0.36.27/drivers/block/vroot.c ---- linux-2.6.32.1/drivers/block/vroot.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/drivers/block/vroot.c 2009-12-03 20:04:56.000000000 +0100 -@@ -0,0 +1,281 @@ -+/* -+ * linux/drivers/block/vroot.c -+ * -+ * written by Herbert Pötzl, 9/11/2002 -+ * ported to 2.6.10 by Herbert Pötzl, 30/12/2004 -+ * -+ * based on the loop.c code by Theodore Ts'o. -+ * -+ * Copyright (C) 2002-2007 by Herbert Pötzl. -+ * Redistribution of this file is permitted under the -+ * GNU General Public License. -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+ -+static int max_vroot = 8; -+ -+static struct vroot_device *vroot_dev; -+static struct gendisk **disks; -+ -+ -+static int vroot_set_dev( -+ struct vroot_device *vr, -+ struct block_device *bdev, -+ unsigned int arg) -+{ -+ struct block_device *real_bdev; -+ struct file *file; -+ struct inode *inode; -+ int error; -+ -+ error = -EBUSY; -+ if (vr->vr_state != Vr_unbound) -+ goto out; -+ -+ error = -EBADF; -+ file = fget(arg); -+ if (!file) -+ goto out; -+ -+ error = -EINVAL; -+ inode = file->f_dentry->d_inode; -+ -+ -+ if (S_ISBLK(inode->i_mode)) { -+ real_bdev = inode->i_bdev; -+ vr->vr_device = real_bdev; -+ __iget(real_bdev->bd_inode); -+ } else -+ goto out_fput; -+ -+ vxdprintk(VXD_CBIT(misc, 0), -+ "vroot[%d]_set_dev: dev=" VXF_DEV, -+ vr->vr_number, VXD_DEV(real_bdev)); -+ -+ vr->vr_state = Vr_bound; -+ error = 0; -+ -+ out_fput: -+ fput(file); -+ out: -+ return error; -+} -+ -+static int vroot_clr_dev( -+ struct vroot_device *vr, -+ struct block_device *bdev) -+{ -+ struct block_device *real_bdev; -+ -+ if (vr->vr_state != Vr_bound) -+ return -ENXIO; -+ if (vr->vr_refcnt > 1) /* we needed one fd for the ioctl */ -+ return -EBUSY; -+ -+ real_bdev = vr->vr_device; -+ -+ vxdprintk(VXD_CBIT(misc, 0), -+ "vroot[%d]_clr_dev: dev=" VXF_DEV, -+ vr->vr_number, VXD_DEV(real_bdev)); -+ -+ bdput(real_bdev); -+ vr->vr_state = Vr_unbound; -+ vr->vr_device = NULL; -+ return 0; -+} -+ -+ -+static int vr_ioctl(struct block_device *bdev, fmode_t mode, -+ unsigned int cmd, unsigned long arg) -+{ -+ struct vroot_device *vr = bdev->bd_disk->private_data; -+ int err; -+ -+ down(&vr->vr_ctl_mutex); -+ switch (cmd) { -+ case VROOT_SET_DEV: -+ err = vroot_set_dev(vr, bdev, arg); -+ break; -+ case VROOT_CLR_DEV: -+ err = vroot_clr_dev(vr, bdev); -+ break; -+ default: -+ err = -EINVAL; -+ break; -+ } -+ up(&vr->vr_ctl_mutex); -+ return err; -+} -+ -+static int vr_open(struct block_device *bdev, fmode_t mode) -+{ -+ struct vroot_device *vr = bdev->bd_disk->private_data; -+ -+ down(&vr->vr_ctl_mutex); -+ vr->vr_refcnt++; -+ up(&vr->vr_ctl_mutex); -+ return 0; -+} -+ -+static int vr_release(struct gendisk *disk, fmode_t mode) -+{ -+ struct vroot_device *vr = disk->private_data; -+ -+ down(&vr->vr_ctl_mutex); -+ --vr->vr_refcnt; -+ up(&vr->vr_ctl_mutex); -+ return 0; -+} -+ -+static struct block_device_operations vr_fops = { -+ .owner = THIS_MODULE, -+ .open = vr_open, -+ .release = vr_release, -+ .ioctl = vr_ioctl, -+}; -+ -+struct block_device *__vroot_get_real_bdev(struct block_device *bdev) -+{ -+ struct inode *inode = bdev->bd_inode; -+ struct vroot_device *vr; -+ struct block_device *real_bdev; -+ int minor = iminor(inode); -+ -+ vr = &vroot_dev[minor]; -+ real_bdev = vr->vr_device; -+ -+ vxdprintk(VXD_CBIT(misc, 0), -+ "vroot[%d]_get_real_bdev: dev=" VXF_DEV, -+ vr->vr_number, VXD_DEV(real_bdev)); -+ -+ if (vr->vr_state != Vr_bound) -+ return ERR_PTR(-ENXIO); -+ -+ __iget(real_bdev->bd_inode); -+ return real_bdev; -+} -+ -+/* -+ * And now the modules code and kernel interface. -+ */ -+ -+module_param(max_vroot, int, 0); -+ -+MODULE_PARM_DESC(max_vroot, "Maximum number of vroot devices (1-256)"); -+MODULE_LICENSE("GPL"); -+MODULE_ALIAS_BLOCKDEV_MAJOR(VROOT_MAJOR); -+ -+MODULE_AUTHOR ("Herbert Pötzl"); -+MODULE_DESCRIPTION ("Virtual Root Device Mapper"); -+ -+ -+int __init vroot_init(void) -+{ -+ int err, i; -+ -+ if (max_vroot < 1 || max_vroot > 256) { -+ max_vroot = MAX_VROOT_DEFAULT; -+ printk(KERN_WARNING "vroot: invalid max_vroot " -+ "(must be between 1 and 256), " -+ "using default (%d)\n", max_vroot); -+ } -+ -+ if (register_blkdev(VROOT_MAJOR, "vroot")) -+ return -EIO; -+ -+ err = -ENOMEM; -+ vroot_dev = kmalloc(max_vroot * sizeof(struct vroot_device), GFP_KERNEL); -+ if (!vroot_dev) -+ goto out_mem1; -+ memset(vroot_dev, 0, max_vroot * sizeof(struct vroot_device)); -+ -+ disks = kmalloc(max_vroot * sizeof(struct gendisk *), GFP_KERNEL); -+ if (!disks) -+ goto out_mem2; -+ -+ for (i = 0; i < max_vroot; i++) { -+ disks[i] = alloc_disk(1); -+ if (!disks[i]) -+ goto out_mem3; -+ disks[i]->queue = blk_alloc_queue(GFP_KERNEL); -+ if (!disks[i]->queue) -+ goto out_mem3; -+ } -+ -+ for (i = 0; i < max_vroot; i++) { -+ struct vroot_device *vr = &vroot_dev[i]; -+ struct gendisk *disk = disks[i]; -+ -+ memset(vr, 0, sizeof(*vr)); -+ init_MUTEX(&vr->vr_ctl_mutex); -+ vr->vr_number = i; -+ disk->major = VROOT_MAJOR; -+ disk->first_minor = i; -+ disk->fops = &vr_fops; -+ sprintf(disk->disk_name, "vroot%d", i); -+ disk->private_data = vr; -+ } -+ -+ err = register_vroot_grb(&__vroot_get_real_bdev); -+ if (err) -+ goto out_mem3; -+ -+ for (i = 0; i < max_vroot; i++) -+ add_disk(disks[i]); -+ printk(KERN_INFO "vroot: loaded (max %d devices)\n", max_vroot); -+ return 0; -+ -+out_mem3: -+ while (i--) -+ put_disk(disks[i]); -+ kfree(disks); -+out_mem2: -+ kfree(vroot_dev); -+out_mem1: -+ unregister_blkdev(VROOT_MAJOR, "vroot"); -+ printk(KERN_ERR "vroot: ran out of memory\n"); -+ return err; -+} -+ -+void vroot_exit(void) -+{ -+ int i; -+ -+ if (unregister_vroot_grb(&__vroot_get_real_bdev)) -+ printk(KERN_WARNING "vroot: cannot unregister grb\n"); -+ -+ for (i = 0; i < max_vroot; i++) { -+ del_gendisk(disks[i]); -+ put_disk(disks[i]); -+ } -+ unregister_blkdev(VROOT_MAJOR, "vroot"); -+ -+ kfree(disks); -+ kfree(vroot_dev); -+} -+ -+module_init(vroot_init); -+module_exit(vroot_exit); -+ -+#ifndef MODULE -+ -+static int __init max_vroot_setup(char *str) -+{ -+ max_vroot = simple_strtol(str, NULL, 0); -+ return 1; -+} -+ -+__setup("max_vroot=", max_vroot_setup); -+ -+#endif -+ -diff -NurpP --minimal linux-2.6.32.1/drivers/char/sysrq.c linux-2.6.32.1-vs2.3.0.36.27/drivers/char/sysrq.c ---- linux-2.6.32.1/drivers/char/sysrq.c 2009-12-03 20:02:20.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/drivers/char/sysrq.c 2009-12-03 20:04:56.000000000 +0100 -@@ -38,6 +38,7 @@ - #include - #include - #include -+#include - - #include - #include -@@ -391,6 +392,21 @@ static struct sysrq_key_op sysrq_unrt_op - .enable_mask = SYSRQ_ENABLE_RTNICE, - }; - -+ -+#ifdef CONFIG_VSERVER_DEBUG -+static void sysrq_handle_vxinfo(int key, struct tty_struct *tty) -+{ -+ dump_vx_info_inactive((key == 'x')?0:1); -+} -+ -+static struct sysrq_key_op sysrq_showvxinfo_op = { -+ .handler = sysrq_handle_vxinfo, -+ .help_msg = "conteXt", -+ .action_msg = "Show Context Info", -+ .enable_mask = SYSRQ_ENABLE_DUMP, -+}; -+#endif -+ - /* Key Operations table and lock */ - static DEFINE_SPINLOCK(sysrq_key_table_lock); - -@@ -445,7 +461,11 @@ static struct sysrq_key_op *sysrq_key_ta - NULL, /* v */ - &sysrq_showstate_blocked_op, /* w */ - /* x: May be registered on ppc/powerpc for xmon */ -+#ifdef CONFIG_VSERVER_DEBUG -+ &sysrq_showvxinfo_op, /* x */ -+#else - NULL, /* x */ -+#endif - /* y: May be registered on sparc64 for global register dump */ - NULL, /* y */ - &sysrq_ftrace_dump_op, /* z */ -@@ -460,6 +480,8 @@ static int sysrq_key_table_key2index(int - retval = key - '0'; - else if ((key >= 'a') && (key <= 'z')) - retval = key + 10 - 'a'; -+ else if ((key >= 'A') && (key <= 'Z')) -+ retval = key + 10 - 'A'; - else - retval = -1; - return retval; -diff -NurpP --minimal linux-2.6.32.1/drivers/char/tty_io.c linux-2.6.32.1-vs2.3.0.36.27/drivers/char/tty_io.c ---- linux-2.6.32.1/drivers/char/tty_io.c 2009-12-03 20:02:20.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/drivers/char/tty_io.c 2009-12-03 20:04:56.000000000 +0100 -@@ -106,6 +106,7 @@ - - #include - #include -+#include - - #undef TTY_DEBUG_HANGUP - -@@ -1966,7 +1967,8 @@ static int tiocsti(struct tty_struct *tt - char ch, mbz = 0; - struct tty_ldisc *ld; - -- if ((current->signal->tty != tty) && !capable(CAP_SYS_ADMIN)) -+ if (((current->signal->tty != tty) && !capable(CAP_SYS_ADMIN)) || -+ !vx_ccaps(VXC_TIOCSTI)) - return -EPERM; - if (get_user(ch, p)) - return -EFAULT; -@@ -2254,6 +2256,7 @@ static int tiocspgrp(struct tty_struct * - return -ENOTTY; - if (get_user(pgrp_nr, p)) - return -EFAULT; -+ pgrp_nr = vx_rmap_pid(pgrp_nr); - if (pgrp_nr < 0) - return -EINVAL; - rcu_read_lock(); -diff -NurpP --minimal linux-2.6.32.1/drivers/infiniband/hw/ipath/ipath_user_pages.c linux-2.6.32.1-vs2.3.0.36.27/drivers/infiniband/hw/ipath/ipath_user_pages.c ---- linux-2.6.32.1/drivers/infiniband/hw/ipath/ipath_user_pages.c 2009-12-03 20:02:23.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/drivers/infiniband/hw/ipath/ipath_user_pages.c 2009-12-04 23:31:17.000000000 +0100 -@@ -34,6 +34,7 @@ - #include - #include - #include -+#include - - #include "ipath_kernel.h" - -@@ -62,7 +63,8 @@ static int __get_user_pages(unsigned lon - lock_limit = current->signal->rlim[RLIMIT_MEMLOCK].rlim_cur >> - PAGE_SHIFT; - -- if (num_pages > lock_limit) { -+ if (num_pages > lock_limit || -+ !vx_vmlocked_avail(current->mm, num_pages)) { - ret = -ENOMEM; - goto bail; - } -@@ -79,7 +81,7 @@ static int __get_user_pages(unsigned lon - goto bail_release; - } - -- current->mm->locked_vm += num_pages; -+ vx_vmlocked_add(current->mm, num_pages); - - ret = 0; - goto bail; -@@ -178,7 +180,7 @@ void ipath_release_user_pages(struct pag - - __ipath_release_user_pages(p, num_pages, 1); - -- current->mm->locked_vm -= num_pages; -+ vx_vmlocked_sub(current->mm, num_pages); - - up_write(¤t->mm->mmap_sem); - } -@@ -195,7 +197,7 @@ static void user_pages_account(struct wo - container_of(_work, struct ipath_user_pages_work, work); - - down_write(&work->mm->mmap_sem); -- work->mm->locked_vm -= work->num_pages; -+ vx_vmlocked_sub(work->mm, work->num_pages); - up_write(&work->mm->mmap_sem); - mmput(work->mm); - kfree(work); -diff -NurpP --minimal linux-2.6.32.1/drivers/md/dm.c linux-2.6.32.1-vs2.3.0.36.27/drivers/md/dm.c ---- linux-2.6.32.1/drivers/md/dm.c 2009-12-03 20:02:25.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/drivers/md/dm.c 2009-12-03 20:04:56.000000000 +0100 -@@ -19,6 +19,7 @@ - #include - #include - #include -+#include - - #include - -@@ -119,6 +120,7 @@ struct mapped_device { - rwlock_t map_lock; - atomic_t holders; - atomic_t open_count; -+ xid_t xid; - - unsigned long flags; - -@@ -323,6 +325,7 @@ static void __exit dm_exit(void) - static int dm_blk_open(struct block_device *bdev, fmode_t mode) - { - struct mapped_device *md; -+ int ret = -ENXIO; - - spin_lock(&_minor_lock); - -@@ -331,18 +334,19 @@ static int dm_blk_open(struct block_devi - goto out; - - if (test_bit(DMF_FREEING, &md->flags) || -- test_bit(DMF_DELETING, &md->flags)) { -- md = NULL; -+ test_bit(DMF_DELETING, &md->flags)) -+ goto out; -+ -+ ret = -EACCES; -+ if (!vx_check(md->xid, VS_IDENT|VS_HOSTID)) - goto out; -- } - - dm_get(md); - atomic_inc(&md->open_count); -- -+ ret = 0; - out: - spin_unlock(&_minor_lock); -- -- return md ? 0 : -ENXIO; -+ return ret; - } - - static int dm_blk_close(struct gendisk *disk, fmode_t mode) -@@ -553,6 +557,14 @@ int dm_set_geometry(struct mapped_device - return 0; - } - -+/* -+ * Get the xid associated with a dm device -+ */ -+xid_t dm_get_xid(struct mapped_device *md) -+{ -+ return md->xid; -+} -+ - /*----------------------------------------------------------------- - * CRUD START: - * A more elegant soln is in the works that uses the queue -@@ -1762,6 +1774,7 @@ static struct mapped_device *alloc_dev(i - INIT_LIST_HEAD(&md->uevent_list); - spin_lock_init(&md->uevent_lock); - -+ md->xid = vx_current_xid(); - md->queue = blk_init_queue(dm_request_fn, NULL); - if (!md->queue) - goto bad_queue; -diff -NurpP --minimal linux-2.6.32.1/drivers/md/dm.h linux-2.6.32.1-vs2.3.0.36.27/drivers/md/dm.h ---- linux-2.6.32.1/drivers/md/dm.h 2009-09-10 15:25:55.000000000 +0200 -+++ linux-2.6.32.1-vs2.3.0.36.27/drivers/md/dm.h 2009-12-03 20:04:56.000000000 +0100 -@@ -41,6 +41,8 @@ struct dm_dev_internal { - struct dm_table; - struct dm_md_mempools; - -+xid_t dm_get_xid(struct mapped_device *md); -+ - /*----------------------------------------------------------------- - * Internal table functions. - *---------------------------------------------------------------*/ -diff -NurpP --minimal linux-2.6.32.1/drivers/md/dm-ioctl.c linux-2.6.32.1-vs2.3.0.36.27/drivers/md/dm-ioctl.c ---- linux-2.6.32.1/drivers/md/dm-ioctl.c 2009-12-03 20:02:25.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/drivers/md/dm-ioctl.c 2009-12-03 20:04:56.000000000 +0100 -@@ -16,6 +16,7 @@ - #include - #include - #include -+#include - - #include - -@@ -101,7 +102,8 @@ static struct hash_cell *__get_name_cell - unsigned int h = hash_str(str); - - list_for_each_entry (hc, _name_buckets + h, name_list) -- if (!strcmp(hc->name, str)) { -+ if (vx_check(dm_get_xid(hc->md), VS_WATCH_P | VS_IDENT) && -+ !strcmp(hc->name, str)) { - dm_get(hc->md); - return hc; - } -@@ -115,7 +117,8 @@ static struct hash_cell *__get_uuid_cell - unsigned int h = hash_str(str); - - list_for_each_entry (hc, _uuid_buckets + h, uuid_list) -- if (!strcmp(hc->uuid, str)) { -+ if (vx_check(dm_get_xid(hc->md), VS_WATCH_P | VS_IDENT) && -+ !strcmp(hc->uuid, str)) { - dm_get(hc->md); - return hc; - } -@@ -352,6 +355,9 @@ typedef int (*ioctl_fn)(struct dm_ioctl - - static int remove_all(struct dm_ioctl *param, size_t param_size) - { -+ if (!vx_check(0, VS_ADMIN)) -+ return -EPERM; -+ - dm_hash_remove_all(1); - param->data_size = 0; - return 0; -@@ -399,6 +405,8 @@ static int list_devices(struct dm_ioctl - */ - for (i = 0; i < NUM_BUCKETS; i++) { - list_for_each_entry (hc, _name_buckets + i, name_list) { -+ if (!vx_check(dm_get_xid(hc->md), VS_WATCH_P | VS_IDENT)) -+ continue; - needed += sizeof(struct dm_name_list); - needed += strlen(hc->name) + 1; - needed += ALIGN_MASK; -@@ -422,6 +430,8 @@ static int list_devices(struct dm_ioctl - */ - for (i = 0; i < NUM_BUCKETS; i++) { - list_for_each_entry (hc, _name_buckets + i, name_list) { -+ if (!vx_check(dm_get_xid(hc->md), VS_WATCH_P | VS_IDENT)) -+ continue; - if (old_nl) - old_nl->next = (uint32_t) ((void *) nl - - (void *) old_nl); -@@ -612,10 +622,11 @@ static struct hash_cell *__find_device_h - if (!md) - goto out; - -- mdptr = dm_get_mdptr(md); -+ if (vx_check(dm_get_xid(md), VS_WATCH_P | VS_IDENT)) -+ mdptr = dm_get_mdptr(md); -+ - if (!mdptr) - dm_put(md); -- - out: - return mdptr; - } -@@ -1445,8 +1456,8 @@ static int ctl_ioctl(uint command, struc - ioctl_fn fn = NULL; - size_t param_size; - -- /* only root can play with this */ -- if (!capable(CAP_SYS_ADMIN)) -+ /* only root and certain contexts can play with this */ -+ if (!vx_capable(CAP_SYS_ADMIN, VXC_ADMIN_MAPPER)) - return -EACCES; - - if (_IOC_TYPE(command) != DM_IOCTL) -diff -NurpP --minimal linux-2.6.32.1/drivers/net/tun.c linux-2.6.32.1-vs2.3.0.36.27/drivers/net/tun.c ---- linux-2.6.32.1/drivers/net/tun.c 2009-12-03 20:02:32.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/drivers/net/tun.c 2009-12-03 20:04:56.000000000 +0100 -@@ -61,6 +61,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -102,6 +103,7 @@ struct tun_struct { - unsigned int flags; - uid_t owner; - gid_t group; -+ nid_t nid; - - struct net_device *dev; - struct fasync_struct *fasync; -@@ -816,6 +818,7 @@ static void tun_setup(struct net_device - - tun->owner = -1; - tun->group = -1; -+ tun->nid = current->nid; - - dev->ethtool_ops = &tun_ethtool_ops; - dev->destructor = tun_free_netdev; -@@ -932,7 +935,7 @@ static int tun_set_iff(struct net *net, - - if (((tun->owner != -1 && cred->euid != tun->owner) || - (tun->group != -1 && !in_egroup_p(tun->group))) && -- !capable(CAP_NET_ADMIN)) -+ !cap_raised(current_cap(), CAP_NET_ADMIN)) - return -EPERM; - err = security_tun_dev_attach(tun->socket.sk); - if (err < 0) -@@ -946,7 +949,7 @@ static int tun_set_iff(struct net *net, - char *name; - unsigned long flags = 0; - -- if (!capable(CAP_NET_ADMIN)) -+ if (!nx_capable(CAP_NET_ADMIN, NXC_TUN_CREATE)) - return -EPERM; - err = security_tun_dev_create(); - if (err < 0) -@@ -1013,6 +1016,9 @@ static int tun_set_iff(struct net *net, - - sk->sk_destruct = tun_sock_destruct; - -+ if (!nx_check(tun->nid, VS_IDENT | VS_HOSTID | VS_ADMIN_P)) -+ return -EPERM; -+ - err = tun_attach(tun, file); - if (err < 0) - goto failed; -@@ -1202,6 +1208,16 @@ static long tun_chr_ioctl(struct file *f - DBG(KERN_INFO "%s: group set to %d\n", tun->dev->name, tun->group); - break; - -+ case TUNSETNID: -+ if (!capable(CAP_CONTEXT)) -+ return -EPERM; -+ -+ /* Set nid owner of the device */ -+ tun->nid = (nid_t) arg; -+ -+ DBG(KERN_INFO "%s: nid owner set to %u\n", tun->dev->name, tun->nid); -+ break; -+ - case TUNSETLINK: - /* Only allow setting the type when the interface is down */ - if (tun->dev->flags & IFF_UP) { -diff -NurpP --minimal linux-2.6.32.1/fs/attr.c linux-2.6.32.1-vs2.3.0.36.27/fs/attr.c ---- linux-2.6.32.1/fs/attr.c 2009-12-03 20:02:51.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/attr.c 2009-12-03 20:04:56.000000000 +0100 -@@ -14,6 +14,9 @@ - #include - #include - #include -+#include -+#include -+#include - - /* Taken over from the old code... */ - -@@ -55,6 +58,10 @@ int inode_change_ok(const struct inode * - if (!is_owner_or_cap(inode)) - goto error; - } -+ -+ if (dx_permission(inode, MAY_WRITE)) -+ goto error; -+ - fine: - retval = 0; - error: -@@ -120,6 +127,8 @@ int inode_setattr(struct inode * inode, - inode->i_uid = attr->ia_uid; - if (ia_valid & ATTR_GID) - inode->i_gid = attr->ia_gid; -+ if ((ia_valid & ATTR_TAG) && IS_TAGGED(inode)) -+ inode->i_tag = attr->ia_tag; - if (ia_valid & ATTR_ATIME) - inode->i_atime = timespec_trunc(attr->ia_atime, - inode->i_sb->s_time_gran); -@@ -214,7 +223,8 @@ int notify_change(struct dentry * dentry - error = inode_change_ok(inode, attr); - if (!error) { - if ((ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid) || -- (ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid)) -+ (ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid) || -+ (ia_valid & ATTR_TAG && attr->ia_tag != inode->i_tag)) - error = vfs_dq_transfer(inode, attr) ? - -EDQUOT : 0; - if (!error) -diff -NurpP --minimal linux-2.6.32.1/fs/binfmt_aout.c linux-2.6.32.1-vs2.3.0.36.27/fs/binfmt_aout.c ---- linux-2.6.32.1/fs/binfmt_aout.c 2009-03-24 14:22:24.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/binfmt_aout.c 2009-12-03 20:04:56.000000000 +0100 -@@ -24,6 +24,7 @@ - #include - #include - #include -+#include - - #include - #include -diff -NurpP --minimal linux-2.6.32.1/fs/binfmt_elf.c linux-2.6.32.1-vs2.3.0.36.27/fs/binfmt_elf.c ---- linux-2.6.32.1/fs/binfmt_elf.c 2009-12-03 20:02:51.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/binfmt_elf.c 2009-12-03 20:04:56.000000000 +0100 -@@ -31,6 +31,7 @@ - #include - #include - #include -+#include - #include - #include - #include -diff -NurpP --minimal linux-2.6.32.1/fs/binfmt_flat.c linux-2.6.32.1-vs2.3.0.36.27/fs/binfmt_flat.c ---- linux-2.6.32.1/fs/binfmt_flat.c 2009-12-03 20:02:51.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/binfmt_flat.c 2009-12-03 20:04:56.000000000 +0100 -@@ -35,6 +35,7 @@ - #include - #include - #include -+#include - - #include - #include -diff -NurpP --minimal linux-2.6.32.1/fs/binfmt_som.c linux-2.6.32.1-vs2.3.0.36.27/fs/binfmt_som.c ---- linux-2.6.32.1/fs/binfmt_som.c 2009-06-11 17:13:02.000000000 +0200 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/binfmt_som.c 2009-12-03 20:04:56.000000000 +0100 -@@ -28,6 +28,7 @@ - #include - #include - #include -+#include - - #include - #include -diff -NurpP --minimal linux-2.6.32.1/fs/block_dev.c linux-2.6.32.1-vs2.3.0.36.27/fs/block_dev.c ---- linux-2.6.32.1/fs/block_dev.c 2009-12-03 20:02:51.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/block_dev.c 2009-12-03 20:04:56.000000000 +0100 -@@ -26,6 +26,7 @@ - #include - #include - #include -+#include - #include - #include "internal.h" - -@@ -555,6 +556,7 @@ struct block_device *bdget(dev_t dev) - bdev->bd_invalidated = 0; - inode->i_mode = S_IFBLK; - inode->i_rdev = dev; -+ inode->i_mdev = dev; - inode->i_bdev = bdev; - inode->i_data.a_ops = &def_blk_aops; - mapping_set_gfp_mask(&inode->i_data, GFP_USER); -@@ -601,6 +603,11 @@ EXPORT_SYMBOL(bdput); - static struct block_device *bd_acquire(struct inode *inode) - { - struct block_device *bdev; -+ dev_t mdev; -+ -+ if (!vs_map_blkdev(inode->i_rdev, &mdev, DATTR_OPEN)) -+ return NULL; -+ inode->i_mdev = mdev; - - spin_lock(&bdev_lock); - bdev = inode->i_bdev; -@@ -611,7 +618,7 @@ static struct block_device *bd_acquire(s - } - spin_unlock(&bdev_lock); - -- bdev = bdget(inode->i_rdev); -+ bdev = bdget(mdev); - if (bdev) { - spin_lock(&bdev_lock); - if (!inode->i_bdev) { -diff -NurpP --minimal linux-2.6.32.1/fs/btrfs/ctree.h linux-2.6.32.1-vs2.3.0.36.27/fs/btrfs/ctree.h ---- linux-2.6.32.1/fs/btrfs/ctree.h 2009-12-03 20:02:51.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/btrfs/ctree.h 2009-12-03 20:04:56.000000000 +0100 -@@ -544,11 +544,14 @@ struct btrfs_inode_item { - /* modification sequence number for NFS */ - __le64 sequence; - -+ __le16 tag; - /* - * a little future expansion, for more than this we can - * just grow the inode item and version it - */ -- __le64 reserved[4]; -+ __le16 reserved16; -+ __le32 reserved32; -+ __le64 reserved[3]; - struct btrfs_timespec atime; - struct btrfs_timespec ctime; - struct btrfs_timespec mtime; -@@ -1155,6 +1158,8 @@ struct btrfs_root { - #define BTRFS_MOUNT_NOSSD (1 << 9) - #define BTRFS_MOUNT_DISCARD (1 << 10) - -+#define BTRFS_MOUNT_TAGGED (1 << 24) -+ - #define btrfs_clear_opt(o, opt) ((o) &= ~BTRFS_MOUNT_##opt) - #define btrfs_set_opt(o, opt) ((o) |= BTRFS_MOUNT_##opt) - #define btrfs_test_opt(root, opt) ((root)->fs_info->mount_opt & \ -@@ -1174,6 +1179,10 @@ struct btrfs_root { - #define BTRFS_INODE_NOATIME (1 << 9) - #define BTRFS_INODE_DIRSYNC (1 << 10) - -+#define BTRFS_INODE_IXUNLINK (1 << 24) -+#define BTRFS_INODE_BARRIER (1 << 25) -+#define BTRFS_INODE_COW (1 << 26) -+ - - /* some macros to generate set/get funcs for the struct fields. This - * assumes there is a lefoo_to_cpu for every type, so lets make a simple -@@ -1376,6 +1385,7 @@ BTRFS_SETGET_FUNCS(inode_block_group, st - BTRFS_SETGET_FUNCS(inode_nlink, struct btrfs_inode_item, nlink, 32); - BTRFS_SETGET_FUNCS(inode_uid, struct btrfs_inode_item, uid, 32); - BTRFS_SETGET_FUNCS(inode_gid, struct btrfs_inode_item, gid, 32); -+BTRFS_SETGET_FUNCS(inode_tag, struct btrfs_inode_item, tag, 16); - BTRFS_SETGET_FUNCS(inode_mode, struct btrfs_inode_item, mode, 32); - BTRFS_SETGET_FUNCS(inode_rdev, struct btrfs_inode_item, rdev, 64); - BTRFS_SETGET_FUNCS(inode_flags, struct btrfs_inode_item, flags, 64); -@@ -2338,6 +2348,7 @@ extern const struct dentry_operations bt - long btrfs_ioctl(struct file *file, unsigned int cmd, unsigned long arg); - void btrfs_update_iflags(struct inode *inode); - void btrfs_inherit_iflags(struct inode *inode, struct inode *dir); -+int btrfs_sync_flags(struct inode *inode, int, int); - - /* file.c */ - int btrfs_sync_file(struct file *file, struct dentry *dentry, int datasync); -diff -NurpP --minimal linux-2.6.32.1/fs/btrfs/disk-io.c linux-2.6.32.1-vs2.3.0.36.27/fs/btrfs/disk-io.c ---- linux-2.6.32.1/fs/btrfs/disk-io.c 2009-12-03 20:02:51.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/btrfs/disk-io.c 2009-12-03 20:04:56.000000000 +0100 -@@ -1723,6 +1723,9 @@ struct btrfs_root *open_ctree(struct sup - goto fail_iput; - } - -+ if (btrfs_test_opt(tree_root, TAGGED)) -+ sb->s_flags |= MS_TAGGED; -+ - features = btrfs_super_incompat_flags(disk_super) & - ~BTRFS_FEATURE_INCOMPAT_SUPP; - if (features) { -diff -NurpP --minimal linux-2.6.32.1/fs/btrfs/inode.c linux-2.6.32.1-vs2.3.0.36.27/fs/btrfs/inode.c ---- linux-2.6.32.1/fs/btrfs/inode.c 2009-12-03 20:02:51.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/btrfs/inode.c 2009-12-03 20:04:56.000000000 +0100 -@@ -36,6 +36,8 @@ - #include - #include - #include -+#include -+ - #include "compat.h" - #include "ctree.h" - #include "disk-io.h" -@@ -2242,6 +2244,8 @@ static void btrfs_read_locked_inode(stru - int maybe_acls; - u64 alloc_group_block; - u32 rdev; -+ uid_t uid; -+ gid_t gid; - int ret; - - path = btrfs_alloc_path(); -@@ -2258,8 +2262,13 @@ static void btrfs_read_locked_inode(stru - - inode->i_mode = btrfs_inode_mode(leaf, inode_item); - inode->i_nlink = btrfs_inode_nlink(leaf, inode_item); -- inode->i_uid = btrfs_inode_uid(leaf, inode_item); -- inode->i_gid = btrfs_inode_gid(leaf, inode_item); -+ -+ uid = btrfs_inode_uid(leaf, inode_item); -+ gid = btrfs_inode_gid(leaf, inode_item); -+ inode->i_uid = INOTAG_UID(DX_TAG(inode), uid, gid); -+ inode->i_gid = INOTAG_GID(DX_TAG(inode), uid, gid); -+ inode->i_tag = INOTAG_TAG(DX_TAG(inode), uid, gid, -+ btrfs_inode_tag(leaf, inode_item)); - btrfs_i_size_write(inode, btrfs_inode_size(leaf, inode_item)); - - tspec = btrfs_inode_atime(inode_item); -@@ -2341,8 +2350,15 @@ static void fill_inode_item(struct btrfs - struct btrfs_inode_item *item, - struct inode *inode) - { -- btrfs_set_inode_uid(leaf, item, inode->i_uid); -- btrfs_set_inode_gid(leaf, item, inode->i_gid); -+ uid_t uid = TAGINO_UID(DX_TAG(inode), inode->i_uid, inode->i_tag); -+ gid_t gid = TAGINO_GID(DX_TAG(inode), inode->i_gid, inode->i_tag); -+ -+ btrfs_set_inode_uid(leaf, item, uid); -+ btrfs_set_inode_gid(leaf, item, gid); -+#ifdef CONFIG_TAGGING_INTERN -+ btrfs_set_inode_tag(leaf, item, inode->i_tag); -+#endif -+ - btrfs_set_inode_size(leaf, item, BTRFS_I(inode)->disk_i_size); - btrfs_set_inode_mode(leaf, item, inode->i_mode); - btrfs_set_inode_nlink(leaf, item, inode->i_nlink); -@@ -4065,6 +4081,7 @@ static struct inode *btrfs_new_inode(str - } else - inode->i_gid = current_fsgid(); - -+ inode->i_tag = dx_current_fstag(root->fs_info->sb); - inode->i_mode = mode; - inode->i_ino = objectid; - inode_set_bytes(inode, 0); -@@ -5836,6 +5853,7 @@ static const struct inode_operations btr - .listxattr = btrfs_listxattr, - .removexattr = btrfs_removexattr, - .permission = btrfs_permission, -+ .sync_flags = btrfs_sync_flags, - }; - static const struct inode_operations btrfs_dir_ro_inode_operations = { - .lookup = btrfs_lookup, -@@ -5911,6 +5929,7 @@ static const struct inode_operations btr - .permission = btrfs_permission, - .fallocate = btrfs_fallocate, - .fiemap = btrfs_fiemap, -+ .sync_flags = btrfs_sync_flags, - }; - static const struct inode_operations btrfs_special_inode_operations = { - .getattr = btrfs_getattr, -diff -NurpP --minimal linux-2.6.32.1/fs/btrfs/ioctl.c linux-2.6.32.1-vs2.3.0.36.27/fs/btrfs/ioctl.c ---- linux-2.6.32.1/fs/btrfs/ioctl.c 2009-12-03 20:02:51.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/btrfs/ioctl.c 2009-12-03 20:04:56.000000000 +0100 -@@ -67,10 +67,13 @@ static unsigned int btrfs_flags_to_ioctl - { - unsigned int iflags = 0; - -- if (flags & BTRFS_INODE_SYNC) -- iflags |= FS_SYNC_FL; - if (flags & BTRFS_INODE_IMMUTABLE) - iflags |= FS_IMMUTABLE_FL; -+ if (flags & BTRFS_INODE_IXUNLINK) -+ iflags |= FS_IXUNLINK_FL; -+ -+ if (flags & BTRFS_INODE_SYNC) -+ iflags |= FS_SYNC_FL; - if (flags & BTRFS_INODE_APPEND) - iflags |= FS_APPEND_FL; - if (flags & BTRFS_INODE_NODUMP) -@@ -80,28 +83,78 @@ static unsigned int btrfs_flags_to_ioctl - if (flags & BTRFS_INODE_DIRSYNC) - iflags |= FS_DIRSYNC_FL; - -+ if (flags & BTRFS_INODE_BARRIER) -+ iflags |= FS_BARRIER_FL; -+ if (flags & BTRFS_INODE_COW) -+ iflags |= FS_COW_FL; - return iflags; - } - - /* -- * Update inode->i_flags based on the btrfs internal flags. -+ * Update inode->i_(v)flags based on the btrfs internal flags. - */ - void btrfs_update_iflags(struct inode *inode) - { - struct btrfs_inode *ip = BTRFS_I(inode); - -- inode->i_flags &= ~(S_SYNC|S_APPEND|S_IMMUTABLE|S_NOATIME|S_DIRSYNC); -+ inode->i_flags &= ~(S_IMMUTABLE | S_IXUNLINK | -+ S_SYNC | S_APPEND | S_NOATIME | S_DIRSYNC); - -- if (ip->flags & BTRFS_INODE_SYNC) -- inode->i_flags |= S_SYNC; - if (ip->flags & BTRFS_INODE_IMMUTABLE) - inode->i_flags |= S_IMMUTABLE; -+ if (ip->flags & BTRFS_INODE_IXUNLINK) -+ inode->i_flags |= S_IXUNLINK; -+ -+ if (ip->flags & BTRFS_INODE_SYNC) -+ inode->i_flags |= S_SYNC; - if (ip->flags & BTRFS_INODE_APPEND) - inode->i_flags |= S_APPEND; - if (ip->flags & BTRFS_INODE_NOATIME) - inode->i_flags |= S_NOATIME; - if (ip->flags & BTRFS_INODE_DIRSYNC) - inode->i_flags |= S_DIRSYNC; -+ -+ inode->i_vflags &= ~(V_BARRIER | V_COW); -+ -+ if (ip->flags & BTRFS_INODE_BARRIER) -+ inode->i_vflags |= V_BARRIER; -+ if (ip->flags & BTRFS_INODE_COW) -+ inode->i_vflags |= V_COW; -+} -+ -+/* -+ * Update btrfs internal flags from inode->i_(v)flags. -+ */ -+void btrfs_update_flags(struct inode *inode) -+{ -+ struct btrfs_inode *ip = BTRFS_I(inode); -+ -+ unsigned int flags = inode->i_flags; -+ unsigned int vflags = inode->i_vflags; -+ -+ ip->flags &= ~(BTRFS_INODE_SYNC | BTRFS_INODE_APPEND | -+ BTRFS_INODE_IMMUTABLE | BTRFS_INODE_IXUNLINK | -+ BTRFS_INODE_NOATIME | BTRFS_INODE_DIRSYNC | -+ BTRFS_INODE_BARRIER | BTRFS_INODE_COW); -+ -+ if (flags & S_IMMUTABLE) -+ ip->flags |= BTRFS_INODE_IMMUTABLE; -+ if (flags & S_IXUNLINK) -+ ip->flags |= BTRFS_INODE_IXUNLINK; -+ -+ if (flags & S_SYNC) -+ ip->flags |= BTRFS_INODE_SYNC; -+ if (flags & S_APPEND) -+ ip->flags |= BTRFS_INODE_APPEND; -+ if (flags & S_NOATIME) -+ ip->flags |= BTRFS_INODE_NOATIME; -+ if (flags & S_DIRSYNC) -+ ip->flags |= BTRFS_INODE_DIRSYNC; -+ -+ if (vflags & V_BARRIER) -+ ip->flags |= BTRFS_INODE_BARRIER; -+ if (vflags & V_COW) -+ ip->flags |= BTRFS_INODE_COW; - } - - /* -@@ -119,7 +172,7 @@ void btrfs_inherit_iflags(struct inode * - flags = BTRFS_I(dir)->flags; - - if (S_ISREG(inode->i_mode)) -- flags &= ~BTRFS_INODE_DIRSYNC; -+ flags &= ~(BTRFS_INODE_DIRSYNC | BTRFS_INODE_BARRIER); - else if (!S_ISDIR(inode->i_mode)) - flags &= (BTRFS_INODE_NODUMP | BTRFS_INODE_NOATIME); - -@@ -127,6 +180,30 @@ void btrfs_inherit_iflags(struct inode * - btrfs_update_iflags(inode); - } - -+int btrfs_sync_flags(struct inode *inode, int flags, int vflags) -+{ -+ struct btrfs_inode *ip = BTRFS_I(inode); -+ struct btrfs_root *root = ip->root; -+ struct btrfs_trans_handle *trans; -+ int ret; -+ -+ trans = btrfs_join_transaction(root, 1); -+ BUG_ON(!trans); -+ -+ inode->i_flags = flags; -+ inode->i_vflags = vflags; -+ btrfs_update_flags(inode); -+ -+ ret = btrfs_update_inode(trans, root, inode); -+ BUG_ON(ret); -+ -+ btrfs_update_iflags(inode); -+ inode->i_ctime = CURRENT_TIME; -+ btrfs_end_transaction(trans, root); -+ -+ return 0; -+} -+ - static int btrfs_ioctl_getflags(struct file *file, void __user *arg) - { - struct btrfs_inode *ip = BTRFS_I(file->f_path.dentry->d_inode); -@@ -149,6 +226,7 @@ static int btrfs_ioctl_setflags(struct f - if (copy_from_user(&flags, arg, sizeof(flags))) - return -EFAULT; - -+ /* maybe add FS_IXUNLINK_FL ? */ - if (flags & ~(FS_IMMUTABLE_FL | FS_APPEND_FL | \ - FS_NOATIME_FL | FS_NODUMP_FL | \ - FS_SYNC_FL | FS_DIRSYNC_FL)) -@@ -161,7 +239,8 @@ static int btrfs_ioctl_setflags(struct f - - flags = btrfs_mask_flags(inode->i_mode, flags); - oldflags = btrfs_flags_to_ioctl(ip->flags); -- if ((flags ^ oldflags) & (FS_APPEND_FL | FS_IMMUTABLE_FL)) { -+ if ((flags ^ oldflags) & (FS_APPEND_FL | -+ FS_IMMUTABLE_FL | FS_IXUNLINK_FL)) { - if (!capable(CAP_LINUX_IMMUTABLE)) { - ret = -EPERM; - goto out_unlock; -@@ -172,14 +251,19 @@ static int btrfs_ioctl_setflags(struct f - if (ret) - goto out_unlock; - -- if (flags & FS_SYNC_FL) -- ip->flags |= BTRFS_INODE_SYNC; -- else -- ip->flags &= ~BTRFS_INODE_SYNC; - if (flags & FS_IMMUTABLE_FL) - ip->flags |= BTRFS_INODE_IMMUTABLE; - else - ip->flags &= ~BTRFS_INODE_IMMUTABLE; -+ if (flags & FS_IXUNLINK_FL) -+ ip->flags |= BTRFS_INODE_IXUNLINK; -+ else -+ ip->flags &= ~BTRFS_INODE_IXUNLINK; -+ -+ if (flags & FS_SYNC_FL) -+ ip->flags |= BTRFS_INODE_SYNC; -+ else -+ ip->flags &= ~BTRFS_INODE_SYNC; - if (flags & FS_APPEND_FL) - ip->flags |= BTRFS_INODE_APPEND; - else -diff -NurpP --minimal linux-2.6.32.1/fs/btrfs/super.c linux-2.6.32.1-vs2.3.0.36.27/fs/btrfs/super.c ---- linux-2.6.32.1/fs/btrfs/super.c 2009-12-03 20:02:51.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/btrfs/super.c 2009-12-03 20:04:56.000000000 +0100 -@@ -67,7 +67,7 @@ enum { - Opt_max_extent, Opt_max_inline, Opt_alloc_start, Opt_nobarrier, - Opt_ssd, Opt_nossd, Opt_ssd_spread, Opt_thread_pool, Opt_noacl, - Opt_compress, Opt_notreelog, Opt_ratio, Opt_flushoncommit, -- Opt_discard, Opt_err, -+ Opt_tag, Opt_notag, Opt_tagid, Opt_discard, Opt_err, - }; - - static match_table_t tokens = { -@@ -90,6 +90,9 @@ static match_table_t tokens = { - {Opt_flushoncommit, "flushoncommit"}, - {Opt_ratio, "metadata_ratio=%d"}, - {Opt_discard, "discard"}, -+ {Opt_tag, "tag"}, -+ {Opt_notag, "notag"}, -+ {Opt_tagid, "tagid=%u"}, - {Opt_err, NULL}, - }; - -@@ -262,6 +265,22 @@ int btrfs_parse_options(struct btrfs_roo - case Opt_discard: - btrfs_set_opt(info->mount_opt, DISCARD); - break; -+#ifndef CONFIG_TAGGING_NONE -+ case Opt_tag: -+ printk(KERN_INFO "btrfs: use tagging\n"); -+ btrfs_set_opt(info->mount_opt, TAGGED); -+ break; -+ case Opt_notag: -+ printk(KERN_INFO "btrfs: disabled tagging\n"); -+ btrfs_clear_opt(info->mount_opt, TAGGED); -+ break; -+#endif -+#ifdef CONFIG_PROPAGATE -+ case Opt_tagid: -+ /* use args[0] */ -+ btrfs_set_opt(info->mount_opt, TAGGED); -+ break; -+#endif - default: - break; - } -@@ -575,6 +594,12 @@ static int btrfs_remount(struct super_bl - if (ret) - return -EINVAL; - -+ if (btrfs_test_opt(root, TAGGED) && !(sb->s_flags & MS_TAGGED)) { -+ printk("btrfs: %s: tagging not permitted on remount.\n", -+ sb->s_id); -+ return -EINVAL; -+ } -+ - if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY)) - return 0; - -diff -NurpP --minimal linux-2.6.32.1/fs/char_dev.c linux-2.6.32.1-vs2.3.0.36.27/fs/char_dev.c ---- linux-2.6.32.1/fs/char_dev.c 2009-12-03 20:02:51.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/char_dev.c 2009-12-03 20:04:56.000000000 +0100 -@@ -20,6 +20,8 @@ - #include - #include - #include -+#include -+#include - - #include "internal.h" - -@@ -368,14 +370,21 @@ static int chrdev_open(struct inode *ino - struct cdev *p; - struct cdev *new = NULL; - int ret = 0; -+ dev_t mdev; -+ -+ if (!vs_map_chrdev(inode->i_rdev, &mdev, DATTR_OPEN)) -+ return -EPERM; -+ inode->i_mdev = mdev; - - spin_lock(&cdev_lock); - p = inode->i_cdev; - if (!p) { - struct kobject *kobj; - int idx; -+ - spin_unlock(&cdev_lock); -- kobj = kobj_lookup(cdev_map, inode->i_rdev, &idx); -+ -+ kobj = kobj_lookup(cdev_map, mdev, &idx); - if (!kobj) - return -ENXIO; - new = container_of(kobj, struct cdev, kobj); -diff -NurpP --minimal linux-2.6.32.1/fs/dcache.c linux-2.6.32.1-vs2.3.0.36.27/fs/dcache.c ---- linux-2.6.32.1/fs/dcache.c 2009-12-03 20:02:51.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/dcache.c 2009-12-03 20:04:56.000000000 +0100 -@@ -33,6 +33,7 @@ - #include - #include - #include -+#include - #include "internal.h" - - int sysctl_vfs_cache_pressure __read_mostly = 100; -@@ -230,6 +231,8 @@ repeat: - return; - } - -+ vx_dentry_dec(dentry); -+ - /* - * AV: ->d_delete() is _NOT_ allowed to block now. - */ -@@ -321,6 +324,7 @@ static inline struct dentry * __dget_loc - { - atomic_inc(&dentry->d_count); - dentry_lru_del_init(dentry); -+ vx_dentry_inc(dentry); - return dentry; - } - -@@ -919,6 +923,9 @@ struct dentry *d_alloc(struct dentry * p - struct dentry *dentry; - char *dname; - -+ if (!vx_dentry_avail(1)) -+ return NULL; -+ - dentry = kmem_cache_alloc(dentry_cache, GFP_KERNEL); - if (!dentry) - return NULL; -@@ -964,6 +971,7 @@ struct dentry *d_alloc(struct dentry * p - if (parent) - list_add(&dentry->d_u.d_child, &parent->d_subdirs); - dentry_stat.nr_dentry++; -+ vx_dentry_inc(dentry); - spin_unlock(&dcache_lock); - - return dentry; -@@ -1407,6 +1415,7 @@ struct dentry * __d_lookup(struct dentry - } - - atomic_inc(&dentry->d_count); -+ vx_dentry_inc(dentry); - found = dentry; - spin_unlock(&dentry->d_lock); - break; -diff -NurpP --minimal linux-2.6.32.1/fs/devpts/inode.c linux-2.6.32.1-vs2.3.0.36.27/fs/devpts/inode.c ---- linux-2.6.32.1/fs/devpts/inode.c 2009-12-03 20:02:51.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/devpts/inode.c 2009-12-03 20:04:56.000000000 +0100 -@@ -24,6 +24,7 @@ - #include - #include - #include -+#include - - #define DEVPTS_DEFAULT_MODE 0600 - /* -@@ -35,6 +36,20 @@ - #define DEVPTS_DEFAULT_PTMX_MODE 0000 - #define PTMX_MINOR 2 - -+static int devpts_permission(struct inode *inode, int mask) -+{ -+ int ret = -EACCES; -+ -+ /* devpts is xid tagged */ -+ if (vx_check((xid_t)inode->i_tag, VS_WATCH_P | VS_IDENT)) -+ ret = generic_permission(inode, mask, NULL); -+ return ret; -+} -+ -+static struct inode_operations devpts_file_inode_operations = { -+ .permission = devpts_permission, -+}; -+ - extern int pty_limit; /* Config limit on Unix98 ptys */ - static DEFINE_MUTEX(allocated_ptys_lock); - -@@ -262,6 +277,25 @@ static int devpts_show_options(struct se - return 0; - } - -+static int devpts_filter(struct dentry *de) -+{ -+ /* devpts is xid tagged */ -+ return vx_check((xid_t)de->d_inode->i_tag, VS_WATCH_P | VS_IDENT); -+} -+ -+static int devpts_readdir(struct file * filp, void * dirent, filldir_t filldir) -+{ -+ return dcache_readdir_filter(filp, dirent, filldir, devpts_filter); -+} -+ -+static struct file_operations devpts_dir_operations = { -+ .open = dcache_dir_open, -+ .release = dcache_dir_close, -+ .llseek = dcache_dir_lseek, -+ .read = generic_read_dir, -+ .readdir = devpts_readdir, -+}; -+ - static const struct super_operations devpts_sops = { - .statfs = simple_statfs, - .remount_fs = devpts_remount, -@@ -301,12 +335,15 @@ devpts_fill_super(struct super_block *s, - inode = new_inode(s); - if (!inode) - goto free_fsi; -+ - inode->i_ino = 1; - inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; - inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO | S_IWUSR; - inode->i_op = &simple_dir_inode_operations; -- inode->i_fop = &simple_dir_operations; -+ inode->i_fop = &devpts_dir_operations; - inode->i_nlink = 2; -+ /* devpts is xid tagged */ -+ inode->i_tag = (tag_t)vx_current_xid(); - - s->s_root = d_alloc_root(inode); - if (s->s_root) -@@ -497,6 +534,9 @@ int devpts_pty_new(struct inode *ptmx_in - inode->i_gid = opts->setgid ? opts->gid : current_fsgid(); - inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; - init_special_inode(inode, S_IFCHR|opts->mode, device); -+ /* devpts is xid tagged */ -+ inode->i_tag = (tag_t)vx_current_xid(); -+ inode->i_op = &devpts_file_inode_operations; - inode->i_private = tty; - tty->driver_data = inode; - -diff -NurpP --minimal linux-2.6.32.1/fs/exec.c linux-2.6.32.1-vs2.3.0.36.27/fs/exec.c ---- linux-2.6.32.1/fs/exec.c 2009-12-03 20:02:51.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/exec.c 2009-12-03 20:04:56.000000000 +0100 -@@ -251,7 +251,9 @@ static int __bprm_mm_init(struct linux_b - if (err) - goto err; - -- mm->stack_vm = mm->total_vm = 1; -+ mm->total_vm = 0; -+ vx_vmpages_inc(mm); -+ mm->stack_vm = 1; - up_write(&mm->mmap_sem); - bprm->p = vma->vm_end - sizeof(void *); - return 0; -@@ -1474,7 +1476,7 @@ static int format_corename(char *corenam - /* UNIX time of coredump */ - case 't': { - struct timeval tv; -- do_gettimeofday(&tv); -+ vx_gettimeofday(&tv); - rc = snprintf(out_ptr, out_end - out_ptr, - "%lu", tv.tv_sec); - if (rc > out_end - out_ptr) -diff -NurpP --minimal linux-2.6.32.1/fs/ext2/balloc.c linux-2.6.32.1-vs2.3.0.36.27/fs/ext2/balloc.c ---- linux-2.6.32.1/fs/ext2/balloc.c 2009-06-11 17:13:03.000000000 +0200 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/ext2/balloc.c 2009-12-03 20:04:56.000000000 +0100 -@@ -701,7 +701,6 @@ ext2_try_to_allocate(struct super_block - start = 0; - end = EXT2_BLOCKS_PER_GROUP(sb); - } -- - BUG_ON(start > EXT2_BLOCKS_PER_GROUP(sb)); - - repeat: -diff -NurpP --minimal linux-2.6.32.1/fs/ext2/ext2.h linux-2.6.32.1-vs2.3.0.36.27/fs/ext2/ext2.h ---- linux-2.6.32.1/fs/ext2/ext2.h 2009-09-10 15:26:21.000000000 +0200 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/ext2/ext2.h 2009-12-03 20:04:56.000000000 +0100 -@@ -131,6 +131,7 @@ extern int ext2_fiemap(struct inode *ino - int __ext2_write_begin(struct file *file, struct address_space *mapping, - loff_t pos, unsigned len, unsigned flags, - struct page **pagep, void **fsdata); -+extern int ext2_sync_flags(struct inode *, int, int); - - /* ioctl.c */ - extern long ext2_ioctl(struct file *, unsigned int, unsigned long); -diff -NurpP --minimal linux-2.6.32.1/fs/ext2/file.c linux-2.6.32.1-vs2.3.0.36.27/fs/ext2/file.c ---- linux-2.6.32.1/fs/ext2/file.c 2009-12-03 20:02:51.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/ext2/file.c 2009-12-03 20:04:56.000000000 +0100 -@@ -87,4 +87,5 @@ const struct inode_operations ext2_file_ - .setattr = ext2_setattr, - .check_acl = ext2_check_acl, - .fiemap = ext2_fiemap, -+ .sync_flags = ext2_sync_flags, - }; -diff -NurpP --minimal linux-2.6.32.1/fs/ext2/ialloc.c linux-2.6.32.1-vs2.3.0.36.27/fs/ext2/ialloc.c ---- linux-2.6.32.1/fs/ext2/ialloc.c 2009-06-11 17:13:03.000000000 +0200 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/ext2/ialloc.c 2009-12-03 20:04:56.000000000 +0100 -@@ -17,6 +17,7 @@ - #include - #include - #include -+#include - #include "ext2.h" - #include "xattr.h" - #include "acl.h" -@@ -560,6 +561,7 @@ got: - } else - inode->i_gid = current_fsgid(); - inode->i_mode = mode; -+ inode->i_tag = dx_current_fstag(sb); - - inode->i_ino = ino; - inode->i_blocks = 0; -diff -NurpP --minimal linux-2.6.32.1/fs/ext2/inode.c linux-2.6.32.1-vs2.3.0.36.27/fs/ext2/inode.c ---- linux-2.6.32.1/fs/ext2/inode.c 2009-12-03 20:02:51.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/ext2/inode.c 2009-12-03 20:04:56.000000000 +0100 -@@ -33,6 +33,7 @@ - #include - #include - #include -+#include - #include "ext2.h" - #include "acl.h" - #include "xip.h" -@@ -1040,7 +1041,7 @@ void ext2_truncate(struct inode *inode) - return; - if (ext2_inode_is_fast_symlink(inode)) - return; -- if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) -+ if (IS_APPEND(inode) || IS_IXORUNLINK(inode)) - return; - - blocksize = inode->i_sb->s_blocksize; -@@ -1178,36 +1179,61 @@ void ext2_set_inode_flags(struct inode * - { - unsigned int flags = EXT2_I(inode)->i_flags; - -- inode->i_flags &= ~(S_SYNC|S_APPEND|S_IMMUTABLE|S_NOATIME|S_DIRSYNC); -+ inode->i_flags &= ~(S_IMMUTABLE | S_IXUNLINK | -+ S_SYNC | S_APPEND | S_NOATIME | S_DIRSYNC); -+ -+ -+ if (flags & EXT2_IMMUTABLE_FL) -+ inode->i_flags |= S_IMMUTABLE; -+ if (flags & EXT2_IXUNLINK_FL) -+ inode->i_flags |= S_IXUNLINK; -+ - if (flags & EXT2_SYNC_FL) - inode->i_flags |= S_SYNC; - if (flags & EXT2_APPEND_FL) - inode->i_flags |= S_APPEND; -- if (flags & EXT2_IMMUTABLE_FL) -- inode->i_flags |= S_IMMUTABLE; - if (flags & EXT2_NOATIME_FL) - inode->i_flags |= S_NOATIME; - if (flags & EXT2_DIRSYNC_FL) - inode->i_flags |= S_DIRSYNC; -+ -+ inode->i_vflags &= ~(V_BARRIER | V_COW); -+ -+ if (flags & EXT2_BARRIER_FL) -+ inode->i_vflags |= V_BARRIER; -+ if (flags & EXT2_COW_FL) -+ inode->i_vflags |= V_COW; - } - - /* Propagate flags from i_flags to EXT2_I(inode)->i_flags */ - void ext2_get_inode_flags(struct ext2_inode_info *ei) - { - unsigned int flags = ei->vfs_inode.i_flags; -+ unsigned int vflags = ei->vfs_inode.i_vflags; -+ -+ ei->i_flags &= ~(EXT2_SYNC_FL | EXT2_APPEND_FL | -+ EXT2_IMMUTABLE_FL | EXT2_IXUNLINK_FL | -+ EXT2_NOATIME_FL | EXT2_DIRSYNC_FL | -+ EXT2_BARRIER_FL | EXT2_COW_FL); -+ -+ if (flags & S_IMMUTABLE) -+ ei->i_flags |= EXT2_IMMUTABLE_FL; -+ if (flags & S_IXUNLINK) -+ ei->i_flags |= EXT2_IXUNLINK_FL; - -- ei->i_flags &= ~(EXT2_SYNC_FL|EXT2_APPEND_FL| -- EXT2_IMMUTABLE_FL|EXT2_NOATIME_FL|EXT2_DIRSYNC_FL); - if (flags & S_SYNC) - ei->i_flags |= EXT2_SYNC_FL; - if (flags & S_APPEND) - ei->i_flags |= EXT2_APPEND_FL; -- if (flags & S_IMMUTABLE) -- ei->i_flags |= EXT2_IMMUTABLE_FL; - if (flags & S_NOATIME) - ei->i_flags |= EXT2_NOATIME_FL; - if (flags & S_DIRSYNC) - ei->i_flags |= EXT2_DIRSYNC_FL; -+ -+ if (vflags & V_BARRIER) -+ ei->i_flags |= EXT2_BARRIER_FL; -+ if (vflags & V_COW) -+ ei->i_flags |= EXT2_COW_FL; - } - - struct inode *ext2_iget (struct super_block *sb, unsigned long ino) -@@ -1217,6 +1243,8 @@ struct inode *ext2_iget (struct super_bl - struct ext2_inode *raw_inode; - struct inode *inode; - long ret = -EIO; -+ uid_t uid; -+ gid_t gid; - int n; - - inode = iget_locked(sb, ino); -@@ -1235,12 +1263,17 @@ struct inode *ext2_iget (struct super_bl - } - - inode->i_mode = le16_to_cpu(raw_inode->i_mode); -- inode->i_uid = (uid_t)le16_to_cpu(raw_inode->i_uid_low); -- inode->i_gid = (gid_t)le16_to_cpu(raw_inode->i_gid_low); -+ uid = (uid_t)le16_to_cpu(raw_inode->i_uid_low); -+ gid = (gid_t)le16_to_cpu(raw_inode->i_gid_low); - if (!(test_opt (inode->i_sb, NO_UID32))) { -- inode->i_uid |= le16_to_cpu(raw_inode->i_uid_high) << 16; -- inode->i_gid |= le16_to_cpu(raw_inode->i_gid_high) << 16; -+ uid |= le16_to_cpu(raw_inode->i_uid_high) << 16; -+ gid |= le16_to_cpu(raw_inode->i_gid_high) << 16; - } -+ inode->i_uid = INOTAG_UID(DX_TAG(inode), uid, gid); -+ inode->i_gid = INOTAG_GID(DX_TAG(inode), uid, gid); -+ inode->i_tag = INOTAG_TAG(DX_TAG(inode), uid, gid, -+ le16_to_cpu(raw_inode->i_raw_tag)); -+ - inode->i_nlink = le16_to_cpu(raw_inode->i_links_count); - inode->i_size = le32_to_cpu(raw_inode->i_size); - inode->i_atime.tv_sec = (signed)le32_to_cpu(raw_inode->i_atime); -@@ -1338,8 +1371,8 @@ int ext2_write_inode(struct inode *inode - struct ext2_inode_info *ei = EXT2_I(inode); - struct super_block *sb = inode->i_sb; - ino_t ino = inode->i_ino; -- uid_t uid = inode->i_uid; -- gid_t gid = inode->i_gid; -+ uid_t uid = TAGINO_UID(DX_TAG(inode), inode->i_uid, inode->i_tag); -+ gid_t gid = TAGINO_GID(DX_TAG(inode), inode->i_gid, inode->i_tag); - struct buffer_head * bh; - struct ext2_inode * raw_inode = ext2_get_inode(sb, ino, &bh); - int n; -@@ -1375,6 +1408,9 @@ int ext2_write_inode(struct inode *inode - raw_inode->i_uid_high = 0; - raw_inode->i_gid_high = 0; - } -+#ifdef CONFIG_TAGGING_INTERN -+ raw_inode->i_raw_tag = cpu_to_le16(inode->i_tag); -+#endif - raw_inode->i_links_count = cpu_to_le16(inode->i_nlink); - raw_inode->i_size = cpu_to_le32(inode->i_size); - raw_inode->i_atime = cpu_to_le32(inode->i_atime.tv_sec); -@@ -1456,7 +1492,8 @@ int ext2_setattr(struct dentry *dentry, - if (error) - return error; - if ((iattr->ia_valid & ATTR_UID && iattr->ia_uid != inode->i_uid) || -- (iattr->ia_valid & ATTR_GID && iattr->ia_gid != inode->i_gid)) { -+ (iattr->ia_valid & ATTR_GID && iattr->ia_gid != inode->i_gid) || -+ (iattr->ia_valid & ATTR_TAG && iattr->ia_tag != inode->i_tag)) { - error = vfs_dq_transfer(inode, iattr) ? -EDQUOT : 0; - if (error) - return error; -diff -NurpP --minimal linux-2.6.32.1/fs/ext2/ioctl.c linux-2.6.32.1-vs2.3.0.36.27/fs/ext2/ioctl.c ---- linux-2.6.32.1/fs/ext2/ioctl.c 2009-09-10 15:26:21.000000000 +0200 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/ext2/ioctl.c 2009-12-03 20:04:56.000000000 +0100 -@@ -17,6 +17,16 @@ - #include - - -+int ext2_sync_flags(struct inode *inode, int flags, int vflags) -+{ -+ inode->i_flags = flags; -+ inode->i_vflags = vflags; -+ ext2_get_inode_flags(EXT2_I(inode)); -+ inode->i_ctime = CURRENT_TIME_SEC; -+ mark_inode_dirty(inode); -+ return 0; -+} -+ - long ext2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) - { - struct inode *inode = filp->f_dentry->d_inode; -@@ -51,6 +61,11 @@ long ext2_ioctl(struct file *filp, unsig - - flags = ext2_mask_flags(inode->i_mode, flags); - -+ if (IS_BARRIER(inode)) { -+ vxwprintk_task(1, "messing with the barrier."); -+ return -EACCES; -+ } -+ - mutex_lock(&inode->i_mutex); - /* Is it quota file? Do not allow user to mess with it */ - if (IS_NOQUOTA(inode)) { -@@ -66,7 +81,9 @@ long ext2_ioctl(struct file *filp, unsig - * - * This test looks nicer. Thanks to Pauline Middelink - */ -- if ((flags ^ oldflags) & (EXT2_APPEND_FL | EXT2_IMMUTABLE_FL)) { -+ if ((oldflags & EXT2_IMMUTABLE_FL) || -+ ((flags ^ oldflags) & (EXT2_APPEND_FL | -+ EXT2_IMMUTABLE_FL | EXT2_IXUNLINK_FL))) { - if (!capable(CAP_LINUX_IMMUTABLE)) { - mutex_unlock(&inode->i_mutex); - ret = -EPERM; -@@ -74,7 +91,7 @@ long ext2_ioctl(struct file *filp, unsig - } - } - -- flags = flags & EXT2_FL_USER_MODIFIABLE; -+ flags &= EXT2_FL_USER_MODIFIABLE; - flags |= oldflags & ~EXT2_FL_USER_MODIFIABLE; - ei->i_flags = flags; - mutex_unlock(&inode->i_mutex); -diff -NurpP --minimal linux-2.6.32.1/fs/ext2/namei.c linux-2.6.32.1-vs2.3.0.36.27/fs/ext2/namei.c ---- linux-2.6.32.1/fs/ext2/namei.c 2009-12-03 20:02:51.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/ext2/namei.c 2009-12-03 20:04:56.000000000 +0100 -@@ -31,6 +31,7 @@ - */ - - #include -+#include - #include "ext2.h" - #include "xattr.h" - #include "acl.h" -@@ -74,6 +75,7 @@ static struct dentry *ext2_lookup(struct - return ERR_PTR(-EIO); - } else { - return ERR_CAST(inode); -+ dx_propagate_tag(nd, inode); - } - } - } -@@ -401,6 +403,7 @@ const struct inode_operations ext2_dir_i - #endif - .setattr = ext2_setattr, - .check_acl = ext2_check_acl, -+ .sync_flags = ext2_sync_flags, - }; - - const struct inode_operations ext2_special_inode_operations = { -diff -NurpP --minimal linux-2.6.32.1/fs/ext2/super.c linux-2.6.32.1-vs2.3.0.36.27/fs/ext2/super.c ---- linux-2.6.32.1/fs/ext2/super.c 2009-09-10 15:26:21.000000000 +0200 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/ext2/super.c 2009-12-03 20:04:56.000000000 +0100 -@@ -382,7 +382,8 @@ enum { - Opt_err_ro, Opt_nouid32, Opt_nocheck, Opt_debug, - Opt_oldalloc, Opt_orlov, Opt_nobh, Opt_user_xattr, Opt_nouser_xattr, - Opt_acl, Opt_noacl, Opt_xip, Opt_ignore, Opt_err, Opt_quota, -- Opt_usrquota, Opt_grpquota, Opt_reservation, Opt_noreservation -+ Opt_usrquota, Opt_grpquota, Opt_reservation, Opt_noreservation, -+ Opt_tag, Opt_notag, Opt_tagid - }; - - static const match_table_t tokens = { -@@ -410,6 +411,9 @@ static const match_table_t tokens = { - {Opt_acl, "acl"}, - {Opt_noacl, "noacl"}, - {Opt_xip, "xip"}, -+ {Opt_tag, "tag"}, -+ {Opt_notag, "notag"}, -+ {Opt_tagid, "tagid=%u"}, - {Opt_grpquota, "grpquota"}, - {Opt_ignore, "noquota"}, - {Opt_quota, "quota"}, -@@ -480,6 +484,20 @@ static int parse_options (char * options - case Opt_nouid32: - set_opt (sbi->s_mount_opt, NO_UID32); - break; -+#ifndef CONFIG_TAGGING_NONE -+ case Opt_tag: -+ set_opt (sbi->s_mount_opt, TAGGED); -+ break; -+ case Opt_notag: -+ clear_opt (sbi->s_mount_opt, TAGGED); -+ break; -+#endif -+#ifdef CONFIG_PROPAGATE -+ case Opt_tagid: -+ /* use args[0] */ -+ set_opt (sbi->s_mount_opt, TAGGED); -+ break; -+#endif - case Opt_nocheck: - clear_opt (sbi->s_mount_opt, CHECK); - break; -@@ -829,6 +847,8 @@ static int ext2_fill_super(struct super_ - if (!parse_options ((char *) data, sbi)) - goto failed_mount; - -+ if (EXT2_SB(sb)->s_mount_opt & EXT2_MOUNT_TAGGED) -+ sb->s_flags |= MS_TAGGED; - sb->s_flags = (sb->s_flags & ~MS_POSIXACL) | - ((EXT2_SB(sb)->s_mount_opt & EXT2_MOUNT_POSIX_ACL) ? - MS_POSIXACL : 0); -@@ -1175,6 +1195,14 @@ static int ext2_remount (struct super_bl - goto restore_opts; - } - -+ if ((sbi->s_mount_opt & EXT2_MOUNT_TAGGED) && -+ !(sb->s_flags & MS_TAGGED)) { -+ printk("EXT2-fs: %s: tagging not permitted on remount.\n", -+ sb->s_id); -+ err = -EINVAL; -+ goto restore_opts; -+ } -+ - sb->s_flags = (sb->s_flags & ~MS_POSIXACL) | - ((sbi->s_mount_opt & EXT2_MOUNT_POSIX_ACL) ? MS_POSIXACL : 0); - -diff -NurpP --minimal linux-2.6.32.1/fs/ext3/file.c linux-2.6.32.1-vs2.3.0.36.27/fs/ext3/file.c ---- linux-2.6.32.1/fs/ext3/file.c 2009-12-03 20:02:51.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/ext3/file.c 2009-12-03 20:04:56.000000000 +0100 -@@ -80,5 +80,6 @@ const struct inode_operations ext3_file_ - #endif - .check_acl = ext3_check_acl, - .fiemap = ext3_fiemap, -+ .sync_flags = ext3_sync_flags, - }; - -diff -NurpP --minimal linux-2.6.32.1/fs/ext3/ialloc.c linux-2.6.32.1-vs2.3.0.36.27/fs/ext3/ialloc.c ---- linux-2.6.32.1/fs/ext3/ialloc.c 2009-09-10 15:26:21.000000000 +0200 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/ext3/ialloc.c 2009-12-03 20:04:56.000000000 +0100 -@@ -23,6 +23,7 @@ - #include - #include - #include -+#include - - #include - -@@ -548,6 +549,7 @@ got: - } else - inode->i_gid = current_fsgid(); - inode->i_mode = mode; -+ inode->i_tag = dx_current_fstag(sb); - - inode->i_ino = ino; - /* This is the optimal IO size (for stat), not the fs block size */ -diff -NurpP --minimal linux-2.6.32.1/fs/ext3/inode.c linux-2.6.32.1-vs2.3.0.36.27/fs/ext3/inode.c ---- linux-2.6.32.1/fs/ext3/inode.c 2009-12-03 20:02:51.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/ext3/inode.c 2009-12-03 20:04:56.000000000 +0100 -@@ -38,6 +38,7 @@ - #include - #include - #include -+#include - #include "xattr.h" - #include "acl.h" - -@@ -2333,7 +2334,7 @@ static void ext3_free_branches(handle_t - - int ext3_can_truncate(struct inode *inode) - { -- if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) -+ if (IS_APPEND(inode) || IS_IXORUNLINK(inode)) - return 0; - if (S_ISREG(inode->i_mode)) - return 1; -@@ -2718,36 +2719,60 @@ void ext3_set_inode_flags(struct inode * - { - unsigned int flags = EXT3_I(inode)->i_flags; - -- inode->i_flags &= ~(S_SYNC|S_APPEND|S_IMMUTABLE|S_NOATIME|S_DIRSYNC); -+ inode->i_flags &= ~(S_IMMUTABLE | S_IXUNLINK | -+ S_SYNC | S_APPEND | S_NOATIME | S_DIRSYNC); -+ -+ if (flags & EXT3_IMMUTABLE_FL) -+ inode->i_flags |= S_IMMUTABLE; -+ if (flags & EXT3_IXUNLINK_FL) -+ inode->i_flags |= S_IXUNLINK; -+ - if (flags & EXT3_SYNC_FL) - inode->i_flags |= S_SYNC; - if (flags & EXT3_APPEND_FL) - inode->i_flags |= S_APPEND; -- if (flags & EXT3_IMMUTABLE_FL) -- inode->i_flags |= S_IMMUTABLE; - if (flags & EXT3_NOATIME_FL) - inode->i_flags |= S_NOATIME; - if (flags & EXT3_DIRSYNC_FL) - inode->i_flags |= S_DIRSYNC; -+ -+ inode->i_vflags &= ~(V_BARRIER | V_COW); -+ -+ if (flags & EXT3_BARRIER_FL) -+ inode->i_vflags |= V_BARRIER; -+ if (flags & EXT3_COW_FL) -+ inode->i_vflags |= V_COW; - } - - /* Propagate flags from i_flags to EXT3_I(inode)->i_flags */ - void ext3_get_inode_flags(struct ext3_inode_info *ei) - { - unsigned int flags = ei->vfs_inode.i_flags; -+ unsigned int vflags = ei->vfs_inode.i_vflags; -+ -+ ei->i_flags &= ~(EXT3_SYNC_FL | EXT3_APPEND_FL | -+ EXT3_IMMUTABLE_FL | EXT3_IXUNLINK_FL | -+ EXT3_NOATIME_FL | EXT3_DIRSYNC_FL | -+ EXT3_BARRIER_FL | EXT3_COW_FL); -+ -+ if (flags & S_IMMUTABLE) -+ ei->i_flags |= EXT3_IMMUTABLE_FL; -+ if (flags & S_IXUNLINK) -+ ei->i_flags |= EXT3_IXUNLINK_FL; - -- ei->i_flags &= ~(EXT3_SYNC_FL|EXT3_APPEND_FL| -- EXT3_IMMUTABLE_FL|EXT3_NOATIME_FL|EXT3_DIRSYNC_FL); - if (flags & S_SYNC) - ei->i_flags |= EXT3_SYNC_FL; - if (flags & S_APPEND) - ei->i_flags |= EXT3_APPEND_FL; -- if (flags & S_IMMUTABLE) -- ei->i_flags |= EXT3_IMMUTABLE_FL; - if (flags & S_NOATIME) - ei->i_flags |= EXT3_NOATIME_FL; - if (flags & S_DIRSYNC) - ei->i_flags |= EXT3_DIRSYNC_FL; -+ -+ if (vflags & V_BARRIER) -+ ei->i_flags |= EXT3_BARRIER_FL; -+ if (vflags & V_COW) -+ ei->i_flags |= EXT3_COW_FL; - } - - struct inode *ext3_iget(struct super_block *sb, unsigned long ino) -@@ -2761,6 +2786,8 @@ struct inode *ext3_iget(struct super_blo - transaction_t *transaction; - long ret; - int block; -+ uid_t uid; -+ gid_t gid; - - inode = iget_locked(sb, ino); - if (!inode) -@@ -2777,12 +2804,17 @@ struct inode *ext3_iget(struct super_blo - bh = iloc.bh; - raw_inode = ext3_raw_inode(&iloc); - inode->i_mode = le16_to_cpu(raw_inode->i_mode); -- inode->i_uid = (uid_t)le16_to_cpu(raw_inode->i_uid_low); -- inode->i_gid = (gid_t)le16_to_cpu(raw_inode->i_gid_low); -+ uid = (uid_t)le16_to_cpu(raw_inode->i_uid_low); -+ gid = (gid_t)le16_to_cpu(raw_inode->i_gid_low); - if(!(test_opt (inode->i_sb, NO_UID32))) { -- inode->i_uid |= le16_to_cpu(raw_inode->i_uid_high) << 16; -- inode->i_gid |= le16_to_cpu(raw_inode->i_gid_high) << 16; -+ uid |= le16_to_cpu(raw_inode->i_uid_high) << 16; -+ gid |= le16_to_cpu(raw_inode->i_gid_high) << 16; - } -+ inode->i_uid = INOTAG_UID(DX_TAG(inode), uid, gid); -+ inode->i_gid = INOTAG_GID(DX_TAG(inode), uid, gid); -+ inode->i_tag = INOTAG_TAG(DX_TAG(inode), uid, gid, -+ le16_to_cpu(raw_inode->i_raw_tag)); -+ - inode->i_nlink = le16_to_cpu(raw_inode->i_links_count); - inode->i_size = le32_to_cpu(raw_inode->i_size); - inode->i_atime.tv_sec = (signed)le32_to_cpu(raw_inode->i_atime); -@@ -2937,6 +2969,8 @@ static int ext3_do_update_inode(handle_t - struct ext3_inode *raw_inode = ext3_raw_inode(iloc); - struct ext3_inode_info *ei = EXT3_I(inode); - struct buffer_head *bh = iloc->bh; -+ uid_t uid = TAGINO_UID(DX_TAG(inode), inode->i_uid, inode->i_tag); -+ gid_t gid = TAGINO_GID(DX_TAG(inode), inode->i_gid, inode->i_tag); - int err = 0, rc, block; - - again: -@@ -2951,29 +2985,32 @@ again: - ext3_get_inode_flags(ei); - raw_inode->i_mode = cpu_to_le16(inode->i_mode); - if(!(test_opt(inode->i_sb, NO_UID32))) { -- raw_inode->i_uid_low = cpu_to_le16(low_16_bits(inode->i_uid)); -- raw_inode->i_gid_low = cpu_to_le16(low_16_bits(inode->i_gid)); -+ raw_inode->i_uid_low = cpu_to_le16(low_16_bits(uid)); -+ raw_inode->i_gid_low = cpu_to_le16(low_16_bits(gid)); - /* - * Fix up interoperability with old kernels. Otherwise, old inodes get - * re-used with the upper 16 bits of the uid/gid intact - */ - if(!ei->i_dtime) { - raw_inode->i_uid_high = -- cpu_to_le16(high_16_bits(inode->i_uid)); -+ cpu_to_le16(high_16_bits(uid)); - raw_inode->i_gid_high = -- cpu_to_le16(high_16_bits(inode->i_gid)); -+ cpu_to_le16(high_16_bits(gid)); - } else { - raw_inode->i_uid_high = 0; - raw_inode->i_gid_high = 0; - } - } else { - raw_inode->i_uid_low = -- cpu_to_le16(fs_high2lowuid(inode->i_uid)); -+ cpu_to_le16(fs_high2lowuid(uid)); - raw_inode->i_gid_low = -- cpu_to_le16(fs_high2lowgid(inode->i_gid)); -+ cpu_to_le16(fs_high2lowgid(gid)); - raw_inode->i_uid_high = 0; - raw_inode->i_gid_high = 0; - } -+#ifdef CONFIG_TAGGING_INTERN -+ raw_inode->i_raw_tag = cpu_to_le16(inode->i_tag); -+#endif - raw_inode->i_links_count = cpu_to_le16(inode->i_nlink); - raw_inode->i_size = cpu_to_le32(ei->i_disksize); - raw_inode->i_atime = cpu_to_le32(inode->i_atime.tv_sec); -@@ -3131,7 +3168,8 @@ int ext3_setattr(struct dentry *dentry, - return error; - - if ((ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid) || -- (ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid)) { -+ (ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid) || -+ (ia_valid & ATTR_TAG && attr->ia_tag != inode->i_tag)) { - handle_t *handle; - - /* (user+group)*(old+new) structure, inode write (sb, -@@ -3153,6 +3191,8 @@ int ext3_setattr(struct dentry *dentry, - inode->i_uid = attr->ia_uid; - if (attr->ia_valid & ATTR_GID) - inode->i_gid = attr->ia_gid; -+ if ((attr->ia_valid & ATTR_TAG) && IS_TAGGED(inode)) -+ inode->i_tag = attr->ia_tag; - error = ext3_mark_inode_dirty(handle, inode); - ext3_journal_stop(handle); - } -diff -NurpP --minimal linux-2.6.32.1/fs/ext3/ioctl.c linux-2.6.32.1-vs2.3.0.36.27/fs/ext3/ioctl.c ---- linux-2.6.32.1/fs/ext3/ioctl.c 2009-06-11 17:13:03.000000000 +0200 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/ext3/ioctl.c 2009-12-03 20:04:56.000000000 +0100 -@@ -8,6 +8,7 @@ - */ - - #include -+#include - #include - #include - #include -@@ -17,6 +18,34 @@ - #include - #include - -+ -+int ext3_sync_flags(struct inode *inode, int flags, int vflags) -+{ -+ handle_t *handle = NULL; -+ struct ext3_iloc iloc; -+ int err; -+ -+ handle = ext3_journal_start(inode, 1); -+ if (IS_ERR(handle)) -+ return PTR_ERR(handle); -+ -+ if (IS_SYNC(inode)) -+ handle->h_sync = 1; -+ err = ext3_reserve_inode_write(handle, inode, &iloc); -+ if (err) -+ goto flags_err; -+ -+ inode->i_flags = flags; -+ inode->i_vflags = vflags; -+ ext3_get_inode_flags(EXT3_I(inode)); -+ inode->i_ctime = CURRENT_TIME_SEC; -+ -+ err = ext3_mark_iloc_dirty(handle, inode, &iloc); -+flags_err: -+ ext3_journal_stop(handle); -+ return err; -+} -+ - long ext3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) - { - struct inode *inode = filp->f_dentry->d_inode; -@@ -50,6 +79,11 @@ long ext3_ioctl(struct file *filp, unsig - - flags = ext3_mask_flags(inode->i_mode, flags); - -+ if (IS_BARRIER(inode)) { -+ vxwprintk_task(1, "messing with the barrier."); -+ return -EACCES; -+ } -+ - mutex_lock(&inode->i_mutex); - - /* Is it quota file? Do not allow user to mess with it */ -@@ -68,7 +102,9 @@ long ext3_ioctl(struct file *filp, unsig - * - * This test looks nicer. Thanks to Pauline Middelink - */ -- if ((flags ^ oldflags) & (EXT3_APPEND_FL | EXT3_IMMUTABLE_FL)) { -+ if ((oldflags & EXT3_IMMUTABLE_FL) || -+ ((flags ^ oldflags) & (EXT3_APPEND_FL | -+ EXT3_IMMUTABLE_FL | EXT3_IXUNLINK_FL))) { - if (!capable(CAP_LINUX_IMMUTABLE)) - goto flags_out; - } -@@ -93,7 +129,7 @@ long ext3_ioctl(struct file *filp, unsig - if (err) - goto flags_err; - -- flags = flags & EXT3_FL_USER_MODIFIABLE; -+ flags &= EXT3_FL_USER_MODIFIABLE; - flags |= oldflags & ~EXT3_FL_USER_MODIFIABLE; - ei->i_flags = flags; - -diff -NurpP --minimal linux-2.6.32.1/fs/ext3/namei.c linux-2.6.32.1-vs2.3.0.36.27/fs/ext3/namei.c ---- linux-2.6.32.1/fs/ext3/namei.c 2009-12-03 20:02:51.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/ext3/namei.c 2009-12-03 20:04:56.000000000 +0100 -@@ -36,6 +36,7 @@ - #include - #include - #include -+#include - - #include "namei.h" - #include "xattr.h" -@@ -912,6 +913,7 @@ restart: - if (bh) - ll_rw_block(READ_META, 1, &bh); - } -+ dx_propagate_tag(nd, inode); - } - if ((bh = bh_use[ra_ptr++]) == NULL) - goto next; -@@ -2446,6 +2448,7 @@ const struct inode_operations ext3_dir_i - .removexattr = generic_removexattr, - #endif - .check_acl = ext3_check_acl, -+ .sync_flags = ext3_sync_flags, - }; - - const struct inode_operations ext3_special_inode_operations = { -diff -NurpP --minimal linux-2.6.32.1/fs/ext3/super.c linux-2.6.32.1-vs2.3.0.36.27/fs/ext3/super.c ---- linux-2.6.32.1/fs/ext3/super.c 2009-12-03 20:02:51.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/ext3/super.c 2009-12-03 20:04:56.000000000 +0100 -@@ -789,7 +789,7 @@ enum { - Opt_usrjquota, Opt_grpjquota, Opt_offusrjquota, Opt_offgrpjquota, - Opt_jqfmt_vfsold, Opt_jqfmt_vfsv0, Opt_quota, Opt_noquota, - Opt_ignore, Opt_barrier, Opt_err, Opt_resize, Opt_usrquota, -- Opt_grpquota -+ Opt_grpquota, Opt_tag, Opt_notag, Opt_tagid - }; - - static const match_table_t tokens = { -@@ -842,6 +842,9 @@ static const match_table_t tokens = { - {Opt_usrquota, "usrquota"}, - {Opt_barrier, "barrier=%u"}, - {Opt_resize, "resize"}, -+ {Opt_tag, "tag"}, -+ {Opt_notag, "notag"}, -+ {Opt_tagid, "tagid=%u"}, - {Opt_err, NULL}, - }; - -@@ -934,6 +937,20 @@ static int parse_options (char *options, - case Opt_nouid32: - set_opt (sbi->s_mount_opt, NO_UID32); - break; -+#ifndef CONFIG_TAGGING_NONE -+ case Opt_tag: -+ set_opt (sbi->s_mount_opt, TAGGED); -+ break; -+ case Opt_notag: -+ clear_opt (sbi->s_mount_opt, TAGGED); -+ break; -+#endif -+#ifdef CONFIG_PROPAGATE -+ case Opt_tagid: -+ /* use args[0] */ -+ set_opt (sbi->s_mount_opt, TAGGED); -+ break; -+#endif - case Opt_nocheck: - clear_opt (sbi->s_mount_opt, CHECK); - break; -@@ -1658,6 +1675,9 @@ static int ext3_fill_super (struct super - NULL, 0)) - goto failed_mount; - -+ if (EXT3_SB(sb)->s_mount_opt & EXT3_MOUNT_TAGGED) -+ sb->s_flags |= MS_TAGGED; -+ - sb->s_flags = (sb->s_flags & ~MS_POSIXACL) | - ((sbi->s_mount_opt & EXT3_MOUNT_POSIX_ACL) ? MS_POSIXACL : 0); - -@@ -2527,6 +2547,14 @@ static int ext3_remount (struct super_bl - if (sbi->s_mount_opt & EXT3_MOUNT_ABORT) - ext3_abort(sb, __func__, "Abort forced by user"); - -+ if ((sbi->s_mount_opt & EXT3_MOUNT_TAGGED) && -+ !(sb->s_flags & MS_TAGGED)) { -+ printk("EXT3-fs: %s: tagging not permitted on remount.\n", -+ sb->s_id); -+ err = -EINVAL; -+ goto restore_opts; -+ } -+ - sb->s_flags = (sb->s_flags & ~MS_POSIXACL) | - ((sbi->s_mount_opt & EXT3_MOUNT_POSIX_ACL) ? MS_POSIXACL : 0); - -diff -NurpP --minimal linux-2.6.32.1/fs/ext4/ext4.h linux-2.6.32.1-vs2.3.0.36.27/fs/ext4/ext4.h ---- linux-2.6.32.1/fs/ext4/ext4.h 2009-12-14 21:29:46.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/ext4/ext4.h 2009-12-14 22:20:55.000000000 +0100 -@@ -284,8 +284,12 @@ struct flex_groups { - #define EXT4_TOPDIR_FL 0x00020000 /* Top of directory hierarchies*/ - #define EXT4_HUGE_FILE_FL 0x00040000 /* Set to each huge file */ - #define EXT4_EXTENTS_FL 0x00080000 /* Inode uses extents */ -+#define EXT4_IXUNLINK_FL 0x08000000 /* Immutable invert on unlink */ - #define EXT4_RESERVED_FL 0x80000000 /* reserved for ext4 lib */ - -+#define EXT4_BARRIER_FL 0x04000000 /* Barrier for chroot() */ -+#define EXT4_COW_FL 0x20000000 /* Copy on Write marker */ -+ - #define EXT4_FL_USER_VISIBLE 0x000BDFFF /* User visible flags */ - #define EXT4_FL_USER_MODIFIABLE 0x000B80FF /* User modifiable flags */ - -@@ -469,7 +473,8 @@ struct ext4_inode { - __le16 l_i_file_acl_high; - __le16 l_i_uid_high; /* these 2 fields */ - __le16 l_i_gid_high; /* were reserved2[0] */ -- __u32 l_i_reserved2; -+ __le16 l_i_tag; /* Context Tag */ -+ __u16 l_i_reserved2; - } linux2; - struct { - __le16 h_i_reserved1; /* Obsoleted fragment number/size which are removed in ext4 */ -@@ -583,6 +588,7 @@ do { \ - #define i_gid_low i_gid - #define i_uid_high osd2.linux2.l_i_uid_high - #define i_gid_high osd2.linux2.l_i_gid_high -+#define i_raw_tag osd2.linux2.l_i_tag - #define i_reserved2 osd2.linux2.l_i_reserved2 - - #elif defined(__GNU__) -@@ -751,6 +757,7 @@ struct ext4_inode_info { - #define EXT4_MOUNT_QUOTA 0x80000 /* Some quota option set */ - #define EXT4_MOUNT_USRQUOTA 0x100000 /* "old" user quota */ - #define EXT4_MOUNT_GRPQUOTA 0x200000 /* "old" group quota */ -+#define EXT4_MOUNT_TAGGED 0x400000 /* Enable Context Tags */ - #define EXT4_MOUNT_JOURNAL_CHECKSUM 0x800000 /* Journal checksums */ - #define EXT4_MOUNT_JOURNAL_ASYNC_COMMIT 0x1000000 /* Journal Async Commit */ - #define EXT4_MOUNT_I_VERSION 0x2000000 /* i_version support */ -@@ -1742,6 +1749,7 @@ extern int ext4_get_blocks(handle_t *han - struct buffer_head *bh, int flags); - extern int ext4_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, - __u64 start, __u64 len); -+extern int ext4_sync_flags(struct inode *, int, int); - /* move_extent.c */ - extern int ext4_move_extents(struct file *o_filp, struct file *d_filp, - __u64 start_orig, __u64 start_donor, -diff -NurpP --minimal linux-2.6.32.1/fs/ext4/file.c linux-2.6.32.1-vs2.3.0.36.27/fs/ext4/file.c ---- linux-2.6.32.1/fs/ext4/file.c 2009-12-03 20:02:51.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/ext4/file.c 2009-12-03 20:04:56.000000000 +0100 -@@ -161,5 +161,6 @@ const struct inode_operations ext4_file_ - .check_acl = ext4_check_acl, - .fallocate = ext4_fallocate, - .fiemap = ext4_fiemap, -+ .sync_flags = ext4_sync_flags, - }; - -diff -NurpP --minimal linux-2.6.32.1/fs/ext4/ialloc.c linux-2.6.32.1-vs2.3.0.36.27/fs/ext4/ialloc.c ---- linux-2.6.32.1/fs/ext4/ialloc.c 2009-12-03 20:02:51.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/ext4/ialloc.c 2009-12-03 20:04:56.000000000 +0100 -@@ -22,6 +22,7 @@ - #include - #include - #include -+#include - #include - - #include "ext4.h" -@@ -995,6 +996,7 @@ got: - } else - inode->i_gid = current_fsgid(); - inode->i_mode = mode; -+ inode->i_tag = dx_current_fstag(sb); - - inode->i_ino = ino + group * EXT4_INODES_PER_GROUP(sb); - /* This is the optimal IO size (for stat), not the fs block size */ -diff -NurpP --minimal linux-2.6.32.1/fs/ext4/inode.c linux-2.6.32.1-vs2.3.0.36.27/fs/ext4/inode.c ---- linux-2.6.32.1/fs/ext4/inode.c 2009-12-14 21:29:46.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/ext4/inode.c 2009-12-14 22:20:55.000000000 +0100 -@@ -38,6 +38,7 @@ - #include - #include - #include -+#include - - #include "ext4_jbd2.h" - #include "xattr.h" -@@ -4384,7 +4385,7 @@ static void ext4_free_branches(handle_t - - int ext4_can_truncate(struct inode *inode) - { -- if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) -+ if (IS_APPEND(inode) || IS_IXORUNLINK(inode)) - return 0; - if (S_ISREG(inode->i_mode)) - return 1; -@@ -4735,36 +4736,60 @@ void ext4_set_inode_flags(struct inode * - { - unsigned int flags = EXT4_I(inode)->i_flags; - -- inode->i_flags &= ~(S_SYNC|S_APPEND|S_IMMUTABLE|S_NOATIME|S_DIRSYNC); -+ inode->i_flags &= ~(S_IMMUTABLE | S_IXUNLINK | -+ S_SYNC | S_APPEND | S_NOATIME | S_DIRSYNC); -+ -+ if (flags & EXT4_IMMUTABLE_FL) -+ inode->i_flags |= S_IMMUTABLE; -+ if (flags & EXT4_IXUNLINK_FL) -+ inode->i_flags |= S_IXUNLINK; -+ - if (flags & EXT4_SYNC_FL) - inode->i_flags |= S_SYNC; - if (flags & EXT4_APPEND_FL) - inode->i_flags |= S_APPEND; -- if (flags & EXT4_IMMUTABLE_FL) -- inode->i_flags |= S_IMMUTABLE; - if (flags & EXT4_NOATIME_FL) - inode->i_flags |= S_NOATIME; - if (flags & EXT4_DIRSYNC_FL) - inode->i_flags |= S_DIRSYNC; -+ -+ inode->i_vflags &= ~(V_BARRIER | V_COW); -+ -+ if (flags & EXT4_BARRIER_FL) -+ inode->i_vflags |= V_BARRIER; -+ if (flags & EXT4_COW_FL) -+ inode->i_vflags |= V_COW; - } - - /* Propagate flags from i_flags to EXT4_I(inode)->i_flags */ - void ext4_get_inode_flags(struct ext4_inode_info *ei) - { - unsigned int flags = ei->vfs_inode.i_flags; -+ unsigned int vflags = ei->vfs_inode.i_vflags; -+ -+ ei->i_flags &= ~(EXT4_SYNC_FL | EXT4_APPEND_FL | -+ EXT4_IMMUTABLE_FL | EXT4_IXUNLINK_FL | -+ EXT4_NOATIME_FL | EXT4_DIRSYNC_FL | -+ EXT4_BARRIER_FL | EXT4_COW_FL); -+ -+ if (flags & S_IMMUTABLE) -+ ei->i_flags |= EXT4_IMMUTABLE_FL; -+ if (flags & S_IXUNLINK) -+ ei->i_flags |= EXT4_IXUNLINK_FL; - -- ei->i_flags &= ~(EXT4_SYNC_FL|EXT4_APPEND_FL| -- EXT4_IMMUTABLE_FL|EXT4_NOATIME_FL|EXT4_DIRSYNC_FL); - if (flags & S_SYNC) - ei->i_flags |= EXT4_SYNC_FL; - if (flags & S_APPEND) - ei->i_flags |= EXT4_APPEND_FL; -- if (flags & S_IMMUTABLE) -- ei->i_flags |= EXT4_IMMUTABLE_FL; - if (flags & S_NOATIME) - ei->i_flags |= EXT4_NOATIME_FL; - if (flags & S_DIRSYNC) - ei->i_flags |= EXT4_DIRSYNC_FL; -+ -+ if (vflags & V_BARRIER) -+ ei->i_flags |= EXT4_BARRIER_FL; -+ if (vflags & V_COW) -+ ei->i_flags |= EXT4_COW_FL; - } - - static blkcnt_t ext4_inode_blocks(struct ext4_inode *raw_inode, -@@ -4799,6 +4824,8 @@ struct inode *ext4_iget(struct super_blo - journal_t *journal = EXT4_SB(sb)->s_journal; - long ret; - int block; -+ uid_t uid; -+ gid_t gid; - - inode = iget_locked(sb, ino); - if (!inode) -@@ -4814,12 +4841,16 @@ struct inode *ext4_iget(struct super_blo - goto bad_inode; - raw_inode = ext4_raw_inode(&iloc); - inode->i_mode = le16_to_cpu(raw_inode->i_mode); -- inode->i_uid = (uid_t)le16_to_cpu(raw_inode->i_uid_low); -- inode->i_gid = (gid_t)le16_to_cpu(raw_inode->i_gid_low); -+ uid = (uid_t)le16_to_cpu(raw_inode->i_uid_low); -+ gid = (gid_t)le16_to_cpu(raw_inode->i_gid_low); - if (!(test_opt(inode->i_sb, NO_UID32))) { -- inode->i_uid |= le16_to_cpu(raw_inode->i_uid_high) << 16; -- inode->i_gid |= le16_to_cpu(raw_inode->i_gid_high) << 16; -+ uid |= le16_to_cpu(raw_inode->i_uid_high) << 16; -+ gid |= le16_to_cpu(raw_inode->i_gid_high) << 16; - } -+ inode->i_uid = INOTAG_UID(DX_TAG(inode), uid, gid); -+ inode->i_gid = INOTAG_GID(DX_TAG(inode), uid, gid); -+ inode->i_tag = INOTAG_TAG(DX_TAG(inode), uid, gid, -+ le16_to_cpu(raw_inode->i_raw_tag)); - inode->i_nlink = le16_to_cpu(raw_inode->i_links_count); - - ei->i_state = 0; -@@ -5038,6 +5069,8 @@ static int ext4_do_update_inode(handle_t - struct ext4_inode *raw_inode = ext4_raw_inode(iloc); - struct ext4_inode_info *ei = EXT4_I(inode); - struct buffer_head *bh = iloc->bh; -+ uid_t uid = TAGINO_UID(DX_TAG(inode), inode->i_uid, inode->i_tag); -+ gid_t gid = TAGINO_GID(DX_TAG(inode), inode->i_gid, inode->i_tag); - int err = 0, rc, block; - - /* For fields not not tracking in the in-memory inode, -@@ -5048,29 +5081,32 @@ static int ext4_do_update_inode(handle_t - ext4_get_inode_flags(ei); - raw_inode->i_mode = cpu_to_le16(inode->i_mode); - if (!(test_opt(inode->i_sb, NO_UID32))) { -- raw_inode->i_uid_low = cpu_to_le16(low_16_bits(inode->i_uid)); -- raw_inode->i_gid_low = cpu_to_le16(low_16_bits(inode->i_gid)); -+ raw_inode->i_uid_low = cpu_to_le16(low_16_bits(uid)); -+ raw_inode->i_gid_low = cpu_to_le16(low_16_bits(gid)); - /* - * Fix up interoperability with old kernels. Otherwise, old inodes get - * re-used with the upper 16 bits of the uid/gid intact - */ - if (!ei->i_dtime) { - raw_inode->i_uid_high = -- cpu_to_le16(high_16_bits(inode->i_uid)); -+ cpu_to_le16(high_16_bits(uid)); - raw_inode->i_gid_high = -- cpu_to_le16(high_16_bits(inode->i_gid)); -+ cpu_to_le16(high_16_bits(gid)); - } else { - raw_inode->i_uid_high = 0; - raw_inode->i_gid_high = 0; - } - } else { - raw_inode->i_uid_low = -- cpu_to_le16(fs_high2lowuid(inode->i_uid)); -+ cpu_to_le16(fs_high2lowuid(uid)); - raw_inode->i_gid_low = -- cpu_to_le16(fs_high2lowgid(inode->i_gid)); -+ cpu_to_le16(fs_high2lowgid(gid)); - raw_inode->i_uid_high = 0; - raw_inode->i_gid_high = 0; - } -+#ifdef CONFIG_TAGGING_INTERN -+ raw_inode->i_raw_tag = cpu_to_le16(inode->i_tag); -+#endif - raw_inode->i_links_count = cpu_to_le16(inode->i_nlink); - - EXT4_INODE_SET_XTIME(i_ctime, inode, raw_inode); -@@ -5255,7 +5291,8 @@ int ext4_setattr(struct dentry *dentry, - return error; - - if ((ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid) || -- (ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid)) { -+ (ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid) || -+ (ia_valid & ATTR_TAG && attr->ia_tag != inode->i_tag)) { - handle_t *handle; - - /* (user+group)*(old+new) structure, inode write (sb, -@@ -5277,6 +5314,8 @@ int ext4_setattr(struct dentry *dentry, - inode->i_uid = attr->ia_uid; - if (attr->ia_valid & ATTR_GID) - inode->i_gid = attr->ia_gid; -+ if ((attr->ia_valid & ATTR_TAG) && IS_TAGGED(inode)) -+ inode->i_tag = attr->ia_tag; - error = ext4_mark_inode_dirty(handle, inode); - ext4_journal_stop(handle); - } -diff -NurpP --minimal linux-2.6.32.1/fs/ext4/ioctl.c linux-2.6.32.1-vs2.3.0.36.27/fs/ext4/ioctl.c ---- linux-2.6.32.1/fs/ext4/ioctl.c 2009-12-14 21:29:46.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/ext4/ioctl.c 2009-12-14 22:20:55.000000000 +0100 -@@ -14,10 +14,39 @@ - #include - #include - #include -+#include - #include - #include "ext4_jbd2.h" - #include "ext4.h" - -+ -+int ext4_sync_flags(struct inode *inode, int flags, int vflags) -+{ -+ handle_t *handle = NULL; -+ struct ext4_iloc iloc; -+ int err; -+ -+ handle = ext4_journal_start(inode, 1); -+ if (IS_ERR(handle)) -+ return PTR_ERR(handle); -+ -+ if (IS_SYNC(inode)) -+ ext4_handle_sync(handle); -+ err = ext4_reserve_inode_write(handle, inode, &iloc); -+ if (err) -+ goto flags_err; -+ -+ inode->i_flags = flags; -+ inode->i_vflags = vflags; -+ ext4_get_inode_flags(EXT4_I(inode)); -+ inode->i_ctime = ext4_current_time(inode); -+ -+ err = ext4_mark_iloc_dirty(handle, inode, &iloc); -+flags_err: -+ ext4_journal_stop(handle); -+ return err; -+} -+ - long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) - { - struct inode *inode = filp->f_dentry->d_inode; -@@ -50,6 +79,11 @@ long ext4_ioctl(struct file *filp, unsig - - flags = ext4_mask_flags(inode->i_mode, flags); - -+ if (IS_BARRIER(inode)) { -+ vxwprintk_task(1, "messing with the barrier."); -+ return -EACCES; -+ } -+ - err = -EPERM; - mutex_lock(&inode->i_mutex); - /* Is it quota file? Do not allow user to mess with it */ -@@ -67,7 +101,9 @@ long ext4_ioctl(struct file *filp, unsig - * - * This test looks nicer. Thanks to Pauline Middelink - */ -- if ((flags ^ oldflags) & (EXT4_APPEND_FL | EXT4_IMMUTABLE_FL)) { -+ if ((oldflags & EXT4_IMMUTABLE_FL) || -+ ((flags ^ oldflags) & (EXT4_APPEND_FL | -+ EXT4_IMMUTABLE_FL | EXT4_IXUNLINK_FL))) { - if (!capable(CAP_LINUX_IMMUTABLE)) - goto flags_out; - } -diff -NurpP --minimal linux-2.6.32.1/fs/ext4/namei.c linux-2.6.32.1-vs2.3.0.36.27/fs/ext4/namei.c ---- linux-2.6.32.1/fs/ext4/namei.c 2009-12-14 21:29:46.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/ext4/namei.c 2009-12-14 22:20:55.000000000 +0100 -@@ -34,6 +34,7 @@ - #include - #include - #include -+#include - #include "ext4.h" - #include "ext4_jbd2.h" - -@@ -941,6 +942,7 @@ restart: - if (bh) - ll_rw_block(READ_META, 1, &bh); - } -+ dx_propagate_tag(nd, inode); - } - if ((bh = bh_use[ra_ptr++]) == NULL) - goto next; -@@ -2533,6 +2535,7 @@ const struct inode_operations ext4_dir_i - #endif - .check_acl = ext4_check_acl, - .fiemap = ext4_fiemap, -+ .sync_flags = ext4_sync_flags, - }; - - const struct inode_operations ext4_special_inode_operations = { -diff -NurpP --minimal linux-2.6.32.1/fs/ext4/super.c linux-2.6.32.1-vs2.3.0.36.27/fs/ext4/super.c ---- linux-2.6.32.1/fs/ext4/super.c 2009-12-14 21:29:46.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/ext4/super.c 2009-12-14 22:22:03.000000000 +0100 -@@ -1091,6 +1091,7 @@ enum { - Opt_block_validity, Opt_noblock_validity, - Opt_inode_readahead_blks, Opt_journal_ioprio, - Opt_discard, Opt_nodiscard, -+ Opt_tag, Opt_notag, Opt_tagid - }; - - static const match_table_t tokens = { -@@ -1158,6 +1159,9 @@ static const match_table_t tokens = { - {Opt_noauto_da_alloc, "noauto_da_alloc"}, - {Opt_discard, "discard"}, - {Opt_nodiscard, "nodiscard"}, -+ {Opt_tag, "tag"}, -+ {Opt_notag, "notag"}, -+ {Opt_tagid, "tagid=%u"}, - {Opt_err, NULL}, - }; - -@@ -1255,6 +1259,20 @@ static int parse_options(char *options, - case Opt_nouid32: - set_opt(sbi->s_mount_opt, NO_UID32); - break; -+#ifndef CONFIG_TAGGING_NONE -+ case Opt_tag: -+ set_opt (sbi->s_mount_opt, TAGGED); -+ break; -+ case Opt_notag: -+ clear_opt (sbi->s_mount_opt, TAGGED); -+ break; -+#endif -+#ifdef CONFIG_PROPAGATE -+ case Opt_tagid: -+ /* use args[0] */ -+ set_opt (sbi->s_mount_opt, TAGGED); -+ break; -+#endif - case Opt_debug: - set_opt(sbi->s_mount_opt, DEBUG); - break; -@@ -2455,6 +2473,9 @@ static int ext4_fill_super(struct super_ - &journal_ioprio, NULL, 0)) - goto failed_mount; - -+ if (EXT4_SB(sb)->s_mount_opt & EXT4_MOUNT_TAGGED) -+ sb->s_flags |= MS_TAGGED; -+ - sb->s_flags = (sb->s_flags & ~MS_POSIXACL) | - ((sbi->s_mount_opt & EXT4_MOUNT_POSIX_ACL) ? MS_POSIXACL : 0); - -@@ -3512,6 +3533,14 @@ static int ext4_remount(struct super_blo - if (sbi->s_mount_flags & EXT4_MF_FS_ABORTED) - ext4_abort(sb, __func__, "Abort forced by user"); - -+ if ((sbi->s_mount_opt & EXT4_MOUNT_TAGGED) && -+ !(sb->s_flags & MS_TAGGED)) { -+ printk("EXT4-fs: %s: tagging not permitted on remount.\n", -+ sb->s_id); -+ err = -EINVAL; -+ goto restore_opts; -+ } -+ - sb->s_flags = (sb->s_flags & ~MS_POSIXACL) | - ((sbi->s_mount_opt & EXT4_MOUNT_POSIX_ACL) ? MS_POSIXACL : 0); - -diff -NurpP --minimal linux-2.6.32.1/fs/fcntl.c linux-2.6.32.1-vs2.3.0.36.27/fs/fcntl.c ---- linux-2.6.32.1/fs/fcntl.c 2009-12-03 20:02:51.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/fcntl.c 2009-12-03 20:04:56.000000000 +0100 -@@ -19,6 +19,7 @@ - #include - #include - #include -+#include - - #include - #include -@@ -102,6 +103,8 @@ SYSCALL_DEFINE3(dup3, unsigned int, oldf - - if (tofree) - filp_close(tofree, files); -+ else -+ vx_openfd_inc(newfd); /* fd was unused */ - - return newfd; - -@@ -426,6 +429,8 @@ SYSCALL_DEFINE3(fcntl, unsigned int, fd, - filp = fget(fd); - if (!filp) - goto out; -+ if (!vx_files_avail(1)) -+ goto out; - - err = security_file_fcntl(filp, cmd, arg); - if (err) { -diff -NurpP --minimal linux-2.6.32.1/fs/file.c linux-2.6.32.1-vs2.3.0.36.27/fs/file.c ---- linux-2.6.32.1/fs/file.c 2009-12-03 20:02:51.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/file.c 2009-12-03 20:04:56.000000000 +0100 -@@ -20,6 +20,7 @@ - #include - #include - #include -+#include - - struct fdtable_defer { - spinlock_t lock; -@@ -368,6 +369,8 @@ struct files_struct *dup_fd(struct files - struct file *f = *old_fds++; - if (f) { - get_file(f); -+ /* TODO: sum it first for check and performance */ -+ vx_openfd_inc(open_files - i); - } else { - /* - * The fd may be claimed in the fd bitmap but not yet -@@ -476,6 +479,7 @@ repeat: - else - FD_CLR(fd, fdt->close_on_exec); - error = fd; -+ vx_openfd_inc(fd); - #if 1 - /* Sanity check */ - if (rcu_dereference(fdt->fd[fd]) != NULL) { -diff -NurpP --minimal linux-2.6.32.1/fs/file_table.c linux-2.6.32.1-vs2.3.0.36.27/fs/file_table.c ---- linux-2.6.32.1/fs/file_table.c 2009-12-03 20:02:51.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/file_table.c 2009-12-03 20:04:56.000000000 +0100 -@@ -22,6 +22,8 @@ - #include - #include - #include -+#include -+#include - - #include - -@@ -131,6 +133,8 @@ struct file *get_empty_filp(void) - spin_lock_init(&f->f_lock); - eventpoll_init_file(f); - /* f->f_version: 0 */ -+ f->f_xid = vx_current_xid(); -+ vx_files_inc(f); - return f; - - over: -@@ -285,6 +289,8 @@ void __fput(struct file *file) - cdev_put(inode->i_cdev); - fops_put(file->f_op); - put_pid(file->f_owner.pid); -+ vx_files_dec(file); -+ file->f_xid = 0; - file_kill(file); - if (file->f_mode & FMODE_WRITE) - drop_file_write_access(file); -@@ -352,6 +358,8 @@ void put_filp(struct file *file) - { - if (atomic_long_dec_and_test(&file->f_count)) { - security_file_free(file); -+ vx_files_dec(file); -+ file->f_xid = 0; - file_kill(file); - file_free(file); - } -diff -NurpP --minimal linux-2.6.32.1/fs/fs_struct.c linux-2.6.32.1-vs2.3.0.36.27/fs/fs_struct.c ---- linux-2.6.32.1/fs/fs_struct.c 2009-06-11 17:13:04.000000000 +0200 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/fs_struct.c 2009-12-03 20:04:56.000000000 +0100 -@@ -4,6 +4,7 @@ - #include - #include - #include -+#include - - /* - * Replace the fs->{rootmnt,root} with {mnt,dentry}. Put the old values. -@@ -77,6 +78,7 @@ void free_fs_struct(struct fs_struct *fs - { - path_put(&fs->root); - path_put(&fs->pwd); -+ atomic_dec(&vs_global_fs); - kmem_cache_free(fs_cachep, fs); - } - -@@ -112,6 +114,7 @@ struct fs_struct *copy_fs_struct(struct - fs->pwd = old->pwd; - path_get(&old->pwd); - read_unlock(&old->lock); -+ atomic_inc(&vs_global_fs); - } - return fs; - } -diff -NurpP --minimal linux-2.6.32.1/fs/gfs2/file.c linux-2.6.32.1-vs2.3.0.36.27/fs/gfs2/file.c ---- linux-2.6.32.1/fs/gfs2/file.c 2009-12-03 20:02:52.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/gfs2/file.c 2009-12-03 20:04:56.000000000 +0100 -@@ -132,6 +132,9 @@ static const u32 fsflags_to_gfs2[32] = { - [7] = GFS2_DIF_NOATIME, - [12] = GFS2_DIF_EXHASH, - [14] = GFS2_DIF_INHERIT_JDATA, -+ [27] = GFS2_DIF_IXUNLINK, -+ [26] = GFS2_DIF_BARRIER, -+ [29] = GFS2_DIF_COW, - }; - - static const u32 gfs2_to_fsflags[32] = { -@@ -141,6 +144,9 @@ static const u32 gfs2_to_fsflags[32] = { - [gfs2fl_NoAtime] = FS_NOATIME_FL, - [gfs2fl_ExHash] = FS_INDEX_FL, - [gfs2fl_InheritJdata] = FS_JOURNAL_DATA_FL, -+ [gfs2fl_IXUnlink] = FS_IXUNLINK_FL, -+ [gfs2fl_Barrier] = FS_BARRIER_FL, -+ [gfs2fl_Cow] = FS_COW_FL, - }; - - static int gfs2_get_flags(struct file *filp, u32 __user *ptr) -@@ -171,10 +177,16 @@ void gfs2_set_inode_flags(struct inode * - { - struct gfs2_inode *ip = GFS2_I(inode); - unsigned int flags = inode->i_flags; -+ unsigned int vflags = inode->i_vflags; -+ -+ flags &= ~(S_IMMUTABLE | S_IXUNLINK | -+ S_SYNC | S_APPEND | S_NOATIME | S_DIRSYNC); - -- flags &= ~(S_SYNC|S_APPEND|S_IMMUTABLE|S_NOATIME|S_DIRSYNC); - if (ip->i_diskflags & GFS2_DIF_IMMUTABLE) - flags |= S_IMMUTABLE; -+ if (ip->i_diskflags & GFS2_DIF_IXUNLINK) -+ flags |= S_IXUNLINK; -+ - if (ip->i_diskflags & GFS2_DIF_APPENDONLY) - flags |= S_APPEND; - if (ip->i_diskflags & GFS2_DIF_NOATIME) -@@ -182,6 +194,43 @@ void gfs2_set_inode_flags(struct inode * - if (ip->i_diskflags & GFS2_DIF_SYNC) - flags |= S_SYNC; - inode->i_flags = flags; -+ -+ vflags &= ~(V_BARRIER | V_COW); -+ -+ if (ip->i_diskflags & GFS2_DIF_BARRIER) -+ vflags |= V_BARRIER; -+ if (ip->i_diskflags & GFS2_DIF_COW) -+ vflags |= V_COW; -+ inode->i_vflags = vflags; -+} -+ -+void gfs2_get_inode_flags(struct inode *inode) -+{ -+ struct gfs2_inode *ip = GFS2_I(inode); -+ unsigned int flags = inode->i_flags; -+ unsigned int vflags = inode->i_vflags; -+ -+ ip->i_diskflags &= ~(GFS2_DIF_APPENDONLY | -+ GFS2_DIF_NOATIME | GFS2_DIF_SYNC | -+ GFS2_DIF_IMMUTABLE | GFS2_DIF_IXUNLINK | -+ GFS2_DIF_BARRIER | GFS2_DIF_COW); -+ -+ if (flags & S_IMMUTABLE) -+ ip->i_diskflags |= GFS2_DIF_IMMUTABLE; -+ if (flags & S_IXUNLINK) -+ ip->i_diskflags |= GFS2_DIF_IXUNLINK; -+ -+ if (flags & S_APPEND) -+ ip->i_diskflags |= GFS2_DIF_APPENDONLY; -+ if (flags & S_NOATIME) -+ ip->i_diskflags |= GFS2_DIF_NOATIME; -+ if (flags & S_SYNC) -+ ip->i_diskflags |= GFS2_DIF_SYNC; -+ -+ if (vflags & V_BARRIER) -+ ip->i_diskflags |= GFS2_DIF_BARRIER; -+ if (vflags & V_COW) -+ ip->i_diskflags |= GFS2_DIF_COW; - } - - /* Flags that can be set by user space */ -@@ -286,6 +335,37 @@ static int gfs2_set_flags(struct file *f - return do_gfs2_set_flags(filp, gfsflags, ~GFS2_DIF_JDATA); - } - -+int gfs2_sync_flags(struct inode *inode, int flags, int vflags) -+{ -+ struct gfs2_inode *ip = GFS2_I(inode); -+ struct gfs2_sbd *sdp = GFS2_SB(inode); -+ struct buffer_head *bh; -+ struct gfs2_holder gh; -+ int error; -+ -+ error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh); -+ if (error) -+ return error; -+ error = gfs2_trans_begin(sdp, RES_DINODE, 0); -+ if (error) -+ goto out; -+ error = gfs2_meta_inode_buffer(ip, &bh); -+ if (error) -+ goto out_trans_end; -+ gfs2_trans_add_bh(ip->i_gl, bh, 1); -+ inode->i_flags = flags; -+ inode->i_vflags = vflags; -+ gfs2_get_inode_flags(inode); -+ gfs2_dinode_out(ip, bh->b_data); -+ brelse(bh); -+ gfs2_set_aops(inode); -+out_trans_end: -+ gfs2_trans_end(sdp); -+out: -+ gfs2_glock_dq_uninit(&gh); -+ return error; -+} -+ - static long gfs2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) - { - switch(cmd) { -diff -NurpP --minimal linux-2.6.32.1/fs/gfs2/inode.h linux-2.6.32.1-vs2.3.0.36.27/fs/gfs2/inode.h ---- linux-2.6.32.1/fs/gfs2/inode.h 2009-09-10 15:26:22.000000000 +0200 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/gfs2/inode.h 2009-12-03 20:04:56.000000000 +0100 -@@ -109,6 +109,7 @@ extern const struct file_operations gfs2 - extern const struct file_operations gfs2_dir_fops_nolock; - - extern void gfs2_set_inode_flags(struct inode *inode); -+extern int gfs2_sync_flags(struct inode *inode, int flags, int vflags); - - #ifdef CONFIG_GFS2_FS_LOCKING_DLM - extern const struct file_operations gfs2_file_fops; -diff -NurpP --minimal linux-2.6.32.1/fs/gfs2/ops_inode.c linux-2.6.32.1-vs2.3.0.36.27/fs/gfs2/ops_inode.c ---- linux-2.6.32.1/fs/gfs2/ops_inode.c 2009-12-03 20:02:52.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/gfs2/ops_inode.c 2009-12-03 20:04:56.000000000 +0100 -@@ -1400,6 +1400,7 @@ const struct inode_operations gfs2_file_ - .listxattr = gfs2_listxattr, - .removexattr = gfs2_removexattr, - .fiemap = gfs2_fiemap, -+ .sync_flags = gfs2_sync_flags, - }; - - const struct inode_operations gfs2_dir_iops = { -@@ -1420,6 +1421,7 @@ const struct inode_operations gfs2_dir_i - .listxattr = gfs2_listxattr, - .removexattr = gfs2_removexattr, - .fiemap = gfs2_fiemap, -+ .sync_flags = gfs2_sync_flags, - }; - - const struct inode_operations gfs2_symlink_iops = { -diff -NurpP --minimal linux-2.6.32.1/fs/hfsplus/ioctl.c linux-2.6.32.1-vs2.3.0.36.27/fs/hfsplus/ioctl.c ---- linux-2.6.32.1/fs/hfsplus/ioctl.c 2008-12-25 00:26:37.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/hfsplus/ioctl.c 2009-12-03 20:04:56.000000000 +0100 -@@ -17,6 +17,7 @@ - #include - #include - #include -+#include - #include - #include "hfsplus_fs.h" - -diff -NurpP --minimal linux-2.6.32.1/fs/inode.c linux-2.6.32.1-vs2.3.0.36.27/fs/inode.c ---- linux-2.6.32.1/fs/inode.c 2009-12-03 20:02:52.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/inode.c 2009-12-03 20:04:56.000000000 +0100 -@@ -133,6 +133,9 @@ int inode_init_always(struct super_block - struct address_space *const mapping = &inode->i_data; - - inode->i_sb = sb; -+ -+ /* essential because of inode slab reuse */ -+ inode->i_tag = 0; - inode->i_blkbits = sb->s_blocksize_bits; - inode->i_flags = 0; - atomic_set(&inode->i_count, 1); -@@ -153,6 +156,7 @@ int inode_init_always(struct super_block - inode->i_bdev = NULL; - inode->i_cdev = NULL; - inode->i_rdev = 0; -+ inode->i_mdev = 0; - inode->dirtied_when = 0; - - if (security_inode_alloc(inode)) -@@ -307,6 +311,8 @@ void __iget(struct inode *inode) - inodes_stat.nr_unused--; - } - -+EXPORT_SYMBOL_GPL(__iget); -+ - /** - * clear_inode - clear an inode - * @inode: inode to clear -@@ -1611,9 +1617,11 @@ void init_special_inode(struct inode *in - if (S_ISCHR(mode)) { - inode->i_fop = &def_chr_fops; - inode->i_rdev = rdev; -+ inode->i_mdev = rdev; - } else if (S_ISBLK(mode)) { - inode->i_fop = &def_blk_fops; - inode->i_rdev = rdev; -+ inode->i_mdev = rdev; - } else if (S_ISFIFO(mode)) - inode->i_fop = &def_fifo_fops; - else if (S_ISSOCK(mode)) -diff -NurpP --minimal linux-2.6.32.1/fs/ioctl.c linux-2.6.32.1-vs2.3.0.36.27/fs/ioctl.c ---- linux-2.6.32.1/fs/ioctl.c 2009-12-03 20:02:52.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/ioctl.c 2009-12-03 20:04:56.000000000 +0100 -@@ -16,6 +16,9 @@ - #include - #include - #include -+#include -+#include -+#include - - #include - -diff -NurpP --minimal linux-2.6.32.1/fs/ioprio.c linux-2.6.32.1-vs2.3.0.36.27/fs/ioprio.c ---- linux-2.6.32.1/fs/ioprio.c 2009-03-24 14:22:26.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/ioprio.c 2009-12-03 20:04:56.000000000 +0100 -@@ -26,6 +26,7 @@ - #include - #include - #include -+#include - - int set_task_ioprio(struct task_struct *task, int ioprio) - { -@@ -123,6 +124,8 @@ SYSCALL_DEFINE3(ioprio_set, int, which, - else - pgrp = find_vpid(who); - do_each_pid_thread(pgrp, PIDTYPE_PGID, p) { -+ if (!vx_check(p->xid, VS_ADMIN_P | VS_IDENT)) -+ continue; - ret = set_task_ioprio(p, ioprio); - if (ret) - break; -@@ -212,6 +215,8 @@ SYSCALL_DEFINE2(ioprio_get, int, which, - else - pgrp = find_vpid(who); - do_each_pid_thread(pgrp, PIDTYPE_PGID, p) { -+ if (!vx_check(p->xid, VS_ADMIN_P | VS_IDENT)) -+ continue; - tmpio = get_task_ioprio(p); - if (tmpio < 0) - continue; -diff -NurpP --minimal linux-2.6.32.1/fs/jfs/acl.c linux-2.6.32.1-vs2.3.0.36.27/fs/jfs/acl.c ---- linux-2.6.32.1/fs/jfs/acl.c 2009-12-03 20:02:52.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/jfs/acl.c 2009-12-03 20:04:56.000000000 +0100 -@@ -216,7 +216,8 @@ int jfs_setattr(struct dentry *dentry, s - return rc; - - if ((iattr->ia_valid & ATTR_UID && iattr->ia_uid != inode->i_uid) || -- (iattr->ia_valid & ATTR_GID && iattr->ia_gid != inode->i_gid)) { -+ (iattr->ia_valid & ATTR_GID && iattr->ia_gid != inode->i_gid) || -+ (iattr->ia_valid & ATTR_TAG && iattr->ia_tag != inode->i_tag)) { - if (vfs_dq_transfer(inode, iattr)) - return -EDQUOT; - } -diff -NurpP --minimal linux-2.6.32.1/fs/jfs/file.c linux-2.6.32.1-vs2.3.0.36.27/fs/jfs/file.c ---- linux-2.6.32.1/fs/jfs/file.c 2009-12-03 20:02:52.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/jfs/file.c 2009-12-03 20:04:56.000000000 +0100 -@@ -98,6 +98,7 @@ const struct inode_operations jfs_file_i - .setattr = jfs_setattr, - .check_acl = jfs_check_acl, - #endif -+ .sync_flags = jfs_sync_flags, - }; - - const struct file_operations jfs_file_operations = { -diff -NurpP --minimal linux-2.6.32.1/fs/jfs/ioctl.c linux-2.6.32.1-vs2.3.0.36.27/fs/jfs/ioctl.c ---- linux-2.6.32.1/fs/jfs/ioctl.c 2008-12-25 00:26:37.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/jfs/ioctl.c 2009-12-03 20:04:56.000000000 +0100 -@@ -11,6 +11,7 @@ - #include - #include - #include -+#include - #include - #include - -@@ -52,6 +53,16 @@ static long jfs_map_ext2(unsigned long f - } - - -+int jfs_sync_flags(struct inode *inode, int flags, int vflags) -+{ -+ inode->i_flags = flags; -+ inode->i_vflags = vflags; -+ jfs_get_inode_flags(JFS_IP(inode)); -+ inode->i_ctime = CURRENT_TIME_SEC; -+ mark_inode_dirty(inode); -+ return 0; -+} -+ - long jfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) - { - struct inode *inode = filp->f_dentry->d_inode; -@@ -85,6 +96,11 @@ long jfs_ioctl(struct file *filp, unsign - if (!S_ISDIR(inode->i_mode)) - flags &= ~JFS_DIRSYNC_FL; - -+ if (IS_BARRIER(inode)) { -+ vxwprintk_task(1, "messing with the barrier."); -+ return -EACCES; -+ } -+ - /* Is it quota file? Do not allow user to mess with it */ - if (IS_NOQUOTA(inode)) { - err = -EPERM; -@@ -102,8 +118,8 @@ long jfs_ioctl(struct file *filp, unsign - * the relevant capability. - */ - if ((oldflags & JFS_IMMUTABLE_FL) || -- ((flags ^ oldflags) & -- (JFS_APPEND_FL | JFS_IMMUTABLE_FL))) { -+ ((flags ^ oldflags) & (JFS_APPEND_FL | -+ JFS_IMMUTABLE_FL | JFS_IXUNLINK_FL))) { - if (!capable(CAP_LINUX_IMMUTABLE)) { - mutex_unlock(&inode->i_mutex); - err = -EPERM; -@@ -111,7 +127,7 @@ long jfs_ioctl(struct file *filp, unsign - } - } - -- flags = flags & JFS_FL_USER_MODIFIABLE; -+ flags &= JFS_FL_USER_MODIFIABLE; - flags |= oldflags & ~JFS_FL_USER_MODIFIABLE; - jfs_inode->mode2 = flags; - -diff -NurpP --minimal linux-2.6.32.1/fs/jfs/jfs_dinode.h linux-2.6.32.1-vs2.3.0.36.27/fs/jfs/jfs_dinode.h ---- linux-2.6.32.1/fs/jfs/jfs_dinode.h 2008-12-25 00:26:37.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/jfs/jfs_dinode.h 2009-12-03 20:04:56.000000000 +0100 -@@ -161,9 +161,13 @@ struct dinode { - - #define JFS_APPEND_FL 0x01000000 /* writes to file may only append */ - #define JFS_IMMUTABLE_FL 0x02000000 /* Immutable file */ -+#define JFS_IXUNLINK_FL 0x08000000 /* Immutable invert on unlink */ - --#define JFS_FL_USER_VISIBLE 0x03F80000 --#define JFS_FL_USER_MODIFIABLE 0x03F80000 -+#define JFS_BARRIER_FL 0x04000000 /* Barrier for chroot() */ -+#define JFS_COW_FL 0x20000000 /* Copy on Write marker */ -+ -+#define JFS_FL_USER_VISIBLE 0x07F80000 -+#define JFS_FL_USER_MODIFIABLE 0x07F80000 - #define JFS_FL_INHERIT 0x03C80000 - - /* These are identical to EXT[23]_IOC_GETFLAGS/SETFLAGS */ -diff -NurpP --minimal linux-2.6.32.1/fs/jfs/jfs_filsys.h linux-2.6.32.1-vs2.3.0.36.27/fs/jfs/jfs_filsys.h ---- linux-2.6.32.1/fs/jfs/jfs_filsys.h 2008-12-25 00:26:37.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/jfs/jfs_filsys.h 2009-12-03 20:04:56.000000000 +0100 -@@ -263,6 +263,7 @@ - #define JFS_NAME_MAX 255 - #define JFS_PATH_MAX BPSIZE - -+#define JFS_TAGGED 0x00800000 /* Context Tagging */ - - /* - * file system state (superblock state) -diff -NurpP --minimal linux-2.6.32.1/fs/jfs/jfs_imap.c linux-2.6.32.1-vs2.3.0.36.27/fs/jfs/jfs_imap.c ---- linux-2.6.32.1/fs/jfs/jfs_imap.c 2009-09-10 15:26:22.000000000 +0200 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/jfs/jfs_imap.c 2009-12-03 20:04:56.000000000 +0100 -@@ -45,6 +45,7 @@ - #include - #include - #include -+#include - - #include "jfs_incore.h" - #include "jfs_inode.h" -@@ -3059,6 +3060,8 @@ static int copy_from_dinode(struct dinod - { - struct jfs_inode_info *jfs_ip = JFS_IP(ip); - struct jfs_sb_info *sbi = JFS_SBI(ip->i_sb); -+ uid_t uid; -+ gid_t gid; - - jfs_ip->fileset = le32_to_cpu(dip->di_fileset); - jfs_ip->mode2 = le32_to_cpu(dip->di_mode); -@@ -3079,14 +3082,18 @@ static int copy_from_dinode(struct dinod - } - ip->i_nlink = le32_to_cpu(dip->di_nlink); - -- jfs_ip->saved_uid = le32_to_cpu(dip->di_uid); -+ uid = le32_to_cpu(dip->di_uid); -+ gid = le32_to_cpu(dip->di_gid); -+ ip->i_tag = INOTAG_TAG(DX_TAG(ip), uid, gid, 0); -+ -+ jfs_ip->saved_uid = INOTAG_UID(DX_TAG(ip), uid, gid); - if (sbi->uid == -1) - ip->i_uid = jfs_ip->saved_uid; - else { - ip->i_uid = sbi->uid; - } - -- jfs_ip->saved_gid = le32_to_cpu(dip->di_gid); -+ jfs_ip->saved_gid = INOTAG_GID(DX_TAG(ip), uid, gid); - if (sbi->gid == -1) - ip->i_gid = jfs_ip->saved_gid; - else { -@@ -3151,14 +3158,12 @@ static void copy_to_dinode(struct dinode - dip->di_size = cpu_to_le64(ip->i_size); - dip->di_nblocks = cpu_to_le64(PBLK2LBLK(ip->i_sb, ip->i_blocks)); - dip->di_nlink = cpu_to_le32(ip->i_nlink); -- if (sbi->uid == -1) -- dip->di_uid = cpu_to_le32(ip->i_uid); -- else -- dip->di_uid = cpu_to_le32(jfs_ip->saved_uid); -- if (sbi->gid == -1) -- dip->di_gid = cpu_to_le32(ip->i_gid); -- else -- dip->di_gid = cpu_to_le32(jfs_ip->saved_gid); -+ -+ dip->di_uid = cpu_to_le32(TAGINO_UID(DX_TAG(ip), -+ (sbi->uid == -1) ? ip->i_uid : jfs_ip->saved_uid, ip->i_tag)); -+ dip->di_gid = cpu_to_le32(TAGINO_GID(DX_TAG(ip), -+ (sbi->gid == -1) ? ip->i_gid : jfs_ip->saved_gid, ip->i_tag)); -+ - jfs_get_inode_flags(jfs_ip); - /* - * mode2 is only needed for storing the higher order bits. -diff -NurpP --minimal linux-2.6.32.1/fs/jfs/jfs_inode.c linux-2.6.32.1-vs2.3.0.36.27/fs/jfs/jfs_inode.c ---- linux-2.6.32.1/fs/jfs/jfs_inode.c 2009-06-11 17:13:05.000000000 +0200 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/jfs/jfs_inode.c 2009-12-03 20:04:56.000000000 +0100 -@@ -18,6 +18,7 @@ - - #include - #include -+#include - #include "jfs_incore.h" - #include "jfs_inode.h" - #include "jfs_filsys.h" -@@ -30,29 +31,46 @@ void jfs_set_inode_flags(struct inode *i - { - unsigned int flags = JFS_IP(inode)->mode2; - -- inode->i_flags &= ~(S_IMMUTABLE | S_APPEND | -- S_NOATIME | S_DIRSYNC | S_SYNC); -+ inode->i_flags &= ~(S_IMMUTABLE | S_IXUNLINK | -+ S_SYNC | S_APPEND | S_NOATIME | S_DIRSYNC); - - if (flags & JFS_IMMUTABLE_FL) - inode->i_flags |= S_IMMUTABLE; -+ if (flags & JFS_IXUNLINK_FL) -+ inode->i_flags |= S_IXUNLINK; -+ -+ if (flags & JFS_SYNC_FL) -+ inode->i_flags |= S_SYNC; - if (flags & JFS_APPEND_FL) - inode->i_flags |= S_APPEND; - if (flags & JFS_NOATIME_FL) - inode->i_flags |= S_NOATIME; - if (flags & JFS_DIRSYNC_FL) - inode->i_flags |= S_DIRSYNC; -- if (flags & JFS_SYNC_FL) -- inode->i_flags |= S_SYNC; -+ -+ inode->i_vflags &= ~(V_BARRIER | V_COW); -+ -+ if (flags & JFS_BARRIER_FL) -+ inode->i_vflags |= V_BARRIER; -+ if (flags & JFS_COW_FL) -+ inode->i_vflags |= V_COW; - } - - void jfs_get_inode_flags(struct jfs_inode_info *jfs_ip) - { - unsigned int flags = jfs_ip->vfs_inode.i_flags; -+ unsigned int vflags = jfs_ip->vfs_inode.i_vflags; -+ -+ jfs_ip->mode2 &= ~(JFS_IMMUTABLE_FL | JFS_IXUNLINK_FL | -+ JFS_APPEND_FL | JFS_NOATIME_FL | -+ JFS_DIRSYNC_FL | JFS_SYNC_FL | -+ JFS_BARRIER_FL | JFS_COW_FL); - -- jfs_ip->mode2 &= ~(JFS_IMMUTABLE_FL | JFS_APPEND_FL | JFS_NOATIME_FL | -- JFS_DIRSYNC_FL | JFS_SYNC_FL); - if (flags & S_IMMUTABLE) - jfs_ip->mode2 |= JFS_IMMUTABLE_FL; -+ if (flags & S_IXUNLINK) -+ jfs_ip->mode2 |= JFS_IXUNLINK_FL; -+ - if (flags & S_APPEND) - jfs_ip->mode2 |= JFS_APPEND_FL; - if (flags & S_NOATIME) -@@ -61,6 +79,11 @@ void jfs_get_inode_flags(struct jfs_inod - jfs_ip->mode2 |= JFS_DIRSYNC_FL; - if (flags & S_SYNC) - jfs_ip->mode2 |= JFS_SYNC_FL; -+ -+ if (vflags & V_BARRIER) -+ jfs_ip->mode2 |= JFS_BARRIER_FL; -+ if (vflags & V_COW) -+ jfs_ip->mode2 |= JFS_COW_FL; - } - - /* -@@ -105,6 +128,7 @@ struct inode *ialloc(struct inode *paren - mode |= S_ISGID; - } else - inode->i_gid = current_fsgid(); -+ inode->i_tag = dx_current_fstag(sb); - - /* - * New inodes need to save sane values on disk when -diff -NurpP --minimal linux-2.6.32.1/fs/jfs/jfs_inode.h linux-2.6.32.1-vs2.3.0.36.27/fs/jfs/jfs_inode.h ---- linux-2.6.32.1/fs/jfs/jfs_inode.h 2009-06-11 17:13:05.000000000 +0200 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/jfs/jfs_inode.h 2009-12-03 20:04:56.000000000 +0100 -@@ -39,6 +39,7 @@ extern struct dentry *jfs_fh_to_dentry(s - extern struct dentry *jfs_fh_to_parent(struct super_block *sb, struct fid *fid, - int fh_len, int fh_type); - extern void jfs_set_inode_flags(struct inode *); -+extern int jfs_sync_flags(struct inode *, int, int); - extern int jfs_get_block(struct inode *, sector_t, struct buffer_head *, int); - - extern const struct address_space_operations jfs_aops; -diff -NurpP --minimal linux-2.6.32.1/fs/jfs/namei.c linux-2.6.32.1-vs2.3.0.36.27/fs/jfs/namei.c ---- linux-2.6.32.1/fs/jfs/namei.c 2009-12-03 20:02:52.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/jfs/namei.c 2009-12-03 20:04:56.000000000 +0100 -@@ -21,6 +21,7 @@ - #include - #include - #include -+#include - #include "jfs_incore.h" - #include "jfs_superblock.h" - #include "jfs_inode.h" -@@ -1476,6 +1477,7 @@ static struct dentry *jfs_lookup(struct - return ERR_CAST(ip); - } - -+ dx_propagate_tag(nd, ip); - dentry = d_splice_alias(ip, dentry); - - if (dentry && (JFS_SBI(dip->i_sb)->mntflag & JFS_OS2)) -@@ -1545,6 +1547,7 @@ const struct inode_operations jfs_dir_in - .setattr = jfs_setattr, - .check_acl = jfs_check_acl, - #endif -+ .sync_flags = jfs_sync_flags, - }; - - const struct file_operations jfs_dir_operations = { -diff -NurpP --minimal linux-2.6.32.1/fs/jfs/super.c linux-2.6.32.1-vs2.3.0.36.27/fs/jfs/super.c ---- linux-2.6.32.1/fs/jfs/super.c 2009-12-03 20:02:52.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/jfs/super.c 2009-12-03 20:04:56.000000000 +0100 -@@ -192,7 +192,8 @@ static void jfs_put_super(struct super_b - enum { - Opt_integrity, Opt_nointegrity, Opt_iocharset, Opt_resize, - Opt_resize_nosize, Opt_errors, Opt_ignore, Opt_err, Opt_quota, -- Opt_usrquota, Opt_grpquota, Opt_uid, Opt_gid, Opt_umask -+ Opt_usrquota, Opt_grpquota, Opt_uid, Opt_gid, Opt_umask, -+ Opt_tag, Opt_notag, Opt_tagid - }; - - static const match_table_t tokens = { -@@ -202,6 +203,10 @@ static const match_table_t tokens = { - {Opt_resize, "resize=%u"}, - {Opt_resize_nosize, "resize"}, - {Opt_errors, "errors=%s"}, -+ {Opt_tag, "tag"}, -+ {Opt_notag, "notag"}, -+ {Opt_tagid, "tagid=%u"}, -+ {Opt_tag, "tagxid"}, - {Opt_ignore, "noquota"}, - {Opt_ignore, "quota"}, - {Opt_usrquota, "usrquota"}, -@@ -336,6 +341,20 @@ static int parse_options(char *options, - } - break; - } -+#ifndef CONFIG_TAGGING_NONE -+ case Opt_tag: -+ *flag |= JFS_TAGGED; -+ break; -+ case Opt_notag: -+ *flag &= JFS_TAGGED; -+ break; -+#endif -+#ifdef CONFIG_PROPAGATE -+ case Opt_tagid: -+ /* use args[0] */ -+ *flag |= JFS_TAGGED; -+ break; -+#endif - default: - printk("jfs: Unrecognized mount option \"%s\" " - " or missing value\n", p); -@@ -366,6 +385,12 @@ static int jfs_remount(struct super_bloc - if (!parse_options(data, sb, &newLVSize, &flag)) { - return -EINVAL; - } -+ if ((flag & JFS_TAGGED) && !(sb->s_flags & MS_TAGGED)) { -+ printk(KERN_ERR "JFS: %s: tagging not permitted on remount.\n", -+ sb->s_id); -+ return -EINVAL; -+ } -+ - lock_kernel(); - if (newLVSize) { - if (sb->s_flags & MS_RDONLY) { -@@ -449,6 +474,9 @@ static int jfs_fill_super(struct super_b - #ifdef CONFIG_JFS_POSIX_ACL - sb->s_flags |= MS_POSIXACL; - #endif -+ /* map mount option tagxid */ -+ if (sbi->flag & JFS_TAGGED) -+ sb->s_flags |= MS_TAGGED; - - if (newLVSize) { - printk(KERN_ERR "resize option for remount only\n"); -diff -NurpP --minimal linux-2.6.32.1/fs/libfs.c linux-2.6.32.1-vs2.3.0.36.27/fs/libfs.c ---- linux-2.6.32.1/fs/libfs.c 2009-12-03 20:02:52.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/libfs.c 2009-12-03 20:04:56.000000000 +0100 -@@ -127,7 +127,8 @@ static inline unsigned char dt_type(stru - * both impossible due to the lock on directory. - */ - --int dcache_readdir(struct file * filp, void * dirent, filldir_t filldir) -+static inline int do_dcache_readdir_filter(struct file *filp, -+ void *dirent, filldir_t filldir, int (*filter)(struct dentry *dentry)) - { - struct dentry *dentry = filp->f_path.dentry; - struct dentry *cursor = filp->private_data; -@@ -160,6 +161,8 @@ int dcache_readdir(struct file * filp, v - next = list_entry(p, struct dentry, d_u.d_child); - if (d_unhashed(next) || !next->d_inode) - continue; -+ if (filter && !filter(next)) -+ continue; - - spin_unlock(&dcache_lock); - if (filldir(dirent, next->d_name.name, -@@ -178,6 +181,18 @@ int dcache_readdir(struct file * filp, v - return 0; - } - -+int dcache_readdir(struct file *filp, void *dirent, filldir_t filldir) -+{ -+ return do_dcache_readdir_filter(filp, dirent, filldir, NULL); -+} -+ -+int dcache_readdir_filter(struct file *filp, void *dirent, filldir_t filldir, -+ int (*filter)(struct dentry *)) -+{ -+ return do_dcache_readdir_filter(filp, dirent, filldir, filter); -+} -+ -+ - ssize_t generic_read_dir(struct file *filp, char __user *buf, size_t siz, loff_t *ppos) - { - return -EISDIR; -@@ -841,6 +856,7 @@ EXPORT_SYMBOL(dcache_dir_close); - EXPORT_SYMBOL(dcache_dir_lseek); - EXPORT_SYMBOL(dcache_dir_open); - EXPORT_SYMBOL(dcache_readdir); -+EXPORT_SYMBOL(dcache_readdir_filter); - EXPORT_SYMBOL(generic_read_dir); - EXPORT_SYMBOL(get_sb_pseudo); - EXPORT_SYMBOL(simple_write_begin); -diff -NurpP --minimal linux-2.6.32.1/fs/locks.c linux-2.6.32.1-vs2.3.0.36.27/fs/locks.c ---- linux-2.6.32.1/fs/locks.c 2009-12-03 20:02:52.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/locks.c 2009-12-03 20:04:56.000000000 +0100 -@@ -127,6 +127,8 @@ - #include - #include - #include -+#include -+#include - - #include - -@@ -148,6 +150,8 @@ static struct kmem_cache *filelock_cache - /* Allocate an empty lock structure. */ - static struct file_lock *locks_alloc_lock(void) - { -+ if (!vx_locks_avail(1)) -+ return NULL; - return kmem_cache_alloc(filelock_cache, GFP_KERNEL); - } - -@@ -174,6 +178,7 @@ static void locks_free_lock(struct file_ - BUG_ON(!list_empty(&fl->fl_block)); - BUG_ON(!list_empty(&fl->fl_link)); - -+ vx_locks_dec(fl); - locks_release_private(fl); - kmem_cache_free(filelock_cache, fl); - } -@@ -194,6 +199,7 @@ void locks_init_lock(struct file_lock *f - fl->fl_start = fl->fl_end = 0; - fl->fl_ops = NULL; - fl->fl_lmops = NULL; -+ fl->fl_xid = -1; - } - - EXPORT_SYMBOL(locks_init_lock); -@@ -248,6 +254,7 @@ void locks_copy_lock(struct file_lock *n - new->fl_file = fl->fl_file; - new->fl_ops = fl->fl_ops; - new->fl_lmops = fl->fl_lmops; -+ new->fl_xid = fl->fl_xid; - - locks_copy_private(new, fl); - } -@@ -286,6 +293,11 @@ static int flock_make_lock(struct file * - fl->fl_flags = FL_FLOCK; - fl->fl_type = type; - fl->fl_end = OFFSET_MAX; -+ -+ vxd_assert(filp->f_xid == vx_current_xid(), -+ "f_xid(%d) == current(%d)", filp->f_xid, vx_current_xid()); -+ fl->fl_xid = filp->f_xid; -+ vx_locks_inc(fl); - - *lock = fl; - return 0; -@@ -451,6 +463,7 @@ static int lease_init(struct file *filp, - - fl->fl_owner = current->files; - fl->fl_pid = current->tgid; -+ fl->fl_xid = vx_current_xid(); - - fl->fl_file = filp; - fl->fl_flags = FL_LEASE; -@@ -470,6 +483,11 @@ static struct file_lock *lease_alloc(str - if (fl == NULL) - return ERR_PTR(error); - -+ fl->fl_xid = vx_current_xid(); -+ if (filp) -+ vxd_assert(filp->f_xid == fl->fl_xid, -+ "f_xid(%d) == fl_xid(%d)", filp->f_xid, fl->fl_xid); -+ vx_locks_inc(fl); - error = lease_init(filp, type, fl); - if (error) { - locks_free_lock(fl); -@@ -770,6 +788,7 @@ static int flock_lock_file(struct file * - if (found) - cond_resched(); - -+ new_fl->fl_xid = -1; - find_conflict: - for_each_lock(inode, before) { - struct file_lock *fl = *before; -@@ -790,6 +809,7 @@ find_conflict: - goto out; - locks_copy_lock(new_fl, request); - locks_insert_lock(before, new_fl); -+ vx_locks_inc(new_fl); - new_fl = NULL; - error = 0; - -@@ -800,7 +820,8 @@ out: - return error; - } - --static int __posix_lock_file(struct inode *inode, struct file_lock *request, struct file_lock *conflock) -+static int __posix_lock_file(struct inode *inode, struct file_lock *request, -+ struct file_lock *conflock, xid_t xid) - { - struct file_lock *fl; - struct file_lock *new_fl = NULL; -@@ -810,6 +831,8 @@ static int __posix_lock_file(struct inod - struct file_lock **before; - int error, added = 0; - -+ vxd_assert(xid == vx_current_xid(), -+ "xid(%d) == current(%d)", xid, vx_current_xid()); - /* - * We may need two file_lock structures for this operation, - * so we get them in advance to avoid races. -@@ -820,7 +843,11 @@ static int __posix_lock_file(struct inod - (request->fl_type != F_UNLCK || - request->fl_start != 0 || request->fl_end != OFFSET_MAX)) { - new_fl = locks_alloc_lock(); -+ new_fl->fl_xid = xid; -+ vx_locks_inc(new_fl); - new_fl2 = locks_alloc_lock(); -+ new_fl2->fl_xid = xid; -+ vx_locks_inc(new_fl2); - } - - lock_kernel(); -@@ -1019,7 +1046,8 @@ static int __posix_lock_file(struct inod - int posix_lock_file(struct file *filp, struct file_lock *fl, - struct file_lock *conflock) - { -- return __posix_lock_file(filp->f_path.dentry->d_inode, fl, conflock); -+ return __posix_lock_file(filp->f_path.dentry->d_inode, -+ fl, conflock, filp->f_xid); - } - EXPORT_SYMBOL(posix_lock_file); - -@@ -1109,7 +1137,7 @@ int locks_mandatory_area(int read_write, - fl.fl_end = offset + count - 1; - - for (;;) { -- error = __posix_lock_file(inode, &fl, NULL); -+ error = __posix_lock_file(inode, &fl, NULL, filp->f_xid); - if (error != FILE_LOCK_DEFERRED) - break; - error = wait_event_interruptible(fl.fl_wait, !fl.fl_next); -@@ -1424,6 +1452,7 @@ int generic_setlease(struct file *filp, - - locks_copy_lock(new_fl, lease); - locks_insert_lock(before, new_fl); -+ vx_locks_inc(new_fl); - - *flp = new_fl; - return 0; -@@ -1779,6 +1808,11 @@ int fcntl_setlk(unsigned int fd, struct - if (file_lock == NULL) - return -ENOLCK; - -+ vxd_assert(filp->f_xid == vx_current_xid(), -+ "f_xid(%d) == current(%d)", filp->f_xid, vx_current_xid()); -+ file_lock->fl_xid = filp->f_xid; -+ vx_locks_inc(file_lock); -+ - /* - * This might block, so we do it before checking the inode. - */ -@@ -1897,6 +1931,11 @@ int fcntl_setlk64(unsigned int fd, struc - if (file_lock == NULL) - return -ENOLCK; - -+ vxd_assert(filp->f_xid == vx_current_xid(), -+ "f_xid(%d) == current(%d)", filp->f_xid, vx_current_xid()); -+ file_lock->fl_xid = filp->f_xid; -+ vx_locks_inc(file_lock); -+ - /* - * This might block, so we do it before checking the inode. - */ -@@ -2162,8 +2201,11 @@ static int locks_show(struct seq_file *f - - lock_get_status(f, fl, (long)f->private, ""); - -- list_for_each_entry(bfl, &fl->fl_block, fl_block) -+ list_for_each_entry(bfl, &fl->fl_block, fl_block) { -+ if (!vx_check(fl->fl_xid, VS_WATCH_P | VS_IDENT)) -+ continue; - lock_get_status(f, bfl, (long)f->private, " ->"); -+ } - - f->private++; - return 0; -diff -NurpP --minimal linux-2.6.32.1/fs/namei.c linux-2.6.32.1-vs2.3.0.36.27/fs/namei.c ---- linux-2.6.32.1/fs/namei.c 2009-12-03 20:02:52.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/namei.c 2009-12-03 20:04:56.000000000 +0100 -@@ -33,6 +33,14 @@ - #include - #include - #include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include - #include - - #define ACC_MODE(x) ("\000\004\002\006"[(x)&O_ACCMODE]) -@@ -169,6 +177,77 @@ void putname(const char *name) - EXPORT_SYMBOL(putname); - #endif - -+static inline int dx_barrier(const struct inode *inode) -+{ -+ if (IS_BARRIER(inode) && !vx_check(0, VS_ADMIN | VS_WATCH)) { -+ vxwprintk_task(1, "did hit the barrier."); -+ return 1; -+ } -+ return 0; -+} -+ -+static int __dx_permission(const struct inode *inode, int mask) -+{ -+ if (dx_barrier(inode)) -+ return -EACCES; -+ -+ if (inode->i_sb->s_magic == DEVPTS_SUPER_MAGIC) { -+ /* devpts is xid tagged */ -+ if (S_ISDIR(inode->i_mode) || -+ vx_check((xid_t)inode->i_tag, VS_IDENT | VS_WATCH_P)) -+ return 0; -+ } -+ else if (inode->i_sb->s_magic == PROC_SUPER_MAGIC) { -+ struct proc_dir_entry *de = PDE(inode); -+ -+ if (de && !vx_hide_check(0, de->vx_flags)) -+ goto out; -+ -+ if ((mask & (MAY_WRITE | MAY_APPEND))) { -+ struct pid *pid; -+ struct task_struct *tsk; -+ -+ if (vx_check(0, VS_ADMIN | VS_WATCH_P) || -+ vx_flags(VXF_STATE_SETUP, 0)) -+ return 0; -+ -+ pid = PROC_I(inode)->pid; -+ if (!pid) -+ goto out; -+ -+ tsk = pid_task(pid, PIDTYPE_PID); -+ vxdprintk(VXD_CBIT(tag, 0), "accessing %p[#%u]", -+ tsk, (tsk ? vx_task_xid(tsk) : 0)); -+ if (tsk && vx_check(vx_task_xid(tsk), VS_IDENT | VS_WATCH_P)) -+ return 0; -+ } -+ else { -+ /* FIXME: Should we block some entries here? */ -+ return 0; -+ } -+ } -+ else { -+ if (dx_notagcheck(inode->i_sb) || -+ dx_check(inode->i_tag, DX_HOSTID | DX_ADMIN | DX_WATCH | -+ DX_IDENT)) -+ return 0; -+ } -+ -+out: -+ return -EACCES; -+} -+ -+int dx_permission(const struct inode *inode, int mask) -+{ -+ int ret = __dx_permission(inode, mask); -+ if (unlikely(ret)) { -+ vxwprintk_task(1, "denied %x access to %s:%p[#%d,%lu]", -+ mask, inode->i_sb->s_id, inode, inode->i_tag, -+ inode->i_ino); -+ } -+ return ret; -+} -+ - /* - * This does basic POSIX ACL permission checking - */ -@@ -268,10 +347,14 @@ int inode_permission(struct inode *inode - /* - * Nobody gets write access to an immutable file. - */ -- if (IS_IMMUTABLE(inode)) -+ if (IS_IMMUTABLE(inode) && !IS_COW(inode)) - return -EACCES; - } - -+ retval = dx_permission(inode, mask); -+ if (retval) -+ return retval; -+ - if (inode->i_op->permission) - retval = inode->i_op->permission(inode, mask); - else -@@ -447,6 +530,9 @@ static int exec_permission_lite(struct i - { - int ret; - -+ if (dx_barrier(inode)) -+ return -EACCES; -+ - if (inode->i_op->permission) { - ret = inode->i_op->permission(inode, MAY_EXEC); - if (!ret) -@@ -762,7 +848,8 @@ static __always_inline void follow_dotdo - - if (nd->path.dentry == nd->root.dentry && - nd->path.mnt == nd->root.mnt) { -- break; -+ /* for sane '/' avoid follow_mount() */ -+ return; - } - spin_lock(&dcache_lock); - if (nd->path.dentry != nd->path.mnt->mnt_root) { -@@ -798,16 +885,30 @@ static int do_lookup(struct nameidata *n - { - struct vfsmount *mnt = nd->path.mnt; - struct dentry *dentry = __d_lookup(nd->path.dentry, name); -+ struct inode *inode; - - if (!dentry) - goto need_lookup; - if (dentry->d_op && dentry->d_op->d_revalidate) - goto need_revalidate; -+ inode = dentry->d_inode; -+ if (!inode) -+ goto done; -+ -+ if (__dx_permission(inode, MAY_ACCESS)) -+ goto hidden; -+ - done: - path->mnt = mnt; - path->dentry = dentry; - __follow_mount(path); - return 0; -+hidden: -+ vxwprintk_task(1, "did lookup hidden %s:%p[#%d,%lu] »%s/%.*s«.", -+ inode->i_sb->s_id, inode, inode->i_tag, inode->i_ino, -+ vxd_path(&nd->path), name->len, name->name); -+ dput(dentry); -+ return -ENOENT; - - need_lookup: - dentry = real_lookup(nd->path.dentry, name, nd); -@@ -1389,7 +1490,7 @@ static int may_delete(struct inode *dir, - if (IS_APPEND(dir)) - return -EPERM; - if (check_sticky(dir, victim->d_inode)||IS_APPEND(victim->d_inode)|| -- IS_IMMUTABLE(victim->d_inode) || IS_SWAPFILE(victim->d_inode)) -+ IS_IXORUNLINK(victim->d_inode) || IS_SWAPFILE(victim->d_inode)) - return -EPERM; - if (isdir) { - if (!S_ISDIR(victim->d_inode->i_mode)) -@@ -1529,6 +1630,14 @@ int may_open(struct path *path, int acc_ - break; - } - -+#ifdef CONFIG_VSERVER_COWBL -+ if (IS_COW(inode) && (flag & FMODE_WRITE)) { -+ if (IS_COW_LINK(inode)) -+ return -EMLINK; -+ inode->i_flags &= ~(S_IXUNLINK|S_IMMUTABLE); -+ mark_inode_dirty(inode); -+ } -+#endif - error = inode_permission(inode, acc_mode); - if (error) - return error; -@@ -1677,7 +1786,11 @@ struct file *do_filp_open(int dfd, const - int count = 0; - int will_write; - int flag = open_to_namei_flags(open_flag); -- -+#ifdef CONFIG_VSERVER_COWBL -+ int rflag = flag; -+ int rmode = mode; -+restart: -+#endif - if (!acc_mode) - acc_mode = MAY_OPEN | ACC_MODE(flag); - -@@ -1825,6 +1938,25 @@ ok: - goto exit; - } - error = may_open(&nd.path, acc_mode, flag); -+#ifdef CONFIG_VSERVER_COWBL -+ if (error == -EMLINK) { -+ struct dentry *dentry; -+ dentry = cow_break_link(pathname); -+ if (IS_ERR(dentry)) { -+ error = PTR_ERR(dentry); -+ goto exit_cow; -+ } -+ dput(dentry); -+ if (will_write) -+ mnt_drop_write(nd.path.mnt); -+ release_open_intent(&nd); -+ path_put(&nd.path); -+ flag = rflag; -+ mode = rmode; -+ goto restart; -+ } -+exit_cow: -+#endif - if (error) { - if (will_write) - mnt_drop_write(nd.path.mnt); -@@ -1987,9 +2119,17 @@ int vfs_mknod(struct inode *dir, struct - if (error) - return error; - -- if ((S_ISCHR(mode) || S_ISBLK(mode)) && !capable(CAP_MKNOD)) -+ if (!(S_ISCHR(mode) || S_ISBLK(mode))) -+ goto okay; -+ -+ if (!capable(CAP_MKNOD)) - return -EPERM; - -+ if (S_ISCHR(mode) && !vs_chrdev_perm(dev, DATTR_CREATE)) -+ return -EPERM; -+ if (S_ISBLK(mode) && !vs_blkdev_perm(dev, DATTR_CREATE)) -+ return -EPERM; -+okay: - if (!dir->i_op->mknod) - return -EPERM; - -@@ -2456,7 +2596,7 @@ int vfs_link(struct dentry *old_dentry, - /* - * A link to an append-only or immutable file cannot be created. - */ -- if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) -+ if (IS_APPEND(inode) || IS_IXORUNLINK(inode)) - return -EPERM; - if (!dir->i_op->link) - return -EPERM; -@@ -2829,6 +2969,219 @@ int vfs_follow_link(struct nameidata *nd - return __vfs_follow_link(nd, link); - } - -+ -+#ifdef CONFIG_VSERVER_COWBL -+ -+#include -+ -+static inline -+long do_cow_splice(struct file *in, struct file *out, size_t len) -+{ -+ loff_t ppos = 0; -+ -+ return do_splice_direct(in, &ppos, out, len, 0); -+} -+ -+struct dentry *cow_break_link(const char *pathname) -+{ -+ int ret, mode, pathlen, redo = 0; -+ struct nameidata old_nd, dir_nd; -+ struct path old_path, new_path; -+ struct dentry *dir, *res = NULL; -+ struct file *old_file; -+ struct file *new_file; -+ char *to, *path, pad='\251'; -+ loff_t size; -+ -+ vxdprintk(VXD_CBIT(misc, 1), "cow_break_link(»%s«)", pathname); -+ path = kmalloc(PATH_MAX, GFP_KERNEL); -+ ret = -ENOMEM; -+ if (!path) -+ goto out; -+ -+ /* old_nd will have refs to dentry and mnt */ -+ ret = path_lookup(pathname, LOOKUP_FOLLOW, &old_nd); -+ vxdprintk(VXD_CBIT(misc, 2), "path_lookup(old): %d", ret); -+ if (ret < 0) -+ goto out_free_path; -+ -+ old_path = old_nd.path; -+ mode = old_path.dentry->d_inode->i_mode; -+ -+ to = d_path(&old_path, path, PATH_MAX-2); -+ pathlen = strlen(to); -+ vxdprintk(VXD_CBIT(misc, 2), "old path »%s« [»%.*s«:%d]", to, -+ old_path.dentry->d_name.len, old_path.dentry->d_name.name, -+ old_path.dentry->d_name.len); -+ -+ to[pathlen + 1] = 0; -+retry: -+ to[pathlen] = pad--; -+ ret = -EMLINK; -+ if (pad <= '\240') -+ goto out_rel_old; -+ -+ vxdprintk(VXD_CBIT(misc, 1), "temp copy »%s«", to); -+ /* dir_nd will have refs to dentry and mnt */ -+ ret = path_lookup(to, -+ LOOKUP_PARENT | LOOKUP_OPEN | LOOKUP_CREATE, &dir_nd); -+ vxdprintk(VXD_CBIT(misc, 2), -+ "path_lookup(new): %d", ret); -+ if (ret < 0) -+ goto retry; -+ -+ /* this puppy downs the inode mutex */ -+ new_path.dentry = lookup_create(&dir_nd, 0); -+ if (!new_path.dentry || IS_ERR(new_path.dentry)) { -+ vxdprintk(VXD_CBIT(misc, 2), -+ "lookup_create(new): %p", new_path.dentry); -+ mutex_unlock(&dir_nd.path.dentry->d_inode->i_mutex); -+ path_put(&dir_nd.path); -+ goto retry; -+ } -+ vxdprintk(VXD_CBIT(misc, 2), -+ "lookup_create(new): %p [»%.*s«:%d]", new_path.dentry, -+ new_path.dentry->d_name.len, new_path.dentry->d_name.name, -+ new_path.dentry->d_name.len); -+ dir = dir_nd.path.dentry; -+ -+ ret = vfs_create(dir_nd.path.dentry->d_inode, new_path.dentry, mode, &dir_nd); -+ vxdprintk(VXD_CBIT(misc, 2), -+ "vfs_create(new): %d", ret); -+ if (ret == -EEXIST) { -+ mutex_unlock(&dir->d_inode->i_mutex); -+ dput(new_path.dentry); -+ path_put(&dir_nd.path); -+ goto retry; -+ } -+ else if (ret < 0) -+ goto out_unlock_new; -+ -+ /* drop out early, ret passes ENOENT */ -+ ret = -ENOENT; -+ if ((redo = d_unhashed(old_path.dentry))) -+ goto out_unlock_new; -+ -+ new_path.mnt = dir_nd.path.mnt; -+ dget(old_path.dentry); -+ mntget(old_path.mnt); -+ /* this one cleans up the dentry/mnt in case of failure */ -+ old_file = dentry_open(old_path.dentry, old_path.mnt, -+ O_RDONLY, current_cred()); -+ vxdprintk(VXD_CBIT(misc, 2), -+ "dentry_open(old): %p", old_file); -+ if (!old_file || IS_ERR(old_file)) { -+ res = IS_ERR(old_file) ? (void *) old_file : res; -+ goto out_unlock_new; -+ } -+ -+ dget(new_path.dentry); -+ mntget(new_path.mnt); -+ /* this one cleans up the dentry/mnt in case of failure */ -+ new_file = dentry_open(new_path.dentry, new_path.mnt, -+ O_WRONLY, current_cred()); -+ vxdprintk(VXD_CBIT(misc, 2), -+ "dentry_open(new): %p", new_file); -+ -+ ret = IS_ERR(new_file) ? PTR_ERR(new_file) : -ENOENT; -+ if (!new_file || IS_ERR(new_file)) -+ goto out_fput_old; -+ -+ size = i_size_read(old_file->f_dentry->d_inode); -+ ret = do_cow_splice(old_file, new_file, size); -+ vxdprintk(VXD_CBIT(misc, 2), "do_splice_direct: %d", ret); -+ if (ret < 0) { -+ goto out_fput_both; -+ } else if (ret < size) { -+ ret = -ENOSPC; -+ goto out_fput_both; -+ } else { -+ struct inode *old_inode = old_path.dentry->d_inode; -+ struct inode *new_inode = new_path.dentry->d_inode; -+ struct iattr attr = { -+ .ia_uid = old_inode->i_uid, -+ .ia_gid = old_inode->i_gid, -+ .ia_valid = ATTR_UID | ATTR_GID -+ }; -+ -+ ret = inode_setattr(new_inode, &attr); -+ if (ret) -+ goto out_fput_both; -+ } -+ -+ mutex_lock(&old_path.dentry->d_inode->i_sb->s_vfs_rename_mutex); -+ -+ /* drop out late */ -+ ret = -ENOENT; -+ if ((redo = d_unhashed(old_path.dentry))) -+ goto out_unlock; -+ -+ vxdprintk(VXD_CBIT(misc, 2), -+ "vfs_rename: [»%*s«:%d] -> [»%*s«:%d]", -+ new_path.dentry->d_name.len, new_path.dentry->d_name.name, -+ new_path.dentry->d_name.len, -+ old_path.dentry->d_name.len, old_path.dentry->d_name.name, -+ old_path.dentry->d_name.len); -+ ret = vfs_rename(dir_nd.path.dentry->d_inode, new_path.dentry, -+ old_nd.path.dentry->d_parent->d_inode, old_path.dentry); -+ vxdprintk(VXD_CBIT(misc, 2), "vfs_rename: %d", ret); -+ res = new_path.dentry; -+ -+out_unlock: -+ mutex_unlock(&old_path.dentry->d_inode->i_sb->s_vfs_rename_mutex); -+ -+out_fput_both: -+ vxdprintk(VXD_CBIT(misc, 3), -+ "fput(new_file=%p[#%ld])", new_file, -+ atomic_long_read(&new_file->f_count)); -+ fput(new_file); -+ -+out_fput_old: -+ vxdprintk(VXD_CBIT(misc, 3), -+ "fput(old_file=%p[#%ld])", old_file, -+ atomic_long_read(&old_file->f_count)); -+ fput(old_file); -+ -+out_unlock_new: -+ mutex_unlock(&dir->d_inode->i_mutex); -+ if (!ret) -+ goto out_redo; -+ -+ /* error path cleanup */ -+ vfs_unlink(dir->d_inode, new_path.dentry); -+ dput(new_path.dentry); -+ -+out_redo: -+ if (!redo) -+ goto out_rel_both; -+ /* lookup dentry once again */ -+ path_put(&old_nd.path); -+ ret = path_lookup(pathname, LOOKUP_FOLLOW, &old_nd); -+ if (ret) -+ goto out_rel_both; -+ -+ new_path.dentry = old_nd.path.dentry; -+ vxdprintk(VXD_CBIT(misc, 2), -+ "path_lookup(redo): %p [»%.*s«:%d]", new_path.dentry, -+ new_path.dentry->d_name.len, new_path.dentry->d_name.name, -+ new_path.dentry->d_name.len); -+ dget(new_path.dentry); -+ res = new_path.dentry; -+ -+out_rel_both: -+ path_put(&dir_nd.path); -+out_rel_old: -+ path_put(&old_nd.path); -+out_free_path: -+ kfree(path); -+out: -+ if (ret) -+ res = ERR_PTR(ret); -+ return res; -+} -+ -+#endif -+ - /* get the link contents into pagecache */ - static char *page_getlink(struct dentry * dentry, struct page **ppage) - { -diff -NurpP --minimal linux-2.6.32.1/fs/namespace.c linux-2.6.32.1-vs2.3.0.36.27/fs/namespace.c ---- linux-2.6.32.1/fs/namespace.c 2009-12-03 20:02:52.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/namespace.c 2009-12-03 20:04:56.000000000 +0100 -@@ -29,6 +29,11 @@ - #include - #include - #include -+#include -+#include -+#include -+#include -+#include - #include - #include - #include "pnode.h" -@@ -567,6 +572,7 @@ static struct vfsmount *clone_mnt(struct - mnt->mnt_root = dget(root); - mnt->mnt_mountpoint = mnt->mnt_root; - mnt->mnt_parent = mnt; -+ mnt->mnt_tag = old->mnt_tag; - - if (flag & CL_SLAVE) { - list_add(&mnt->mnt_slave, &old->mnt_slave_list); -@@ -661,6 +667,31 @@ static inline void mangle(struct seq_fil - seq_escape(m, s, " \t\n\\"); - } - -+static int mnt_is_reachable(struct vfsmount *mnt) -+{ -+ struct path root; -+ struct dentry *point; -+ int ret; -+ -+ if (mnt == mnt->mnt_ns->root) -+ return 1; -+ -+ spin_lock(&vfsmount_lock); -+ root = current->fs->root; -+ point = root.dentry; -+ -+ while ((mnt != mnt->mnt_parent) && (mnt != root.mnt)) { -+ point = mnt->mnt_mountpoint; -+ mnt = mnt->mnt_parent; -+ } -+ -+ ret = (mnt == root.mnt) && is_subdir(point, root.dentry); -+ -+ spin_unlock(&vfsmount_lock); -+ -+ return ret; -+} -+ - /* - * Simple .show_options callback for filesystems which don't want to - * implement more complex mount option showing. -@@ -748,6 +779,8 @@ static int show_sb_opts(struct seq_file - { MS_SYNCHRONOUS, ",sync" }, - { MS_DIRSYNC, ",dirsync" }, - { MS_MANDLOCK, ",mand" }, -+ { MS_TAGGED, ",tag" }, -+ { MS_NOTAGCHECK, ",notagcheck" }, - { 0, NULL } - }; - const struct proc_fs_info *fs_infop; -@@ -795,10 +828,20 @@ static int show_vfsmnt(struct seq_file * - int err = 0; - struct path mnt_path = { .dentry = mnt->mnt_root, .mnt = mnt }; - -- mangle(m, mnt->mnt_devname ? mnt->mnt_devname : "none"); -- seq_putc(m, ' '); -- seq_path(m, &mnt_path, " \t\n\\"); -- seq_putc(m, ' '); -+ if (vx_flags(VXF_HIDE_MOUNT, 0)) -+ return SEQ_SKIP; -+ if (!mnt_is_reachable(mnt) && !vx_check(0, VS_WATCH_P)) -+ return SEQ_SKIP; -+ -+ if (!vx_check(0, VS_ADMIN|VS_WATCH) && -+ mnt == current->fs->root.mnt) { -+ seq_puts(m, "/dev/root / "); -+ } else { -+ mangle(m, mnt->mnt_devname ? mnt->mnt_devname : "none"); -+ seq_putc(m, ' '); -+ seq_path(m, &mnt_path, " \t\n\\"); -+ seq_putc(m, ' '); -+ } - show_type(m, mnt->mnt_sb); - seq_puts(m, __mnt_is_readonly(mnt) ? " ro" : " rw"); - err = show_sb_opts(m, mnt->mnt_sb); -@@ -828,6 +871,11 @@ static int show_mountinfo(struct seq_fil - struct path root = p->root; - int err = 0; - -+ if (vx_flags(VXF_HIDE_MOUNT, 0)) -+ return SEQ_SKIP; -+ if (!mnt_is_reachable(mnt) && !vx_check(0, VS_WATCH_P)) -+ return SEQ_SKIP; -+ - seq_printf(m, "%i %i %u:%u ", mnt->mnt_id, mnt->mnt_parent->mnt_id, - MAJOR(sb->s_dev), MINOR(sb->s_dev)); - seq_dentry(m, mnt->mnt_root, " \t\n\\"); -@@ -886,17 +934,27 @@ static int show_vfsstat(struct seq_file - struct path mnt_path = { .dentry = mnt->mnt_root, .mnt = mnt }; - int err = 0; - -- /* device */ -- if (mnt->mnt_devname) { -- seq_puts(m, "device "); -- mangle(m, mnt->mnt_devname); -- } else -- seq_puts(m, "no device"); -+ if (vx_flags(VXF_HIDE_MOUNT, 0)) -+ return SEQ_SKIP; -+ if (!mnt_is_reachable(mnt) && !vx_check(0, VS_WATCH_P)) -+ return SEQ_SKIP; - -- /* mount point */ -- seq_puts(m, " mounted on "); -- seq_path(m, &mnt_path, " \t\n\\"); -- seq_putc(m, ' '); -+ if (!vx_check(0, VS_ADMIN|VS_WATCH) && -+ mnt == current->fs->root.mnt) { -+ seq_puts(m, "device /dev/root mounted on / "); -+ } else { -+ /* device */ -+ if (mnt->mnt_devname) { -+ seq_puts(m, "device "); -+ mangle(m, mnt->mnt_devname); -+ } else -+ seq_puts(m, "no device"); -+ -+ /* mount point */ -+ seq_puts(m, " mounted on "); -+ seq_path(m, &mnt_path, " \t\n\\"); -+ seq_putc(m, ' '); -+ } - - /* file system type */ - seq_puts(m, "with fstype "); -@@ -1130,7 +1188,7 @@ SYSCALL_DEFINE2(umount, char __user *, n - goto dput_and_out; - - retval = -EPERM; -- if (!capable(CAP_SYS_ADMIN)) -+ if (!vx_capable(CAP_SYS_ADMIN, VXC_SECURE_MOUNT)) - goto dput_and_out; - - retval = do_umount(path.mnt, flags); -@@ -1156,7 +1214,7 @@ SYSCALL_DEFINE1(oldumount, char __user * - - static int mount_is_safe(struct path *path) - { -- if (capable(CAP_SYS_ADMIN)) -+ if (vx_capable(CAP_SYS_ADMIN, VXC_SECURE_MOUNT)) - return 0; - return -EPERM; - #ifdef notyet -@@ -1420,7 +1478,7 @@ static int do_change_type(struct path *p - int type = flag & ~MS_REC; - int err = 0; - -- if (!capable(CAP_SYS_ADMIN)) -+ if (!vx_capable(CAP_SYS_ADMIN, VXC_NAMESPACE)) - return -EPERM; - - if (path->dentry != path->mnt->mnt_root) -@@ -1447,11 +1505,13 @@ static int do_change_type(struct path *p - * do loopback mount. - */ - static int do_loopback(struct path *path, char *old_name, -- int recurse) -+ tag_t tag, unsigned long flags, int mnt_flags) - { - struct path old_path; - struct vfsmount *mnt = NULL; - int err = mount_is_safe(path); -+ int recurse = flags & MS_REC; -+ - if (err) - return err; - if (!old_name || !*old_name) -@@ -1485,6 +1545,7 @@ static int do_loopback(struct path *path - spin_unlock(&vfsmount_lock); - release_mounts(&umount_list); - } -+ mnt->mnt_flags = mnt_flags; - - out: - up_write(&namespace_sem); -@@ -1515,12 +1576,12 @@ static int change_mount_flags(struct vfs - * on it - tough luck. - */ - static int do_remount(struct path *path, int flags, int mnt_flags, -- void *data) -+ void *data, xid_t xid) - { - int err; - struct super_block *sb = path->mnt->mnt_sb; - -- if (!capable(CAP_SYS_ADMIN)) -+ if (!vx_capable(CAP_SYS_ADMIN, VXC_SECURE_REMOUNT)) - return -EPERM; - - if (!check_mnt(path->mnt)) -@@ -1562,7 +1623,7 @@ static int do_move_mount(struct path *pa - struct path old_path, parent_path; - struct vfsmount *p; - int err = 0; -- if (!capable(CAP_SYS_ADMIN)) -+ if (!vx_capable(CAP_SYS_ADMIN, VXC_SECURE_MOUNT)) - return -EPERM; - if (!old_name || !*old_name) - return -EINVAL; -@@ -1644,7 +1705,7 @@ static int do_new_mount(struct path *pat - return -EINVAL; - - /* we need capabilities... */ -- if (!capable(CAP_SYS_ADMIN)) -+ if (!vx_capable(CAP_SYS_ADMIN, VXC_SECURE_MOUNT)) - return -EPERM; - - lock_kernel(); -@@ -1908,6 +1969,7 @@ long do_mount(char *dev_name, char *dir_ - struct path path; - int retval = 0; - int mnt_flags = 0; -+ tag_t tag = 0; - - /* Discard magic */ - if ((flags & MS_MGC_MSK) == MS_MGC_VAL) -@@ -1925,6 +1987,12 @@ long do_mount(char *dev_name, char *dir_ - if (!(flags & MS_NOATIME)) - mnt_flags |= MNT_RELATIME; - -+ if (dx_parse_tag(data_page, &tag, 1, &mnt_flags, &flags)) { -+ /* FIXME: bind and re-mounts get the tag flag? */ -+ if (flags & (MS_BIND|MS_REMOUNT)) -+ flags |= MS_TAGID; -+ } -+ - /* Separate the per-mountpoint flags */ - if (flags & MS_NOSUID) - mnt_flags |= MNT_NOSUID; -@@ -1941,6 +2009,8 @@ long do_mount(char *dev_name, char *dir_ - if (flags & MS_RDONLY) - mnt_flags |= MNT_READONLY; - -+ if (!capable(CAP_SYS_ADMIN)) -+ mnt_flags |= MNT_NODEV; - flags &= ~(MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_ACTIVE | - MS_NOATIME | MS_NODIRATIME | MS_RELATIME| MS_KERNMOUNT | - MS_STRICTATIME); -@@ -1957,9 +2027,9 @@ long do_mount(char *dev_name, char *dir_ - - if (flags & MS_REMOUNT) - retval = do_remount(&path, flags & ~MS_REMOUNT, mnt_flags, -- data_page); -+ data_page, tag); - else if (flags & MS_BIND) -- retval = do_loopback(&path, dev_name, flags & MS_REC); -+ retval = do_loopback(&path, dev_name, tag, flags, mnt_flags); - else if (flags & (MS_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE)) - retval = do_change_type(&path, flags); - else if (flags & MS_MOVE) -@@ -2038,6 +2108,7 @@ static struct mnt_namespace *dup_mnt_ns( - q = next_mnt(q, new_ns->root); - } - up_write(&namespace_sem); -+ atomic_inc(&vs_global_mnt_ns); - - if (rootmnt) - mntput(rootmnt); -@@ -2182,9 +2253,10 @@ SYSCALL_DEFINE2(pivot_root, const char _ - down_write(&namespace_sem); - mutex_lock(&old.dentry->d_inode->i_mutex); - error = -EINVAL; -- if (IS_MNT_SHARED(old.mnt) || -+ if ((IS_MNT_SHARED(old.mnt) || - IS_MNT_SHARED(new.mnt->mnt_parent) || -- IS_MNT_SHARED(root.mnt->mnt_parent)) -+ IS_MNT_SHARED(root.mnt->mnt_parent)) && -+ !vx_flags(VXF_STATE_SETUP, 0)) - goto out2; - if (!check_mnt(root.mnt)) - goto out2; -@@ -2320,6 +2392,7 @@ void put_mnt_ns(struct mnt_namespace *ns - spin_unlock(&vfsmount_lock); - up_write(&namespace_sem); - release_mounts(&umount_list); -+ atomic_dec(&vs_global_mnt_ns); - kfree(ns); - } - EXPORT_SYMBOL(put_mnt_ns); -diff -NurpP --minimal linux-2.6.32.1/fs/nfs/client.c linux-2.6.32.1-vs2.3.0.36.27/fs/nfs/client.c ---- linux-2.6.32.1/fs/nfs/client.c 2009-12-03 20:02:52.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/nfs/client.c 2009-12-03 20:04:56.000000000 +0100 -@@ -738,6 +738,9 @@ static int nfs_init_server_rpcclient(str - if (server->flags & NFS_MOUNT_SOFT) - server->client->cl_softrtry = 1; - -+ server->client->cl_tag = 0; -+ if (server->flags & NFS_MOUNT_TAGGED) -+ server->client->cl_tag = 1; - return 0; - } - -@@ -909,6 +912,10 @@ static void nfs_server_set_fsinfo(struct - server->acdirmin = server->acdirmax = 0; - } - -+ /* FIXME: needs fsinfo -+ if (server->flags & NFS_MOUNT_TAGGED) -+ sb->s_flags |= MS_TAGGED; */ -+ - server->maxfilesize = fsinfo->maxfilesize; - - /* We're airborne Set socket buffersize */ -diff -NurpP --minimal linux-2.6.32.1/fs/nfs/dir.c linux-2.6.32.1-vs2.3.0.36.27/fs/nfs/dir.c ---- linux-2.6.32.1/fs/nfs/dir.c 2009-12-03 20:02:52.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/nfs/dir.c 2009-12-03 20:04:56.000000000 +0100 -@@ -33,6 +33,7 @@ - #include - #include - #include -+#include - - #include "nfs4_fs.h" - #include "delegation.h" -@@ -949,6 +950,7 @@ static struct dentry *nfs_lookup(struct - if (IS_ERR(res)) - goto out_unblock_sillyrename; - -+ dx_propagate_tag(nd, inode); - no_entry: - res = d_materialise_unique(dentry, inode); - if (res != NULL) { -diff -NurpP --minimal linux-2.6.32.1/fs/nfs/inode.c linux-2.6.32.1-vs2.3.0.36.27/fs/nfs/inode.c ---- linux-2.6.32.1/fs/nfs/inode.c 2009-12-03 20:02:52.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/nfs/inode.c 2009-12-03 20:04:56.000000000 +0100 -@@ -36,6 +36,7 @@ - #include - #include - #include -+#include - - #include - #include -@@ -279,6 +280,8 @@ nfs_fhget(struct super_block *sb, struct - if (inode->i_state & I_NEW) { - struct nfs_inode *nfsi = NFS_I(inode); - unsigned long now = jiffies; -+ uid_t uid; -+ gid_t gid; - - /* We set i_ino for the few things that still rely on it, - * such as stat(2) */ -@@ -327,8 +330,8 @@ nfs_fhget(struct super_block *sb, struct - nfsi->change_attr = 0; - inode->i_size = 0; - inode->i_nlink = 0; -- inode->i_uid = -2; -- inode->i_gid = -2; -+ uid = -2; -+ gid = -2; - inode->i_blocks = 0; - memset(nfsi->cookieverf, 0, sizeof(nfsi->cookieverf)); - -@@ -365,13 +368,13 @@ nfs_fhget(struct super_block *sb, struct - else if (nfs_server_capable(inode, NFS_CAP_NLINK)) - nfsi->cache_validity |= NFS_INO_INVALID_ATTR; - if (fattr->valid & NFS_ATTR_FATTR_OWNER) -- inode->i_uid = fattr->uid; -+ uid = fattr->uid; - else if (nfs_server_capable(inode, NFS_CAP_OWNER)) - nfsi->cache_validity |= NFS_INO_INVALID_ATTR - | NFS_INO_INVALID_ACCESS - | NFS_INO_INVALID_ACL; - if (fattr->valid & NFS_ATTR_FATTR_GROUP) -- inode->i_gid = fattr->gid; -+ gid = fattr->gid; - else if (nfs_server_capable(inode, NFS_CAP_OWNER_GROUP)) - nfsi->cache_validity |= NFS_INO_INVALID_ATTR - | NFS_INO_INVALID_ACCESS -@@ -384,6 +387,11 @@ nfs_fhget(struct super_block *sb, struct - */ - inode->i_blocks = nfs_calc_block_size(fattr->du.nfs3.used); - } -+ inode->i_uid = INOTAG_UID(DX_TAG(inode), uid, gid); -+ inode->i_gid = INOTAG_GID(DX_TAG(inode), uid, gid); -+ inode->i_tag = INOTAG_TAG(DX_TAG(inode), uid, gid, 0); -+ /* maybe fattr->xid someday */ -+ - nfsi->attrtimeo = NFS_MINATTRTIMEO(inode); - nfsi->attrtimeo_timestamp = now; - nfsi->access_cache = RB_ROOT; -@@ -496,6 +504,8 @@ void nfs_setattr_update_inode(struct ino - inode->i_uid = attr->ia_uid; - if ((attr->ia_valid & ATTR_GID) != 0) - inode->i_gid = attr->ia_gid; -+ if ((attr->ia_valid & ATTR_TAG) && IS_TAGGED(inode)) -+ inode->i_tag = attr->ia_tag; - NFS_I(inode)->cache_validity |= NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL; - spin_unlock(&inode->i_lock); - } -@@ -906,6 +916,9 @@ static int nfs_check_inode_attributes(st - struct nfs_inode *nfsi = NFS_I(inode); - loff_t cur_size, new_isize; - unsigned long invalid = 0; -+ uid_t uid; -+ gid_t gid; -+ tag_t tag; - - - /* Has the inode gone and changed behind our back? */ -@@ -929,13 +942,18 @@ static int nfs_check_inode_attributes(st - invalid |= NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE; - } - -+ uid = INOTAG_UID(DX_TAG(inode), fattr->uid, fattr->gid); -+ gid = INOTAG_GID(DX_TAG(inode), fattr->uid, fattr->gid); -+ tag = INOTAG_TAG(DX_TAG(inode), fattr->uid, fattr->gid, 0); -+ - /* Have any file permissions changed? */ - if ((fattr->valid & NFS_ATTR_FATTR_MODE) && (inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO)) - invalid |= NFS_INO_INVALID_ATTR | NFS_INO_INVALID_ACCESS | NFS_INO_INVALID_ACL; -- if ((fattr->valid & NFS_ATTR_FATTR_OWNER) && inode->i_uid != fattr->uid) -+ if ((fattr->valid & NFS_ATTR_FATTR_OWNER) && uid != fattr->uid) - invalid |= NFS_INO_INVALID_ATTR | NFS_INO_INVALID_ACCESS | NFS_INO_INVALID_ACL; -- if ((fattr->valid & NFS_ATTR_FATTR_GROUP) && inode->i_gid != fattr->gid) -+ if ((fattr->valid & NFS_ATTR_FATTR_GROUP) && gid != fattr->gid) - invalid |= NFS_INO_INVALID_ATTR | NFS_INO_INVALID_ACCESS | NFS_INO_INVALID_ACL; -+ /* maybe check for tag too? */ - - /* Has the link count changed? */ - if ((fattr->valid & NFS_ATTR_FATTR_NLINK) && inode->i_nlink != fattr->nlink) -@@ -1150,6 +1168,9 @@ static int nfs_update_inode(struct inode - unsigned long invalid = 0; - unsigned long now = jiffies; - unsigned long save_cache_validity; -+ uid_t uid; -+ gid_t gid; -+ tag_t tag; - - dfprintk(VFS, "NFS: %s(%s/%ld ct=%d info=0x%x)\n", - __func__, inode->i_sb->s_id, inode->i_ino, -@@ -1252,6 +1273,9 @@ static int nfs_update_inode(struct inode - | NFS_INO_REVAL_PAGECACHE - | NFS_INO_REVAL_FORCED); - -+ uid = INOTAG_UID(DX_TAG(inode), fattr->uid, fattr->gid); -+ gid = INOTAG_GID(DX_TAG(inode), fattr->uid, fattr->gid); -+ tag = INOTAG_TAG(DX_TAG(inode), fattr->uid, fattr->gid, 0); - - if (fattr->valid & NFS_ATTR_FATTR_ATIME) - memcpy(&inode->i_atime, &fattr->atime, sizeof(inode->i_atime)); -@@ -1271,9 +1295,9 @@ static int nfs_update_inode(struct inode - | NFS_INO_REVAL_FORCED); - - if (fattr->valid & NFS_ATTR_FATTR_OWNER) { -- if (inode->i_uid != fattr->uid) { -+ if (uid != fattr->uid) { - invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL; -- inode->i_uid = fattr->uid; -+ uid = fattr->uid; - } - } else if (server->caps & NFS_CAP_OWNER) - invalid |= save_cache_validity & (NFS_INO_INVALID_ATTR -@@ -1282,9 +1306,9 @@ static int nfs_update_inode(struct inode - | NFS_INO_REVAL_FORCED); - - if (fattr->valid & NFS_ATTR_FATTR_GROUP) { -- if (inode->i_gid != fattr->gid) { -+ if (gid != fattr->gid) { - invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL; -- inode->i_gid = fattr->gid; -+ gid = fattr->gid; - } - } else if (server->caps & NFS_CAP_OWNER_GROUP) - invalid |= save_cache_validity & (NFS_INO_INVALID_ATTR -@@ -1292,6 +1316,10 @@ static int nfs_update_inode(struct inode - | NFS_INO_INVALID_ACL - | NFS_INO_REVAL_FORCED); - -+ inode->i_uid = uid; -+ inode->i_gid = gid; -+ inode->i_tag = tag; -+ - if (fattr->valid & NFS_ATTR_FATTR_NLINK) { - if (inode->i_nlink != fattr->nlink) { - invalid |= NFS_INO_INVALID_ATTR; -diff -NurpP --minimal linux-2.6.32.1/fs/nfs/nfs3xdr.c linux-2.6.32.1-vs2.3.0.36.27/fs/nfs/nfs3xdr.c ---- linux-2.6.32.1/fs/nfs/nfs3xdr.c 2009-12-03 20:02:52.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/nfs/nfs3xdr.c 2009-12-03 20:04:56.000000000 +0100 -@@ -21,6 +21,7 @@ - #include - #include - #include -+#include - #include "internal.h" - - #define NFSDBG_FACILITY NFSDBG_XDR -@@ -176,7 +177,7 @@ xdr_decode_fattr(__be32 *p, struct nfs_f - } - - static inline __be32 * --xdr_encode_sattr(__be32 *p, struct iattr *attr) -+xdr_encode_sattr(__be32 *p, struct iattr *attr, int tag) - { - if (attr->ia_valid & ATTR_MODE) { - *p++ = xdr_one; -@@ -184,15 +185,17 @@ xdr_encode_sattr(__be32 *p, struct iattr - } else { - *p++ = xdr_zero; - } -- if (attr->ia_valid & ATTR_UID) { -+ if (attr->ia_valid & ATTR_UID || -+ (tag && (attr->ia_valid & ATTR_TAG))) { - *p++ = xdr_one; -- *p++ = htonl(attr->ia_uid); -+ *p++ = htonl(TAGINO_UID(tag, attr->ia_uid, attr->ia_tag)); - } else { - *p++ = xdr_zero; - } -- if (attr->ia_valid & ATTR_GID) { -+ if (attr->ia_valid & ATTR_GID || -+ (tag && (attr->ia_valid & ATTR_TAG))) { - *p++ = xdr_one; -- *p++ = htonl(attr->ia_gid); -+ *p++ = htonl(TAGINO_GID(tag, attr->ia_gid, attr->ia_tag)); - } else { - *p++ = xdr_zero; - } -@@ -279,7 +282,8 @@ static int - nfs3_xdr_sattrargs(struct rpc_rqst *req, __be32 *p, struct nfs3_sattrargs *args) - { - p = xdr_encode_fhandle(p, args->fh); -- p = xdr_encode_sattr(p, args->sattr); -+ p = xdr_encode_sattr(p, args->sattr, -+ req->rq_task->tk_client->cl_tag); - *p++ = htonl(args->guard); - if (args->guard) - p = xdr_encode_time3(p, &args->guardtime); -@@ -384,7 +388,8 @@ nfs3_xdr_createargs(struct rpc_rqst *req - *p++ = args->verifier[0]; - *p++ = args->verifier[1]; - } else -- p = xdr_encode_sattr(p, args->sattr); -+ p = xdr_encode_sattr(p, args->sattr, -+ req->rq_task->tk_client->cl_tag); - - req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); - return 0; -@@ -398,7 +403,8 @@ nfs3_xdr_mkdirargs(struct rpc_rqst *req, - { - p = xdr_encode_fhandle(p, args->fh); - p = xdr_encode_array(p, args->name, args->len); -- p = xdr_encode_sattr(p, args->sattr); -+ p = xdr_encode_sattr(p, args->sattr, -+ req->rq_task->tk_client->cl_tag); - req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); - return 0; - } -@@ -411,7 +417,8 @@ nfs3_xdr_symlinkargs(struct rpc_rqst *re - { - p = xdr_encode_fhandle(p, args->fromfh); - p = xdr_encode_array(p, args->fromname, args->fromlen); -- p = xdr_encode_sattr(p, args->sattr); -+ p = xdr_encode_sattr(p, args->sattr, -+ req->rq_task->tk_client->cl_tag); - *p++ = htonl(args->pathlen); - req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); - -@@ -429,7 +436,8 @@ nfs3_xdr_mknodargs(struct rpc_rqst *req, - p = xdr_encode_fhandle(p, args->fh); - p = xdr_encode_array(p, args->name, args->len); - *p++ = htonl(args->type); -- p = xdr_encode_sattr(p, args->sattr); -+ p = xdr_encode_sattr(p, args->sattr, -+ req->rq_task->tk_client->cl_tag); - if (args->type == NF3CHR || args->type == NF3BLK) { - *p++ = htonl(MAJOR(args->rdev)); - *p++ = htonl(MINOR(args->rdev)); -diff -NurpP --minimal linux-2.6.32.1/fs/nfs/nfsroot.c linux-2.6.32.1-vs2.3.0.36.27/fs/nfs/nfsroot.c ---- linux-2.6.32.1/fs/nfs/nfsroot.c 2009-09-10 15:26:23.000000000 +0200 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/nfs/nfsroot.c 2009-12-03 20:04:56.000000000 +0100 -@@ -122,12 +122,12 @@ static int mount_port __initdata = 0; / - enum { - /* Options that take integer arguments */ - Opt_port, Opt_rsize, Opt_wsize, Opt_timeo, Opt_retrans, Opt_acregmin, -- Opt_acregmax, Opt_acdirmin, Opt_acdirmax, -+ Opt_acregmax, Opt_acdirmin, Opt_acdirmax, Opt_tagid, - /* Options that take no arguments */ - Opt_soft, Opt_hard, Opt_intr, - Opt_nointr, Opt_posix, Opt_noposix, Opt_cto, Opt_nocto, Opt_ac, - Opt_noac, Opt_lock, Opt_nolock, Opt_v2, Opt_v3, Opt_udp, Opt_tcp, -- Opt_acl, Opt_noacl, -+ Opt_acl, Opt_noacl, Opt_tag, Opt_notag, - /* Error token */ - Opt_err - }; -@@ -164,6 +164,9 @@ static const match_table_t tokens __init - {Opt_tcp, "tcp"}, - {Opt_acl, "acl"}, - {Opt_noacl, "noacl"}, -+ {Opt_tag, "tag"}, -+ {Opt_notag, "notag"}, -+ {Opt_tagid, "tagid=%u"}, - {Opt_err, NULL} - - }; -@@ -275,6 +278,20 @@ static int __init root_nfs_parse(char *n - case Opt_noacl: - nfs_data.flags |= NFS_MOUNT_NOACL; - break; -+#ifndef CONFIG_TAGGING_NONE -+ case Opt_tag: -+ nfs_data.flags |= NFS_MOUNT_TAGGED; -+ break; -+ case Opt_notag: -+ nfs_data.flags &= ~NFS_MOUNT_TAGGED; -+ break; -+#endif -+#ifdef CONFIG_PROPAGATE -+ case Opt_tagid: -+ /* use args[0] */ -+ nfs_data.flags |= NFS_MOUNT_TAGGED; -+ break; -+#endif - default: - printk(KERN_WARNING "Root-NFS: unknown " - "option: %s\n", p); -diff -NurpP --minimal linux-2.6.32.1/fs/nfs/super.c linux-2.6.32.1-vs2.3.0.36.27/fs/nfs/super.c ---- linux-2.6.32.1/fs/nfs/super.c 2009-12-03 20:02:52.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/nfs/super.c 2009-12-03 20:04:56.000000000 +0100 -@@ -53,6 +53,7 @@ - #include - #include - #include -+#include - - #include - #include -@@ -551,6 +552,7 @@ static void nfs_show_mount_options(struc - { NFS_MOUNT_NORDIRPLUS, ",nordirplus", "" }, - { NFS_MOUNT_UNSHARED, ",nosharecache", "" }, - { NFS_MOUNT_NORESVPORT, ",noresvport", "" }, -+ { NFS_MOUNT_TAGGED, ",tag", "" }, - { 0, NULL, NULL } - }; - const struct proc_nfs_info *nfs_infop; -diff -NurpP --minimal linux-2.6.32.1/fs/nfsd/auth.c linux-2.6.32.1-vs2.3.0.36.27/fs/nfsd/auth.c ---- linux-2.6.32.1/fs/nfsd/auth.c 2009-12-03 20:02:52.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/nfsd/auth.c 2009-12-03 20:04:56.000000000 +0100 -@@ -10,6 +10,7 @@ - #include - #include - #include -+#include - #include "auth.h" - - int nfsexp_flags(struct svc_rqst *rqstp, struct svc_export *exp) -@@ -44,6 +45,9 @@ int nfsd_setuser(struct svc_rqst *rqstp, - - new->fsuid = rqstp->rq_cred.cr_uid; - new->fsgid = rqstp->rq_cred.cr_gid; -+ /* FIXME: this desperately needs a tag :) -+ new->xid = (xid_t)INOTAG_TAG(DX_TAG_NFSD, cred.cr_uid, cred.cr_gid, 0); -+ */ - - rqgi = rqstp->rq_cred.cr_group_info; - -diff -NurpP --minimal linux-2.6.32.1/fs/nfsd/nfs3xdr.c linux-2.6.32.1-vs2.3.0.36.27/fs/nfsd/nfs3xdr.c ---- linux-2.6.32.1/fs/nfsd/nfs3xdr.c 2009-12-03 20:02:52.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/nfsd/nfs3xdr.c 2009-12-03 20:04:56.000000000 +0100 -@@ -21,6 +21,7 @@ - #include - #include - #include -+#include - #include "auth.h" - - #define NFSDDBG_FACILITY NFSDDBG_XDR -@@ -108,6 +109,8 @@ static __be32 * - decode_sattr3(__be32 *p, struct iattr *iap) - { - u32 tmp; -+ uid_t uid = 0; -+ gid_t gid = 0; - - iap->ia_valid = 0; - -@@ -117,12 +120,15 @@ decode_sattr3(__be32 *p, struct iattr *i - } - if (*p++) { - iap->ia_valid |= ATTR_UID; -- iap->ia_uid = ntohl(*p++); -+ uid = ntohl(*p++); - } - if (*p++) { - iap->ia_valid |= ATTR_GID; -- iap->ia_gid = ntohl(*p++); -+ gid = ntohl(*p++); - } -+ iap->ia_uid = INOTAG_UID(DX_TAG_NFSD, uid, gid); -+ iap->ia_gid = INOTAG_GID(DX_TAG_NFSD, uid, gid); -+ iap->ia_tag = INOTAG_TAG(DX_TAG_NFSD, uid, gid, 0); - if (*p++) { - u64 newsize; - -@@ -178,8 +184,12 @@ encode_fattr3(struct svc_rqst *rqstp, __ - *p++ = htonl(nfs3_ftypes[(stat->mode & S_IFMT) >> 12]); - *p++ = htonl((u32) stat->mode); - *p++ = htonl((u32) stat->nlink); -- *p++ = htonl((u32) nfsd_ruid(rqstp, stat->uid)); -- *p++ = htonl((u32) nfsd_rgid(rqstp, stat->gid)); -+ *p++ = htonl((u32) nfsd_ruid(rqstp, -+ TAGINO_UID(0 /* FIXME: DX_TAG(dentry->d_inode) */, -+ stat->uid, stat->tag))); -+ *p++ = htonl((u32) nfsd_rgid(rqstp, -+ TAGINO_GID(0 /* FIXME: DX_TAG(dentry->d_inode) */, -+ stat->gid, stat->tag))); - if (S_ISLNK(stat->mode) && stat->size > NFS3_MAXPATHLEN) { - p = xdr_encode_hyper(p, (u64) NFS3_MAXPATHLEN); - } else { -diff -NurpP --minimal linux-2.6.32.1/fs/nfsd/nfs4xdr.c linux-2.6.32.1-vs2.3.0.36.27/fs/nfsd/nfs4xdr.c ---- linux-2.6.32.1/fs/nfsd/nfs4xdr.c 2009-12-03 20:02:52.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/nfsd/nfs4xdr.c 2009-12-03 20:04:56.000000000 +0100 -@@ -57,6 +57,7 @@ - #include - #include - #include -+#include - - #define NFSDDBG_FACILITY NFSDDBG_XDR - -@@ -2050,14 +2051,18 @@ out_acl: - WRITE32(stat.nlink); - } - if (bmval1 & FATTR4_WORD1_OWNER) { -- status = nfsd4_encode_user(rqstp, stat.uid, &p, &buflen); -+ status = nfsd4_encode_user(rqstp, -+ TAGINO_UID(DX_TAG(dentry->d_inode), -+ stat.uid, stat.tag), &p, &buflen); - if (status == nfserr_resource) - goto out_resource; - if (status) - goto out; - } - if (bmval1 & FATTR4_WORD1_OWNER_GROUP) { -- status = nfsd4_encode_group(rqstp, stat.gid, &p, &buflen); -+ status = nfsd4_encode_group(rqstp, -+ TAGINO_GID(DX_TAG(dentry->d_inode), -+ stat.gid, stat.tag), &p, &buflen); - if (status == nfserr_resource) - goto out_resource; - if (status) -diff -NurpP --minimal linux-2.6.32.1/fs/nfsd/nfsxdr.c linux-2.6.32.1-vs2.3.0.36.27/fs/nfsd/nfsxdr.c ---- linux-2.6.32.1/fs/nfsd/nfsxdr.c 2008-12-25 00:26:37.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/nfsd/nfsxdr.c 2009-12-03 20:04:56.000000000 +0100 -@@ -15,6 +15,7 @@ - #include - #include - #include -+#include - #include "auth.h" - - #define NFSDDBG_FACILITY NFSDDBG_XDR -@@ -98,6 +99,8 @@ static __be32 * - decode_sattr(__be32 *p, struct iattr *iap) - { - u32 tmp, tmp1; -+ uid_t uid = 0; -+ gid_t gid = 0; - - iap->ia_valid = 0; - -@@ -111,12 +114,15 @@ decode_sattr(__be32 *p, struct iattr *ia - } - if ((tmp = ntohl(*p++)) != (u32)-1) { - iap->ia_valid |= ATTR_UID; -- iap->ia_uid = tmp; -+ uid = tmp; - } - if ((tmp = ntohl(*p++)) != (u32)-1) { - iap->ia_valid |= ATTR_GID; -- iap->ia_gid = tmp; -+ gid = tmp; - } -+ iap->ia_uid = INOTAG_UID(DX_TAG_NFSD, uid, gid); -+ iap->ia_gid = INOTAG_GID(DX_TAG_NFSD, uid, gid); -+ iap->ia_tag = INOTAG_TAG(DX_TAG_NFSD, uid, gid, 0); - if ((tmp = ntohl(*p++)) != (u32)-1) { - iap->ia_valid |= ATTR_SIZE; - iap->ia_size = tmp; -@@ -161,8 +167,10 @@ encode_fattr(struct svc_rqst *rqstp, __b - *p++ = htonl(nfs_ftypes[type >> 12]); - *p++ = htonl((u32) stat->mode); - *p++ = htonl((u32) stat->nlink); -- *p++ = htonl((u32) nfsd_ruid(rqstp, stat->uid)); -- *p++ = htonl((u32) nfsd_rgid(rqstp, stat->gid)); -+ *p++ = htonl((u32) nfsd_ruid(rqstp, -+ TAGINO_UID(DX_TAG(dentry->d_inode), stat->uid, stat->tag))); -+ *p++ = htonl((u32) nfsd_rgid(rqstp, -+ TAGINO_GID(DX_TAG(dentry->d_inode), stat->gid, stat->tag))); - - if (S_ISLNK(type) && stat->size > NFS_MAXPATHLEN) { - *p++ = htonl(NFS_MAXPATHLEN); -diff -NurpP --minimal linux-2.6.32.1/fs/ocfs2/dlm/dlmfs.c linux-2.6.32.1-vs2.3.0.36.27/fs/ocfs2/dlm/dlmfs.c ---- linux-2.6.32.1/fs/ocfs2/dlm/dlmfs.c 2009-12-03 20:02:53.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/ocfs2/dlm/dlmfs.c 2009-12-03 20:04:56.000000000 +0100 -@@ -43,6 +43,7 @@ - #include - #include - #include -+#include - - #include - -@@ -342,6 +343,7 @@ static struct inode *dlmfs_get_root_inod - inode->i_mode = mode; - inode->i_uid = current_fsuid(); - inode->i_gid = current_fsgid(); -+ inode->i_tag = dx_current_fstag(sb); - inode->i_mapping->backing_dev_info = &dlmfs_backing_dev_info; - inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; - inc_nlink(inode); -@@ -367,6 +369,7 @@ static struct inode *dlmfs_get_inode(str - inode->i_mode = mode; - inode->i_uid = current_fsuid(); - inode->i_gid = current_fsgid(); -+ inode->i_tag = dx_current_fstag(sb); - inode->i_mapping->backing_dev_info = &dlmfs_backing_dev_info; - inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; - -diff -NurpP --minimal linux-2.6.32.1/fs/ocfs2/dlmglue.c linux-2.6.32.1-vs2.3.0.36.27/fs/ocfs2/dlmglue.c ---- linux-2.6.32.1/fs/ocfs2/dlmglue.c 2009-12-03 20:02:53.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/ocfs2/dlmglue.c 2009-12-03 20:04:56.000000000 +0100 -@@ -1991,6 +1991,7 @@ static void __ocfs2_stuff_meta_lvb(struc - lvb->lvb_iclusters = cpu_to_be32(oi->ip_clusters); - lvb->lvb_iuid = cpu_to_be32(inode->i_uid); - lvb->lvb_igid = cpu_to_be32(inode->i_gid); -+ lvb->lvb_itag = cpu_to_be16(inode->i_tag); - lvb->lvb_imode = cpu_to_be16(inode->i_mode); - lvb->lvb_inlink = cpu_to_be16(inode->i_nlink); - lvb->lvb_iatime_packed = -@@ -2045,6 +2046,7 @@ static void ocfs2_refresh_inode_from_lvb - - inode->i_uid = be32_to_cpu(lvb->lvb_iuid); - inode->i_gid = be32_to_cpu(lvb->lvb_igid); -+ inode->i_tag = be16_to_cpu(lvb->lvb_itag); - inode->i_mode = be16_to_cpu(lvb->lvb_imode); - inode->i_nlink = be16_to_cpu(lvb->lvb_inlink); - ocfs2_unpack_timespec(&inode->i_atime, -diff -NurpP --minimal linux-2.6.32.1/fs/ocfs2/dlmglue.h linux-2.6.32.1-vs2.3.0.36.27/fs/ocfs2/dlmglue.h ---- linux-2.6.32.1/fs/ocfs2/dlmglue.h 2009-12-03 20:02:53.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/ocfs2/dlmglue.h 2009-12-03 20:04:56.000000000 +0100 -@@ -46,7 +46,8 @@ struct ocfs2_meta_lvb { - __be16 lvb_inlink; - __be32 lvb_iattr; - __be32 lvb_igeneration; -- __be32 lvb_reserved2; -+ __be16 lvb_itag; -+ __be16 lvb_reserved2; - }; - - #define OCFS2_QINFO_LVB_VERSION 1 -diff -NurpP --minimal linux-2.6.32.1/fs/ocfs2/file.c linux-2.6.32.1-vs2.3.0.36.27/fs/ocfs2/file.c ---- linux-2.6.32.1/fs/ocfs2/file.c 2009-12-03 20:02:53.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/ocfs2/file.c 2009-12-03 20:04:56.000000000 +0100 -@@ -960,13 +960,15 @@ int ocfs2_setattr(struct dentry *dentry, - mlog(0, "uid change: %d\n", attr->ia_uid); - if (attr->ia_valid & ATTR_GID) - mlog(0, "gid change: %d\n", attr->ia_gid); -+ if (attr->ia_valid & ATTR_TAG) -+ mlog(0, "tag change: %d\n", attr->ia_tag); - if (attr->ia_valid & ATTR_SIZE) - mlog(0, "size change...\n"); - if (attr->ia_valid & (ATTR_ATIME | ATTR_MTIME | ATTR_CTIME)) - mlog(0, "time change...\n"); - - #define OCFS2_VALID_ATTRS (ATTR_ATIME | ATTR_MTIME | ATTR_CTIME | ATTR_SIZE \ -- | ATTR_GID | ATTR_UID | ATTR_MODE) -+ | ATTR_GID | ATTR_UID | ATTR_TAG | ATTR_MODE) - if (!(attr->ia_valid & OCFS2_VALID_ATTRS)) { - mlog(0, "can't handle attrs: 0x%x\n", attr->ia_valid); - return 0; -diff -NurpP --minimal linux-2.6.32.1/fs/ocfs2/inode.c linux-2.6.32.1-vs2.3.0.36.27/fs/ocfs2/inode.c ---- linux-2.6.32.1/fs/ocfs2/inode.c 2009-12-03 20:02:53.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/ocfs2/inode.c 2009-12-03 20:04:56.000000000 +0100 -@@ -29,6 +29,7 @@ - #include - #include - #include -+#include - - #include - -@@ -79,11 +80,13 @@ void ocfs2_set_inode_flags(struct inode - { - unsigned int flags = OCFS2_I(inode)->ip_attr; - -- inode->i_flags &= ~(S_IMMUTABLE | -+ inode->i_flags &= ~(S_IMMUTABLE | S_IXUNLINK | - S_SYNC | S_APPEND | S_NOATIME | S_DIRSYNC); - - if (flags & OCFS2_IMMUTABLE_FL) - inode->i_flags |= S_IMMUTABLE; -+ if (flags & OCFS2_IXUNLINK_FL) -+ inode->i_flags |= S_IXUNLINK; - - if (flags & OCFS2_SYNC_FL) - inode->i_flags |= S_SYNC; -@@ -93,25 +96,44 @@ void ocfs2_set_inode_flags(struct inode - inode->i_flags |= S_NOATIME; - if (flags & OCFS2_DIRSYNC_FL) - inode->i_flags |= S_DIRSYNC; -+ -+ inode->i_vflags &= ~(V_BARRIER | V_COW); -+ -+ if (flags & OCFS2_BARRIER_FL) -+ inode->i_vflags |= V_BARRIER; -+ if (flags & OCFS2_COW_FL) -+ inode->i_vflags |= V_COW; - } - - /* Propagate flags from i_flags to OCFS2_I(inode)->ip_attr */ - void ocfs2_get_inode_flags(struct ocfs2_inode_info *oi) - { - unsigned int flags = oi->vfs_inode.i_flags; -+ unsigned int vflags = oi->vfs_inode.i_vflags; -+ -+ oi->ip_attr &= ~(OCFS2_SYNC_FL | OCFS2_APPEND_FL | -+ OCFS2_IMMUTABLE_FL | OCFS2_IXUNLINK_FL | -+ OCFS2_NOATIME_FL | OCFS2_DIRSYNC_FL | -+ OCFS2_BARRIER_FL | OCFS2_COW_FL); -+ -+ if (flags & S_IMMUTABLE) -+ oi->ip_attr |= OCFS2_IMMUTABLE_FL; -+ if (flags & S_IXUNLINK) -+ oi->ip_attr |= OCFS2_IXUNLINK_FL; - -- oi->ip_attr &= ~(OCFS2_SYNC_FL|OCFS2_APPEND_FL| -- OCFS2_IMMUTABLE_FL|OCFS2_NOATIME_FL|OCFS2_DIRSYNC_FL); - if (flags & S_SYNC) - oi->ip_attr |= OCFS2_SYNC_FL; - if (flags & S_APPEND) - oi->ip_attr |= OCFS2_APPEND_FL; -- if (flags & S_IMMUTABLE) -- oi->ip_attr |= OCFS2_IMMUTABLE_FL; - if (flags & S_NOATIME) - oi->ip_attr |= OCFS2_NOATIME_FL; - if (flags & S_DIRSYNC) - oi->ip_attr |= OCFS2_DIRSYNC_FL; -+ -+ if (vflags & V_BARRIER) -+ oi->ip_attr |= OCFS2_BARRIER_FL; -+ if (vflags & V_COW) -+ oi->ip_attr |= OCFS2_COW_FL; - } - - struct inode *ocfs2_ilookup(struct super_block *sb, u64 blkno) -@@ -246,6 +268,8 @@ void ocfs2_populate_inode(struct inode * - struct super_block *sb; - struct ocfs2_super *osb; - int use_plocks = 1; -+ uid_t uid; -+ gid_t gid; - - mlog_entry("(0x%p, size:%llu)\n", inode, - (unsigned long long)le64_to_cpu(fe->i_size)); -@@ -277,8 +301,12 @@ void ocfs2_populate_inode(struct inode * - inode->i_generation = le32_to_cpu(fe->i_generation); - inode->i_rdev = huge_decode_dev(le64_to_cpu(fe->id1.dev1.i_rdev)); - inode->i_mode = le16_to_cpu(fe->i_mode); -- inode->i_uid = le32_to_cpu(fe->i_uid); -- inode->i_gid = le32_to_cpu(fe->i_gid); -+ uid = le32_to_cpu(fe->i_uid); -+ gid = le32_to_cpu(fe->i_gid); -+ inode->i_uid = INOTAG_UID(DX_TAG(inode), uid, gid); -+ inode->i_gid = INOTAG_GID(DX_TAG(inode), uid, gid); -+ inode->i_tag = INOTAG_TAG(DX_TAG(inode), uid, gid, -+ /* le16_to_cpu(raw_inode->i_raw_tag)i */ 0); - - /* Fast symlinks will have i_size but no allocated clusters. */ - if (S_ISLNK(inode->i_mode) && !fe->i_clusters) -diff -NurpP --minimal linux-2.6.32.1/fs/ocfs2/inode.h linux-2.6.32.1-vs2.3.0.36.27/fs/ocfs2/inode.h ---- linux-2.6.32.1/fs/ocfs2/inode.h 2009-12-03 20:02:53.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/ocfs2/inode.h 2009-12-03 20:04:56.000000000 +0100 -@@ -150,6 +150,7 @@ struct buffer_head *ocfs2_bread(struct i - - void ocfs2_set_inode_flags(struct inode *inode); - void ocfs2_get_inode_flags(struct ocfs2_inode_info *oi); -+int ocfs2_sync_flags(struct inode *inode, int, int); - - static inline blkcnt_t ocfs2_inode_sector_count(struct inode *inode) - { -diff -NurpP --minimal linux-2.6.32.1/fs/ocfs2/ioctl.c linux-2.6.32.1-vs2.3.0.36.27/fs/ocfs2/ioctl.c ---- linux-2.6.32.1/fs/ocfs2/ioctl.c 2009-12-03 20:02:53.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/ocfs2/ioctl.c 2009-12-03 20:04:56.000000000 +0100 -@@ -42,7 +42,41 @@ static int ocfs2_get_inode_attr(struct i - return status; - } - --static int ocfs2_set_inode_attr(struct inode *inode, unsigned flags, -+int ocfs2_sync_flags(struct inode *inode, int flags, int vflags) -+{ -+ struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); -+ struct buffer_head *bh = NULL; -+ handle_t *handle = NULL; -+ int status; -+ -+ status = ocfs2_inode_lock(inode, &bh, 1); -+ if (status < 0) { -+ mlog_errno(status); -+ return status; -+ } -+ handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS); -+ if (IS_ERR(handle)) { -+ status = PTR_ERR(handle); -+ mlog_errno(status); -+ goto bail_unlock; -+ } -+ -+ inode->i_flags = flags; -+ inode->i_vflags = vflags; -+ ocfs2_get_inode_flags(OCFS2_I(inode)); -+ -+ status = ocfs2_mark_inode_dirty(handle, inode, bh); -+ if (status < 0) -+ mlog_errno(status); -+ -+ ocfs2_commit_trans(osb, handle); -+bail_unlock: -+ ocfs2_inode_unlock(inode, 1); -+ brelse(bh); -+ return status; -+} -+ -+int ocfs2_set_inode_attr(struct inode *inode, unsigned flags, - unsigned mask) - { - struct ocfs2_inode_info *ocfs2_inode = OCFS2_I(inode); -@@ -67,6 +101,11 @@ static int ocfs2_set_inode_attr(struct i - if (!S_ISDIR(inode->i_mode)) - flags &= ~OCFS2_DIRSYNC_FL; - -+ if (IS_BARRIER(inode)) { -+ vxwprintk_task(1, "messing with the barrier."); -+ goto bail_unlock; -+ } -+ - handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS); - if (IS_ERR(handle)) { - status = PTR_ERR(handle); -@@ -108,6 +147,7 @@ bail: - return status; - } - -+ - long ocfs2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) - { - struct inode *inode = filp->f_path.dentry->d_inode; -diff -NurpP --minimal linux-2.6.32.1/fs/ocfs2/namei.c linux-2.6.32.1-vs2.3.0.36.27/fs/ocfs2/namei.c ---- linux-2.6.32.1/fs/ocfs2/namei.c 2009-12-03 20:02:53.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/ocfs2/namei.c 2009-12-03 20:04:56.000000000 +0100 -@@ -41,6 +41,7 @@ - #include - #include - #include -+#include - - #define MLOG_MASK_PREFIX ML_NAMEI - #include -@@ -481,6 +482,7 @@ static int ocfs2_mknod_locked(struct ocf - u64 fe_blkno = 0; - u16 suballoc_bit; - u16 feat; -+ tag_t tag; - - *new_fe_bh = NULL; - -@@ -524,8 +526,11 @@ static int ocfs2_mknod_locked(struct ocf - fe->i_blkno = cpu_to_le64(fe_blkno); - fe->i_suballoc_bit = cpu_to_le16(suballoc_bit); - fe->i_suballoc_slot = cpu_to_le16(inode_ac->ac_alloc_slot); -- fe->i_uid = cpu_to_le32(inode->i_uid); -- fe->i_gid = cpu_to_le32(inode->i_gid); -+ -+ tag = dx_current_fstag(osb->sb); -+ fe->i_uid = cpu_to_le32(TAGINO_UID(DX_TAG(inode), inode->i_uid, tag)); -+ fe->i_gid = cpu_to_le32(TAGINO_GID(DX_TAG(inode), inode->i_gid, tag)); -+ inode->i_tag = tag; - fe->i_mode = cpu_to_le16(inode->i_mode); - if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) - fe->id1.dev1.i_rdev = cpu_to_le64(huge_encode_dev(dev)); -diff -NurpP --minimal linux-2.6.32.1/fs/ocfs2/ocfs2_fs.h linux-2.6.32.1-vs2.3.0.36.27/fs/ocfs2/ocfs2_fs.h ---- linux-2.6.32.1/fs/ocfs2/ocfs2_fs.h 2009-12-03 20:02:53.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/ocfs2/ocfs2_fs.h 2009-12-03 20:04:56.000000000 +0100 -@@ -231,18 +231,23 @@ - #define OCFS2_HAS_REFCOUNT_FL (0x0010) - - /* Inode attributes, keep in sync with EXT2 */ --#define OCFS2_SECRM_FL (0x00000001) /* Secure deletion */ --#define OCFS2_UNRM_FL (0x00000002) /* Undelete */ --#define OCFS2_COMPR_FL (0x00000004) /* Compress file */ --#define OCFS2_SYNC_FL (0x00000008) /* Synchronous updates */ --#define OCFS2_IMMUTABLE_FL (0x00000010) /* Immutable file */ --#define OCFS2_APPEND_FL (0x00000020) /* writes to file may only append */ --#define OCFS2_NODUMP_FL (0x00000040) /* do not dump file */ --#define OCFS2_NOATIME_FL (0x00000080) /* do not update atime */ --#define OCFS2_DIRSYNC_FL (0x00010000) /* dirsync behaviour (directories only) */ -+#define OCFS2_SECRM_FL FS_SECRM_FL /* Secure deletion */ -+#define OCFS2_UNRM_FL FS_UNRM_FL /* Undelete */ -+#define OCFS2_COMPR_FL FS_COMPR_FL /* Compress file */ -+#define OCFS2_SYNC_FL FS_SYNC_FL /* Synchronous updates */ -+#define OCFS2_IMMUTABLE_FL FS_IMMUTABLE_FL /* Immutable file */ -+#define OCFS2_APPEND_FL FS_APPEND_FL /* writes to file may only append */ -+#define OCFS2_NODUMP_FL FS_NODUMP_FL /* do not dump file */ -+#define OCFS2_NOATIME_FL FS_NOATIME_FL /* do not update atime */ - --#define OCFS2_FL_VISIBLE (0x000100FF) /* User visible flags */ --#define OCFS2_FL_MODIFIABLE (0x000100FF) /* User modifiable flags */ -+#define OCFS2_DIRSYNC_FL FS_DIRSYNC_FL /* dirsync behaviour (directories only) */ -+#define OCFS2_IXUNLINK_FL FS_IXUNLINK_FL /* Immutable invert on unlink */ -+ -+#define OCFS2_BARRIER_FL FS_BARRIER_FL /* Barrier for chroot() */ -+#define OCFS2_COW_FL FS_COW_FL /* Copy on Write marker */ -+ -+#define OCFS2_FL_VISIBLE (0x010300FF) /* User visible flags */ -+#define OCFS2_FL_MODIFIABLE (0x010300FF) /* User modifiable flags */ - - /* - * Extent record flags (e_node.leaf.flags) -diff -NurpP --minimal linux-2.6.32.1/fs/ocfs2/ocfs2.h linux-2.6.32.1-vs2.3.0.36.27/fs/ocfs2/ocfs2.h ---- linux-2.6.32.1/fs/ocfs2/ocfs2.h 2009-12-03 20:02:53.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/ocfs2/ocfs2.h 2009-12-03 20:04:56.000000000 +0100 -@@ -248,6 +248,7 @@ enum ocfs2_mount_options - OCFS2_MOUNT_POSIX_ACL = 1 << 8, /* POSIX access control lists */ - OCFS2_MOUNT_USRQUOTA = 1 << 9, /* We support user quotas */ - OCFS2_MOUNT_GRPQUOTA = 1 << 10, /* We support group quotas */ -+ OCFS2_MOUNT_TAGGED = 1 << 11, /* use tagging */ - }; - - #define OCFS2_OSB_SOFT_RO 0x0001 -diff -NurpP --minimal linux-2.6.32.1/fs/ocfs2/super.c linux-2.6.32.1-vs2.3.0.36.27/fs/ocfs2/super.c ---- linux-2.6.32.1/fs/ocfs2/super.c 2009-12-03 20:02:53.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/ocfs2/super.c 2009-12-03 20:04:56.000000000 +0100 -@@ -173,6 +173,7 @@ enum { - Opt_noacl, - Opt_usrquota, - Opt_grpquota, -+ Opt_tag, Opt_notag, Opt_tagid, - Opt_err, - }; - -@@ -199,6 +200,9 @@ static const match_table_t tokens = { - {Opt_noacl, "noacl"}, - {Opt_usrquota, "usrquota"}, - {Opt_grpquota, "grpquota"}, -+ {Opt_tag, "tag"}, -+ {Opt_notag, "notag"}, -+ {Opt_tagid, "tagid=%u"}, - {Opt_err, NULL} - }; - -@@ -605,6 +609,13 @@ static int ocfs2_remount(struct super_bl - goto out; - } - -+ if ((osb->s_mount_opt & OCFS2_MOUNT_TAGGED) != -+ (parsed_options.mount_opt & OCFS2_MOUNT_TAGGED)) { -+ ret = -EINVAL; -+ mlog(ML_ERROR, "Cannot change tagging on remount\n"); -+ goto out; -+ } -+ - if ((osb->s_mount_opt & OCFS2_MOUNT_HB_LOCAL) != - (parsed_options.mount_opt & OCFS2_MOUNT_HB_LOCAL)) { - ret = -EINVAL; -@@ -1148,6 +1159,9 @@ static int ocfs2_fill_super(struct super - - ocfs2_complete_mount_recovery(osb); - -+ if (osb->s_mount_opt & OCFS2_MOUNT_TAGGED) -+ sb->s_flags |= MS_TAGGED; -+ - if (ocfs2_mount_local(osb)) - snprintf(nodestr, sizeof(nodestr), "local"); - else -@@ -1426,6 +1440,20 @@ static int ocfs2_parse_options(struct su - printk(KERN_INFO "ocfs2 (no)acl options not supported\n"); - break; - #endif -+#ifndef CONFIG_TAGGING_NONE -+ case Opt_tag: -+ mopt->mount_opt |= OCFS2_MOUNT_TAGGED; -+ break; -+ case Opt_notag: -+ mopt->mount_opt &= ~OCFS2_MOUNT_TAGGED; -+ break; -+#endif -+#ifdef CONFIG_PROPAGATE -+ case Opt_tagid: -+ /* use args[0] */ -+ mopt->mount_opt |= OCFS2_MOUNT_TAGGED; -+ break; -+#endif - default: - mlog(ML_ERROR, - "Unrecognized mount option \"%s\" " -diff -NurpP --minimal linux-2.6.32.1/fs/open.c linux-2.6.32.1-vs2.3.0.36.27/fs/open.c ---- linux-2.6.32.1/fs/open.c 2009-12-03 20:02:53.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/open.c 2009-12-03 20:04:56.000000000 +0100 -@@ -30,22 +30,30 @@ - #include - #include - #include -+#include -+#include -+#include -+#include - - int vfs_statfs(struct dentry *dentry, struct kstatfs *buf) - { - int retval = -ENODEV; - - if (dentry) { -+ struct super_block *sb = dentry->d_sb; -+ - retval = -ENOSYS; -- if (dentry->d_sb->s_op->statfs) { -+ if (sb->s_op->statfs) { - memset(buf, 0, sizeof(*buf)); - retval = security_sb_statfs(dentry); - if (retval) - return retval; -- retval = dentry->d_sb->s_op->statfs(dentry, buf); -+ retval = sb->s_op->statfs(dentry, buf); - if (retval == 0 && buf->f_frsize == 0) - buf->f_frsize = buf->f_bsize; - } -+ if (!vx_check(0, VS_ADMIN|VS_WATCH)) -+ vx_vsi_statfs(sb, buf); - } - return retval; - } -@@ -640,6 +648,10 @@ SYSCALL_DEFINE3(fchmodat, int, dfd, cons - error = user_path_at(dfd, filename, LOOKUP_FOLLOW, &path); - if (error) - goto out; -+ -+ error = cow_check_and_break(&path); -+ if (error) -+ goto dput_and_out; - inode = path.dentry->d_inode; - - error = mnt_want_write(path.mnt); -@@ -673,11 +685,11 @@ static int chown_common(struct dentry * - newattrs.ia_valid = ATTR_CTIME; - if (user != (uid_t) -1) { - newattrs.ia_valid |= ATTR_UID; -- newattrs.ia_uid = user; -+ newattrs.ia_uid = dx_map_uid(user); - } - if (group != (gid_t) -1) { - newattrs.ia_valid |= ATTR_GID; -- newattrs.ia_gid = group; -+ newattrs.ia_gid = dx_map_gid(group); - } - if (!S_ISDIR(inode->i_mode)) - newattrs.ia_valid |= -@@ -700,7 +712,11 @@ SYSCALL_DEFINE3(chown, const char __user - error = mnt_want_write(path.mnt); - if (error) - goto out_release; -- error = chown_common(path.dentry, user, group); -+#ifdef CONFIG_VSERVER_COWBL -+ error = cow_check_and_break(&path); -+ if (!error) -+#endif -+ error = chown_common(path.dentry, user, group); - mnt_drop_write(path.mnt); - out_release: - path_put(&path); -@@ -725,7 +741,11 @@ SYSCALL_DEFINE5(fchownat, int, dfd, cons - error = mnt_want_write(path.mnt); - if (error) - goto out_release; -- error = chown_common(path.dentry, user, group); -+#ifdef CONFIG_VSERVER_COWBL -+ error = cow_check_and_break(&path); -+ if (!error) -+#endif -+ error = chown_common(path.dentry, user, group); - mnt_drop_write(path.mnt); - out_release: - path_put(&path); -@@ -744,7 +764,11 @@ SYSCALL_DEFINE3(lchown, const char __use - error = mnt_want_write(path.mnt); - if (error) - goto out_release; -- error = chown_common(path.dentry, user, group); -+#ifdef CONFIG_VSERVER_COWBL -+ error = cow_check_and_break(&path); -+ if (!error) -+#endif -+ error = chown_common(path.dentry, user, group); - mnt_drop_write(path.mnt); - out_release: - path_put(&path); -@@ -990,6 +1014,7 @@ static void __put_unused_fd(struct files - __FD_CLR(fd, fdt->open_fds); - if (fd < files->next_fd) - files->next_fd = fd; -+ vx_openfd_dec(fd); - } - - void put_unused_fd(unsigned int fd) -diff -NurpP --minimal linux-2.6.32.1/fs/proc/array.c linux-2.6.32.1-vs2.3.0.36.27/fs/proc/array.c ---- linux-2.6.32.1/fs/proc/array.c 2009-12-03 20:02:53.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/proc/array.c 2009-12-03 20:04:56.000000000 +0100 -@@ -83,6 +83,8 @@ - #include - #include - #include -+#include -+#include - - #include - #include -@@ -139,8 +141,9 @@ static const char *task_state_array[] = - "D (disk sleep)", /* 2 */ - "T (stopped)", /* 4 */ - "T (tracing stop)", /* 8 */ -- "Z (zombie)", /* 16 */ -- "X (dead)" /* 32 */ -+ "H (on hold)", /* 16 */ -+ "Z (zombie)", /* 32 */ -+ "X (dead)", /* 64 */ - }; - - static inline const char *get_task_state(struct task_struct *tsk) -@@ -167,6 +170,9 @@ static inline void task_state(struct seq - rcu_read_lock(); - ppid = pid_alive(p) ? - task_tgid_nr_ns(rcu_dereference(p->real_parent), ns) : 0; -+ if (unlikely(vx_current_initpid(p->pid))) -+ ppid = 0; -+ - tpid = 0; - if (pid_alive(p)) { - struct task_struct *tracer = tracehook_tracer_task(p); -@@ -282,7 +288,7 @@ static inline void task_sig(struct seq_f - } - - static void render_cap_t(struct seq_file *m, const char *header, -- kernel_cap_t *a) -+ struct vx_info *vxi, kernel_cap_t *a) - { - unsigned __capi; - -@@ -307,10 +313,11 @@ static inline void task_cap(struct seq_f - cap_bset = cred->cap_bset; - rcu_read_unlock(); - -- render_cap_t(m, "CapInh:\t", &cap_inheritable); -- render_cap_t(m, "CapPrm:\t", &cap_permitted); -- render_cap_t(m, "CapEff:\t", &cap_effective); -- render_cap_t(m, "CapBnd:\t", &cap_bset); -+ /* FIXME: maybe move the p->vx_info masking to __task_cred() ? */ -+ render_cap_t(m, "CapInh:\t", p->vx_info, &cap_inheritable); -+ render_cap_t(m, "CapPrm:\t", p->vx_info, &cap_permitted); -+ render_cap_t(m, "CapEff:\t", p->vx_info, &cap_effective); -+ render_cap_t(m, "CapBnd:\t", p->vx_info, &cap_bset); - } - - static inline void task_context_switch_counts(struct seq_file *m, -@@ -410,6 +417,42 @@ static void task_show_stack_usage(struct - } - #endif /* CONFIG_MMU */ - -+int proc_pid_nsproxy(struct seq_file *m, struct pid_namespace *ns, -+ struct pid *pid, struct task_struct *task) -+{ -+ seq_printf(m, "Proxy:\t%p(%c)\n" -+ "Count:\t%u\n" -+ "uts:\t%p(%c)\n" -+ "ipc:\t%p(%c)\n" -+ "mnt:\t%p(%c)\n" -+ "pid:\t%p(%c)\n" -+ "net:\t%p(%c)\n", -+ task->nsproxy, -+ (task->nsproxy == init_task.nsproxy ? 'I' : '-'), -+ atomic_read(&task->nsproxy->count), -+ task->nsproxy->uts_ns, -+ (task->nsproxy->uts_ns == init_task.nsproxy->uts_ns ? 'I' : '-'), -+ task->nsproxy->ipc_ns, -+ (task->nsproxy->ipc_ns == init_task.nsproxy->ipc_ns ? 'I' : '-'), -+ task->nsproxy->mnt_ns, -+ (task->nsproxy->mnt_ns == init_task.nsproxy->mnt_ns ? 'I' : '-'), -+ task->nsproxy->pid_ns, -+ (task->nsproxy->pid_ns == init_task.nsproxy->pid_ns ? 'I' : '-'), -+ task->nsproxy->net_ns, -+ (task->nsproxy->net_ns == init_task.nsproxy->net_ns ? 'I' : '-')); -+ return 0; -+} -+ -+void task_vs_id(struct seq_file *m, struct task_struct *task) -+{ -+ if (task_vx_flags(task, VXF_HIDE_VINFO, 0)) -+ return; -+ -+ seq_printf(m, "VxID: %d\n", vx_task_xid(task)); -+ seq_printf(m, "NxID: %d\n", nx_task_nid(task)); -+} -+ -+ - int proc_pid_status(struct seq_file *m, struct pid_namespace *ns, - struct pid *pid, struct task_struct *task) - { -@@ -425,6 +468,7 @@ int proc_pid_status(struct seq_file *m, - task_sig(m, task); - task_cap(m, task); - cpuset_task_status_allowed(m, task); -+ task_vs_id(m, task); - #if defined(CONFIG_S390) - task_show_regs(m, task); - #endif -@@ -542,6 +586,17 @@ static int do_task_stat(struct seq_file - /* convert nsec -> ticks */ - start_time = nsec_to_clock_t(start_time); - -+ /* fixup start time for virt uptime */ -+ if (vx_flags(VXF_VIRT_UPTIME, 0)) { -+ unsigned long long bias = -+ current->vx_info->cvirt.bias_clock; -+ -+ if (start_time > bias) -+ start_time -= bias; -+ else -+ start_time = 0; -+ } -+ - seq_printf(m, "%d (%s) %c %d %d %d %d %d %u %lu \ - %lu %lu %lu %lu %lu %ld %ld %ld %ld %d 0 %llu %lu %ld %lu %lu %lu %lu %lu \ - %lu %lu %lu %lu %lu %lu %lu %lu %d %d %u %u %llu %lu %ld\n", -diff -NurpP --minimal linux-2.6.32.1/fs/proc/base.c linux-2.6.32.1-vs2.3.0.36.27/fs/proc/base.c ---- linux-2.6.32.1/fs/proc/base.c 2009-12-03 20:02:53.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/proc/base.c 2009-12-03 20:04:56.000000000 +0100 -@@ -81,6 +81,8 @@ - #include - #include - #include -+#include -+#include - #include "internal.h" - - /* NOTE: -@@ -1047,12 +1049,17 @@ static ssize_t oom_adjust_write(struct f - return -ESRCH; - } - -- if (oom_adjust < task->signal->oom_adj && !capable(CAP_SYS_RESOURCE)) { -+ if (oom_adjust < task->signal->oom_adj && -+ !vx_capable(CAP_SYS_RESOURCE, VXC_OOM_ADJUST)) { - unlock_task_sighand(task, &flags); - put_task_struct(task); - return -EACCES; - } - -+ /* prevent guest processes from circumventing the oom killer */ -+ if (vx_current_xid() && (oom_adjust == OOM_DISABLE)) -+ oom_adjust = OOM_ADJUST_MIN; -+ - task->signal->oom_adj = oom_adjust; - - unlock_task_sighand(task, &flags); -@@ -1092,7 +1099,7 @@ static ssize_t proc_loginuid_write(struc - ssize_t length; - uid_t loginuid; - -- if (!capable(CAP_AUDIT_CONTROL)) -+ if (!vx_capable(CAP_AUDIT_CONTROL, VXC_AUDIT_CONTROL)) - return -EPERM; - - if (current != pid_task(proc_pid(inode), PIDTYPE_PID)) -@@ -1458,6 +1465,8 @@ static struct inode *proc_pid_make_inode - inode->i_gid = cred->egid; - rcu_read_unlock(); - } -+ /* procfs is xid tagged */ -+ inode->i_tag = (tag_t)vx_task_xid(task); - security_task_to_inode(task, inode); - - out: -@@ -2008,6 +2017,13 @@ static struct dentry *proc_pident_lookup - if (!task) - goto out_no_task; - -+ /* TODO: maybe we can come up with a generic approach? */ -+ if (task_vx_flags(task, VXF_HIDE_VINFO, 0) && -+ (dentry->d_name.len == 5) && -+ (!memcmp(dentry->d_name.name, "vinfo", 5) || -+ !memcmp(dentry->d_name.name, "ninfo", 5))) -+ goto out; -+ - /* - * Yes, it does not scale. And it should not. Don't add - * new entries into /proc// without very good reasons. -@@ -2399,7 +2415,7 @@ out_iput: - static struct dentry *proc_base_lookup(struct inode *dir, struct dentry *dentry) - { - struct dentry *error; -- struct task_struct *task = get_proc_task(dir); -+ struct task_struct *task = get_proc_task_real(dir); - const struct pid_entry *p, *last; - - error = ERR_PTR(-ENOENT); -@@ -2489,6 +2505,9 @@ static int proc_pid_personality(struct s - static const struct file_operations proc_task_operations; - static const struct inode_operations proc_task_inode_operations; - -+extern int proc_pid_vx_info(struct task_struct *, char *); -+extern int proc_pid_nx_info(struct task_struct *, char *); -+ - static const struct pid_entry tgid_base_stuff[] = { - DIR("task", S_IRUGO|S_IXUGO, proc_task_inode_operations, proc_task_operations), - DIR("fd", S_IRUSR|S_IXUSR, proc_fd_inode_operations, proc_fd_operations), -@@ -2547,6 +2566,8 @@ static const struct pid_entry tgid_base_ - #ifdef CONFIG_CGROUPS - REG("cgroup", S_IRUGO, proc_cgroup_operations), - #endif -+ INF("vinfo", S_IRUGO, proc_pid_vx_info), -+ INF("ninfo", S_IRUGO, proc_pid_nx_info), - INF("oom_score", S_IRUGO, proc_oom_score), - REG("oom_adj", S_IRUGO|S_IWUSR, proc_oom_adjust_operations), - #ifdef CONFIG_AUDITSYSCALL -@@ -2562,6 +2583,7 @@ static const struct pid_entry tgid_base_ - #ifdef CONFIG_TASK_IO_ACCOUNTING - INF("io", S_IRUGO, proc_tgid_io_accounting), - #endif -+ ONE("nsproxy", S_IRUGO, proc_pid_nsproxy), - }; - - static int proc_tgid_base_readdir(struct file * filp, -@@ -2753,7 +2775,7 @@ retry: - iter.task = NULL; - pid = find_ge_pid(iter.tgid, ns); - if (pid) { -- iter.tgid = pid_nr_ns(pid, ns); -+ iter.tgid = pid_unmapped_nr_ns(pid, ns); - iter.task = pid_task(pid, PIDTYPE_PID); - /* What we to know is if the pid we have find is the - * pid of a thread_group_leader. Testing for task -@@ -2783,7 +2805,7 @@ static int proc_pid_fill_cache(struct fi - struct tgid_iter iter) - { - char name[PROC_NUMBUF]; -- int len = snprintf(name, sizeof(name), "%d", iter.tgid); -+ int len = snprintf(name, sizeof(name), "%d", vx_map_tgid(iter.tgid)); - return proc_fill_cache(filp, dirent, filldir, name, len, - proc_pid_instantiate, iter.task, NULL); - } -@@ -2792,7 +2814,7 @@ static int proc_pid_fill_cache(struct fi - int proc_pid_readdir(struct file * filp, void * dirent, filldir_t filldir) - { - unsigned int nr = filp->f_pos - FIRST_PROCESS_ENTRY; -- struct task_struct *reaper = get_proc_task(filp->f_path.dentry->d_inode); -+ struct task_struct *reaper = get_proc_task_real(filp->f_path.dentry->d_inode); - struct tgid_iter iter; - struct pid_namespace *ns; - -@@ -2812,6 +2834,8 @@ int proc_pid_readdir(struct file * filp, - iter.task; - iter.tgid += 1, iter = next_tgid(ns, iter)) { - filp->f_pos = iter.tgid + TGID_OFFSET; -+ if (!vx_proc_task_visible(iter.task)) -+ continue; - if (proc_pid_fill_cache(filp, dirent, filldir, iter) < 0) { - put_task_struct(iter.task); - goto out; -@@ -2958,6 +2982,8 @@ static struct dentry *proc_task_lookup(s - tid = name_to_int(dentry); - if (tid == ~0U) - goto out; -+ if (vx_current_initpid(tid)) -+ goto out; - - ns = dentry->d_sb->s_fs_info; - rcu_read_lock(); -diff -NurpP --minimal linux-2.6.32.1/fs/proc/generic.c linux-2.6.32.1-vs2.3.0.36.27/fs/proc/generic.c ---- linux-2.6.32.1/fs/proc/generic.c 2009-06-11 17:13:07.000000000 +0200 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/proc/generic.c 2009-12-03 20:04:56.000000000 +0100 -@@ -20,6 +20,7 @@ - #include - #include - #include -+#include - #include - - #include "internal.h" -@@ -425,6 +426,8 @@ struct dentry *proc_lookup_de(struct pro - for (de = de->subdir; de ; de = de->next) { - if (de->namelen != dentry->d_name.len) - continue; -+ if (!vx_hide_check(0, de->vx_flags)) -+ continue; - if (!memcmp(dentry->d_name.name, de->name, de->namelen)) { - unsigned int ino; - -@@ -433,6 +436,8 @@ struct dentry *proc_lookup_de(struct pro - spin_unlock(&proc_subdir_lock); - error = -EINVAL; - inode = proc_get_inode(dir->i_sb, ino, de); -+ /* generic proc entries belong to the host */ -+ inode->i_tag = 0; - goto out_unlock; - } - } -@@ -510,6 +515,8 @@ int proc_readdir_de(struct proc_dir_entr - - /* filldir passes info to user space */ - de_get(de); -+ if (!vx_hide_check(0, de->vx_flags)) -+ goto skip; - spin_unlock(&proc_subdir_lock); - if (filldir(dirent, de->name, de->namelen, filp->f_pos, - de->low_ino, de->mode >> 12) < 0) { -@@ -517,6 +524,7 @@ int proc_readdir_de(struct proc_dir_entr - goto out; - } - spin_lock(&proc_subdir_lock); -+ skip: - filp->f_pos++; - next = de->next; - de_put(de); -@@ -631,6 +639,7 @@ static struct proc_dir_entry *__proc_cre - ent->nlink = nlink; - atomic_set(&ent->count, 1); - ent->pde_users = 0; -+ ent->vx_flags = IATTR_PROC_DEFAULT; - spin_lock_init(&ent->pde_unload_lock); - ent->pde_unload_completion = NULL; - INIT_LIST_HEAD(&ent->pde_openers); -@@ -654,7 +663,8 @@ struct proc_dir_entry *proc_symlink(cons - kfree(ent->data); - kfree(ent); - ent = NULL; -- } -+ } else -+ ent->vx_flags = IATTR_PROC_SYMLINK; - } else { - kfree(ent); - ent = NULL; -diff -NurpP --minimal linux-2.6.32.1/fs/proc/inode.c linux-2.6.32.1-vs2.3.0.36.27/fs/proc/inode.c ---- linux-2.6.32.1/fs/proc/inode.c 2009-06-11 17:13:07.000000000 +0200 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/proc/inode.c 2009-12-03 20:04:56.000000000 +0100 -@@ -459,6 +459,8 @@ struct inode *proc_get_inode(struct supe - inode->i_uid = de->uid; - inode->i_gid = de->gid; - } -+ if (de->vx_flags) -+ PROC_I(inode)->vx_flags = de->vx_flags; - if (de->size) - inode->i_size = de->size; - if (de->nlink) -diff -NurpP --minimal linux-2.6.32.1/fs/proc/internal.h linux-2.6.32.1-vs2.3.0.36.27/fs/proc/internal.h ---- linux-2.6.32.1/fs/proc/internal.h 2009-09-10 15:26:23.000000000 +0200 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/proc/internal.h 2009-12-03 20:04:56.000000000 +0100 -@@ -10,6 +10,7 @@ - */ - - #include -+#include - - extern struct proc_dir_entry proc_root; - #ifdef CONFIG_PROC_SYSCTL -@@ -51,6 +52,9 @@ extern int proc_pid_status(struct seq_fi - struct pid *pid, struct task_struct *task); - extern int proc_pid_statm(struct seq_file *m, struct pid_namespace *ns, - struct pid *pid, struct task_struct *task); -+extern int proc_pid_nsproxy(struct seq_file *m, struct pid_namespace *ns, -+ struct pid *pid, struct task_struct *task); -+ - extern loff_t mem_lseek(struct file *file, loff_t offset, int orig); - - extern const struct file_operations proc_maps_operations; -@@ -70,11 +74,16 @@ static inline struct pid *proc_pid(struc - return PROC_I(inode)->pid; - } - --static inline struct task_struct *get_proc_task(struct inode *inode) -+static inline struct task_struct *get_proc_task_real(struct inode *inode) - { - return get_pid_task(proc_pid(inode), PIDTYPE_PID); - } - -+static inline struct task_struct *get_proc_task(struct inode *inode) -+{ -+ return vx_get_proc_task(inode, proc_pid(inode)); -+} -+ - static inline int proc_fd(struct inode *inode) - { - return PROC_I(inode)->fd; -diff -NurpP --minimal linux-2.6.32.1/fs/proc/loadavg.c linux-2.6.32.1-vs2.3.0.36.27/fs/proc/loadavg.c ---- linux-2.6.32.1/fs/proc/loadavg.c 2009-09-10 15:26:23.000000000 +0200 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/proc/loadavg.c 2009-12-03 20:04:56.000000000 +0100 -@@ -12,15 +12,27 @@ - - static int loadavg_proc_show(struct seq_file *m, void *v) - { -+ unsigned long running; -+ unsigned int threads; - unsigned long avnrun[3]; - - get_avenrun(avnrun, FIXED_1/200, 0); - -+ if (vx_flags(VXF_VIRT_LOAD, 0)) { -+ struct vx_info *vxi = current_vx_info(); -+ -+ running = atomic_read(&vxi->cvirt.nr_running); -+ threads = atomic_read(&vxi->cvirt.nr_threads); -+ } else { -+ running = nr_running(); -+ threads = nr_threads; -+ } -+ - seq_printf(m, "%lu.%02lu %lu.%02lu %lu.%02lu %ld/%d %d\n", - LOAD_INT(avnrun[0]), LOAD_FRAC(avnrun[0]), - LOAD_INT(avnrun[1]), LOAD_FRAC(avnrun[1]), - LOAD_INT(avnrun[2]), LOAD_FRAC(avnrun[2]), -- nr_running(), nr_threads, -+ running, threads, - task_active_pid_ns(current)->last_pid); - return 0; - } -diff -NurpP --minimal linux-2.6.32.1/fs/proc/meminfo.c linux-2.6.32.1-vs2.3.0.36.27/fs/proc/meminfo.c ---- linux-2.6.32.1/fs/proc/meminfo.c 2009-12-03 20:02:53.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/proc/meminfo.c 2009-12-03 20:04:56.000000000 +0100 -@@ -41,7 +41,7 @@ static int meminfo_proc_show(struct seq_ - - cached = global_page_state(NR_FILE_PAGES) - - total_swapcache_pages - i.bufferram; -- if (cached < 0) -+ if (cached < 0 || vx_flags(VXF_VIRT_MEM, 0)) - cached = 0; - - get_vmalloc_info(&vmi); -diff -NurpP --minimal linux-2.6.32.1/fs/proc/root.c linux-2.6.32.1-vs2.3.0.36.27/fs/proc/root.c ---- linux-2.6.32.1/fs/proc/root.c 2009-06-11 17:13:07.000000000 +0200 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/proc/root.c 2009-12-03 20:04:56.000000000 +0100 -@@ -18,9 +18,14 @@ - #include - #include - #include -+#include - - #include "internal.h" - -+struct proc_dir_entry *proc_virtual; -+ -+extern void proc_vx_init(void); -+ - static int proc_test_super(struct super_block *sb, void *data) - { - return sb->s_fs_info == data; -@@ -136,6 +141,7 @@ void __init proc_root_init(void) - #endif - proc_mkdir("bus", NULL); - proc_sys_init(); -+ proc_vx_init(); - } - - static int proc_root_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat -@@ -203,6 +209,7 @@ struct proc_dir_entry proc_root = { - .proc_iops = &proc_root_inode_operations, - .proc_fops = &proc_root_operations, - .parent = &proc_root, -+ .vx_flags = IATTR_ADMIN | IATTR_WATCH, - }; - - int pid_ns_prepare_proc(struct pid_namespace *ns) -diff -NurpP --minimal linux-2.6.32.1/fs/proc/uptime.c linux-2.6.32.1-vs2.3.0.36.27/fs/proc/uptime.c ---- linux-2.6.32.1/fs/proc/uptime.c 2009-12-03 20:02:53.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/proc/uptime.c 2009-12-03 20:04:56.000000000 +0100 -@@ -4,22 +4,22 @@ - #include - #include - #include --#include -+#include - #include - - static int uptime_proc_show(struct seq_file *m, void *v) - { - struct timespec uptime; - struct timespec idle; -- int i; -- cputime_t idletime = cputime_zero; -- -- for_each_possible_cpu(i) -- idletime = cputime64_add(idletime, kstat_cpu(i).cpustat.idle); -+ cputime_t idletime = cputime_add(init_task.utime, init_task.stime); - - do_posix_clock_monotonic_gettime(&uptime); - monotonic_to_bootbased(&uptime); - cputime_to_timespec(idletime, &idle); -+ -+ if (vx_flags(VXF_VIRT_UPTIME, 0)) -+ vx_vsi_uptime(&uptime, &idle); -+ - seq_printf(m, "%lu.%02lu %lu.%02lu\n", - (unsigned long) uptime.tv_sec, - (uptime.tv_nsec / (NSEC_PER_SEC / 100)), -diff -NurpP --minimal linux-2.6.32.1/fs/quota/quota.c linux-2.6.32.1-vs2.3.0.36.27/fs/quota/quota.c ---- linux-2.6.32.1/fs/quota/quota.c 2009-09-10 15:26:24.000000000 +0200 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/quota/quota.c 2009-12-03 20:04:56.000000000 +0100 -@@ -18,6 +18,7 @@ - #include - #include - #include -+#include - - /* Check validity of generic quotactl commands */ - static int generic_quotactl_valid(struct super_block *sb, int type, int cmd, -@@ -83,11 +84,11 @@ static int generic_quotactl_valid(struct - if (cmd == Q_GETQUOTA) { - if (((type == USRQUOTA && current_euid() != id) || - (type == GRPQUOTA && !in_egroup_p(id))) && -- !capable(CAP_SYS_ADMIN)) -+ !vx_capable(CAP_SYS_ADMIN, VXC_QUOTA_CTL)) - return -EPERM; - } - else if (cmd != Q_GETFMT && cmd != Q_SYNC && cmd != Q_GETINFO) -- if (!capable(CAP_SYS_ADMIN)) -+ if (!vx_capable(CAP_SYS_ADMIN, VXC_QUOTA_CTL)) - return -EPERM; - - return 0; -@@ -135,10 +136,10 @@ static int xqm_quotactl_valid(struct sup - if (cmd == Q_XGETQUOTA) { - if (((type == XQM_USRQUOTA && current_euid() != id) || - (type == XQM_GRPQUOTA && !in_egroup_p(id))) && -- !capable(CAP_SYS_ADMIN)) -+ !vx_capable(CAP_SYS_ADMIN, VXC_QUOTA_CTL)) - return -EPERM; - } else if (cmd != Q_XGETQSTAT && cmd != Q_XQUOTASYNC) { -- if (!capable(CAP_SYS_ADMIN)) -+ if (!vx_capable(CAP_SYS_ADMIN, VXC_QUOTA_CTL)) - return -EPERM; - } - -@@ -351,6 +352,46 @@ static int do_quotactl(struct super_bloc - return 0; - } - -+#if defined(CONFIG_BLK_DEV_VROOT) || defined(CONFIG_BLK_DEV_VROOT_MODULE) -+ -+#include -+#include -+#include -+#include -+#include -+ -+static vroot_grb_func *vroot_get_real_bdev = NULL; -+ -+static spinlock_t vroot_grb_lock = SPIN_LOCK_UNLOCKED; -+ -+int register_vroot_grb(vroot_grb_func *func) { -+ int ret = -EBUSY; -+ -+ spin_lock(&vroot_grb_lock); -+ if (!vroot_get_real_bdev) { -+ vroot_get_real_bdev = func; -+ ret = 0; -+ } -+ spin_unlock(&vroot_grb_lock); -+ return ret; -+} -+EXPORT_SYMBOL(register_vroot_grb); -+ -+int unregister_vroot_grb(vroot_grb_func *func) { -+ int ret = -EINVAL; -+ -+ spin_lock(&vroot_grb_lock); -+ if (vroot_get_real_bdev) { -+ vroot_get_real_bdev = NULL; -+ ret = 0; -+ } -+ spin_unlock(&vroot_grb_lock); -+ return ret; -+} -+EXPORT_SYMBOL(unregister_vroot_grb); -+ -+#endif -+ - /* - * look up a superblock on which quota ops will be performed - * - use the name of a block device to find the superblock thereon -@@ -368,6 +409,22 @@ static struct super_block *quotactl_bloc - putname(tmp); - if (IS_ERR(bdev)) - return ERR_CAST(bdev); -+#if defined(CONFIG_BLK_DEV_VROOT) || defined(CONFIG_BLK_DEV_VROOT_MODULE) -+ if (bdev && bdev->bd_inode && -+ imajor(bdev->bd_inode) == VROOT_MAJOR) { -+ struct block_device *bdnew = (void *)-EINVAL; -+ -+ if (vroot_get_real_bdev) -+ bdnew = vroot_get_real_bdev(bdev); -+ else -+ vxdprintk(VXD_CBIT(misc, 0), -+ "vroot_get_real_bdev not set"); -+ bdput(bdev); -+ if (IS_ERR(bdnew)) -+ return ERR_PTR(PTR_ERR(bdnew)); -+ bdev = bdnew; -+ } -+#endif - sb = get_super(bdev); - bdput(bdev); - if (!sb) -diff -NurpP --minimal linux-2.6.32.1/fs/reiserfs/file.c linux-2.6.32.1-vs2.3.0.36.27/fs/reiserfs/file.c ---- linux-2.6.32.1/fs/reiserfs/file.c 2009-06-11 17:13:08.000000000 +0200 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/reiserfs/file.c 2009-12-03 20:04:56.000000000 +0100 -@@ -307,4 +307,5 @@ const struct inode_operations reiserfs_f - .listxattr = reiserfs_listxattr, - .removexattr = reiserfs_removexattr, - .permission = reiserfs_permission, -+ .sync_flags = reiserfs_sync_flags, - }; -diff -NurpP --minimal linux-2.6.32.1/fs/reiserfs/inode.c linux-2.6.32.1-vs2.3.0.36.27/fs/reiserfs/inode.c ---- linux-2.6.32.1/fs/reiserfs/inode.c 2009-09-10 15:26:24.000000000 +0200 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/reiserfs/inode.c 2009-12-03 20:04:56.000000000 +0100 -@@ -18,6 +18,7 @@ - #include - #include - #include -+#include - - int reiserfs_commit_write(struct file *f, struct page *page, - unsigned from, unsigned to); -@@ -1117,6 +1118,8 @@ static void init_inode(struct inode *ino - struct buffer_head *bh; - struct item_head *ih; - __u32 rdev; -+ uid_t uid; -+ gid_t gid; - //int version = ITEM_VERSION_1; - - bh = PATH_PLAST_BUFFER(path); -@@ -1138,12 +1141,13 @@ static void init_inode(struct inode *ino - (struct stat_data_v1 *)B_I_PITEM(bh, ih); - unsigned long blocks; - -+ uid = sd_v1_uid(sd); -+ gid = sd_v1_gid(sd); -+ - set_inode_item_key_version(inode, KEY_FORMAT_3_5); - set_inode_sd_version(inode, STAT_DATA_V1); - inode->i_mode = sd_v1_mode(sd); - inode->i_nlink = sd_v1_nlink(sd); -- inode->i_uid = sd_v1_uid(sd); -- inode->i_gid = sd_v1_gid(sd); - inode->i_size = sd_v1_size(sd); - inode->i_atime.tv_sec = sd_v1_atime(sd); - inode->i_mtime.tv_sec = sd_v1_mtime(sd); -@@ -1185,11 +1189,12 @@ static void init_inode(struct inode *ino - // (directories and symlinks) - struct stat_data *sd = (struct stat_data *)B_I_PITEM(bh, ih); - -+ uid = sd_v2_uid(sd); -+ gid = sd_v2_gid(sd); -+ - inode->i_mode = sd_v2_mode(sd); - inode->i_nlink = sd_v2_nlink(sd); -- inode->i_uid = sd_v2_uid(sd); - inode->i_size = sd_v2_size(sd); -- inode->i_gid = sd_v2_gid(sd); - inode->i_mtime.tv_sec = sd_v2_mtime(sd); - inode->i_atime.tv_sec = sd_v2_atime(sd); - inode->i_ctime.tv_sec = sd_v2_ctime(sd); -@@ -1219,6 +1224,10 @@ static void init_inode(struct inode *ino - sd_attrs_to_i_attrs(sd_v2_attrs(sd), inode); - } - -+ inode->i_uid = INOTAG_UID(DX_TAG(inode), uid, gid); -+ inode->i_gid = INOTAG_GID(DX_TAG(inode), uid, gid); -+ inode->i_tag = INOTAG_TAG(DX_TAG(inode), uid, gid, 0); -+ - pathrelse(path); - if (S_ISREG(inode->i_mode)) { - inode->i_op = &reiserfs_file_inode_operations; -@@ -1241,13 +1250,15 @@ static void init_inode(struct inode *ino - static void inode2sd(void *sd, struct inode *inode, loff_t size) - { - struct stat_data *sd_v2 = (struct stat_data *)sd; -+ uid_t uid = TAGINO_UID(DX_TAG(inode), inode->i_uid, inode->i_tag); -+ gid_t gid = TAGINO_GID(DX_TAG(inode), inode->i_gid, inode->i_tag); - __u16 flags; - -+ set_sd_v2_uid(sd_v2, uid); -+ set_sd_v2_gid(sd_v2, gid); - set_sd_v2_mode(sd_v2, inode->i_mode); - set_sd_v2_nlink(sd_v2, inode->i_nlink); -- set_sd_v2_uid(sd_v2, inode->i_uid); - set_sd_v2_size(sd_v2, size); -- set_sd_v2_gid(sd_v2, inode->i_gid); - set_sd_v2_mtime(sd_v2, inode->i_mtime.tv_sec); - set_sd_v2_atime(sd_v2, inode->i_atime.tv_sec); - set_sd_v2_ctime(sd_v2, inode->i_ctime.tv_sec); -@@ -2828,14 +2839,19 @@ int reiserfs_commit_write(struct file *f - void sd_attrs_to_i_attrs(__u16 sd_attrs, struct inode *inode) - { - if (reiserfs_attrs(inode->i_sb)) { -- if (sd_attrs & REISERFS_SYNC_FL) -- inode->i_flags |= S_SYNC; -- else -- inode->i_flags &= ~S_SYNC; - if (sd_attrs & REISERFS_IMMUTABLE_FL) - inode->i_flags |= S_IMMUTABLE; - else - inode->i_flags &= ~S_IMMUTABLE; -+ if (sd_attrs & REISERFS_IXUNLINK_FL) -+ inode->i_flags |= S_IXUNLINK; -+ else -+ inode->i_flags &= ~S_IXUNLINK; -+ -+ if (sd_attrs & REISERFS_SYNC_FL) -+ inode->i_flags |= S_SYNC; -+ else -+ inode->i_flags &= ~S_SYNC; - if (sd_attrs & REISERFS_APPEND_FL) - inode->i_flags |= S_APPEND; - else -@@ -2848,6 +2864,15 @@ void sd_attrs_to_i_attrs(__u16 sd_attrs, - REISERFS_I(inode)->i_flags |= i_nopack_mask; - else - REISERFS_I(inode)->i_flags &= ~i_nopack_mask; -+ -+ if (sd_attrs & REISERFS_BARRIER_FL) -+ inode->i_vflags |= V_BARRIER; -+ else -+ inode->i_vflags &= ~V_BARRIER; -+ if (sd_attrs & REISERFS_COW_FL) -+ inode->i_vflags |= V_COW; -+ else -+ inode->i_vflags &= ~V_COW; - } - } - -@@ -2858,6 +2883,11 @@ void i_attrs_to_sd_attrs(struct inode *i - *sd_attrs |= REISERFS_IMMUTABLE_FL; - else - *sd_attrs &= ~REISERFS_IMMUTABLE_FL; -+ if (inode->i_flags & S_IXUNLINK) -+ *sd_attrs |= REISERFS_IXUNLINK_FL; -+ else -+ *sd_attrs &= ~REISERFS_IXUNLINK_FL; -+ - if (inode->i_flags & S_SYNC) - *sd_attrs |= REISERFS_SYNC_FL; - else -@@ -2870,6 +2900,15 @@ void i_attrs_to_sd_attrs(struct inode *i - *sd_attrs |= REISERFS_NOTAIL_FL; - else - *sd_attrs &= ~REISERFS_NOTAIL_FL; -+ -+ if (inode->i_vflags & V_BARRIER) -+ *sd_attrs |= REISERFS_BARRIER_FL; -+ else -+ *sd_attrs &= ~REISERFS_BARRIER_FL; -+ if (inode->i_vflags & V_COW) -+ *sd_attrs |= REISERFS_COW_FL; -+ else -+ *sd_attrs &= ~REISERFS_COW_FL; - } - } - -@@ -3090,9 +3129,11 @@ int reiserfs_setattr(struct dentry *dent - } - - error = inode_change_ok(inode, attr); -+ - if (!error) { - if ((ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid) || -- (ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid)) { -+ (ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid) || -+ (ia_valid & ATTR_TAG && attr->ia_tag != inode->i_tag)) { - error = reiserfs_chown_xattrs(inode, attr); - - if (!error) { -@@ -3122,6 +3163,9 @@ int reiserfs_setattr(struct dentry *dent - inode->i_uid = attr->ia_uid; - if (attr->ia_valid & ATTR_GID) - inode->i_gid = attr->ia_gid; -+ if ((attr->ia_valid & ATTR_TAG) && -+ IS_TAGGED(inode)) -+ inode->i_tag = attr->ia_tag; - mark_inode_dirty(inode); - error = - journal_end(&th, inode->i_sb, jbegin_count); -diff -NurpP --minimal linux-2.6.32.1/fs/reiserfs/ioctl.c linux-2.6.32.1-vs2.3.0.36.27/fs/reiserfs/ioctl.c ---- linux-2.6.32.1/fs/reiserfs/ioctl.c 2009-06-11 17:13:08.000000000 +0200 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/reiserfs/ioctl.c 2009-12-03 20:04:56.000000000 +0100 -@@ -7,11 +7,27 @@ - #include - #include - #include -+#include - #include - #include - #include - #include - -+ -+int reiserfs_sync_flags(struct inode *inode, int flags, int vflags) -+{ -+ __u16 sd_attrs = 0; -+ -+ inode->i_flags = flags; -+ inode->i_vflags = vflags; -+ -+ i_attrs_to_sd_attrs(inode, &sd_attrs); -+ REISERFS_I(inode)->i_attrs = sd_attrs; -+ inode->i_ctime = CURRENT_TIME_SEC; -+ mark_inode_dirty(inode); -+ return 0; -+} -+ - /* - ** reiserfs_ioctl - handler for ioctl for inode - ** supported commands: -@@ -23,7 +39,7 @@ - int reiserfs_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, - unsigned long arg) - { -- unsigned int flags; -+ unsigned int flags, oldflags; - int err = 0; - - switch (cmd) { -@@ -43,6 +59,7 @@ int reiserfs_ioctl(struct inode *inode, - - flags = REISERFS_I(inode)->i_attrs; - i_attrs_to_sd_attrs(inode, (__u16 *) & flags); -+ flags &= REISERFS_FL_USER_VISIBLE; - return put_user(flags, (int __user *)arg); - case REISERFS_IOC_SETFLAGS:{ - if (!reiserfs_attrs(inode->i_sb)) -@@ -60,6 +77,10 @@ int reiserfs_ioctl(struct inode *inode, - err = -EFAULT; - goto setflags_out; - } -+ if (IS_BARRIER(inode)) { -+ vxwprintk_task(1, "messing with the barrier."); -+ return -EACCES; -+ } - /* - * Is it quota file? Do not allow user to mess with it - */ -@@ -84,6 +105,10 @@ int reiserfs_ioctl(struct inode *inode, - goto setflags_out; - } - } -+ -+ oldflags = REISERFS_I(inode)->i_attrs; -+ flags &= REISERFS_FL_USER_MODIFIABLE; -+ flags |= oldflags & ~REISERFS_FL_USER_MODIFIABLE; - sd_attrs_to_i_attrs(flags, inode); - REISERFS_I(inode)->i_attrs = flags; - inode->i_ctime = CURRENT_TIME_SEC; -diff -NurpP --minimal linux-2.6.32.1/fs/reiserfs/namei.c linux-2.6.32.1-vs2.3.0.36.27/fs/reiserfs/namei.c ---- linux-2.6.32.1/fs/reiserfs/namei.c 2009-06-11 17:13:08.000000000 +0200 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/reiserfs/namei.c 2009-12-03 20:04:56.000000000 +0100 -@@ -17,6 +17,7 @@ - #include - #include - #include -+#include - - #define INC_DIR_INODE_NLINK(i) if (i->i_nlink != 1) { inc_nlink(i); if (i->i_nlink >= REISERFS_LINK_MAX) i->i_nlink=1; } - #define DEC_DIR_INODE_NLINK(i) if (i->i_nlink != 1) drop_nlink(i); -@@ -354,6 +355,7 @@ static struct dentry *reiserfs_lookup(st - if (retval == IO_ERROR) { - return ERR_PTR(-EIO); - } -+ dx_propagate_tag(nd, inode); - - return d_splice_alias(inode, dentry); - } -@@ -570,6 +572,7 @@ static int new_inode_init(struct inode * - } else { - inode->i_gid = current_fsgid(); - } -+ inode->i_tag = dx_current_fstag(inode->i_sb); - vfs_dq_init(inode); - return 0; - } -@@ -1515,6 +1518,7 @@ const struct inode_operations reiserfs_d - .listxattr = reiserfs_listxattr, - .removexattr = reiserfs_removexattr, - .permission = reiserfs_permission, -+ .sync_flags = reiserfs_sync_flags, - }; - - /* -diff -NurpP --minimal linux-2.6.32.1/fs/reiserfs/super.c linux-2.6.32.1-vs2.3.0.36.27/fs/reiserfs/super.c ---- linux-2.6.32.1/fs/reiserfs/super.c 2009-12-03 20:02:53.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/reiserfs/super.c 2009-12-03 20:04:56.000000000 +0100 -@@ -884,6 +884,14 @@ static int reiserfs_parse_options(struct - {"user_xattr",.setmask = 1 << REISERFS_UNSUPPORTED_OPT}, - {"nouser_xattr",.clrmask = 1 << REISERFS_UNSUPPORTED_OPT}, - #endif -+#ifndef CONFIG_TAGGING_NONE -+ {"tagxid",.setmask = 1 << REISERFS_TAGGED}, -+ {"tag",.setmask = 1 << REISERFS_TAGGED}, -+ {"notag",.clrmask = 1 << REISERFS_TAGGED}, -+#endif -+#ifdef CONFIG_PROPAGATE -+ {"tag",.arg_required = 'T',.values = NULL}, -+#endif - #ifdef CONFIG_REISERFS_FS_POSIX_ACL - {"acl",.setmask = 1 << REISERFS_POSIXACL}, - {"noacl",.clrmask = 1 << REISERFS_POSIXACL}, -@@ -1190,6 +1198,14 @@ static int reiserfs_remount(struct super - handle_quota_files(s, qf_names, &qfmt); - #endif - -+ if ((mount_options & (1 << REISERFS_TAGGED)) && -+ !(s->s_flags & MS_TAGGED)) { -+ reiserfs_warning(s, "super-vs01", -+ "reiserfs: tagging not permitted on remount."); -+ err = -EINVAL; -+ goto out_err; -+ } -+ - handle_attrs(s); - - /* Add options that are safe here */ -@@ -1652,6 +1668,10 @@ static int reiserfs_fill_super(struct su - goto error; - } - -+ /* map mount option tagxid */ -+ if (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_TAGGED)) -+ s->s_flags |= MS_TAGGED; -+ - rs = SB_DISK_SUPER_BLOCK(s); - /* Let's do basic sanity check to verify that underlying device is not - smaller than the filesystem. If the check fails then abort and scream, -diff -NurpP --minimal linux-2.6.32.1/fs/reiserfs/xattr.c linux-2.6.32.1-vs2.3.0.36.27/fs/reiserfs/xattr.c ---- linux-2.6.32.1/fs/reiserfs/xattr.c 2009-09-10 15:26:24.000000000 +0200 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/reiserfs/xattr.c 2009-12-03 20:04:56.000000000 +0100 -@@ -39,6 +39,7 @@ - #include - #include - #include -+#include - #include - #include - #include -diff -NurpP --minimal linux-2.6.32.1/fs/stat.c linux-2.6.32.1-vs2.3.0.36.27/fs/stat.c ---- linux-2.6.32.1/fs/stat.c 2009-06-11 17:13:08.000000000 +0200 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/stat.c 2009-12-03 20:04:56.000000000 +0100 -@@ -26,6 +26,7 @@ void generic_fillattr(struct inode *inod - stat->nlink = inode->i_nlink; - stat->uid = inode->i_uid; - stat->gid = inode->i_gid; -+ stat->tag = inode->i_tag; - stat->rdev = inode->i_rdev; - stat->atime = inode->i_atime; - stat->mtime = inode->i_mtime; -diff -NurpP --minimal linux-2.6.32.1/fs/super.c linux-2.6.32.1-vs2.3.0.36.27/fs/super.c ---- linux-2.6.32.1/fs/super.c 2009-12-03 20:02:53.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/super.c 2009-12-03 20:04:56.000000000 +0100 -@@ -37,6 +37,9 @@ - #include - #include - #include -+#include -+#include -+#include - #include - #include "internal.h" - -@@ -913,12 +916,18 @@ struct vfsmount * - vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void *data) - { - struct vfsmount *mnt; -+ struct super_block *sb; - char *secdata = NULL; - int error; - - if (!type) - return ERR_PTR(-ENODEV); - -+ error = -EPERM; -+ if ((type->fs_flags & FS_BINARY_MOUNTDATA) && -+ !vx_capable(CAP_SYS_ADMIN, VXC_BINARY_MOUNT)) -+ goto out; -+ - error = -ENOMEM; - mnt = alloc_vfsmnt(name); - if (!mnt) -@@ -937,9 +946,17 @@ vfs_kern_mount(struct file_system_type * - error = type->get_sb(type, flags, name, data, mnt); - if (error < 0) - goto out_free_secdata; -- BUG_ON(!mnt->mnt_sb); - -- error = security_sb_kern_mount(mnt->mnt_sb, flags, secdata); -+ sb = mnt->mnt_sb; -+ BUG_ON(!sb); -+ -+ error = -EPERM; -+ if (!vx_capable(CAP_SYS_ADMIN, VXC_BINARY_MOUNT) && !sb->s_bdev && -+ (sb->s_magic != PROC_SUPER_MAGIC) && -+ (sb->s_magic != DEVPTS_SUPER_MAGIC)) -+ goto out_sb; -+ -+ error = security_sb_kern_mount(sb, flags, secdata); - if (error) - goto out_sb; - -diff -NurpP --minimal linux-2.6.32.1/fs/sysfs/mount.c linux-2.6.32.1-vs2.3.0.36.27/fs/sysfs/mount.c ---- linux-2.6.32.1/fs/sysfs/mount.c 2009-06-11 17:13:08.000000000 +0200 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/sysfs/mount.c 2009-12-03 20:04:56.000000000 +0100 -@@ -47,7 +47,7 @@ static int sysfs_fill_super(struct super - - sb->s_blocksize = PAGE_CACHE_SIZE; - sb->s_blocksize_bits = PAGE_CACHE_SHIFT; -- sb->s_magic = SYSFS_MAGIC; -+ sb->s_magic = SYSFS_SUPER_MAGIC; - sb->s_op = &sysfs_ops; - sb->s_time_gran = 1; - sysfs_sb = sb; -diff -NurpP --minimal linux-2.6.32.1/fs/utimes.c linux-2.6.32.1-vs2.3.0.36.27/fs/utimes.c ---- linux-2.6.32.1/fs/utimes.c 2009-03-24 14:22:37.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/utimes.c 2009-12-03 20:04:56.000000000 +0100 -@@ -8,6 +8,8 @@ - #include - #include - #include -+#include -+#include - #include - #include - -diff -NurpP --minimal linux-2.6.32.1/fs/xattr.c linux-2.6.32.1-vs2.3.0.36.27/fs/xattr.c ---- linux-2.6.32.1/fs/xattr.c 2009-12-03 20:02:53.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/xattr.c 2009-12-03 20:04:56.000000000 +0100 -@@ -18,6 +18,7 @@ - #include - #include - #include -+#include - #include - - -diff -NurpP --minimal linux-2.6.32.1/fs/xfs/linux-2.6/xfs_ioctl.c linux-2.6.32.1-vs2.3.0.36.27/fs/xfs/linux-2.6/xfs_ioctl.c ---- linux-2.6.32.1/fs/xfs/linux-2.6/xfs_ioctl.c 2009-09-10 15:26:24.000000000 +0200 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/xfs/linux-2.6/xfs_ioctl.c 2009-12-03 20:04:56.000000000 +0100 -@@ -34,7 +34,6 @@ - #include "xfs_dir2_sf.h" - #include "xfs_dinode.h" - #include "xfs_inode.h" --#include "xfs_ioctl.h" - #include "xfs_btree.h" - #include "xfs_ialloc.h" - #include "xfs_rtalloc.h" -@@ -742,6 +741,10 @@ xfs_merge_ioc_xflags( - xflags |= XFS_XFLAG_IMMUTABLE; - else - xflags &= ~XFS_XFLAG_IMMUTABLE; -+ if (flags & FS_IXUNLINK_FL) -+ xflags |= XFS_XFLAG_IXUNLINK; -+ else -+ xflags &= ~XFS_XFLAG_IXUNLINK; - if (flags & FS_APPEND_FL) - xflags |= XFS_XFLAG_APPEND; - else -@@ -770,6 +773,8 @@ xfs_di2lxflags( - - if (di_flags & XFS_DIFLAG_IMMUTABLE) - flags |= FS_IMMUTABLE_FL; -+ if (di_flags & XFS_DIFLAG_IXUNLINK) -+ flags |= FS_IXUNLINK_FL; - if (di_flags & XFS_DIFLAG_APPEND) - flags |= FS_APPEND_FL; - if (di_flags & XFS_DIFLAG_SYNC) -@@ -828,6 +833,8 @@ xfs_set_diflags( - di_flags = (ip->i_d.di_flags & XFS_DIFLAG_PREALLOC); - if (xflags & XFS_XFLAG_IMMUTABLE) - di_flags |= XFS_DIFLAG_IMMUTABLE; -+ if (xflags & XFS_XFLAG_IXUNLINK) -+ di_flags |= XFS_DIFLAG_IXUNLINK; - if (xflags & XFS_XFLAG_APPEND) - di_flags |= XFS_DIFLAG_APPEND; - if (xflags & XFS_XFLAG_SYNC) -@@ -870,6 +877,10 @@ xfs_diflags_to_linux( - inode->i_flags |= S_IMMUTABLE; - else - inode->i_flags &= ~S_IMMUTABLE; -+ if (xflags & XFS_XFLAG_IXUNLINK) -+ inode->i_flags |= S_IXUNLINK; -+ else -+ inode->i_flags &= ~S_IXUNLINK; - if (xflags & XFS_XFLAG_APPEND) - inode->i_flags |= S_APPEND; - else -@@ -1346,10 +1357,18 @@ xfs_file_ioctl( - case XFS_IOC_FSGETXATTRA: - return xfs_ioc_fsgetxattr(ip, 1, arg); - case XFS_IOC_FSSETXATTR: -+ if (IS_BARRIER(inode)) { -+ vxwprintk_task(1, "messing with the barrier."); -+ return -XFS_ERROR(EACCES); -+ } - return xfs_ioc_fssetxattr(ip, filp, arg); - case XFS_IOC_GETXFLAGS: - return xfs_ioc_getxflags(ip, arg); - case XFS_IOC_SETXFLAGS: -+ if (IS_BARRIER(inode)) { -+ vxwprintk_task(1, "messing with the barrier."); -+ return -XFS_ERROR(EACCES); -+ } - return xfs_ioc_setxflags(ip, filp, arg); - - case XFS_IOC_FSSETDM: { -diff -NurpP --minimal linux-2.6.32.1/fs/xfs/linux-2.6/xfs_ioctl.h linux-2.6.32.1-vs2.3.0.36.27/fs/xfs/linux-2.6/xfs_ioctl.h ---- linux-2.6.32.1/fs/xfs/linux-2.6/xfs_ioctl.h 2009-03-24 14:22:37.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/xfs/linux-2.6/xfs_ioctl.h 2009-12-03 20:04:56.000000000 +0100 -@@ -70,6 +70,12 @@ xfs_handle_to_dentry( - void __user *uhandle, - u32 hlen); - -+extern int -+xfs_sync_flags( -+ struct inode *inode, -+ int flags, -+ int vflags); -+ - extern long - xfs_file_ioctl( - struct file *filp, -diff -NurpP --minimal linux-2.6.32.1/fs/xfs/linux-2.6/xfs_iops.c linux-2.6.32.1-vs2.3.0.36.27/fs/xfs/linux-2.6/xfs_iops.c ---- linux-2.6.32.1/fs/xfs/linux-2.6/xfs_iops.c 2009-12-03 20:02:53.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/xfs/linux-2.6/xfs_iops.c 2009-12-03 20:04:56.000000000 +0100 -@@ -36,6 +36,7 @@ - #include "xfs_attr_sf.h" - #include "xfs_dinode.h" - #include "xfs_inode.h" -+#include "xfs_ioctl.h" - #include "xfs_bmap.h" - #include "xfs_btree.h" - #include "xfs_ialloc.h" -@@ -55,6 +56,7 @@ - #include - #include - #include -+#include - - /* - * Bring the timestamps in the XFS inode uptodate. -@@ -495,6 +497,7 @@ xfs_vn_getattr( - stat->nlink = ip->i_d.di_nlink; - stat->uid = ip->i_d.di_uid; - stat->gid = ip->i_d.di_gid; -+ stat->tag = ip->i_d.di_tag; - stat->ino = ip->i_ino; - stat->atime = inode->i_atime; - stat->mtime = inode->i_mtime; -@@ -686,6 +689,7 @@ static const struct inode_operations xfs - .listxattr = xfs_vn_listxattr, - .fallocate = xfs_vn_fallocate, - .fiemap = xfs_vn_fiemap, -+ .sync_flags = xfs_sync_flags, - }; - - static const struct inode_operations xfs_dir_inode_operations = { -@@ -711,6 +715,7 @@ static const struct inode_operations xfs - .getxattr = generic_getxattr, - .removexattr = generic_removexattr, - .listxattr = xfs_vn_listxattr, -+ .sync_flags = xfs_sync_flags, - }; - - static const struct inode_operations xfs_dir_ci_inode_operations = { -@@ -760,6 +765,10 @@ xfs_diflags_to_iflags( - inode->i_flags |= S_IMMUTABLE; - else - inode->i_flags &= ~S_IMMUTABLE; -+ if (ip->i_d.di_flags & XFS_DIFLAG_IXUNLINK) -+ inode->i_flags |= S_IXUNLINK; -+ else -+ inode->i_flags &= ~S_IXUNLINK; - if (ip->i_d.di_flags & XFS_DIFLAG_APPEND) - inode->i_flags |= S_APPEND; - else -@@ -772,6 +781,15 @@ xfs_diflags_to_iflags( - inode->i_flags |= S_NOATIME; - else - inode->i_flags &= ~S_NOATIME; -+ -+ if (ip->i_d.di_vflags & XFS_DIVFLAG_BARRIER) -+ inode->i_vflags |= V_BARRIER; -+ else -+ inode->i_vflags &= ~V_BARRIER; -+ if (ip->i_d.di_vflags & XFS_DIVFLAG_COW) -+ inode->i_vflags |= V_COW; -+ else -+ inode->i_vflags &= ~V_COW; - } - - /* -@@ -800,6 +818,7 @@ xfs_setup_inode( - inode->i_nlink = ip->i_d.di_nlink; - inode->i_uid = ip->i_d.di_uid; - inode->i_gid = ip->i_d.di_gid; -+ inode->i_tag = ip->i_d.di_tag; - - switch (inode->i_mode & S_IFMT) { - case S_IFBLK: -diff -NurpP --minimal linux-2.6.32.1/fs/xfs/linux-2.6/xfs_linux.h linux-2.6.32.1-vs2.3.0.36.27/fs/xfs/linux-2.6/xfs_linux.h ---- linux-2.6.32.1/fs/xfs/linux-2.6/xfs_linux.h 2009-09-10 15:26:24.000000000 +0200 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/xfs/linux-2.6/xfs_linux.h 2009-12-03 20:04:56.000000000 +0100 -@@ -119,6 +119,7 @@ - - #define current_cpu() (raw_smp_processor_id()) - #define current_pid() (current->pid) -+#define current_fstag(cred,vp) (dx_current_fstag((vp)->i_sb)) - #define current_test_flags(f) (current->flags & (f)) - #define current_set_flags_nested(sp, f) \ - (*(sp) = current->flags, current->flags |= (f)) -diff -NurpP --minimal linux-2.6.32.1/fs/xfs/linux-2.6/xfs_super.c linux-2.6.32.1-vs2.3.0.36.27/fs/xfs/linux-2.6/xfs_super.c ---- linux-2.6.32.1/fs/xfs/linux-2.6/xfs_super.c 2009-12-03 20:02:53.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/xfs/linux-2.6/xfs_super.c 2009-12-03 20:04:56.000000000 +0100 -@@ -117,6 +117,9 @@ mempool_t *xfs_ioend_pool; - #define MNTOPT_DMAPI "dmapi" /* DMI enabled (DMAPI / XDSM) */ - #define MNTOPT_XDSM "xdsm" /* DMI enabled (DMAPI / XDSM) */ - #define MNTOPT_DMI "dmi" /* DMI enabled (DMAPI / XDSM) */ -+#define MNTOPT_TAGXID "tagxid" /* context tagging for inodes */ -+#define MNTOPT_TAGGED "tag" /* context tagging for inodes */ -+#define MNTOPT_NOTAGTAG "notag" /* do not use context tagging */ - - /* - * Table driven mount option parser. -@@ -125,10 +128,14 @@ mempool_t *xfs_ioend_pool; - * in the future, too. - */ - enum { -+ Opt_tag, Opt_notag, - Opt_barrier, Opt_nobarrier, Opt_err - }; - - static const match_table_t tokens = { -+ {Opt_tag, "tagxid"}, -+ {Opt_tag, "tag"}, -+ {Opt_notag, "notag"}, - {Opt_barrier, "barrier"}, - {Opt_nobarrier, "nobarrier"}, - {Opt_err, NULL} -@@ -382,6 +389,19 @@ xfs_parseargs( - } else if (!strcmp(this_char, "irixsgid")) { - cmn_err(CE_WARN, - "XFS: irixsgid is now a sysctl(2) variable, option is deprecated."); -+#ifndef CONFIG_TAGGING_NONE -+ } else if (!strcmp(this_char, MNTOPT_TAGGED)) { -+ mp->m_flags |= XFS_MOUNT_TAGGED; -+ } else if (!strcmp(this_char, MNTOPT_NOTAGTAG)) { -+ mp->m_flags &= ~XFS_MOUNT_TAGGED; -+ } else if (!strcmp(this_char, MNTOPT_TAGXID)) { -+ mp->m_flags |= XFS_MOUNT_TAGGED; -+#endif -+#ifdef CONFIG_PROPAGATE -+ } else if (!strcmp(this_char, MNTOPT_TAGGED)) { -+ /* use value */ -+ mp->m_flags |= XFS_MOUNT_TAGGED; -+#endif - } else { - cmn_err(CE_WARN, - "XFS: unknown mount option [%s].", this_char); -@@ -1270,6 +1290,16 @@ xfs_fs_remount( - case Opt_nobarrier: - mp->m_flags &= ~XFS_MOUNT_BARRIER; - break; -+ case Opt_tag: -+ if (!(sb->s_flags & MS_TAGGED)) { -+ printk(KERN_INFO -+ "XFS: %s: tagging not permitted on remount.\n", -+ sb->s_id); -+ return -EINVAL; -+ } -+ break; -+ case Opt_notag: -+ break; - default: - /* - * Logically we would return an error here to prevent -@@ -1477,6 +1507,9 @@ xfs_fs_fill_super( - - XFS_SEND_MOUNT(mp, DM_RIGHT_NULL, mtpt, mp->m_fsname); - -+ if (mp->m_flags & XFS_MOUNT_TAGGED) -+ sb->s_flags |= MS_TAGGED; -+ - sb->s_magic = XFS_SB_MAGIC; - sb->s_blocksize = mp->m_sb.sb_blocksize; - sb->s_blocksize_bits = ffs(sb->s_blocksize) - 1; -diff -NurpP --minimal linux-2.6.32.1/fs/xfs/xfs_dinode.h linux-2.6.32.1-vs2.3.0.36.27/fs/xfs/xfs_dinode.h ---- linux-2.6.32.1/fs/xfs/xfs_dinode.h 2009-06-11 17:13:09.000000000 +0200 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/xfs/xfs_dinode.h 2009-12-03 20:04:56.000000000 +0100 -@@ -50,7 +50,9 @@ typedef struct xfs_dinode { - __be32 di_gid; /* owner's group id */ - __be32 di_nlink; /* number of links to file */ - __be16 di_projid; /* owner's project id */ -- __u8 di_pad[8]; /* unused, zeroed space */ -+ __be16 di_tag; /* context tagging */ -+ __be16 di_vflags; /* vserver specific flags */ -+ __u8 di_pad[4]; /* unused, zeroed space */ - __be16 di_flushiter; /* incremented on flush */ - xfs_timestamp_t di_atime; /* time last accessed */ - xfs_timestamp_t di_mtime; /* time last modified */ -@@ -183,6 +185,8 @@ static inline void xfs_dinode_put_rdev(s - #define XFS_DIFLAG_EXTSZINHERIT_BIT 12 /* inherit inode extent size */ - #define XFS_DIFLAG_NODEFRAG_BIT 13 /* do not reorganize/defragment */ - #define XFS_DIFLAG_FILESTREAM_BIT 14 /* use filestream allocator */ -+#define XFS_DIFLAG_IXUNLINK_BIT 15 /* Immutable inver on unlink */ -+ - #define XFS_DIFLAG_REALTIME (1 << XFS_DIFLAG_REALTIME_BIT) - #define XFS_DIFLAG_PREALLOC (1 << XFS_DIFLAG_PREALLOC_BIT) - #define XFS_DIFLAG_NEWRTBM (1 << XFS_DIFLAG_NEWRTBM_BIT) -@@ -198,6 +202,7 @@ static inline void xfs_dinode_put_rdev(s - #define XFS_DIFLAG_EXTSZINHERIT (1 << XFS_DIFLAG_EXTSZINHERIT_BIT) - #define XFS_DIFLAG_NODEFRAG (1 << XFS_DIFLAG_NODEFRAG_BIT) - #define XFS_DIFLAG_FILESTREAM (1 << XFS_DIFLAG_FILESTREAM_BIT) -+#define XFS_DIFLAG_IXUNLINK (1 << XFS_DIFLAG_IXUNLINK_BIT) - - #ifdef CONFIG_XFS_RT - #define XFS_IS_REALTIME_INODE(ip) ((ip)->i_d.di_flags & XFS_DIFLAG_REALTIME) -@@ -210,6 +215,10 @@ static inline void xfs_dinode_put_rdev(s - XFS_DIFLAG_IMMUTABLE | XFS_DIFLAG_APPEND | XFS_DIFLAG_SYNC | \ - XFS_DIFLAG_NOATIME | XFS_DIFLAG_NODUMP | XFS_DIFLAG_RTINHERIT | \ - XFS_DIFLAG_PROJINHERIT | XFS_DIFLAG_NOSYMLINKS | XFS_DIFLAG_EXTSIZE | \ -- XFS_DIFLAG_EXTSZINHERIT | XFS_DIFLAG_NODEFRAG | XFS_DIFLAG_FILESTREAM) -+ XFS_DIFLAG_EXTSZINHERIT | XFS_DIFLAG_NODEFRAG | XFS_DIFLAG_FILESTREAM | \ -+ XFS_DIFLAG_IXUNLINK) -+ -+#define XFS_DIVFLAG_BARRIER 0x01 -+#define XFS_DIVFLAG_COW 0x02 - - #endif /* __XFS_DINODE_H__ */ -diff -NurpP --minimal linux-2.6.32.1/fs/xfs/xfs_fs.h linux-2.6.32.1-vs2.3.0.36.27/fs/xfs/xfs_fs.h ---- linux-2.6.32.1/fs/xfs/xfs_fs.h 2009-12-03 20:02:53.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/xfs/xfs_fs.h 2009-12-03 20:04:56.000000000 +0100 -@@ -67,6 +67,9 @@ struct fsxattr { - #define XFS_XFLAG_EXTSZINHERIT 0x00001000 /* inherit inode extent size */ - #define XFS_XFLAG_NODEFRAG 0x00002000 /* do not defragment */ - #define XFS_XFLAG_FILESTREAM 0x00004000 /* use filestream allocator */ -+#define XFS_XFLAG_IXUNLINK 0x00008000 /* immutable invert on unlink */ -+#define XFS_XFLAG_BARRIER 0x10000000 /* chroot() barrier */ -+#define XFS_XFLAG_COW 0x20000000 /* copy on write mark */ - #define XFS_XFLAG_HASATTR 0x80000000 /* no DIFLAG for this */ - - /* -@@ -292,7 +295,8 @@ typedef struct xfs_bstat { - __s32 bs_extents; /* number of extents */ - __u32 bs_gen; /* generation count */ - __u16 bs_projid; /* project id */ -- unsigned char bs_pad[14]; /* pad space, unused */ -+ __u16 bs_tag; /* context tagging */ -+ unsigned char bs_pad[12]; /* pad space, unused */ - __u32 bs_dmevmask; /* DMIG event mask */ - __u16 bs_dmstate; /* DMIG state info */ - __u16 bs_aextents; /* attribute number of extents */ -diff -NurpP --minimal linux-2.6.32.1/fs/xfs/xfs_ialloc.c linux-2.6.32.1-vs2.3.0.36.27/fs/xfs/xfs_ialloc.c ---- linux-2.6.32.1/fs/xfs/xfs_ialloc.c 2009-12-03 20:02:53.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/xfs/xfs_ialloc.c 2009-12-03 20:04:56.000000000 +0100 -@@ -41,7 +41,6 @@ - #include "xfs_error.h" - #include "xfs_bmap.h" - -- - /* - * Allocation group level functions. - */ -diff -NurpP --minimal linux-2.6.32.1/fs/xfs/xfs_inode.c linux-2.6.32.1-vs2.3.0.36.27/fs/xfs/xfs_inode.c ---- linux-2.6.32.1/fs/xfs/xfs_inode.c 2009-12-03 20:02:54.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/xfs/xfs_inode.c 2009-12-03 20:04:56.000000000 +0100 -@@ -249,6 +249,7 @@ xfs_inotobp( - return 0; - } - -+#include - - /* - * This routine is called to map an inode to the buffer containing -@@ -654,15 +655,25 @@ xfs_iformat_btree( - STATIC void - xfs_dinode_from_disk( - xfs_icdinode_t *to, -- xfs_dinode_t *from) -+ xfs_dinode_t *from, -+ int tagged) - { -+ uint32_t uid, gid, tag; -+ - to->di_magic = be16_to_cpu(from->di_magic); - to->di_mode = be16_to_cpu(from->di_mode); - to->di_version = from ->di_version; - to->di_format = from->di_format; - to->di_onlink = be16_to_cpu(from->di_onlink); -- to->di_uid = be32_to_cpu(from->di_uid); -- to->di_gid = be32_to_cpu(from->di_gid); -+ -+ uid = be32_to_cpu(from->di_uid); -+ gid = be32_to_cpu(from->di_gid); -+ tag = be16_to_cpu(from->di_tag); -+ -+ to->di_uid = INOTAG_UID(tagged, uid, gid); -+ to->di_gid = INOTAG_GID(tagged, uid, gid); -+ to->di_tag = INOTAG_TAG(tagged, uid, gid, tag); -+ - to->di_nlink = be32_to_cpu(from->di_nlink); - to->di_projid = be16_to_cpu(from->di_projid); - memcpy(to->di_pad, from->di_pad, sizeof(to->di_pad)); -@@ -683,21 +694,26 @@ xfs_dinode_from_disk( - to->di_dmevmask = be32_to_cpu(from->di_dmevmask); - to->di_dmstate = be16_to_cpu(from->di_dmstate); - to->di_flags = be16_to_cpu(from->di_flags); -+ to->di_vflags = be16_to_cpu(from->di_vflags); - to->di_gen = be32_to_cpu(from->di_gen); - } - - void - xfs_dinode_to_disk( - xfs_dinode_t *to, -- xfs_icdinode_t *from) -+ xfs_icdinode_t *from, -+ int tagged) - { - to->di_magic = cpu_to_be16(from->di_magic); - to->di_mode = cpu_to_be16(from->di_mode); - to->di_version = from ->di_version; - to->di_format = from->di_format; - to->di_onlink = cpu_to_be16(from->di_onlink); -- to->di_uid = cpu_to_be32(from->di_uid); -- to->di_gid = cpu_to_be32(from->di_gid); -+ -+ to->di_uid = cpu_to_be32(TAGINO_UID(tagged, from->di_uid, from->di_tag)); -+ to->di_gid = cpu_to_be32(TAGINO_GID(tagged, from->di_gid, from->di_tag)); -+ to->di_tag = cpu_to_be16(TAGINO_TAG(tagged, from->di_tag)); -+ - to->di_nlink = cpu_to_be32(from->di_nlink); - to->di_projid = cpu_to_be16(from->di_projid); - memcpy(to->di_pad, from->di_pad, sizeof(to->di_pad)); -@@ -718,12 +734,14 @@ xfs_dinode_to_disk( - to->di_dmevmask = cpu_to_be32(from->di_dmevmask); - to->di_dmstate = cpu_to_be16(from->di_dmstate); - to->di_flags = cpu_to_be16(from->di_flags); -+ to->di_vflags = cpu_to_be16(from->di_vflags); - to->di_gen = cpu_to_be32(from->di_gen); - } - - STATIC uint - _xfs_dic2xflags( -- __uint16_t di_flags) -+ __uint16_t di_flags, -+ __uint16_t di_vflags) - { - uint flags = 0; - -@@ -734,6 +752,8 @@ _xfs_dic2xflags( - flags |= XFS_XFLAG_PREALLOC; - if (di_flags & XFS_DIFLAG_IMMUTABLE) - flags |= XFS_XFLAG_IMMUTABLE; -+ if (di_flags & XFS_DIFLAG_IXUNLINK) -+ flags |= XFS_XFLAG_IXUNLINK; - if (di_flags & XFS_DIFLAG_APPEND) - flags |= XFS_XFLAG_APPEND; - if (di_flags & XFS_DIFLAG_SYNC) -@@ -758,6 +778,10 @@ _xfs_dic2xflags( - flags |= XFS_XFLAG_FILESTREAM; - } - -+ if (di_vflags & XFS_DIVFLAG_BARRIER) -+ flags |= FS_BARRIER_FL; -+ if (di_vflags & XFS_DIVFLAG_COW) -+ flags |= FS_COW_FL; - return flags; - } - -@@ -767,7 +791,7 @@ xfs_ip2xflags( - { - xfs_icdinode_t *dic = &ip->i_d; - -- return _xfs_dic2xflags(dic->di_flags) | -+ return _xfs_dic2xflags(dic->di_flags, dic->di_vflags) | - (XFS_IFORK_Q(ip) ? XFS_XFLAG_HASATTR : 0); - } - -@@ -775,7 +799,8 @@ uint - xfs_dic2xflags( - xfs_dinode_t *dip) - { -- return _xfs_dic2xflags(be16_to_cpu(dip->di_flags)) | -+ return _xfs_dic2xflags(be16_to_cpu(dip->di_flags), -+ be16_to_cpu(dip->di_vflags)) | - (XFS_DFORK_Q(dip) ? XFS_XFLAG_HASATTR : 0); - } - -@@ -811,7 +836,6 @@ xfs_iread( - if (error) - return error; - dip = (xfs_dinode_t *)xfs_buf_offset(bp, ip->i_imap.im_boffset); -- - /* - * If we got something that isn't an inode it means someone - * (nfs or dmi) has a stale handle. -@@ -836,7 +860,8 @@ xfs_iread( - * Otherwise, just get the truly permanent information. - */ - if (dip->di_mode) { -- xfs_dinode_from_disk(&ip->i_d, dip); -+ xfs_dinode_from_disk(&ip->i_d, dip, -+ mp->m_flags & XFS_MOUNT_TAGGED); - error = xfs_iformat(ip, dip); - if (error) { - #ifdef DEBUG -@@ -1036,6 +1061,7 @@ xfs_ialloc( - ASSERT(ip->i_d.di_nlink == nlink); - ip->i_d.di_uid = current_fsuid(); - ip->i_d.di_gid = current_fsgid(); -+ ip->i_d.di_tag = current_fstag(cr, &ip->i_vnode); - ip->i_d.di_projid = prid; - memset(&(ip->i_d.di_pad[0]), 0, sizeof(ip->i_d.di_pad)); - -@@ -1096,6 +1122,7 @@ xfs_ialloc( - ip->i_d.di_dmevmask = 0; - ip->i_d.di_dmstate = 0; - ip->i_d.di_flags = 0; -+ ip->i_d.di_vflags = 0; - flags = XFS_ILOG_CORE; - switch (mode & S_IFMT) { - case S_IFIFO: -@@ -2172,6 +2199,7 @@ xfs_ifree( - } - ip->i_d.di_mode = 0; /* mark incore inode as free */ - ip->i_d.di_flags = 0; -+ ip->i_d.di_vflags = 0; - ip->i_d.di_dmevmask = 0; - ip->i_d.di_forkoff = 0; /* mark the attr fork not in use */ - ip->i_df.if_ext_max = -@@ -3139,7 +3167,8 @@ xfs_iflush_int( - * because if the inode is dirty at all the core must - * be. - */ -- xfs_dinode_to_disk(dip, &ip->i_d); -+ xfs_dinode_to_disk(dip, &ip->i_d, -+ mp->m_flags & XFS_MOUNT_TAGGED); - - /* Wrap, we never let the log put out DI_MAX_FLUSH */ - if (ip->i_d.di_flushiter == DI_MAX_FLUSH) -diff -NurpP --minimal linux-2.6.32.1/fs/xfs/xfs_inode.h linux-2.6.32.1-vs2.3.0.36.27/fs/xfs/xfs_inode.h ---- linux-2.6.32.1/fs/xfs/xfs_inode.h 2009-12-03 20:02:54.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/xfs/xfs_inode.h 2009-12-03 20:04:56.000000000 +0100 -@@ -135,7 +135,9 @@ typedef struct xfs_icdinode { - __uint32_t di_gid; /* owner's group id */ - __uint32_t di_nlink; /* number of links to file */ - __uint16_t di_projid; /* owner's project id */ -- __uint8_t di_pad[8]; /* unused, zeroed space */ -+ __uint16_t di_tag; /* context tagging */ -+ __uint16_t di_vflags; /* vserver specific flags */ -+ __uint8_t di_pad[4]; /* unused, zeroed space */ - __uint16_t di_flushiter; /* incremented on flush */ - xfs_ictimestamp_t di_atime; /* time last accessed */ - xfs_ictimestamp_t di_mtime; /* time last modified */ -@@ -569,7 +571,7 @@ int xfs_itobp(struct xfs_mount *, struc - int xfs_iread(struct xfs_mount *, struct xfs_trans *, - struct xfs_inode *, xfs_daddr_t, uint); - void xfs_dinode_to_disk(struct xfs_dinode *, -- struct xfs_icdinode *); -+ struct xfs_icdinode *, int); - void xfs_idestroy_fork(struct xfs_inode *, int); - void xfs_idata_realloc(struct xfs_inode *, int, int); - void xfs_iroot_realloc(struct xfs_inode *, int, int); -diff -NurpP --minimal linux-2.6.32.1/fs/xfs/xfs_itable.c linux-2.6.32.1-vs2.3.0.36.27/fs/xfs/xfs_itable.c ---- linux-2.6.32.1/fs/xfs/xfs_itable.c 2009-12-03 20:02:54.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/xfs/xfs_itable.c 2009-12-03 20:04:56.000000000 +0100 -@@ -84,6 +84,7 @@ xfs_bulkstat_one_iget( - buf->bs_mode = dic->di_mode; - buf->bs_uid = dic->di_uid; - buf->bs_gid = dic->di_gid; -+ buf->bs_tag = dic->di_tag; - buf->bs_size = dic->di_size; - - /* -diff -NurpP --minimal linux-2.6.32.1/fs/xfs/xfs_log_recover.c linux-2.6.32.1-vs2.3.0.36.27/fs/xfs/xfs_log_recover.c ---- linux-2.6.32.1/fs/xfs/xfs_log_recover.c 2009-12-03 20:02:54.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/xfs/xfs_log_recover.c 2009-12-03 20:04:56.000000000 +0100 -@@ -2467,7 +2467,8 @@ xlog_recover_do_inode_trans( - } - - /* The core is in in-core format */ -- xfs_dinode_to_disk(dip, (xfs_icdinode_t *)item->ri_buf[1].i_addr); -+ xfs_dinode_to_disk(dip, (xfs_icdinode_t *)item->ri_buf[1].i_addr, -+ mp->m_flags & XFS_MOUNT_TAGGED); - - /* the rest is in on-disk format */ - if (item->ri_buf[1].i_len > sizeof(struct xfs_icdinode)) { -diff -NurpP --minimal linux-2.6.32.1/fs/xfs/xfs_mount.h linux-2.6.32.1-vs2.3.0.36.27/fs/xfs/xfs_mount.h ---- linux-2.6.32.1/fs/xfs/xfs_mount.h 2009-12-03 20:02:54.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/xfs/xfs_mount.h 2009-12-03 20:04:56.000000000 +0100 -@@ -283,6 +283,7 @@ typedef struct xfs_mount { - allocator */ - #define XFS_MOUNT_NOATTR2 (1ULL << 25) /* disable use of attr2 format */ - -+#define XFS_MOUNT_TAGGED (1ULL << 31) /* context tagging */ - - /* - * Default minimum read and write sizes. -diff -NurpP --minimal linux-2.6.32.1/fs/xfs/xfs_vnodeops.c linux-2.6.32.1-vs2.3.0.36.27/fs/xfs/xfs_vnodeops.c ---- linux-2.6.32.1/fs/xfs/xfs_vnodeops.c 2009-12-03 20:02:54.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/xfs/xfs_vnodeops.c 2009-12-03 20:04:56.000000000 +0100 -@@ -54,6 +54,80 @@ - #include "xfs_filestream.h" - #include "xfs_vnodeops.h" - -+ -+STATIC void -+xfs_get_inode_flags( -+ xfs_inode_t *ip) -+{ -+ struct inode *inode = VFS_I(ip); -+ unsigned int flags = inode->i_flags; -+ unsigned int vflags = inode->i_vflags; -+ -+ if (flags & S_IMMUTABLE) -+ ip->i_d.di_flags |= XFS_DIFLAG_IMMUTABLE; -+ else -+ ip->i_d.di_flags &= ~XFS_DIFLAG_IMMUTABLE; -+ if (flags & S_IXUNLINK) -+ ip->i_d.di_flags |= XFS_DIFLAG_IXUNLINK; -+ else -+ ip->i_d.di_flags &= ~XFS_DIFLAG_IXUNLINK; -+ -+ if (vflags & V_BARRIER) -+ ip->i_d.di_vflags |= XFS_DIVFLAG_BARRIER; -+ else -+ ip->i_d.di_vflags &= ~XFS_DIVFLAG_BARRIER; -+ if (vflags & V_COW) -+ ip->i_d.di_vflags |= XFS_DIVFLAG_COW; -+ else -+ ip->i_d.di_vflags &= ~XFS_DIVFLAG_COW; -+} -+ -+int -+xfs_sync_flags( -+ struct inode *inode, -+ int flags, -+ int vflags) -+{ -+ struct xfs_inode *ip = XFS_I(inode); -+ struct xfs_mount *mp = ip->i_mount; -+ struct xfs_trans *tp; -+ unsigned int lock_flags = 0; -+ int code; -+ -+ tp = xfs_trans_alloc(mp, XFS_TRANS_SETATTR_NOT_SIZE); -+ code = xfs_trans_reserve(tp, 0, XFS_ICHANGE_LOG_RES(mp), 0, 0, 0); -+ if (code) -+ goto error_out; -+ -+ lock_flags = XFS_ILOCK_EXCL; -+ xfs_ilock(ip, lock_flags); -+ -+ xfs_trans_ijoin(tp, ip, lock_flags); -+ xfs_trans_ihold(tp, ip); -+ -+ inode->i_flags = flags; -+ inode->i_vflags = vflags; -+ xfs_get_inode_flags(ip); -+ -+ xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); -+ xfs_ichgtime(ip, XFS_ICHGTIME_CHG); -+ -+ XFS_STATS_INC(xs_ig_attrchg); -+ -+ if (mp->m_flags & XFS_MOUNT_WSYNC) -+ xfs_trans_set_sync(tp); -+ code = xfs_trans_commit(tp, 0); -+ xfs_iunlock(ip, lock_flags); -+ return code; -+ -+error_out: -+ xfs_trans_cancel(tp, 0); -+ if (lock_flags) -+ xfs_iunlock(ip, lock_flags); -+ return code; -+} -+ -+ - int - xfs_setattr( - struct xfs_inode *ip, -@@ -69,6 +143,7 @@ xfs_setattr( - uint commit_flags=0; - uid_t uid=0, iuid=0; - gid_t gid=0, igid=0; -+ tag_t tag=0, itag=0; - int timeflags = 0; - struct xfs_dquot *udqp, *gdqp, *olddquot1, *olddquot2; - int need_iolock = 1; -@@ -165,7 +240,7 @@ xfs_setattr( - /* - * Change file ownership. Must be the owner or privileged. - */ -- if (mask & (ATTR_UID|ATTR_GID)) { -+ if (mask & (ATTR_UID|ATTR_GID|ATTR_TAG)) { - /* - * These IDs could have changed since we last looked at them. - * But, we're assured that if the ownership did change -@@ -174,8 +249,10 @@ xfs_setattr( - */ - iuid = ip->i_d.di_uid; - igid = ip->i_d.di_gid; -+ itag = ip->i_d.di_tag; - gid = (mask & ATTR_GID) ? iattr->ia_gid : igid; - uid = (mask & ATTR_UID) ? iattr->ia_uid : iuid; -+ tag = (mask & ATTR_TAG) ? iattr->ia_tag : itag; - - /* - * Do a quota reservation only if uid/gid is actually -@@ -183,7 +260,8 @@ xfs_setattr( - */ - if (XFS_IS_QUOTA_RUNNING(mp) && - ((XFS_IS_UQUOTA_ON(mp) && iuid != uid) || -- (XFS_IS_GQUOTA_ON(mp) && igid != gid))) { -+ (XFS_IS_GQUOTA_ON(mp) && igid != gid) || -+ (XFS_IS_GQUOTA_ON(mp) && itag != tag))) { - ASSERT(tp); - code = xfs_qm_vop_chown_reserve(tp, ip, udqp, gdqp, - capable(CAP_FOWNER) ? -@@ -336,7 +414,7 @@ xfs_setattr( - /* - * Change file ownership. Must be the owner or privileged. - */ -- if (mask & (ATTR_UID|ATTR_GID)) { -+ if (mask & (ATTR_UID|ATTR_GID|ATTR_TAG)) { - /* - * CAP_FSETID overrides the following restrictions: - * -@@ -352,6 +430,10 @@ xfs_setattr( - * Change the ownerships and register quota modifications - * in the transaction. - */ -+ if (itag != tag) { -+ ip->i_d.di_tag = tag; -+ inode->i_tag = tag; -+ } - if (iuid != uid) { - if (XFS_IS_QUOTA_RUNNING(mp) && XFS_IS_UQUOTA_ON(mp)) { - ASSERT(mask & ATTR_UID); -diff -NurpP --minimal linux-2.6.32.1/fs/xfs/xfs_vnodeops.h linux-2.6.32.1-vs2.3.0.36.27/fs/xfs/xfs_vnodeops.h ---- linux-2.6.32.1/fs/xfs/xfs_vnodeops.h 2009-09-10 15:26:24.000000000 +0200 -+++ linux-2.6.32.1-vs2.3.0.36.27/fs/xfs/xfs_vnodeops.h 2009-12-03 20:04:56.000000000 +0100 -@@ -14,6 +14,7 @@ struct xfs_inode; - struct xfs_iomap; - - -+int xfs_sync_xflags(struct xfs_inode *ip); - int xfs_setattr(struct xfs_inode *ip, struct iattr *vap, int flags); - #define XFS_ATTR_DMI 0x01 /* invocation from a DMI function */ - #define XFS_ATTR_NONBLOCK 0x02 /* return EAGAIN if operation would block */ -diff -NurpP --minimal linux-2.6.32.1/include/asm-generic/tlb.h linux-2.6.32.1-vs2.3.0.36.27/include/asm-generic/tlb.h ---- linux-2.6.32.1/include/asm-generic/tlb.h 2009-09-10 15:26:24.000000000 +0200 -+++ linux-2.6.32.1-vs2.3.0.36.27/include/asm-generic/tlb.h 2009-12-03 20:04:56.000000000 +0100 -@@ -14,6 +14,7 @@ - #define _ASM_GENERIC__TLB_H - - #include -+#include - #include - #include - -diff -NurpP --minimal linux-2.6.32.1/include/linux/capability.h linux-2.6.32.1-vs2.3.0.36.27/include/linux/capability.h ---- linux-2.6.32.1/include/linux/capability.h 2009-12-03 20:02:54.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/include/linux/capability.h 2009-12-03 20:04:56.000000000 +0100 -@@ -285,6 +285,7 @@ struct cpu_vfs_cap_data { - arbitrary SCSI commands */ - /* Allow setting encryption key on loopback filesystem */ - /* Allow setting zone reclaim policy */ -+/* Allow the selection of a security context */ - - #define CAP_SYS_ADMIN 21 - -@@ -357,7 +358,13 @@ struct cpu_vfs_cap_data { - - #define CAP_MAC_ADMIN 33 - --#define CAP_LAST_CAP CAP_MAC_ADMIN -+/* Allow context manipulations */ -+/* Allow changing context info on files */ -+ -+#define CAP_CONTEXT 34 -+ -+ -+#define CAP_LAST_CAP CAP_CONTEXT - - #define cap_valid(x) ((x) >= 0 && (x) <= CAP_LAST_CAP) - -diff -NurpP --minimal linux-2.6.32.1/include/linux/devpts_fs.h linux-2.6.32.1-vs2.3.0.36.27/include/linux/devpts_fs.h ---- linux-2.6.32.1/include/linux/devpts_fs.h 2008-12-25 00:26:37.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/include/linux/devpts_fs.h 2009-12-03 20:04:56.000000000 +0100 -@@ -45,5 +45,4 @@ static inline void devpts_pty_kill(struc - - #endif - -- - #endif /* _LINUX_DEVPTS_FS_H */ -diff -NurpP --minimal linux-2.6.32.1/include/linux/ext2_fs.h linux-2.6.32.1-vs2.3.0.36.27/include/linux/ext2_fs.h ---- linux-2.6.32.1/include/linux/ext2_fs.h 2009-03-24 14:22:41.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/include/linux/ext2_fs.h 2009-12-03 20:04:56.000000000 +0100 -@@ -189,8 +189,12 @@ struct ext2_group_desc - #define EXT2_NOTAIL_FL FS_NOTAIL_FL /* file tail should not be merged */ - #define EXT2_DIRSYNC_FL FS_DIRSYNC_FL /* dirsync behaviour (directories only) */ - #define EXT2_TOPDIR_FL FS_TOPDIR_FL /* Top of directory hierarchies*/ -+#define EXT2_IXUNLINK_FL FS_IXUNLINK_FL /* Immutable invert on unlink */ - #define EXT2_RESERVED_FL FS_RESERVED_FL /* reserved for ext2 lib */ - -+#define EXT2_BARRIER_FL FS_BARRIER_FL /* Barrier for chroot() */ -+#define EXT2_COW_FL FS_COW_FL /* Copy on Write marker */ -+ - #define EXT2_FL_USER_VISIBLE FS_FL_USER_VISIBLE /* User visible flags */ - #define EXT2_FL_USER_MODIFIABLE FS_FL_USER_MODIFIABLE /* User modifiable flags */ - -@@ -274,7 +278,8 @@ struct ext2_inode { - __u16 i_pad1; - __le16 l_i_uid_high; /* these 2 fields */ - __le16 l_i_gid_high; /* were reserved2[0] */ -- __u32 l_i_reserved2; -+ __le16 l_i_tag; /* Context Tag */ -+ __u16 l_i_reserved2; - } linux2; - struct { - __u8 h_i_frag; /* Fragment number */ -@@ -303,6 +308,7 @@ struct ext2_inode { - #define i_gid_low i_gid - #define i_uid_high osd2.linux2.l_i_uid_high - #define i_gid_high osd2.linux2.l_i_gid_high -+#define i_raw_tag osd2.linux2.l_i_tag - #define i_reserved2 osd2.linux2.l_i_reserved2 - #endif - -@@ -347,6 +353,7 @@ struct ext2_inode { - #define EXT2_MOUNT_USRQUOTA 0x020000 /* user quota */ - #define EXT2_MOUNT_GRPQUOTA 0x040000 /* group quota */ - #define EXT2_MOUNT_RESERVATION 0x080000 /* Preallocation */ -+#define EXT2_MOUNT_TAGGED (1<<24) /* Enable Context Tags */ - - - #define clear_opt(o, opt) o &= ~EXT2_MOUNT_##opt -diff -NurpP --minimal linux-2.6.32.1/include/linux/ext3_fs.h linux-2.6.32.1-vs2.3.0.36.27/include/linux/ext3_fs.h ---- linux-2.6.32.1/include/linux/ext3_fs.h 2009-09-10 15:26:25.000000000 +0200 -+++ linux-2.6.32.1-vs2.3.0.36.27/include/linux/ext3_fs.h 2009-12-03 20:04:56.000000000 +0100 -@@ -173,10 +173,14 @@ struct ext3_group_desc - #define EXT3_NOTAIL_FL 0x00008000 /* file tail should not be merged */ - #define EXT3_DIRSYNC_FL 0x00010000 /* dirsync behaviour (directories only) */ - #define EXT3_TOPDIR_FL 0x00020000 /* Top of directory hierarchies*/ -+#define EXT3_IXUNLINK_FL 0x08000000 /* Immutable invert on unlink */ - #define EXT3_RESERVED_FL 0x80000000 /* reserved for ext3 lib */ - --#define EXT3_FL_USER_VISIBLE 0x0003DFFF /* User visible flags */ --#define EXT3_FL_USER_MODIFIABLE 0x000380FF /* User modifiable flags */ -+#define EXT3_BARRIER_FL 0x04000000 /* Barrier for chroot() */ -+#define EXT3_COW_FL 0x20000000 /* Copy on Write marker */ -+ -+#define EXT3_FL_USER_VISIBLE 0x0103DFFF /* User visible flags */ -+#define EXT3_FL_USER_MODIFIABLE 0x010380FF /* User modifiable flags */ - - /* Flags that should be inherited by new inodes from their parent. */ - #define EXT3_FL_INHERITED (EXT3_SECRM_FL | EXT3_UNRM_FL | EXT3_COMPR_FL |\ -@@ -320,7 +324,8 @@ struct ext3_inode { - __u16 i_pad1; - __le16 l_i_uid_high; /* these 2 fields */ - __le16 l_i_gid_high; /* were reserved2[0] */ -- __u32 l_i_reserved2; -+ __le16 l_i_tag; /* Context Tag */ -+ __u16 l_i_reserved2; - } linux2; - struct { - __u8 h_i_frag; /* Fragment number */ -@@ -351,6 +356,7 @@ struct ext3_inode { - #define i_gid_low i_gid - #define i_uid_high osd2.linux2.l_i_uid_high - #define i_gid_high osd2.linux2.l_i_gid_high -+#define i_raw_tag osd2.linux2.l_i_tag - #define i_reserved2 osd2.linux2.l_i_reserved2 - - #elif defined(__GNU__) -@@ -414,6 +420,7 @@ struct ext3_inode { - #define EXT3_MOUNT_GRPQUOTA 0x200000 /* "old" group quota */ - #define EXT3_MOUNT_DATA_ERR_ABORT 0x400000 /* Abort on file data write - * error in ordered mode */ -+#define EXT3_MOUNT_TAGGED (1<<24) /* Enable Context Tags */ - - /* Compatibility, for having both ext2_fs.h and ext3_fs.h included at once */ - #ifndef _LINUX_EXT2_FS_H -@@ -892,6 +899,7 @@ extern void ext3_get_inode_flags(struct - extern void ext3_set_aops(struct inode *inode); - extern int ext3_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, - u64 start, u64 len); -+extern int ext3_sync_flags(struct inode *, int, int); - - /* ioctl.c */ - extern long ext3_ioctl(struct file *, unsigned int, unsigned long); -diff -NurpP --minimal linux-2.6.32.1/include/linux/fs.h linux-2.6.32.1-vs2.3.0.36.27/include/linux/fs.h ---- linux-2.6.32.1/include/linux/fs.h 2009-12-03 20:02:55.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/include/linux/fs.h 2009-12-03 20:04:56.000000000 +0100 -@@ -205,6 +205,9 @@ struct inodes_stat_t { - #define MS_KERNMOUNT (1<<22) /* this is a kern_mount call */ - #define MS_I_VERSION (1<<23) /* Update inode I_version field */ - #define MS_STRICTATIME (1<<24) /* Always perform atime updates */ -+#define MS_TAGGED (1<<25) /* use generic inode tagging */ -+#define MS_TAGID (1<<26) /* use specific tag for this mount */ -+#define MS_NOTAGCHECK (1<<27) /* don't check tags */ - #define MS_ACTIVE (1<<30) - #define MS_NOUSER (1<<31) - -@@ -231,6 +234,14 @@ struct inodes_stat_t { - #define S_NOCMTIME 128 /* Do not update file c/mtime */ - #define S_SWAPFILE 256 /* Do not truncate: swapon got its bmaps */ - #define S_PRIVATE 512 /* Inode is fs-internal */ -+#define S_IXUNLINK 1024 /* Immutable Invert on unlink */ -+ -+/* Linux-VServer related Inode flags */ -+ -+#define V_VALID 1 -+#define V_XATTR 2 -+#define V_BARRIER 4 /* Barrier for chroot() */ -+#define V_COW 8 /* Copy on Write */ - - /* - * Note that nosuid etc flags are inode-specific: setting some file-system -@@ -253,12 +264,15 @@ struct inodes_stat_t { - #define IS_DIRSYNC(inode) (__IS_FLG(inode, MS_SYNCHRONOUS|MS_DIRSYNC) || \ - ((inode)->i_flags & (S_SYNC|S_DIRSYNC))) - #define IS_MANDLOCK(inode) __IS_FLG(inode, MS_MANDLOCK) --#define IS_NOATIME(inode) __IS_FLG(inode, MS_RDONLY|MS_NOATIME) --#define IS_I_VERSION(inode) __IS_FLG(inode, MS_I_VERSION) -+#define IS_NOATIME(inode) __IS_FLG(inode, MS_RDONLY|MS_NOATIME) -+#define IS_I_VERSION(inode) __IS_FLG(inode, MS_I_VERSION) -+#define IS_TAGGED(inode) __IS_FLG(inode, MS_TAGGED) - - #define IS_NOQUOTA(inode) ((inode)->i_flags & S_NOQUOTA) - #define IS_APPEND(inode) ((inode)->i_flags & S_APPEND) - #define IS_IMMUTABLE(inode) ((inode)->i_flags & S_IMMUTABLE) -+#define IS_IXUNLINK(inode) ((inode)->i_flags & S_IXUNLINK) -+#define IS_IXORUNLINK(inode) ((IS_IXUNLINK(inode) ? S_IMMUTABLE : 0) ^ IS_IMMUTABLE(inode)) - #define IS_POSIXACL(inode) __IS_FLG(inode, MS_POSIXACL) - - #define IS_DEADDIR(inode) ((inode)->i_flags & S_DEAD) -@@ -266,6 +280,16 @@ struct inodes_stat_t { - #define IS_SWAPFILE(inode) ((inode)->i_flags & S_SWAPFILE) - #define IS_PRIVATE(inode) ((inode)->i_flags & S_PRIVATE) - -+#define IS_BARRIER(inode) (S_ISDIR((inode)->i_mode) && ((inode)->i_vflags & V_BARRIER)) -+ -+#ifdef CONFIG_VSERVER_COWBL -+# define IS_COW(inode) (IS_IXUNLINK(inode) && IS_IMMUTABLE(inode)) -+# define IS_COW_LINK(inode) (S_ISREG((inode)->i_mode) && ((inode)->i_nlink > 1)) -+#else -+# define IS_COW(inode) (0) -+# define IS_COW_LINK(inode) (0) -+#endif -+ - /* the read-only stuff doesn't really belong here, but any other place is - probably as bad and I don't want to create yet another include file. */ - -@@ -347,11 +371,14 @@ struct inodes_stat_t { - #define FS_TOPDIR_FL 0x00020000 /* Top of directory hierarchies*/ - #define FS_EXTENT_FL 0x00080000 /* Extents */ - #define FS_DIRECTIO_FL 0x00100000 /* Use direct i/o */ -+#define FS_IXUNLINK_FL 0x08000000 /* Immutable invert on unlink */ - #define FS_RESERVED_FL 0x80000000 /* reserved for ext2 lib */ - --#define FS_FL_USER_VISIBLE 0x0003DFFF /* User visible flags */ --#define FS_FL_USER_MODIFIABLE 0x000380FF /* User modifiable flags */ -+#define FS_BARRIER_FL 0x04000000 /* Barrier for chroot() */ -+#define FS_COW_FL 0x20000000 /* Copy on Write marker */ - -+#define FS_FL_USER_VISIBLE 0x0103DFFF /* User visible flags */ -+#define FS_FL_USER_MODIFIABLE 0x010380FF /* User modifiable flags */ - - #define SYNC_FILE_RANGE_WAIT_BEFORE 1 - #define SYNC_FILE_RANGE_WRITE 2 -@@ -433,6 +460,7 @@ typedef void (dio_iodone_t)(struct kiocb - #define ATTR_KILL_PRIV (1 << 14) - #define ATTR_OPEN (1 << 15) /* Truncating from open(O_TRUNC) */ - #define ATTR_TIMES_SET (1 << 16) -+#define ATTR_TAG (1 << 17) - - /* - * This is the Inode Attributes structure, used for notify_change(). It -@@ -448,6 +476,7 @@ struct iattr { - umode_t ia_mode; - uid_t ia_uid; - gid_t ia_gid; -+ tag_t ia_tag; - loff_t ia_size; - struct timespec ia_atime; - struct timespec ia_mtime; -@@ -461,6 +490,9 @@ struct iattr { - struct file *ia_file; - }; - -+#define ATTR_FLAG_BARRIER 512 /* Barrier for chroot() */ -+#define ATTR_FLAG_IXUNLINK 1024 /* Immutable invert on unlink */ -+ - /* - * Includes for diskquotas. - */ -@@ -726,7 +758,9 @@ struct inode { - unsigned int i_nlink; - uid_t i_uid; - gid_t i_gid; -+ tag_t i_tag; - dev_t i_rdev; -+ dev_t i_mdev; - u64 i_version; - loff_t i_size; - #ifdef __NEED_I_SIZE_ORDERED -@@ -773,7 +807,8 @@ struct inode { - unsigned long i_state; - unsigned long dirtied_when; /* jiffies of first dirtying */ - -- unsigned int i_flags; -+ unsigned short i_flags; -+ unsigned short i_vflags; - - atomic_t i_writecount; - #ifdef CONFIG_SECURITY -@@ -861,12 +896,12 @@ static inline void i_size_write(struct i - - static inline unsigned iminor(const struct inode *inode) - { -- return MINOR(inode->i_rdev); -+ return MINOR(inode->i_mdev); - } - - static inline unsigned imajor(const struct inode *inode) - { -- return MAJOR(inode->i_rdev); -+ return MAJOR(inode->i_mdev); - } - - extern struct block_device *I_BDEV(struct inode *inode); -@@ -925,6 +960,7 @@ struct file { - loff_t f_pos; - struct fown_struct f_owner; - const struct cred *f_cred; -+ xid_t f_xid; - struct file_ra_state f_ra; - - u64 f_version; -@@ -1066,6 +1102,7 @@ struct file_lock { - struct file *fl_file; - loff_t fl_start; - loff_t fl_end; -+ xid_t fl_xid; - - struct fasync_struct * fl_fasync; /* for lease break notifications */ - unsigned long fl_break_time; /* for nonblocking lease breaks */ -@@ -1531,6 +1568,7 @@ struct inode_operations { - ssize_t (*getxattr) (struct dentry *, const char *, void *, size_t); - ssize_t (*listxattr) (struct dentry *, char *, size_t); - int (*removexattr) (struct dentry *, const char *); -+ int (*sync_flags) (struct inode *, int, int); - void (*truncate_range)(struct inode *, loff_t, loff_t); - long (*fallocate)(struct inode *inode, int mode, loff_t offset, - loff_t len); -@@ -1551,6 +1589,7 @@ extern ssize_t vfs_readv(struct file *, - unsigned long, loff_t *); - extern ssize_t vfs_writev(struct file *, const struct iovec __user *, - unsigned long, loff_t *); -+ssize_t vfs_sendfile(struct file *, struct file *, loff_t *, size_t, loff_t); - - struct super_operations { - struct inode *(*alloc_inode)(struct super_block *sb); -@@ -2347,6 +2386,7 @@ extern int dcache_dir_open(struct inode - extern int dcache_dir_close(struct inode *, struct file *); - extern loff_t dcache_dir_lseek(struct file *, loff_t, int); - extern int dcache_readdir(struct file *, void *, filldir_t); -+extern int dcache_readdir_filter(struct file *, void *, filldir_t, int (*)(struct dentry *)); - extern int simple_getattr(struct vfsmount *, struct dentry *, struct kstat *); - extern int simple_statfs(struct dentry *, struct kstatfs *); - extern int simple_link(struct dentry *, struct inode *, struct dentry *); -diff -NurpP --minimal linux-2.6.32.1/include/linux/gfs2_ondisk.h linux-2.6.32.1-vs2.3.0.36.27/include/linux/gfs2_ondisk.h ---- linux-2.6.32.1/include/linux/gfs2_ondisk.h 2009-12-03 20:02:55.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/include/linux/gfs2_ondisk.h 2009-12-03 20:04:56.000000000 +0100 -@@ -235,6 +235,9 @@ enum { - gfs2fl_NoAtime = 7, - gfs2fl_Sync = 8, - gfs2fl_System = 9, -+ gfs2fl_IXUnlink = 16, -+ gfs2fl_Barrier = 17, -+ gfs2fl_Cow = 18, - gfs2fl_TruncInProg = 29, - gfs2fl_InheritDirectio = 30, - gfs2fl_InheritJdata = 31, -@@ -251,6 +254,9 @@ enum { - #define GFS2_DIF_NOATIME 0x00000080 - #define GFS2_DIF_SYNC 0x00000100 - #define GFS2_DIF_SYSTEM 0x00000200 /* New in gfs2 */ -+#define GFS2_DIF_IXUNLINK 0x00010000 -+#define GFS2_DIF_BARRIER 0x00020000 -+#define GFS2_DIF_COW 0x00040000 - #define GFS2_DIF_TRUNC_IN_PROG 0x20000000 /* New in gfs2 */ - #define GFS2_DIF_INHERIT_DIRECTIO 0x40000000 - #define GFS2_DIF_INHERIT_JDATA 0x80000000 -diff -NurpP --minimal linux-2.6.32.1/include/linux/if_tun.h linux-2.6.32.1-vs2.3.0.36.27/include/linux/if_tun.h ---- linux-2.6.32.1/include/linux/if_tun.h 2009-12-03 20:02:55.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/include/linux/if_tun.h 2009-12-03 20:04:56.000000000 +0100 -@@ -48,6 +48,7 @@ - #define TUNGETIFF _IOR('T', 210, unsigned int) - #define TUNGETSNDBUF _IOR('T', 211, int) - #define TUNSETSNDBUF _IOW('T', 212, int) -+#define TUNSETNID _IOW('T', 215, int) - - /* TUNSETIFF ifr flags */ - #define IFF_TUN 0x0001 -diff -NurpP --minimal linux-2.6.32.1/include/linux/init_task.h linux-2.6.32.1-vs2.3.0.36.27/include/linux/init_task.h ---- linux-2.6.32.1/include/linux/init_task.h 2009-12-03 20:02:55.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/include/linux/init_task.h 2009-12-03 20:04:56.000000000 +0100 -@@ -184,6 +184,10 @@ extern struct cred init_cred; - INIT_FTRACE_GRAPH \ - INIT_TRACE_RECURSION \ - INIT_TASK_RCU_PREEMPT(tsk) \ -+ .xid = 0, \ -+ .vx_info = NULL, \ -+ .nid = 0, \ -+ .nx_info = NULL, \ - } - - -diff -NurpP --minimal linux-2.6.32.1/include/linux/ipc.h linux-2.6.32.1-vs2.3.0.36.27/include/linux/ipc.h ---- linux-2.6.32.1/include/linux/ipc.h 2009-12-03 20:02:55.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/include/linux/ipc.h 2009-12-03 20:04:56.000000000 +0100 -@@ -91,6 +91,7 @@ struct kern_ipc_perm - key_t key; - uid_t uid; - gid_t gid; -+ xid_t xid; - uid_t cuid; - gid_t cgid; - mode_t mode; -diff -NurpP --minimal linux-2.6.32.1/include/linux/Kbuild linux-2.6.32.1-vs2.3.0.36.27/include/linux/Kbuild ---- linux-2.6.32.1/include/linux/Kbuild 2009-12-03 20:02:54.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/include/linux/Kbuild 2009-12-03 20:04:56.000000000 +0100 -@@ -382,5 +382,8 @@ unifdef-y += xattr.h - unifdef-y += xfrm.h - - objhdr-y += version.h -+ -+header-y += vserver/ - header-y += wimax.h - header-y += wimax/ -+ -diff -NurpP --minimal linux-2.6.32.1/include/linux/loop.h linux-2.6.32.1-vs2.3.0.36.27/include/linux/loop.h ---- linux-2.6.32.1/include/linux/loop.h 2009-09-10 15:26:25.000000000 +0200 -+++ linux-2.6.32.1-vs2.3.0.36.27/include/linux/loop.h 2009-12-03 20:04:56.000000000 +0100 -@@ -45,6 +45,7 @@ struct loop_device { - struct loop_func_table *lo_encryption; - __u32 lo_init[2]; - uid_t lo_key_owner; /* Who set the key */ -+ xid_t lo_xid; - int (*ioctl)(struct loop_device *, int cmd, - unsigned long arg); - -diff -NurpP --minimal linux-2.6.32.1/include/linux/magic.h linux-2.6.32.1-vs2.3.0.36.27/include/linux/magic.h ---- linux-2.6.32.1/include/linux/magic.h 2009-12-03 20:02:55.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/include/linux/magic.h 2009-12-03 20:04:56.000000000 +0100 -@@ -3,7 +3,7 @@ - - #define ADFS_SUPER_MAGIC 0xadf5 - #define AFFS_SUPER_MAGIC 0xadff --#define AFS_SUPER_MAGIC 0x5346414F -+#define AFS_SUPER_MAGIC 0x5346414F - #define AUTOFS_SUPER_MAGIC 0x0187 - #define CODA_SUPER_MAGIC 0x73757245 - #define CRAMFS_MAGIC 0x28cd3d45 /* some random number */ -@@ -38,6 +38,7 @@ - #define NFS_SUPER_MAGIC 0x6969 - #define OPENPROM_SUPER_MAGIC 0x9fa1 - #define PROC_SUPER_MAGIC 0x9fa0 -+#define DEVPTS_SUPER_MAGIC 0x1cd1 - #define QNX4_SUPER_MAGIC 0x002f /* qnx4 fs detection */ - - #define REISERFS_SUPER_MAGIC 0x52654973 /* used by gcc */ -diff -NurpP --minimal linux-2.6.32.1/include/linux/major.h linux-2.6.32.1-vs2.3.0.36.27/include/linux/major.h ---- linux-2.6.32.1/include/linux/major.h 2009-09-10 15:26:25.000000000 +0200 -+++ linux-2.6.32.1-vs2.3.0.36.27/include/linux/major.h 2009-12-03 20:04:56.000000000 +0100 -@@ -15,6 +15,7 @@ - #define HD_MAJOR IDE0_MAJOR - #define PTY_SLAVE_MAJOR 3 - #define TTY_MAJOR 4 -+#define VROOT_MAJOR 4 - #define TTYAUX_MAJOR 5 - #define LP_MAJOR 6 - #define VCS_MAJOR 7 -diff -NurpP --minimal linux-2.6.32.1/include/linux/mm_types.h linux-2.6.32.1-vs2.3.0.36.27/include/linux/mm_types.h ---- linux-2.6.32.1/include/linux/mm_types.h 2009-12-03 20:02:55.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/include/linux/mm_types.h 2009-12-03 20:04:56.000000000 +0100 -@@ -246,6 +246,7 @@ struct mm_struct { - - /* Architecture-specific MM context */ - mm_context_t context; -+ struct vx_info *mm_vx_info; - - /* Swap token stuff */ - /* -diff -NurpP --minimal linux-2.6.32.1/include/linux/mount.h linux-2.6.32.1-vs2.3.0.36.27/include/linux/mount.h ---- linux-2.6.32.1/include/linux/mount.h 2009-09-10 15:26:25.000000000 +0200 -+++ linux-2.6.32.1-vs2.3.0.36.27/include/linux/mount.h 2009-12-03 20:04:56.000000000 +0100 -@@ -36,6 +36,9 @@ struct mnt_namespace; - #define MNT_UNBINDABLE 0x2000 /* if the vfsmount is a unbindable mount */ - #define MNT_PNODE_MASK 0x3000 /* propagation flag mask */ - -+#define MNT_TAGID 0x10000 -+#define MNT_NOTAG 0x20000 -+ - struct vfsmount { - struct list_head mnt_hash; - struct vfsmount *mnt_parent; /* fs we are mounted on */ -@@ -70,6 +73,7 @@ struct vfsmount { - #else - int mnt_writers; - #endif -+ tag_t mnt_tag; /* tagging used for vfsmount */ - }; - - static inline int *get_mnt_writers_ptr(struct vfsmount *mnt) -diff -NurpP --minimal linux-2.6.32.1/include/linux/net.h linux-2.6.32.1-vs2.3.0.36.27/include/linux/net.h ---- linux-2.6.32.1/include/linux/net.h 2009-12-03 20:02:55.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/include/linux/net.h 2009-12-03 20:04:56.000000000 +0100 -@@ -69,6 +69,7 @@ struct net; - #define SOCK_NOSPACE 2 - #define SOCK_PASSCRED 3 - #define SOCK_PASSSEC 4 -+#define SOCK_USER_SOCKET 5 - - #ifndef ARCH_HAS_SOCKET_TYPES - /** -diff -NurpP --minimal linux-2.6.32.1/include/linux/nfs_mount.h linux-2.6.32.1-vs2.3.0.36.27/include/linux/nfs_mount.h ---- linux-2.6.32.1/include/linux/nfs_mount.h 2009-03-24 14:22:43.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/include/linux/nfs_mount.h 2009-12-03 20:04:56.000000000 +0100 -@@ -63,7 +63,8 @@ struct nfs_mount_data { - #define NFS_MOUNT_SECFLAVOUR 0x2000 /* 5 */ - #define NFS_MOUNT_NORDIRPLUS 0x4000 /* 5 */ - #define NFS_MOUNT_UNSHARED 0x8000 /* 5 */ --#define NFS_MOUNT_FLAGMASK 0xFFFF -+#define NFS_MOUNT_TAGGED 0x10000 /* context tagging */ -+#define NFS_MOUNT_FLAGMASK 0x1FFFF - - /* The following are for internal use only */ - #define NFS_MOUNT_LOOKUP_CACHE_NONEG 0x10000 -diff -NurpP --minimal linux-2.6.32.1/include/linux/nsproxy.h linux-2.6.32.1-vs2.3.0.36.27/include/linux/nsproxy.h ---- linux-2.6.32.1/include/linux/nsproxy.h 2009-06-11 17:13:17.000000000 +0200 -+++ linux-2.6.32.1-vs2.3.0.36.27/include/linux/nsproxy.h 2009-12-03 20:04:56.000000000 +0100 -@@ -3,6 +3,7 @@ - - #include - #include -+#include - - struct mnt_namespace; - struct uts_namespace; -@@ -63,22 +64,33 @@ static inline struct nsproxy *task_nspro - } - - int copy_namespaces(unsigned long flags, struct task_struct *tsk); -+struct nsproxy *copy_nsproxy(struct nsproxy *orig); - void exit_task_namespaces(struct task_struct *tsk); - void switch_task_namespaces(struct task_struct *tsk, struct nsproxy *new); - void free_nsproxy(struct nsproxy *ns); - int unshare_nsproxy_namespaces(unsigned long, struct nsproxy **, - struct fs_struct *); - --static inline void put_nsproxy(struct nsproxy *ns) -+#define get_nsproxy(n) __get_nsproxy(n, __FILE__, __LINE__) -+ -+static inline void __get_nsproxy(struct nsproxy *ns, -+ const char *_file, int _line) - { -- if (atomic_dec_and_test(&ns->count)) { -- free_nsproxy(ns); -- } -+ vxlprintk(VXD_CBIT(space, 0), "get_nsproxy(%p[%u])", -+ ns, atomic_read(&ns->count), _file, _line); -+ atomic_inc(&ns->count); - } - --static inline void get_nsproxy(struct nsproxy *ns) -+#define put_nsproxy(n) __put_nsproxy(n, __FILE__, __LINE__) -+ -+static inline void __put_nsproxy(struct nsproxy *ns, -+ const char *_file, int _line) - { -- atomic_inc(&ns->count); -+ vxlprintk(VXD_CBIT(space, 0), "put_nsproxy(%p[%u])", -+ ns, atomic_read(&ns->count), _file, _line); -+ if (atomic_dec_and_test(&ns->count)) { -+ free_nsproxy(ns); -+ } - } - - #ifdef CONFIG_CGROUP_NS -diff -NurpP --minimal linux-2.6.32.1/include/linux/pid.h linux-2.6.32.1-vs2.3.0.36.27/include/linux/pid.h ---- linux-2.6.32.1/include/linux/pid.h 2009-03-24 14:22:43.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/include/linux/pid.h 2009-12-03 20:04:56.000000000 +0100 -@@ -8,7 +8,8 @@ enum pid_type - PIDTYPE_PID, - PIDTYPE_PGID, - PIDTYPE_SID, -- PIDTYPE_MAX -+ PIDTYPE_MAX, -+ PIDTYPE_REALPID - }; - - /* -@@ -160,6 +161,7 @@ static inline pid_t pid_nr(struct pid *p - } - - pid_t pid_nr_ns(struct pid *pid, struct pid_namespace *ns); -+pid_t pid_unmapped_nr_ns(struct pid *pid, struct pid_namespace *ns); - pid_t pid_vnr(struct pid *pid); - - #define do_each_pid_task(pid, type, task) \ -diff -NurpP --minimal linux-2.6.32.1/include/linux/proc_fs.h linux-2.6.32.1-vs2.3.0.36.27/include/linux/proc_fs.h ---- linux-2.6.32.1/include/linux/proc_fs.h 2009-12-03 20:02:56.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/include/linux/proc_fs.h 2009-12-03 20:04:56.000000000 +0100 -@@ -56,6 +56,7 @@ struct proc_dir_entry { - nlink_t nlink; - uid_t uid; - gid_t gid; -+ int vx_flags; - loff_t size; - const struct inode_operations *proc_iops; - /* -@@ -250,12 +251,18 @@ kclist_add(struct kcore_list *new, void - extern void kclist_add(struct kcore_list *, void *, size_t, int type); - #endif - -+struct vx_info; -+struct nx_info; -+ - union proc_op { - int (*proc_get_link)(struct inode *, struct path *); - int (*proc_read)(struct task_struct *task, char *page); - int (*proc_show)(struct seq_file *m, - struct pid_namespace *ns, struct pid *pid, - struct task_struct *task); -+ int (*proc_vs_read)(char *page); -+ int (*proc_vxi_read)(struct vx_info *vxi, char *page); -+ int (*proc_nxi_read)(struct nx_info *nxi, char *page); - }; - - struct ctl_table_header; -@@ -263,6 +270,7 @@ struct ctl_table; - - struct proc_inode { - struct pid *pid; -+ int vx_flags; - int fd; - union proc_op op; - struct proc_dir_entry *pde; -diff -NurpP --minimal linux-2.6.32.1/include/linux/quotaops.h linux-2.6.32.1-vs2.3.0.36.27/include/linux/quotaops.h ---- linux-2.6.32.1/include/linux/quotaops.h 2009-12-03 20:02:56.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/include/linux/quotaops.h 2009-12-03 20:04:56.000000000 +0100 -@@ -8,6 +8,7 @@ - #define _LINUX_QUOTAOPS_ - - #include -+#include - - static inline struct quota_info *sb_dqopt(struct super_block *sb) - { -@@ -154,10 +155,14 @@ static inline void vfs_dq_init(struct in - * a transaction (deadlocks possible otherwise) */ - static inline int vfs_dq_prealloc_space_nodirty(struct inode *inode, qsize_t nr) - { -+ if (dl_alloc_space(inode, nr)) -+ return 1; - if (sb_any_quota_active(inode->i_sb)) { - /* Used space is updated in alloc_space() */ -- if (inode->i_sb->dq_op->alloc_space(inode, nr, 1) == NO_QUOTA) -+ if (inode->i_sb->dq_op->alloc_space(inode, nr, 1) == NO_QUOTA) { -+ dl_free_space(inode, nr); - return 1; -+ } - } - else - inode_add_bytes(inode, nr); -@@ -174,10 +179,14 @@ static inline int vfs_dq_prealloc_space( - - static inline int vfs_dq_alloc_space_nodirty(struct inode *inode, qsize_t nr) - { -+ if (dl_alloc_space(inode, nr)) -+ return 1; - if (sb_any_quota_active(inode->i_sb)) { - /* Used space is updated in alloc_space() */ -- if (inode->i_sb->dq_op->alloc_space(inode, nr, 0) == NO_QUOTA) -+ if (inode->i_sb->dq_op->alloc_space(inode, nr, 0) == NO_QUOTA) { -+ dl_free_space(inode, nr); - return 1; -+ } - } - else - inode_add_bytes(inode, nr); -@@ -194,20 +203,28 @@ static inline int vfs_dq_alloc_space(str - - static inline int vfs_dq_reserve_space(struct inode *inode, qsize_t nr) - { -+ if (dl_reserve_space(inode, nr)) -+ return 1; - if (sb_any_quota_active(inode->i_sb)) { - /* Used space is updated in alloc_space() */ -- if (inode->i_sb->dq_op->reserve_space(inode, nr, 0) == NO_QUOTA) -+ if (inode->i_sb->dq_op->reserve_space(inode, nr, 0) == NO_QUOTA) { -+ dl_release_space(inode, nr); - return 1; -+ } - } - return 0; - } - - static inline int vfs_dq_alloc_inode(struct inode *inode) - { -+ if (dl_alloc_inode(inode)) -+ return 1; - if (sb_any_quota_active(inode->i_sb)) { - vfs_dq_init(inode); -- if (inode->i_sb->dq_op->alloc_inode(inode, 1) == NO_QUOTA) -+ if (inode->i_sb->dq_op->alloc_inode(inode, 1) == NO_QUOTA) { -+ dl_free_inode(inode); - return 1; -+ } - } - return 0; - } -@@ -217,9 +234,13 @@ static inline int vfs_dq_alloc_inode(str - */ - static inline int vfs_dq_claim_space(struct inode *inode, qsize_t nr) - { -+ if (dl_claim_space(inode, nr)) -+ return 1; - if (sb_any_quota_active(inode->i_sb)) { -- if (inode->i_sb->dq_op->claim_space(inode, nr) == NO_QUOTA) -+ if (inode->i_sb->dq_op->claim_space(inode, nr) == NO_QUOTA) { -+ dl_release_space(inode, nr); - return 1; -+ } - } else - inode_add_bytes(inode, nr); - -@@ -235,6 +256,7 @@ void vfs_dq_release_reservation_space(st - { - if (sb_any_quota_active(inode->i_sb)) - inode->i_sb->dq_op->release_rsv(inode, nr); -+ dl_release_space(inode, nr); - } - - static inline void vfs_dq_free_space_nodirty(struct inode *inode, qsize_t nr) -@@ -243,6 +265,7 @@ static inline void vfs_dq_free_space_nod - inode->i_sb->dq_op->free_space(inode, nr); - else - inode_sub_bytes(inode, nr); -+ dl_free_space(inode, nr); - } - - static inline void vfs_dq_free_space(struct inode *inode, qsize_t nr) -@@ -255,6 +278,7 @@ static inline void vfs_dq_free_inode(str - { - if (sb_any_quota_active(inode->i_sb)) - inode->i_sb->dq_op->free_inode(inode, 1); -+ dl_free_inode(inode); - } - - /* Cannot be called inside a transaction */ -@@ -358,6 +382,8 @@ static inline int vfs_dq_transfer(struct - - static inline int vfs_dq_prealloc_space_nodirty(struct inode *inode, qsize_t nr) - { -+ if (dl_alloc_space(inode, nr)) -+ return 1; - inode_add_bytes(inode, nr); - return 0; - } -@@ -371,6 +397,8 @@ static inline int vfs_dq_prealloc_space( - - static inline int vfs_dq_alloc_space_nodirty(struct inode *inode, qsize_t nr) - { -+ if (dl_alloc_space(inode, nr)) -+ return 1; - inode_add_bytes(inode, nr); - return 0; - } -@@ -384,22 +412,28 @@ static inline int vfs_dq_alloc_space(str - - static inline int vfs_dq_reserve_space(struct inode *inode, qsize_t nr) - { -+ if (dl_reserve_space(inode, nr)) -+ return 1; - return 0; - } - - static inline int vfs_dq_claim_space(struct inode *inode, qsize_t nr) - { -+ if (dl_claim_space(inode, nr)) -+ return 1; - return vfs_dq_alloc_space(inode, nr); - } - - static inline - int vfs_dq_release_reservation_space(struct inode *inode, qsize_t nr) - { -+ dl_release_space(inode, nr); - return 0; - } - - static inline void vfs_dq_free_space_nodirty(struct inode *inode, qsize_t nr) - { -+ dl_free_space(inode, nr); - inode_sub_bytes(inode, nr); - } - -diff -NurpP --minimal linux-2.6.32.1/include/linux/reboot.h linux-2.6.32.1-vs2.3.0.36.27/include/linux/reboot.h ---- linux-2.6.32.1/include/linux/reboot.h 2008-12-25 00:26:37.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/include/linux/reboot.h 2009-12-03 22:06:59.000000000 +0100 -@@ -33,6 +33,7 @@ - #define LINUX_REBOOT_CMD_RESTART2 0xA1B2C3D4 - #define LINUX_REBOOT_CMD_SW_SUSPEND 0xD000FCE2 - #define LINUX_REBOOT_CMD_KEXEC 0x45584543 -+#define LINUX_REBOOT_CMD_OOM 0xDEADBEEF - - - #ifdef __KERNEL__ -diff -NurpP --minimal linux-2.6.32.1/include/linux/reiserfs_fs.h linux-2.6.32.1-vs2.3.0.36.27/include/linux/reiserfs_fs.h ---- linux-2.6.32.1/include/linux/reiserfs_fs.h 2009-09-10 15:26:26.000000000 +0200 -+++ linux-2.6.32.1-vs2.3.0.36.27/include/linux/reiserfs_fs.h 2009-12-03 20:04:56.000000000 +0100 -@@ -899,6 +899,11 @@ struct stat_data_v1 { - #define REISERFS_COMPR_FL FS_COMPR_FL - #define REISERFS_NOTAIL_FL FS_NOTAIL_FL - -+/* unfortunately reiserfs sdattr is only 16 bit */ -+#define REISERFS_IXUNLINK_FL (FS_IXUNLINK_FL >> 16) -+#define REISERFS_BARRIER_FL (FS_BARRIER_FL >> 16) -+#define REISERFS_COW_FL (FS_COW_FL >> 16) -+ - /* persistent flags that file inherits from the parent directory */ - #define REISERFS_INHERIT_MASK ( REISERFS_IMMUTABLE_FL | \ - REISERFS_SYNC_FL | \ -@@ -908,6 +913,9 @@ struct stat_data_v1 { - REISERFS_COMPR_FL | \ - REISERFS_NOTAIL_FL ) - -+#define REISERFS_FL_USER_VISIBLE 0x80FF -+#define REISERFS_FL_USER_MODIFIABLE 0x80FF -+ - /* Stat Data on disk (reiserfs version of UFS disk inode minus the - address blocks) */ - struct stat_data { -@@ -1989,6 +1997,7 @@ static inline void reiserfs_update_sd(st - void sd_attrs_to_i_attrs(__u16 sd_attrs, struct inode *inode); - void i_attrs_to_sd_attrs(struct inode *inode, __u16 * sd_attrs); - int reiserfs_setattr(struct dentry *dentry, struct iattr *attr); -+int reiserfs_sync_flags(struct inode *inode, int, int); - - /* namei.c */ - void set_de_name_and_namelen(struct reiserfs_dir_entry *de); -diff -NurpP --minimal linux-2.6.32.1/include/linux/reiserfs_fs_sb.h linux-2.6.32.1-vs2.3.0.36.27/include/linux/reiserfs_fs_sb.h ---- linux-2.6.32.1/include/linux/reiserfs_fs_sb.h 2009-09-10 15:26:26.000000000 +0200 -+++ linux-2.6.32.1-vs2.3.0.36.27/include/linux/reiserfs_fs_sb.h 2009-12-03 20:04:56.000000000 +0100 -@@ -456,6 +456,7 @@ enum reiserfs_mount_options { - REISERFS_EXPOSE_PRIVROOT, - REISERFS_BARRIER_NONE, - REISERFS_BARRIER_FLUSH, -+ REISERFS_TAGGED, - - /* Actions on error */ - REISERFS_ERROR_PANIC, -diff -NurpP --minimal linux-2.6.32.1/include/linux/sched.h linux-2.6.32.1-vs2.3.0.36.27/include/linux/sched.h ---- linux-2.6.32.1/include/linux/sched.h 2009-12-14 21:29:46.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/include/linux/sched.h 2009-12-14 22:20:55.000000000 +0100 -@@ -390,25 +390,28 @@ extern void arch_unmap_area_topdown(stru - * The mm counters are not protected by its page_table_lock, - * so must be incremented atomically. - */ --#define set_mm_counter(mm, member, value) atomic_long_set(&(mm)->_##member, value) --#define get_mm_counter(mm, member) ((unsigned long)atomic_long_read(&(mm)->_##member)) --#define add_mm_counter(mm, member, value) atomic_long_add(value, &(mm)->_##member) --#define inc_mm_counter(mm, member) atomic_long_inc(&(mm)->_##member) --#define dec_mm_counter(mm, member) atomic_long_dec(&(mm)->_##member) -+#define __set_mm_counter(mm, member, value) \ -+ atomic_long_set(&(mm)->_##member, value) -+#define get_mm_counter(mm, member) \ -+ ((unsigned long)atomic_long_read(&(mm)->_##member)) - - #else /* !USE_SPLIT_PTLOCKS */ - /* - * The mm counters are protected by its page_table_lock, - * so can be incremented directly. - */ --#define set_mm_counter(mm, member, value) (mm)->_##member = (value) -+#define __set_mm_counter(mm, member, value) (mm)->_##member = (value) - #define get_mm_counter(mm, member) ((mm)->_##member) --#define add_mm_counter(mm, member, value) (mm)->_##member += (value) --#define inc_mm_counter(mm, member) (mm)->_##member++ --#define dec_mm_counter(mm, member) (mm)->_##member-- - - #endif /* !USE_SPLIT_PTLOCKS */ - -+#define set_mm_counter(mm, member, value) \ -+ vx_ ## member ## pages_sub((mm), (get_mm_counter(mm, member) - value)) -+#define add_mm_counter(mm, member, value) \ -+ vx_ ## member ## pages_add((mm), (value)) -+#define inc_mm_counter(mm, member) vx_ ## member ## pages_inc((mm)) -+#define dec_mm_counter(mm, member) vx_ ## member ## pages_dec((mm)) -+ - #define get_mm_rss(mm) \ - (get_mm_counter(mm, file_rss) + get_mm_counter(mm, anon_rss)) - #define update_hiwater_rss(mm) do { \ -@@ -1183,6 +1186,12 @@ struct sched_entity { - u64 nr_wakeups_affine_attempts; - u64 nr_wakeups_passive; - u64 nr_wakeups_idle; -+#ifdef CONFIG_CFS_HARD_LIMITS -+ u64 throttle_start; -+ u64 throttle_max; -+ u64 throttle_count; -+ u64 throttle_sum; -+#endif - #endif - - #ifdef CONFIG_FAIR_GROUP_SCHED -@@ -1393,6 +1402,14 @@ struct task_struct { - #endif - seccomp_t seccomp; - -+/* vserver context data */ -+ struct vx_info *vx_info; -+ struct nx_info *nx_info; -+ -+ xid_t xid; -+ nid_t nid; -+ tag_t tag; -+ - /* Thread group tracking */ - u32 parent_exec_id; - u32 self_exec_id; -@@ -1618,6 +1635,11 @@ struct pid_namespace; - pid_t __task_pid_nr_ns(struct task_struct *task, enum pid_type type, - struct pid_namespace *ns); - -+#include -+#include -+#include -+#include -+ - static inline pid_t task_pid_nr(struct task_struct *tsk) - { - return tsk->pid; -@@ -1631,7 +1653,8 @@ static inline pid_t task_pid_nr_ns(struc - - static inline pid_t task_pid_vnr(struct task_struct *tsk) - { -- return __task_pid_nr_ns(tsk, PIDTYPE_PID, NULL); -+ // return __task_pid_nr_ns(tsk, PIDTYPE_PID, NULL); -+ return vx_map_pid(__task_pid_nr_ns(tsk, PIDTYPE_PID, NULL)); - } - - -@@ -1644,7 +1667,7 @@ pid_t task_tgid_nr_ns(struct task_struct - - static inline pid_t task_tgid_vnr(struct task_struct *tsk) - { -- return pid_vnr(task_tgid(tsk)); -+ return vx_map_tgid(pid_vnr(task_tgid(tsk))); - } - - -diff -NurpP --minimal linux-2.6.32.1/include/linux/shmem_fs.h linux-2.6.32.1-vs2.3.0.36.27/include/linux/shmem_fs.h ---- linux-2.6.32.1/include/linux/shmem_fs.h 2009-12-03 20:02:56.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/include/linux/shmem_fs.h 2009-12-03 20:04:56.000000000 +0100 -@@ -8,6 +8,9 @@ - - #define SHMEM_NR_DIRECT 16 - -+#define TMPFS_SUPER_MAGIC 0x01021994 -+ -+ - struct shmem_inode_info { - spinlock_t lock; - unsigned long flags; -diff -NurpP --minimal linux-2.6.32.1/include/linux/stat.h linux-2.6.32.1-vs2.3.0.36.27/include/linux/stat.h ---- linux-2.6.32.1/include/linux/stat.h 2008-12-25 00:26:37.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/include/linux/stat.h 2009-12-03 20:04:56.000000000 +0100 -@@ -66,6 +66,7 @@ struct kstat { - unsigned int nlink; - uid_t uid; - gid_t gid; -+ tag_t tag; - dev_t rdev; - loff_t size; - struct timespec atime; -diff -NurpP --minimal linux-2.6.32.1/include/linux/sunrpc/auth.h linux-2.6.32.1-vs2.3.0.36.27/include/linux/sunrpc/auth.h ---- linux-2.6.32.1/include/linux/sunrpc/auth.h 2009-12-03 20:02:56.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/include/linux/sunrpc/auth.h 2009-12-03 20:04:56.000000000 +0100 -@@ -25,6 +25,7 @@ - struct auth_cred { - uid_t uid; - gid_t gid; -+ tag_t tag; - struct group_info *group_info; - unsigned char machine_cred : 1; - }; -diff -NurpP --minimal linux-2.6.32.1/include/linux/sunrpc/clnt.h linux-2.6.32.1-vs2.3.0.36.27/include/linux/sunrpc/clnt.h ---- linux-2.6.32.1/include/linux/sunrpc/clnt.h 2009-12-03 20:02:56.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/include/linux/sunrpc/clnt.h 2009-12-03 20:04:56.000000000 +0100 -@@ -49,7 +49,8 @@ struct rpc_clnt { - unsigned int cl_softrtry : 1,/* soft timeouts */ - cl_discrtry : 1,/* disconnect before retry */ - cl_autobind : 1,/* use getport() */ -- cl_chatty : 1;/* be verbose */ -+ cl_chatty : 1,/* be verbose */ -+ cl_tag : 1;/* context tagging */ - - struct rpc_rtt * cl_rtt; /* RTO estimator data */ - const struct rpc_timeout *cl_timeout; /* Timeout strategy */ -diff -NurpP --minimal linux-2.6.32.1/include/linux/syscalls.h linux-2.6.32.1-vs2.3.0.36.27/include/linux/syscalls.h ---- linux-2.6.32.1/include/linux/syscalls.h 2009-12-03 20:02:56.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/include/linux/syscalls.h 2009-12-03 20:04:56.000000000 +0100 -@@ -546,6 +546,8 @@ asmlinkage long sys_symlink(const char _ - asmlinkage long sys_unlink(const char __user *pathname); - asmlinkage long sys_rename(const char __user *oldname, - const char __user *newname); -+asmlinkage long sys_copyfile(const char __user *from, const char __user *to, -+ umode_t mode); - asmlinkage long sys_chmod(const char __user *filename, mode_t mode); - asmlinkage long sys_fchmod(unsigned int fd, mode_t mode); - -diff -NurpP --minimal linux-2.6.32.1/include/linux/sysctl.h linux-2.6.32.1-vs2.3.0.36.27/include/linux/sysctl.h ---- linux-2.6.32.1/include/linux/sysctl.h 2009-12-03 20:02:56.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/include/linux/sysctl.h 2009-12-03 20:04:56.000000000 +0100 -@@ -69,6 +69,7 @@ enum - CTL_ABI=9, /* Binary emulation */ - CTL_CPU=10, /* CPU stuff (speed scaling, etc) */ - CTL_ARLAN=254, /* arlan wireless driver */ -+ CTL_VSERVER=4242, /* Linux-VServer debug */ - CTL_S390DBF=5677, /* s390 debug */ - CTL_SUNRPC=7249, /* sunrpc debug */ - CTL_PM=9899, /* frv power management */ -@@ -103,6 +104,7 @@ enum - - KERN_PANIC=15, /* int: panic timeout */ - KERN_REALROOTDEV=16, /* real root device to mount after initrd */ -+ KERN_VSHELPER=17, /* string: path to vshelper policy agent */ - - KERN_SPARC_REBOOT=21, /* reboot command on Sparc */ - KERN_CTLALTDEL=22, /* int: allow ctl-alt-del to reboot */ -diff -NurpP --minimal linux-2.6.32.1/include/linux/sysfs.h linux-2.6.32.1-vs2.3.0.36.27/include/linux/sysfs.h ---- linux-2.6.32.1/include/linux/sysfs.h 2008-12-25 00:26:37.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/include/linux/sysfs.h 2009-12-03 20:04:56.000000000 +0100 -@@ -17,6 +17,8 @@ - #include - #include - -+#define SYSFS_SUPER_MAGIC 0x62656572 -+ - struct kobject; - struct module; - -diff -NurpP --minimal linux-2.6.32.1/include/linux/time.h linux-2.6.32.1-vs2.3.0.36.27/include/linux/time.h ---- linux-2.6.32.1/include/linux/time.h 2009-12-03 20:02:56.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/include/linux/time.h 2009-12-03 20:04:56.000000000 +0100 -@@ -237,6 +237,9 @@ static __always_inline void timespec_add - a->tv_sec += __iter_div_u64_rem(a->tv_nsec + ns, NSEC_PER_SEC, &ns); - a->tv_nsec = ns; - } -+ -+#include -+ - #endif /* __KERNEL__ */ - - #define NFDBITS __NFDBITS -diff -NurpP --minimal linux-2.6.32.1/include/linux/types.h linux-2.6.32.1-vs2.3.0.36.27/include/linux/types.h ---- linux-2.6.32.1/include/linux/types.h 2009-09-10 15:26:26.000000000 +0200 -+++ linux-2.6.32.1-vs2.3.0.36.27/include/linux/types.h 2009-12-03 20:04:56.000000000 +0100 -@@ -37,6 +37,9 @@ typedef __kernel_uid32_t uid_t; - typedef __kernel_gid32_t gid_t; - typedef __kernel_uid16_t uid16_t; - typedef __kernel_gid16_t gid16_t; -+typedef unsigned int xid_t; -+typedef unsigned int nid_t; -+typedef unsigned int tag_t; - - typedef unsigned long uintptr_t; - -diff -NurpP --minimal linux-2.6.32.1/include/linux/vroot.h linux-2.6.32.1-vs2.3.0.36.27/include/linux/vroot.h ---- linux-2.6.32.1/include/linux/vroot.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/include/linux/vroot.h 2009-12-03 20:04:56.000000000 +0100 -@@ -0,0 +1,51 @@ -+ -+/* -+ * include/linux/vroot.h -+ * -+ * written by Herbert Pötzl, 9/11/2002 -+ * ported to 2.6 by Herbert Pötzl, 30/12/2004 -+ * -+ * Copyright (C) 2002-2007 by Herbert Pötzl. -+ * Redistribution of this file is permitted under the -+ * GNU General Public License. -+ */ -+ -+#ifndef _LINUX_VROOT_H -+#define _LINUX_VROOT_H -+ -+ -+#ifdef __KERNEL__ -+ -+/* Possible states of device */ -+enum { -+ Vr_unbound, -+ Vr_bound, -+}; -+ -+struct vroot_device { -+ int vr_number; -+ int vr_refcnt; -+ -+ struct semaphore vr_ctl_mutex; -+ struct block_device *vr_device; -+ int vr_state; -+}; -+ -+ -+typedef struct block_device *(vroot_grb_func)(struct block_device *); -+ -+extern int register_vroot_grb(vroot_grb_func *); -+extern int unregister_vroot_grb(vroot_grb_func *); -+ -+#endif /* __KERNEL__ */ -+ -+#define MAX_VROOT_DEFAULT 8 -+ -+/* -+ * IOCTL commands --- we will commandeer 0x56 ('V') -+ */ -+ -+#define VROOT_SET_DEV 0x5600 -+#define VROOT_CLR_DEV 0x5601 -+ -+#endif /* _LINUX_VROOT_H */ -diff -NurpP --minimal linux-2.6.32.1/include/linux/vs_base.h linux-2.6.32.1-vs2.3.0.36.27/include/linux/vs_base.h ---- linux-2.6.32.1/include/linux/vs_base.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/include/linux/vs_base.h 2009-12-03 20:04:56.000000000 +0100 -@@ -0,0 +1,10 @@ -+#ifndef _VS_BASE_H -+#define _VS_BASE_H -+ -+#include "vserver/base.h" -+#include "vserver/check.h" -+#include "vserver/debug.h" -+ -+#else -+#warning duplicate inclusion -+#endif -diff -NurpP --minimal linux-2.6.32.1/include/linux/vs_context.h linux-2.6.32.1-vs2.3.0.36.27/include/linux/vs_context.h ---- linux-2.6.32.1/include/linux/vs_context.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/include/linux/vs_context.h 2009-12-03 20:04:56.000000000 +0100 -@@ -0,0 +1,242 @@ -+#ifndef _VS_CONTEXT_H -+#define _VS_CONTEXT_H -+ -+#include "vserver/base.h" -+#include "vserver/check.h" -+#include "vserver/context.h" -+#include "vserver/history.h" -+#include "vserver/debug.h" -+ -+#include -+ -+ -+#define get_vx_info(i) __get_vx_info(i, __FILE__, __LINE__, __HERE__) -+ -+static inline struct vx_info *__get_vx_info(struct vx_info *vxi, -+ const char *_file, int _line, void *_here) -+{ -+ if (!vxi) -+ return NULL; -+ -+ vxlprintk(VXD_CBIT(xid, 2), "get_vx_info(%p[#%d.%d])", -+ vxi, vxi ? vxi->vx_id : 0, -+ vxi ? atomic_read(&vxi->vx_usecnt) : 0, -+ _file, _line); -+ __vxh_get_vx_info(vxi, _here); -+ -+ atomic_inc(&vxi->vx_usecnt); -+ return vxi; -+} -+ -+ -+extern void free_vx_info(struct vx_info *); -+ -+#define put_vx_info(i) __put_vx_info(i, __FILE__, __LINE__, __HERE__) -+ -+static inline void __put_vx_info(struct vx_info *vxi, -+ const char *_file, int _line, void *_here) -+{ -+ if (!vxi) -+ return; -+ -+ vxlprintk(VXD_CBIT(xid, 2), "put_vx_info(%p[#%d.%d])", -+ vxi, vxi ? vxi->vx_id : 0, -+ vxi ? atomic_read(&vxi->vx_usecnt) : 0, -+ _file, _line); -+ __vxh_put_vx_info(vxi, _here); -+ -+ if (atomic_dec_and_test(&vxi->vx_usecnt)) -+ free_vx_info(vxi); -+} -+ -+ -+#define init_vx_info(p, i) \ -+ __init_vx_info(p, i, __FILE__, __LINE__, __HERE__) -+ -+static inline void __init_vx_info(struct vx_info **vxp, struct vx_info *vxi, -+ const char *_file, int _line, void *_here) -+{ -+ if (vxi) { -+ vxlprintk(VXD_CBIT(xid, 3), -+ "init_vx_info(%p[#%d.%d])", -+ vxi, vxi ? vxi->vx_id : 0, -+ vxi ? atomic_read(&vxi->vx_usecnt) : 0, -+ _file, _line); -+ __vxh_init_vx_info(vxi, vxp, _here); -+ -+ atomic_inc(&vxi->vx_usecnt); -+ } -+ *vxp = vxi; -+} -+ -+ -+#define set_vx_info(p, i) \ -+ __set_vx_info(p, i, __FILE__, __LINE__, __HERE__) -+ -+static inline void __set_vx_info(struct vx_info **vxp, struct vx_info *vxi, -+ const char *_file, int _line, void *_here) -+{ -+ struct vx_info *vxo; -+ -+ if (!vxi) -+ return; -+ -+ vxlprintk(VXD_CBIT(xid, 3), "set_vx_info(%p[#%d.%d])", -+ vxi, vxi ? vxi->vx_id : 0, -+ vxi ? atomic_read(&vxi->vx_usecnt) : 0, -+ _file, _line); -+ __vxh_set_vx_info(vxi, vxp, _here); -+ -+ atomic_inc(&vxi->vx_usecnt); -+ vxo = xchg(vxp, vxi); -+ BUG_ON(vxo); -+} -+ -+ -+#define clr_vx_info(p) __clr_vx_info(p, __FILE__, __LINE__, __HERE__) -+ -+static inline void __clr_vx_info(struct vx_info **vxp, -+ const char *_file, int _line, void *_here) -+{ -+ struct vx_info *vxo; -+ -+ vxo = xchg(vxp, NULL); -+ if (!vxo) -+ return; -+ -+ vxlprintk(VXD_CBIT(xid, 3), "clr_vx_info(%p[#%d.%d])", -+ vxo, vxo ? vxo->vx_id : 0, -+ vxo ? atomic_read(&vxo->vx_usecnt) : 0, -+ _file, _line); -+ __vxh_clr_vx_info(vxo, vxp, _here); -+ -+ if (atomic_dec_and_test(&vxo->vx_usecnt)) -+ free_vx_info(vxo); -+} -+ -+ -+#define claim_vx_info(v, p) \ -+ __claim_vx_info(v, p, __FILE__, __LINE__, __HERE__) -+ -+static inline void __claim_vx_info(struct vx_info *vxi, -+ struct task_struct *task, -+ const char *_file, int _line, void *_here) -+{ -+ vxlprintk(VXD_CBIT(xid, 3), "claim_vx_info(%p[#%d.%d.%d]) %p", -+ vxi, vxi ? vxi->vx_id : 0, -+ vxi ? atomic_read(&vxi->vx_usecnt) : 0, -+ vxi ? atomic_read(&vxi->vx_tasks) : 0, -+ task, _file, _line); -+ __vxh_claim_vx_info(vxi, task, _here); -+ -+ atomic_inc(&vxi->vx_tasks); -+} -+ -+ -+extern void unhash_vx_info(struct vx_info *); -+ -+#define release_vx_info(v, p) \ -+ __release_vx_info(v, p, __FILE__, __LINE__, __HERE__) -+ -+static inline void __release_vx_info(struct vx_info *vxi, -+ struct task_struct *task, -+ const char *_file, int _line, void *_here) -+{ -+ vxlprintk(VXD_CBIT(xid, 3), "release_vx_info(%p[#%d.%d.%d]) %p", -+ vxi, vxi ? vxi->vx_id : 0, -+ vxi ? atomic_read(&vxi->vx_usecnt) : 0, -+ vxi ? atomic_read(&vxi->vx_tasks) : 0, -+ task, _file, _line); -+ __vxh_release_vx_info(vxi, task, _here); -+ -+ might_sleep(); -+ -+ if (atomic_dec_and_test(&vxi->vx_tasks)) -+ unhash_vx_info(vxi); -+} -+ -+ -+#define task_get_vx_info(p) \ -+ __task_get_vx_info(p, __FILE__, __LINE__, __HERE__) -+ -+static inline struct vx_info *__task_get_vx_info(struct task_struct *p, -+ const char *_file, int _line, void *_here) -+{ -+ struct vx_info *vxi; -+ -+ task_lock(p); -+ vxlprintk(VXD_CBIT(xid, 5), "task_get_vx_info(%p)", -+ p, _file, _line); -+ vxi = __get_vx_info(p->vx_info, _file, _line, _here); -+ task_unlock(p); -+ return vxi; -+} -+ -+ -+static inline void __wakeup_vx_info(struct vx_info *vxi) -+{ -+ if (waitqueue_active(&vxi->vx_wait)) -+ wake_up_interruptible(&vxi->vx_wait); -+} -+ -+ -+#define enter_vx_info(v, s) __enter_vx_info(v, s, __FILE__, __LINE__) -+ -+static inline void __enter_vx_info(struct vx_info *vxi, -+ struct vx_info_save *vxis, const char *_file, int _line) -+{ -+ vxlprintk(VXD_CBIT(xid, 5), "enter_vx_info(%p[#%d],%p) %p[#%d,%p]", -+ vxi, vxi ? vxi->vx_id : 0, vxis, current, -+ current->xid, current->vx_info, _file, _line); -+ vxis->vxi = xchg(¤t->vx_info, vxi); -+ vxis->xid = current->xid; -+ current->xid = vxi ? vxi->vx_id : 0; -+} -+ -+#define leave_vx_info(s) __leave_vx_info(s, __FILE__, __LINE__) -+ -+static inline void __leave_vx_info(struct vx_info_save *vxis, -+ const char *_file, int _line) -+{ -+ vxlprintk(VXD_CBIT(xid, 5), "leave_vx_info(%p[#%d,%p]) %p[#%d,%p]", -+ vxis, vxis->xid, vxis->vxi, current, -+ current->xid, current->vx_info, _file, _line); -+ (void)xchg(¤t->vx_info, vxis->vxi); -+ current->xid = vxis->xid; -+} -+ -+ -+static inline void __enter_vx_admin(struct vx_info_save *vxis) -+{ -+ vxis->vxi = xchg(¤t->vx_info, NULL); -+ vxis->xid = xchg(¤t->xid, (xid_t)0); -+} -+ -+static inline void __leave_vx_admin(struct vx_info_save *vxis) -+{ -+ (void)xchg(¤t->xid, vxis->xid); -+ (void)xchg(¤t->vx_info, vxis->vxi); -+} -+ -+#define task_is_init(p) \ -+ __task_is_init(p, __FILE__, __LINE__, __HERE__) -+ -+static inline int __task_is_init(struct task_struct *p, -+ const char *_file, int _line, void *_here) -+{ -+ int is_init = is_global_init(p); -+ -+ task_lock(p); -+ if (p->vx_info) -+ is_init = p->vx_info->vx_initpid == p->pid; -+ task_unlock(p); -+ return is_init; -+} -+ -+extern void exit_vx_info(struct task_struct *, int); -+extern void exit_vx_info_early(struct task_struct *, int); -+ -+ -+#else -+#warning duplicate inclusion -+#endif -diff -NurpP --minimal linux-2.6.32.1/include/linux/vs_cowbl.h linux-2.6.32.1-vs2.3.0.36.27/include/linux/vs_cowbl.h ---- linux-2.6.32.1/include/linux/vs_cowbl.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/include/linux/vs_cowbl.h 2009-12-03 20:04:56.000000000 +0100 -@@ -0,0 +1,47 @@ -+#ifndef _VS_COWBL_H -+#define _VS_COWBL_H -+ -+#include -+#include -+#include -+ -+extern struct dentry *cow_break_link(const char *pathname); -+ -+static inline int cow_check_and_break(struct path *path) -+{ -+ struct inode *inode = path->dentry->d_inode; -+ int error = 0; -+ -+ /* do we need this check? */ -+ if (IS_RDONLY(inode)) -+ return -EROFS; -+ -+ if (IS_COW(inode)) { -+ if (IS_COW_LINK(inode)) { -+ struct dentry *new_dentry, *old_dentry = path->dentry; -+ char *pp, *buf; -+ -+ buf = kmalloc(PATH_MAX, GFP_KERNEL); -+ if (!buf) { -+ return -ENOMEM; -+ } -+ pp = d_path(path, buf, PATH_MAX); -+ new_dentry = cow_break_link(pp); -+ kfree(buf); -+ if (!IS_ERR(new_dentry)) { -+ path->dentry = new_dentry; -+ dput(old_dentry); -+ } else -+ error = PTR_ERR(new_dentry); -+ } else { -+ inode->i_flags &= ~(S_IXUNLINK | S_IMMUTABLE); -+ inode->i_ctime = CURRENT_TIME; -+ mark_inode_dirty(inode); -+ } -+ } -+ return error; -+} -+ -+#else -+#warning duplicate inclusion -+#endif -diff -NurpP --minimal linux-2.6.32.1/include/linux/vs_cvirt.h linux-2.6.32.1-vs2.3.0.36.27/include/linux/vs_cvirt.h ---- linux-2.6.32.1/include/linux/vs_cvirt.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/include/linux/vs_cvirt.h 2009-12-03 20:04:56.000000000 +0100 -@@ -0,0 +1,50 @@ -+#ifndef _VS_CVIRT_H -+#define _VS_CVIRT_H -+ -+#include "vserver/cvirt.h" -+#include "vserver/context.h" -+#include "vserver/base.h" -+#include "vserver/check.h" -+#include "vserver/debug.h" -+ -+ -+static inline void vx_activate_task(struct task_struct *p) -+{ -+ struct vx_info *vxi; -+ -+ if ((vxi = p->vx_info)) { -+ vx_update_load(vxi); -+ atomic_inc(&vxi->cvirt.nr_running); -+ } -+} -+ -+static inline void vx_deactivate_task(struct task_struct *p) -+{ -+ struct vx_info *vxi; -+ -+ if ((vxi = p->vx_info)) { -+ vx_update_load(vxi); -+ atomic_dec(&vxi->cvirt.nr_running); -+ } -+} -+ -+static inline void vx_uninterruptible_inc(struct task_struct *p) -+{ -+ struct vx_info *vxi; -+ -+ if ((vxi = p->vx_info)) -+ atomic_inc(&vxi->cvirt.nr_uninterruptible); -+} -+ -+static inline void vx_uninterruptible_dec(struct task_struct *p) -+{ -+ struct vx_info *vxi; -+ -+ if ((vxi = p->vx_info)) -+ atomic_dec(&vxi->cvirt.nr_uninterruptible); -+} -+ -+ -+#else -+#warning duplicate inclusion -+#endif -diff -NurpP --minimal linux-2.6.32.1/include/linux/vs_device.h linux-2.6.32.1-vs2.3.0.36.27/include/linux/vs_device.h ---- linux-2.6.32.1/include/linux/vs_device.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/include/linux/vs_device.h 2009-12-03 20:04:56.000000000 +0100 -@@ -0,0 +1,45 @@ -+#ifndef _VS_DEVICE_H -+#define _VS_DEVICE_H -+ -+#include "vserver/base.h" -+#include "vserver/device.h" -+#include "vserver/debug.h" -+ -+ -+#ifdef CONFIG_VSERVER_DEVICE -+ -+int vs_map_device(struct vx_info *, dev_t, dev_t *, umode_t); -+ -+#define vs_device_perm(v, d, m, p) \ -+ ((vs_map_device(current_vx_info(), d, NULL, m) & (p)) == (p)) -+ -+#else -+ -+static inline -+int vs_map_device(struct vx_info *vxi, -+ dev_t device, dev_t *target, umode_t mode) -+{ -+ if (target) -+ *target = device; -+ return ~0; -+} -+ -+#define vs_device_perm(v, d, m, p) ((p) == (p)) -+ -+#endif -+ -+ -+#define vs_map_chrdev(d, t, p) \ -+ ((vs_map_device(current_vx_info(), d, t, S_IFCHR) & (p)) == (p)) -+#define vs_map_blkdev(d, t, p) \ -+ ((vs_map_device(current_vx_info(), d, t, S_IFBLK) & (p)) == (p)) -+ -+#define vs_chrdev_perm(d, p) \ -+ vs_device_perm(current_vx_info(), d, S_IFCHR, p) -+#define vs_blkdev_perm(d, p) \ -+ vs_device_perm(current_vx_info(), d, S_IFBLK, p) -+ -+ -+#else -+#warning duplicate inclusion -+#endif -diff -NurpP --minimal linux-2.6.32.1/include/linux/vs_dlimit.h linux-2.6.32.1-vs2.3.0.36.27/include/linux/vs_dlimit.h ---- linux-2.6.32.1/include/linux/vs_dlimit.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/include/linux/vs_dlimit.h 2009-12-03 20:04:56.000000000 +0100 -@@ -0,0 +1,216 @@ -+#ifndef _VS_DLIMIT_H -+#define _VS_DLIMIT_H -+ -+#include -+ -+#include "vserver/dlimit.h" -+#include "vserver/base.h" -+#include "vserver/debug.h" -+ -+ -+#define get_dl_info(i) __get_dl_info(i, __FILE__, __LINE__) -+ -+static inline struct dl_info *__get_dl_info(struct dl_info *dli, -+ const char *_file, int _line) -+{ -+ if (!dli) -+ return NULL; -+ vxlprintk(VXD_CBIT(dlim, 4), "get_dl_info(%p[#%d.%d])", -+ dli, dli ? dli->dl_tag : 0, -+ dli ? atomic_read(&dli->dl_usecnt) : 0, -+ _file, _line); -+ atomic_inc(&dli->dl_usecnt); -+ return dli; -+} -+ -+ -+#define free_dl_info(i) \ -+ call_rcu(&(i)->dl_rcu, rcu_free_dl_info) -+ -+#define put_dl_info(i) __put_dl_info(i, __FILE__, __LINE__) -+ -+static inline void __put_dl_info(struct dl_info *dli, -+ const char *_file, int _line) -+{ -+ if (!dli) -+ return; -+ vxlprintk(VXD_CBIT(dlim, 4), "put_dl_info(%p[#%d.%d])", -+ dli, dli ? dli->dl_tag : 0, -+ dli ? atomic_read(&dli->dl_usecnt) : 0, -+ _file, _line); -+ if (atomic_dec_and_test(&dli->dl_usecnt)) -+ free_dl_info(dli); -+} -+ -+ -+#define __dlimit_char(d) ((d) ? '*' : ' ') -+ -+static inline int __dl_alloc_space(struct super_block *sb, -+ tag_t tag, dlsize_t nr, const char *file, int line) -+{ -+ struct dl_info *dli = NULL; -+ int ret = 0; -+ -+ if (nr == 0) -+ goto out; -+ dli = locate_dl_info(sb, tag); -+ if (!dli) -+ goto out; -+ -+ spin_lock(&dli->dl_lock); -+ ret = (dli->dl_space_used + nr > dli->dl_space_total); -+ if (!ret) -+ dli->dl_space_used += nr; -+ spin_unlock(&dli->dl_lock); -+ put_dl_info(dli); -+out: -+ vxlprintk(VXD_CBIT(dlim, 1), -+ "ALLOC (%p,#%d)%c %lld bytes (%d)", -+ sb, tag, __dlimit_char(dli), (long long)nr, -+ ret, file, line); -+ return ret; -+} -+ -+static inline void __dl_free_space(struct super_block *sb, -+ tag_t tag, dlsize_t nr, const char *_file, int _line) -+{ -+ struct dl_info *dli = NULL; -+ -+ if (nr == 0) -+ goto out; -+ dli = locate_dl_info(sb, tag); -+ if (!dli) -+ goto out; -+ -+ spin_lock(&dli->dl_lock); -+ if (dli->dl_space_used > nr) -+ dli->dl_space_used -= nr; -+ else -+ dli->dl_space_used = 0; -+ spin_unlock(&dli->dl_lock); -+ put_dl_info(dli); -+out: -+ vxlprintk(VXD_CBIT(dlim, 1), -+ "FREE (%p,#%d)%c %lld bytes", -+ sb, tag, __dlimit_char(dli), (long long)nr, -+ _file, _line); -+} -+ -+static inline int __dl_alloc_inode(struct super_block *sb, -+ tag_t tag, const char *_file, int _line) -+{ -+ struct dl_info *dli; -+ int ret = 0; -+ -+ dli = locate_dl_info(sb, tag); -+ if (!dli) -+ goto out; -+ -+ spin_lock(&dli->dl_lock); -+ ret = (dli->dl_inodes_used >= dli->dl_inodes_total); -+ if (!ret) -+ dli->dl_inodes_used++; -+ spin_unlock(&dli->dl_lock); -+ put_dl_info(dli); -+out: -+ vxlprintk(VXD_CBIT(dlim, 0), -+ "ALLOC (%p,#%d)%c inode (%d)", -+ sb, tag, __dlimit_char(dli), ret, _file, _line); -+ return ret; -+} -+ -+static inline void __dl_free_inode(struct super_block *sb, -+ tag_t tag, const char *_file, int _line) -+{ -+ struct dl_info *dli; -+ -+ dli = locate_dl_info(sb, tag); -+ if (!dli) -+ goto out; -+ -+ spin_lock(&dli->dl_lock); -+ if (dli->dl_inodes_used > 1) -+ dli->dl_inodes_used--; -+ else -+ dli->dl_inodes_used = 0; -+ spin_unlock(&dli->dl_lock); -+ put_dl_info(dli); -+out: -+ vxlprintk(VXD_CBIT(dlim, 0), -+ "FREE (%p,#%d)%c inode", -+ sb, tag, __dlimit_char(dli), _file, _line); -+} -+ -+static inline void __dl_adjust_block(struct super_block *sb, tag_t tag, -+ unsigned long long *free_blocks, unsigned long long *root_blocks, -+ const char *_file, int _line) -+{ -+ struct dl_info *dli; -+ uint64_t broot, bfree; -+ -+ dli = locate_dl_info(sb, tag); -+ if (!dli) -+ return; -+ -+ spin_lock(&dli->dl_lock); -+ broot = (dli->dl_space_total - -+ (dli->dl_space_total >> 10) * dli->dl_nrlmult) -+ >> sb->s_blocksize_bits; -+ bfree = (dli->dl_space_total - dli->dl_space_used) -+ >> sb->s_blocksize_bits; -+ spin_unlock(&dli->dl_lock); -+ -+ vxlprintk(VXD_CBIT(dlim, 2), -+ "ADJUST: %lld,%lld on %lld,%lld [mult=%d]", -+ (long long)bfree, (long long)broot, -+ *free_blocks, *root_blocks, dli->dl_nrlmult, -+ _file, _line); -+ if (free_blocks) { -+ if (*free_blocks > bfree) -+ *free_blocks = bfree; -+ } -+ if (root_blocks) { -+ if (*root_blocks > broot) -+ *root_blocks = broot; -+ } -+ put_dl_info(dli); -+} -+ -+#define dl_prealloc_space(in, bytes) \ -+ __dl_alloc_space((in)->i_sb, (in)->i_tag, (dlsize_t)(bytes), \ -+ __FILE__, __LINE__ ) -+ -+#define dl_alloc_space(in, bytes) \ -+ __dl_alloc_space((in)->i_sb, (in)->i_tag, (dlsize_t)(bytes), \ -+ __FILE__, __LINE__ ) -+ -+#define dl_reserve_space(in, bytes) \ -+ __dl_alloc_space((in)->i_sb, (in)->i_tag, (dlsize_t)(bytes), \ -+ __FILE__, __LINE__ ) -+ -+#define dl_claim_space(in, bytes) (0) -+ -+#define dl_release_space(in, bytes) \ -+ __dl_free_space((in)->i_sb, (in)->i_tag, (dlsize_t)(bytes), \ -+ __FILE__, __LINE__ ) -+ -+#define dl_free_space(in, bytes) \ -+ __dl_free_space((in)->i_sb, (in)->i_tag, (dlsize_t)(bytes), \ -+ __FILE__, __LINE__ ) -+ -+ -+ -+#define dl_alloc_inode(in) \ -+ __dl_alloc_inode((in)->i_sb, (in)->i_tag, __FILE__, __LINE__ ) -+ -+#define dl_free_inode(in) \ -+ __dl_free_inode((in)->i_sb, (in)->i_tag, __FILE__, __LINE__ ) -+ -+ -+#define dl_adjust_block(sb, tag, fb, rb) \ -+ __dl_adjust_block(sb, tag, fb, rb, __FILE__, __LINE__ ) -+ -+ -+#else -+#warning duplicate inclusion -+#endif -diff -NurpP --minimal linux-2.6.32.1/include/linux/vserver/base.h linux-2.6.32.1-vs2.3.0.36.27/include/linux/vserver/base.h ---- linux-2.6.32.1/include/linux/vserver/base.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/include/linux/vserver/base.h 2009-12-03 20:04:56.000000000 +0100 -@@ -0,0 +1,170 @@ -+#ifndef _VX_BASE_H -+#define _VX_BASE_H -+ -+ -+/* context state changes */ -+ -+enum { -+ VSC_STARTUP = 1, -+ VSC_SHUTDOWN, -+ -+ VSC_NETUP, -+ VSC_NETDOWN, -+}; -+ -+ -+ -+#define vx_task_xid(t) ((t)->xid) -+ -+#define vx_current_xid() vx_task_xid(current) -+ -+#define current_vx_info() (current->vx_info) -+ -+ -+#define nx_task_nid(t) ((t)->nid) -+ -+#define nx_current_nid() nx_task_nid(current) -+ -+#define current_nx_info() (current->nx_info) -+ -+ -+/* generic flag merging */ -+ -+#define vs_check_flags(v, m, f) (((v) & (m)) ^ (f)) -+ -+#define vs_mask_flags(v, f, m) (((v) & ~(m)) | ((f) & (m))) -+ -+#define vs_mask_mask(v, f, m) (((v) & ~(m)) | ((v) & (f) & (m))) -+ -+#define vs_check_bit(v, n) ((v) & (1LL << (n))) -+ -+ -+/* context flags */ -+ -+#define __vx_flags(v) ((v) ? (v)->vx_flags : 0) -+ -+#define vx_current_flags() __vx_flags(current_vx_info()) -+ -+#define vx_info_flags(v, m, f) \ -+ vs_check_flags(__vx_flags(v), m, f) -+ -+#define task_vx_flags(t, m, f) \ -+ ((t) && vx_info_flags((t)->vx_info, m, f)) -+ -+#define vx_flags(m, f) vx_info_flags(current_vx_info(), m, f) -+ -+ -+/* context caps */ -+ -+#define __vx_ccaps(v) ((v) ? (v)->vx_ccaps : 0) -+ -+#define vx_current_ccaps() __vx_ccaps(current_vx_info()) -+ -+#define vx_info_ccaps(v, c) (__vx_ccaps(v) & (c)) -+ -+#define vx_ccaps(c) vx_info_ccaps(current_vx_info(), (c)) -+ -+ -+ -+/* network flags */ -+ -+#define __nx_flags(n) ((n) ? (n)->nx_flags : 0) -+ -+#define nx_current_flags() __nx_flags(current_nx_info()) -+ -+#define nx_info_flags(n, m, f) \ -+ vs_check_flags(__nx_flags(n), m, f) -+ -+#define task_nx_flags(t, m, f) \ -+ ((t) && nx_info_flags((t)->nx_info, m, f)) -+ -+#define nx_flags(m, f) nx_info_flags(current_nx_info(), m, f) -+ -+ -+/* network caps */ -+ -+#define __nx_ncaps(n) ((n) ? (n)->nx_ncaps : 0) -+ -+#define nx_current_ncaps() __nx_ncaps(current_nx_info()) -+ -+#define nx_info_ncaps(n, c) (__nx_ncaps(n) & (c)) -+ -+#define nx_ncaps(c) nx_info_ncaps(current_nx_info(), c) -+ -+ -+/* context mask capabilities */ -+ -+#define __vx_mcaps(v) ((v) ? (v)->vx_ccaps >> 32UL : ~0 ) -+ -+#define vx_info_mcaps(v, c) (__vx_mcaps(v) & (c)) -+ -+#define vx_mcaps(c) vx_info_mcaps(current_vx_info(), c) -+ -+ -+/* context bcap mask */ -+ -+#define __vx_bcaps(v) ((v)->vx_bcaps) -+ -+#define vx_current_bcaps() __vx_bcaps(current_vx_info()) -+ -+ -+/* mask given bcaps */ -+ -+#define vx_info_mbcaps(v, c) ((v) ? cap_intersect(__vx_bcaps(v), c) : c) -+ -+#define vx_mbcaps(c) vx_info_mbcaps(current_vx_info(), c) -+ -+ -+/* masked cap_bset */ -+ -+#define vx_info_cap_bset(v) vx_info_mbcaps(v, current->cap_bset) -+ -+#define vx_current_cap_bset() vx_info_cap_bset(current_vx_info()) -+ -+#if 0 -+#define vx_info_mbcap(v, b) \ -+ (!vx_info_flags(v, VXF_STATE_SETUP, 0) ? \ -+ vx_info_bcaps(v, b) : (b)) -+ -+#define task_vx_mbcap(t, b) \ -+ vx_info_mbcap((t)->vx_info, (t)->b) -+ -+#define vx_mbcap(b) task_vx_mbcap(current, b) -+#endif -+ -+#define vx_cap_raised(v, c, f) cap_raised(vx_info_mbcaps(v, c), f) -+ -+#define vx_capable(b, c) (capable(b) || \ -+ (cap_raised(current_cap(), b) && vx_ccaps(c))) -+ -+#define nx_capable(b, c) (capable(b) || \ -+ (cap_raised(current_cap(), b) && nx_ncaps(c))) -+ -+#define vx_task_initpid(t, n) \ -+ ((t)->vx_info && \ -+ ((t)->vx_info->vx_initpid == (n))) -+ -+#define vx_current_initpid(n) vx_task_initpid(current, n) -+ -+ -+/* context unshare mask */ -+ -+#define __vx_umask(v) ((v)->vx_umask) -+ -+#define vx_current_umask() __vx_umask(current_vx_info()) -+ -+#define vx_can_unshare(b, f) (capable(b) || \ -+ (cap_raised(current_cap(), b) && \ -+ !((f) & ~vx_current_umask()))) -+ -+ -+#define __vx_state(v) ((v) ? ((v)->vx_state) : 0) -+ -+#define vx_info_state(v, m) (__vx_state(v) & (m)) -+ -+ -+#define __nx_state(n) ((n) ? ((n)->nx_state) : 0) -+ -+#define nx_info_state(n, m) (__nx_state(n) & (m)) -+ -+#endif -diff -NurpP --minimal linux-2.6.32.1/include/linux/vserver/cacct_cmd.h linux-2.6.32.1-vs2.3.0.36.27/include/linux/vserver/cacct_cmd.h ---- linux-2.6.32.1/include/linux/vserver/cacct_cmd.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/include/linux/vserver/cacct_cmd.h 2009-12-03 20:04:56.000000000 +0100 -@@ -0,0 +1,23 @@ -+#ifndef _VX_CACCT_CMD_H -+#define _VX_CACCT_CMD_H -+ -+ -+/* virtual host info name commands */ -+ -+#define VCMD_sock_stat VC_CMD(VSTAT, 5, 0) -+ -+struct vcmd_sock_stat_v0 { -+ uint32_t field; -+ uint32_t count[3]; -+ uint64_t total[3]; -+}; -+ -+ -+#ifdef __KERNEL__ -+ -+#include -+ -+extern int vc_sock_stat(struct vx_info *, void __user *); -+ -+#endif /* __KERNEL__ */ -+#endif /* _VX_CACCT_CMD_H */ -diff -NurpP --minimal linux-2.6.32.1/include/linux/vserver/cacct_def.h linux-2.6.32.1-vs2.3.0.36.27/include/linux/vserver/cacct_def.h ---- linux-2.6.32.1/include/linux/vserver/cacct_def.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/include/linux/vserver/cacct_def.h 2009-12-03 20:04:56.000000000 +0100 -@@ -0,0 +1,43 @@ -+#ifndef _VX_CACCT_DEF_H -+#define _VX_CACCT_DEF_H -+ -+#include -+#include -+ -+ -+struct _vx_sock_acc { -+ atomic_long_t count; -+ atomic_long_t total; -+}; -+ -+/* context sub struct */ -+ -+struct _vx_cacct { -+ struct _vx_sock_acc sock[VXA_SOCK_SIZE][3]; -+ atomic_t slab[8]; -+ atomic_t page[6][8]; -+}; -+ -+#ifdef CONFIG_VSERVER_DEBUG -+ -+static inline void __dump_vx_cacct(struct _vx_cacct *cacct) -+{ -+ int i, j; -+ -+ printk("\t_vx_cacct:"); -+ for (i = 0; i < 6; i++) { -+ struct _vx_sock_acc *ptr = cacct->sock[i]; -+ -+ printk("\t [%d] =", i); -+ for (j = 0; j < 3; j++) { -+ printk(" [%d] = %8lu, %8lu", j, -+ atomic_long_read(&ptr[j].count), -+ atomic_long_read(&ptr[j].total)); -+ } -+ printk("\n"); -+ } -+} -+ -+#endif -+ -+#endif /* _VX_CACCT_DEF_H */ -diff -NurpP --minimal linux-2.6.32.1/include/linux/vserver/cacct.h linux-2.6.32.1-vs2.3.0.36.27/include/linux/vserver/cacct.h ---- linux-2.6.32.1/include/linux/vserver/cacct.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/include/linux/vserver/cacct.h 2009-12-03 20:04:56.000000000 +0100 -@@ -0,0 +1,15 @@ -+#ifndef _VX_CACCT_H -+#define _VX_CACCT_H -+ -+ -+enum sock_acc_field { -+ VXA_SOCK_UNSPEC = 0, -+ VXA_SOCK_UNIX, -+ VXA_SOCK_INET, -+ VXA_SOCK_INET6, -+ VXA_SOCK_PACKET, -+ VXA_SOCK_OTHER, -+ VXA_SOCK_SIZE /* array size */ -+}; -+ -+#endif /* _VX_CACCT_H */ -diff -NurpP --minimal linux-2.6.32.1/include/linux/vserver/cacct_int.h linux-2.6.32.1-vs2.3.0.36.27/include/linux/vserver/cacct_int.h ---- linux-2.6.32.1/include/linux/vserver/cacct_int.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/include/linux/vserver/cacct_int.h 2009-12-03 20:04:56.000000000 +0100 -@@ -0,0 +1,21 @@ -+#ifndef _VX_CACCT_INT_H -+#define _VX_CACCT_INT_H -+ -+ -+#ifdef __KERNEL__ -+ -+static inline -+unsigned long vx_sock_count(struct _vx_cacct *cacct, int type, int pos) -+{ -+ return atomic_long_read(&cacct->sock[type][pos].count); -+} -+ -+ -+static inline -+unsigned long vx_sock_total(struct _vx_cacct *cacct, int type, int pos) -+{ -+ return atomic_long_read(&cacct->sock[type][pos].total); -+} -+ -+#endif /* __KERNEL__ */ -+#endif /* _VX_CACCT_INT_H */ -diff -NurpP --minimal linux-2.6.32.1/include/linux/vserver/check.h linux-2.6.32.1-vs2.3.0.36.27/include/linux/vserver/check.h ---- linux-2.6.32.1/include/linux/vserver/check.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/include/linux/vserver/check.h 2009-12-03 20:04:56.000000000 +0100 -@@ -0,0 +1,89 @@ -+#ifndef _VS_CHECK_H -+#define _VS_CHECK_H -+ -+ -+#define MAX_S_CONTEXT 65535 /* Arbitrary limit */ -+ -+#ifdef CONFIG_VSERVER_DYNAMIC_IDS -+#define MIN_D_CONTEXT 49152 /* dynamic contexts start here */ -+#else -+#define MIN_D_CONTEXT 65536 -+#endif -+ -+/* check conditions */ -+ -+#define VS_ADMIN 0x0001 -+#define VS_WATCH 0x0002 -+#define VS_HIDE 0x0004 -+#define VS_HOSTID 0x0008 -+ -+#define VS_IDENT 0x0010 -+#define VS_EQUIV 0x0020 -+#define VS_PARENT 0x0040 -+#define VS_CHILD 0x0080 -+ -+#define VS_ARG_MASK 0x00F0 -+ -+#define VS_DYNAMIC 0x0100 -+#define VS_STATIC 0x0200 -+ -+#define VS_ATR_MASK 0x0F00 -+ -+#ifdef CONFIG_VSERVER_PRIVACY -+#define VS_ADMIN_P (0) -+#define VS_WATCH_P (0) -+#else -+#define VS_ADMIN_P VS_ADMIN -+#define VS_WATCH_P VS_WATCH -+#endif -+ -+#define VS_HARDIRQ 0x1000 -+#define VS_SOFTIRQ 0x2000 -+#define VS_IRQ 0x4000 -+ -+#define VS_IRQ_MASK 0xF000 -+ -+#include -+ -+/* -+ * check current context for ADMIN/WATCH and -+ * optionally against supplied argument -+ */ -+static inline int __vs_check(int cid, int id, unsigned int mode) -+{ -+ if (mode & VS_ARG_MASK) { -+ if ((mode & VS_IDENT) && (id == cid)) -+ return 1; -+ } -+ if (mode & VS_ATR_MASK) { -+ if ((mode & VS_DYNAMIC) && -+ (id >= MIN_D_CONTEXT) && -+ (id <= MAX_S_CONTEXT)) -+ return 1; -+ if ((mode & VS_STATIC) && -+ (id > 1) && (id < MIN_D_CONTEXT)) -+ return 1; -+ } -+ if (mode & VS_IRQ_MASK) { -+ if ((mode & VS_IRQ) && unlikely(in_interrupt())) -+ return 1; -+ if ((mode & VS_HARDIRQ) && unlikely(in_irq())) -+ return 1; -+ if ((mode & VS_SOFTIRQ) && unlikely(in_softirq())) -+ return 1; -+ } -+ return (((mode & VS_ADMIN) && (cid == 0)) || -+ ((mode & VS_WATCH) && (cid == 1)) || -+ ((mode & VS_HOSTID) && (id == 0))); -+} -+ -+#define vx_check(c, m) __vs_check(vx_current_xid(), c, (m) | VS_IRQ) -+ -+#define vx_weak_check(c, m) ((m) ? vx_check(c, m) : 1) -+ -+ -+#define nx_check(c, m) __vs_check(nx_current_nid(), c, m) -+ -+#define nx_weak_check(c, m) ((m) ? nx_check(c, m) : 1) -+ -+#endif -diff -NurpP --minimal linux-2.6.32.1/include/linux/vserver/context_cmd.h linux-2.6.32.1-vs2.3.0.36.27/include/linux/vserver/context_cmd.h ---- linux-2.6.32.1/include/linux/vserver/context_cmd.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/include/linux/vserver/context_cmd.h 2009-12-03 20:04:56.000000000 +0100 -@@ -0,0 +1,145 @@ -+#ifndef _VX_CONTEXT_CMD_H -+#define _VX_CONTEXT_CMD_H -+ -+ -+/* vinfo commands */ -+ -+#define VCMD_task_xid VC_CMD(VINFO, 1, 0) -+ -+#ifdef __KERNEL__ -+extern int vc_task_xid(uint32_t); -+ -+#endif /* __KERNEL__ */ -+ -+#define VCMD_vx_info VC_CMD(VINFO, 5, 0) -+ -+struct vcmd_vx_info_v0 { -+ uint32_t xid; -+ uint32_t initpid; -+ /* more to come */ -+}; -+ -+#ifdef __KERNEL__ -+extern int vc_vx_info(struct vx_info *, void __user *); -+ -+#endif /* __KERNEL__ */ -+ -+#define VCMD_ctx_stat VC_CMD(VSTAT, 0, 0) -+ -+struct vcmd_ctx_stat_v0 { -+ uint32_t usecnt; -+ uint32_t tasks; -+ /* more to come */ -+}; -+ -+#ifdef __KERNEL__ -+extern int vc_ctx_stat(struct vx_info *, void __user *); -+ -+#endif /* __KERNEL__ */ -+ -+/* context commands */ -+ -+#define VCMD_ctx_create_v0 VC_CMD(VPROC, 1, 0) -+#define VCMD_ctx_create VC_CMD(VPROC, 1, 1) -+ -+struct vcmd_ctx_create { -+ uint64_t flagword; -+}; -+ -+#define VCMD_ctx_migrate_v0 VC_CMD(PROCMIG, 1, 0) -+#define VCMD_ctx_migrate VC_CMD(PROCMIG, 1, 1) -+ -+struct vcmd_ctx_migrate { -+ uint64_t flagword; -+}; -+ -+#ifdef __KERNEL__ -+extern int vc_ctx_create(uint32_t, void __user *); -+extern int vc_ctx_migrate(struct vx_info *, void __user *); -+ -+#endif /* __KERNEL__ */ -+ -+ -+/* flag commands */ -+ -+#define VCMD_get_cflags VC_CMD(FLAGS, 1, 0) -+#define VCMD_set_cflags VC_CMD(FLAGS, 2, 0) -+ -+struct vcmd_ctx_flags_v0 { -+ uint64_t flagword; -+ uint64_t mask; -+}; -+ -+#ifdef __KERNEL__ -+extern int vc_get_cflags(struct vx_info *, void __user *); -+extern int vc_set_cflags(struct vx_info *, void __user *); -+ -+#endif /* __KERNEL__ */ -+ -+ -+/* context caps commands */ -+ -+#define VCMD_get_ccaps VC_CMD(FLAGS, 3, 1) -+#define VCMD_set_ccaps VC_CMD(FLAGS, 4, 1) -+ -+struct vcmd_ctx_caps_v1 { -+ uint64_t ccaps; -+ uint64_t cmask; -+}; -+ -+#ifdef __KERNEL__ -+extern int vc_get_ccaps(struct vx_info *, void __user *); -+extern int vc_set_ccaps(struct vx_info *, void __user *); -+ -+#endif /* __KERNEL__ */ -+ -+ -+/* bcaps commands */ -+ -+#define VCMD_get_bcaps VC_CMD(FLAGS, 9, 0) -+#define VCMD_set_bcaps VC_CMD(FLAGS, 10, 0) -+ -+struct vcmd_bcaps { -+ uint64_t bcaps; -+ uint64_t bmask; -+}; -+ -+#ifdef __KERNEL__ -+extern int vc_get_bcaps(struct vx_info *, void __user *); -+extern int vc_set_bcaps(struct vx_info *, void __user *); -+ -+#endif /* __KERNEL__ */ -+ -+ -+/* umask commands */ -+ -+#define VCMD_get_umask VC_CMD(FLAGS, 13, 0) -+#define VCMD_set_umask VC_CMD(FLAGS, 14, 0) -+ -+struct vcmd_umask { -+ uint64_t umask; -+ uint64_t mask; -+}; -+ -+#ifdef __KERNEL__ -+extern int vc_get_umask(struct vx_info *, void __user *); -+extern int vc_set_umask(struct vx_info *, void __user *); -+ -+#endif /* __KERNEL__ */ -+ -+ -+/* OOM badness */ -+ -+#define VCMD_get_badness VC_CMD(MEMCTRL, 5, 0) -+#define VCMD_set_badness VC_CMD(MEMCTRL, 6, 0) -+ -+struct vcmd_badness_v0 { -+ int64_t bias; -+}; -+ -+#ifdef __KERNEL__ -+extern int vc_get_badness(struct vx_info *, void __user *); -+extern int vc_set_badness(struct vx_info *, void __user *); -+ -+#endif /* __KERNEL__ */ -+#endif /* _VX_CONTEXT_CMD_H */ -diff -NurpP --minimal linux-2.6.32.1/include/linux/vserver/context.h linux-2.6.32.1-vs2.3.0.36.27/include/linux/vserver/context.h ---- linux-2.6.32.1/include/linux/vserver/context.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/include/linux/vserver/context.h 2009-12-03 20:04:56.000000000 +0100 -@@ -0,0 +1,183 @@ -+#ifndef _VX_CONTEXT_H -+#define _VX_CONTEXT_H -+ -+#include -+#include -+ -+ -+/* context flags */ -+ -+#define VXF_INFO_SCHED 0x00000002 -+#define VXF_INFO_NPROC 0x00000004 -+#define VXF_INFO_PRIVATE 0x00000008 -+ -+#define VXF_INFO_INIT 0x00000010 -+#define VXF_INFO_HIDE 0x00000020 -+#define VXF_INFO_ULIMIT 0x00000040 -+#define VXF_INFO_NSPACE 0x00000080 -+ -+#define VXF_SCHED_HARD 0x00000100 -+#define VXF_SCHED_PRIO 0x00000200 -+#define VXF_SCHED_PAUSE 0x00000400 -+ -+#define VXF_VIRT_MEM 0x00010000 -+#define VXF_VIRT_UPTIME 0x00020000 -+#define VXF_VIRT_CPU 0x00040000 -+#define VXF_VIRT_LOAD 0x00080000 -+#define VXF_VIRT_TIME 0x00100000 -+ -+#define VXF_HIDE_MOUNT 0x01000000 -+/* was VXF_HIDE_NETIF 0x02000000 */ -+#define VXF_HIDE_VINFO 0x04000000 -+ -+#define VXF_STATE_SETUP (1ULL << 32) -+#define VXF_STATE_INIT (1ULL << 33) -+#define VXF_STATE_ADMIN (1ULL << 34) -+ -+#define VXF_SC_HELPER (1ULL << 36) -+#define VXF_REBOOT_KILL (1ULL << 37) -+#define VXF_PERSISTENT (1ULL << 38) -+ -+#define VXF_FORK_RSS (1ULL << 48) -+#define VXF_PROLIFIC (1ULL << 49) -+ -+#define VXF_IGNEG_NICE (1ULL << 52) -+ -+#define VXF_ONE_TIME (0x0007ULL << 32) -+ -+#define VXF_INIT_SET (VXF_STATE_SETUP | VXF_STATE_INIT | VXF_STATE_ADMIN) -+ -+ -+/* context migration */ -+ -+#define VXM_SET_INIT 0x00000001 -+#define VXM_SET_REAPER 0x00000002 -+ -+/* context caps */ -+ -+#define VXC_CAP_MASK 0x00000000 -+ -+#define VXC_SET_UTSNAME 0x00000001 -+#define VXC_SET_RLIMIT 0x00000002 -+#define VXC_FS_SECURITY 0x00000004 -+#define VXC_TIOCSTI 0x00000010 -+ -+/* was VXC_RAW_ICMP 0x00000100 */ -+#define VXC_SYSLOG 0x00001000 -+#define VXC_OOM_ADJUST 0x00002000 -+#define VXC_AUDIT_CONTROL 0x00004000 -+ -+#define VXC_SECURE_MOUNT 0x00010000 -+#define VXC_SECURE_REMOUNT 0x00020000 -+#define VXC_BINARY_MOUNT 0x00040000 -+ -+#define VXC_QUOTA_CTL 0x00100000 -+#define VXC_ADMIN_MAPPER 0x00200000 -+#define VXC_ADMIN_CLOOP 0x00400000 -+ -+#define VXC_KTHREAD 0x01000000 -+#define VXC_NAMESPACE 0x02000000 -+ -+ -+#ifdef __KERNEL__ -+ -+#include -+#include -+#include -+ -+#include "limit_def.h" -+#include "sched_def.h" -+#include "cvirt_def.h" -+#include "cacct_def.h" -+#include "device_def.h" -+ -+#define VX_SPACES 2 -+ -+struct _vx_info_pc { -+ struct _vx_sched_pc sched_pc; -+ struct _vx_cvirt_pc cvirt_pc; -+}; -+ -+struct vx_info { -+ struct hlist_node vx_hlist; /* linked list of contexts */ -+ xid_t vx_id; /* context id */ -+ atomic_t vx_usecnt; /* usage count */ -+ atomic_t vx_tasks; /* tasks count */ -+ struct vx_info *vx_parent; /* parent context */ -+ int vx_state; /* context state */ -+ -+ unsigned long vx_nsmask[VX_SPACES]; /* assignment mask */ -+ struct nsproxy *vx_nsproxy[VX_SPACES]; /* private namespaces */ -+ struct fs_struct *vx_fs[VX_SPACES]; /* private namespace fs */ -+ -+ uint64_t vx_flags; /* context flags */ -+ uint64_t vx_ccaps; /* context caps (vserver) */ -+ kernel_cap_t vx_bcaps; /* bounding caps (system) */ -+ unsigned long vx_umask; /* unshare mask (guest) */ -+ -+ struct task_struct *vx_reaper; /* guest reaper process */ -+ pid_t vx_initpid; /* PID of guest init */ -+ int64_t vx_badness_bias; /* OOM points bias */ -+ -+ struct _vx_limit limit; /* vserver limits */ -+ struct _vx_sched sched; /* vserver scheduler */ -+ struct _vx_cvirt cvirt; /* virtual/bias stuff */ -+ struct _vx_cacct cacct; /* context accounting */ -+ -+ struct _vx_device dmap; /* default device map targets */ -+ -+#ifndef CONFIG_SMP -+ struct _vx_info_pc info_pc; /* per cpu data */ -+#else -+ struct _vx_info_pc *ptr_pc; /* per cpu array */ -+#endif -+ -+ wait_queue_head_t vx_wait; /* context exit waitqueue */ -+ int reboot_cmd; /* last sys_reboot() cmd */ -+ int exit_code; /* last process exit code */ -+ -+ char vx_name[65]; /* vserver name */ -+}; -+ -+#ifndef CONFIG_SMP -+#define vx_ptr_pc(vxi) (&(vxi)->info_pc) -+#define vx_per_cpu(vxi, v, id) vx_ptr_pc(vxi)->v -+#else -+#define vx_ptr_pc(vxi) ((vxi)->ptr_pc) -+#define vx_per_cpu(vxi, v, id) per_cpu_ptr(vx_ptr_pc(vxi), id)->v -+#endif -+ -+#define vx_cpu(vxi, v) vx_per_cpu(vxi, v, smp_processor_id()) -+ -+ -+struct vx_info_save { -+ struct vx_info *vxi; -+ xid_t xid; -+}; -+ -+ -+/* status flags */ -+ -+#define VXS_HASHED 0x0001 -+#define VXS_PAUSED 0x0010 -+#define VXS_SHUTDOWN 0x0100 -+#define VXS_HELPER 0x1000 -+#define VXS_RELEASED 0x8000 -+ -+ -+extern void claim_vx_info(struct vx_info *, struct task_struct *); -+extern void release_vx_info(struct vx_info *, struct task_struct *); -+ -+extern struct vx_info *lookup_vx_info(int); -+extern struct vx_info *lookup_or_create_vx_info(int); -+ -+extern int get_xid_list(int, unsigned int *, int); -+extern int xid_is_hashed(xid_t); -+ -+extern int vx_migrate_task(struct task_struct *, struct vx_info *, int); -+ -+extern long vs_state_change(struct vx_info *, unsigned int); -+ -+ -+#endif /* __KERNEL__ */ -+#endif /* _VX_CONTEXT_H */ -diff -NurpP --minimal linux-2.6.32.1/include/linux/vserver/cvirt_cmd.h linux-2.6.32.1-vs2.3.0.36.27/include/linux/vserver/cvirt_cmd.h ---- linux-2.6.32.1/include/linux/vserver/cvirt_cmd.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/include/linux/vserver/cvirt_cmd.h 2009-12-03 20:04:56.000000000 +0100 -@@ -0,0 +1,53 @@ -+#ifndef _VX_CVIRT_CMD_H -+#define _VX_CVIRT_CMD_H -+ -+ -+/* virtual host info name commands */ -+ -+#define VCMD_set_vhi_name VC_CMD(VHOST, 1, 0) -+#define VCMD_get_vhi_name VC_CMD(VHOST, 2, 0) -+ -+struct vcmd_vhi_name_v0 { -+ uint32_t field; -+ char name[65]; -+}; -+ -+ -+enum vhi_name_field { -+ VHIN_CONTEXT = 0, -+ VHIN_SYSNAME, -+ VHIN_NODENAME, -+ VHIN_RELEASE, -+ VHIN_VERSION, -+ VHIN_MACHINE, -+ VHIN_DOMAINNAME, -+}; -+ -+ -+#ifdef __KERNEL__ -+ -+#include -+ -+extern int vc_set_vhi_name(struct vx_info *, void __user *); -+extern int vc_get_vhi_name(struct vx_info *, void __user *); -+ -+#endif /* __KERNEL__ */ -+ -+#define VCMD_virt_stat VC_CMD(VSTAT, 3, 0) -+ -+struct vcmd_virt_stat_v0 { -+ uint64_t offset; -+ uint64_t uptime; -+ uint32_t nr_threads; -+ uint32_t nr_running; -+ uint32_t nr_uninterruptible; -+ uint32_t nr_onhold; -+ uint32_t nr_forks; -+ uint32_t load[3]; -+}; -+ -+#ifdef __KERNEL__ -+extern int vc_virt_stat(struct vx_info *, void __user *); -+ -+#endif /* __KERNEL__ */ -+#endif /* _VX_CVIRT_CMD_H */ -diff -NurpP --minimal linux-2.6.32.1/include/linux/vserver/cvirt_def.h linux-2.6.32.1-vs2.3.0.36.27/include/linux/vserver/cvirt_def.h ---- linux-2.6.32.1/include/linux/vserver/cvirt_def.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/include/linux/vserver/cvirt_def.h 2009-12-03 20:04:56.000000000 +0100 -@@ -0,0 +1,80 @@ -+#ifndef _VX_CVIRT_DEF_H -+#define _VX_CVIRT_DEF_H -+ -+#include -+#include -+#include -+#include -+#include -+ -+ -+struct _vx_usage_stat { -+ uint64_t user; -+ uint64_t nice; -+ uint64_t system; -+ uint64_t softirq; -+ uint64_t irq; -+ uint64_t idle; -+ uint64_t iowait; -+}; -+ -+struct _vx_syslog { -+ wait_queue_head_t log_wait; -+ spinlock_t logbuf_lock; /* lock for the log buffer */ -+ -+ unsigned long log_start; /* next char to be read by syslog() */ -+ unsigned long con_start; /* next char to be sent to consoles */ -+ unsigned long log_end; /* most-recently-written-char + 1 */ -+ unsigned long logged_chars; /* #chars since last read+clear operation */ -+ -+ char log_buf[1024]; -+}; -+ -+ -+/* context sub struct */ -+ -+struct _vx_cvirt { -+ atomic_t nr_threads; /* number of current threads */ -+ atomic_t nr_running; /* number of running threads */ -+ atomic_t nr_uninterruptible; /* number of uninterruptible threads */ -+ -+ atomic_t nr_onhold; /* processes on hold */ -+ uint32_t onhold_last; /* jiffies when put on hold */ -+ -+ struct timeval bias_tv; /* time offset to the host */ -+ struct timespec bias_idle; -+ struct timespec bias_uptime; /* context creation point */ -+ uint64_t bias_clock; /* offset in clock_t */ -+ -+ spinlock_t load_lock; /* lock for the load averages */ -+ atomic_t load_updates; /* nr of load updates done so far */ -+ uint32_t load_last; /* last time load was calculated */ -+ uint32_t load[3]; /* load averages 1,5,15 */ -+ -+ atomic_t total_forks; /* number of forks so far */ -+ -+ struct _vx_syslog syslog; -+}; -+ -+struct _vx_cvirt_pc { -+ struct _vx_usage_stat cpustat; -+}; -+ -+ -+#ifdef CONFIG_VSERVER_DEBUG -+ -+static inline void __dump_vx_cvirt(struct _vx_cvirt *cvirt) -+{ -+ printk("\t_vx_cvirt:\n"); -+ printk("\t threads: %4d, %4d, %4d, %4d\n", -+ atomic_read(&cvirt->nr_threads), -+ atomic_read(&cvirt->nr_running), -+ atomic_read(&cvirt->nr_uninterruptible), -+ atomic_read(&cvirt->nr_onhold)); -+ /* add rest here */ -+ printk("\t total_forks = %d\n", atomic_read(&cvirt->total_forks)); -+} -+ -+#endif -+ -+#endif /* _VX_CVIRT_DEF_H */ -diff -NurpP --minimal linux-2.6.32.1/include/linux/vserver/cvirt.h linux-2.6.32.1-vs2.3.0.36.27/include/linux/vserver/cvirt.h ---- linux-2.6.32.1/include/linux/vserver/cvirt.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/include/linux/vserver/cvirt.h 2009-12-03 20:04:56.000000000 +0100 -@@ -0,0 +1,20 @@ -+#ifndef _VX_CVIRT_H -+#define _VX_CVIRT_H -+ -+ -+#ifdef __KERNEL__ -+ -+struct timespec; -+ -+void vx_vsi_uptime(struct timespec *, struct timespec *); -+ -+ -+struct vx_info; -+ -+void vx_update_load(struct vx_info *); -+ -+ -+int vx_do_syslog(int, char __user *, int); -+ -+#endif /* __KERNEL__ */ -+#endif /* _VX_CVIRT_H */ -diff -NurpP --minimal linux-2.6.32.1/include/linux/vserver/debug_cmd.h linux-2.6.32.1-vs2.3.0.36.27/include/linux/vserver/debug_cmd.h ---- linux-2.6.32.1/include/linux/vserver/debug_cmd.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/include/linux/vserver/debug_cmd.h 2009-12-03 20:04:56.000000000 +0100 -@@ -0,0 +1,58 @@ -+#ifndef _VX_DEBUG_CMD_H -+#define _VX_DEBUG_CMD_H -+ -+ -+/* debug commands */ -+ -+#define VCMD_dump_history VC_CMD(DEBUG, 1, 0) -+ -+#define VCMD_read_history VC_CMD(DEBUG, 5, 0) -+#define VCMD_read_monitor VC_CMD(DEBUG, 6, 0) -+ -+struct vcmd_read_history_v0 { -+ uint32_t index; -+ uint32_t count; -+ char __user *data; -+}; -+ -+struct vcmd_read_monitor_v0 { -+ uint32_t index; -+ uint32_t count; -+ char __user *data; -+}; -+ -+ -+#ifdef __KERNEL__ -+ -+#ifdef CONFIG_COMPAT -+ -+#include -+ -+struct vcmd_read_history_v0_x32 { -+ uint32_t index; -+ uint32_t count; -+ compat_uptr_t data_ptr; -+}; -+ -+struct vcmd_read_monitor_v0_x32 { -+ uint32_t index; -+ uint32_t count; -+ compat_uptr_t data_ptr; -+}; -+ -+#endif /* CONFIG_COMPAT */ -+ -+extern int vc_dump_history(uint32_t); -+ -+extern int vc_read_history(uint32_t, void __user *); -+extern int vc_read_monitor(uint32_t, void __user *); -+ -+#ifdef CONFIG_COMPAT -+ -+extern int vc_read_history_x32(uint32_t, void __user *); -+extern int vc_read_monitor_x32(uint32_t, void __user *); -+ -+#endif /* CONFIG_COMPAT */ -+ -+#endif /* __KERNEL__ */ -+#endif /* _VX_DEBUG_CMD_H */ -diff -NurpP --minimal linux-2.6.32.1/include/linux/vserver/debug.h linux-2.6.32.1-vs2.3.0.36.27/include/linux/vserver/debug.h ---- linux-2.6.32.1/include/linux/vserver/debug.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/include/linux/vserver/debug.h 2009-12-03 20:04:56.000000000 +0100 -@@ -0,0 +1,127 @@ -+#ifndef _VX_DEBUG_H -+#define _VX_DEBUG_H -+ -+ -+#define VXD_CBIT(n, m) (vx_debug_ ## n & (1 << (m))) -+#define VXD_CMIN(n, m) (vx_debug_ ## n > (m)) -+#define VXD_MASK(n, m) (vx_debug_ ## n & (m)) -+ -+#define VXD_DEV(d) (d), (d)->bd_inode->i_ino, \ -+ imajor((d)->bd_inode), iminor((d)->bd_inode) -+#define VXF_DEV "%p[%lu,%d:%d]" -+ -+ -+#define vxd_path(p) \ -+ ({ static char _buffer[PATH_MAX]; \ -+ d_path(p, _buffer, sizeof(_buffer)); }) -+ -+#define vxd_cond_path(n) \ -+ ((n) ? vxd_path(&(n)->path) : "" ) -+ -+ -+#ifdef CONFIG_VSERVER_DEBUG -+ -+extern unsigned int vx_debug_switch; -+extern unsigned int vx_debug_xid; -+extern unsigned int vx_debug_nid; -+extern unsigned int vx_debug_tag; -+extern unsigned int vx_debug_net; -+extern unsigned int vx_debug_limit; -+extern unsigned int vx_debug_cres; -+extern unsigned int vx_debug_dlim; -+extern unsigned int vx_debug_quota; -+extern unsigned int vx_debug_cvirt; -+extern unsigned int vx_debug_space; -+extern unsigned int vx_debug_misc; -+ -+ -+#define VX_LOGLEVEL "vxD: " -+#define VX_PROC_FMT "%p: " -+#define VX_PROCESS current -+ -+#define vxdprintk(c, f, x...) \ -+ do { \ -+ if (c) \ -+ printk(VX_LOGLEVEL VX_PROC_FMT f "\n", \ -+ VX_PROCESS , ##x); \ -+ } while (0) -+ -+#define vxlprintk(c, f, x...) \ -+ do { \ -+ if (c) \ -+ printk(VX_LOGLEVEL f " @%s:%d\n", x); \ -+ } while (0) -+ -+#define vxfprintk(c, f, x...) \ -+ do { \ -+ if (c) \ -+ printk(VX_LOGLEVEL f " %s@%s:%d\n", x); \ -+ } while (0) -+ -+ -+struct vx_info; -+ -+void dump_vx_info(struct vx_info *, int); -+void dump_vx_info_inactive(int); -+ -+#else /* CONFIG_VSERVER_DEBUG */ -+ -+#define vx_debug_switch 0 -+#define vx_debug_xid 0 -+#define vx_debug_nid 0 -+#define vx_debug_tag 0 -+#define vx_debug_net 0 -+#define vx_debug_limit 0 -+#define vx_debug_cres 0 -+#define vx_debug_dlim 0 -+#define vx_debug_cvirt 0 -+ -+#define vxdprintk(x...) do { } while (0) -+#define vxlprintk(x...) do { } while (0) -+#define vxfprintk(x...) do { } while (0) -+ -+#endif /* CONFIG_VSERVER_DEBUG */ -+ -+ -+#ifdef CONFIG_VSERVER_WARN -+ -+#define VX_WARNLEVEL KERN_WARNING "vxW: " -+#define VX_WARN_TASK "[»%s«,%u:#%u|%u|%u] " -+#define VX_WARN_XID "[xid #%u] " -+#define VX_WARN_NID "[nid #%u] " -+#define VX_WARN_TAG "[tag #%u] " -+ -+#define vxwprintk(c, f, x...) \ -+ do { \ -+ if (c) \ -+ printk(VX_WARNLEVEL f "\n", ##x); \ -+ } while (0) -+ -+#else /* CONFIG_VSERVER_WARN */ -+ -+#define vxwprintk(x...) do { } while (0) -+ -+#endif /* CONFIG_VSERVER_WARN */ -+ -+#define vxwprintk_task(c, f, x...) \ -+ vxwprintk(c, VX_WARN_TASK f, \ -+ current->comm, current->pid, \ -+ current->xid, current->nid, current->tag, ##x) -+#define vxwprintk_xid(c, f, x...) \ -+ vxwprintk(c, VX_WARN_XID f, current->xid, x) -+#define vxwprintk_nid(c, f, x...) \ -+ vxwprintk(c, VX_WARN_NID f, current->nid, x) -+#define vxwprintk_tag(c, f, x...) \ -+ vxwprintk(c, VX_WARN_TAG f, current->tag, x) -+ -+#ifdef CONFIG_VSERVER_DEBUG -+#define vxd_assert_lock(l) assert_spin_locked(l) -+#define vxd_assert(c, f, x...) vxlprintk(!(c), \ -+ "assertion [" f "] failed.", ##x, __FILE__, __LINE__) -+#else -+#define vxd_assert_lock(l) do { } while (0) -+#define vxd_assert(c, f, x...) do { } while (0) -+#endif -+ -+ -+#endif /* _VX_DEBUG_H */ -diff -NurpP --minimal linux-2.6.32.1/include/linux/vserver/device_cmd.h linux-2.6.32.1-vs2.3.0.36.27/include/linux/vserver/device_cmd.h ---- linux-2.6.32.1/include/linux/vserver/device_cmd.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/include/linux/vserver/device_cmd.h 2009-12-03 20:04:56.000000000 +0100 -@@ -0,0 +1,44 @@ -+#ifndef _VX_DEVICE_CMD_H -+#define _VX_DEVICE_CMD_H -+ -+ -+/* device vserver commands */ -+ -+#define VCMD_set_mapping VC_CMD(DEVICE, 1, 0) -+#define VCMD_unset_mapping VC_CMD(DEVICE, 2, 0) -+ -+struct vcmd_set_mapping_v0 { -+ const char __user *device; -+ const char __user *target; -+ uint32_t flags; -+}; -+ -+ -+#ifdef __KERNEL__ -+ -+#ifdef CONFIG_COMPAT -+ -+#include -+ -+struct vcmd_set_mapping_v0_x32 { -+ compat_uptr_t device_ptr; -+ compat_uptr_t target_ptr; -+ uint32_t flags; -+}; -+ -+#endif /* CONFIG_COMPAT */ -+ -+#include -+ -+extern int vc_set_mapping(struct vx_info *, void __user *); -+extern int vc_unset_mapping(struct vx_info *, void __user *); -+ -+#ifdef CONFIG_COMPAT -+ -+extern int vc_set_mapping_x32(struct vx_info *, void __user *); -+extern int vc_unset_mapping_x32(struct vx_info *, void __user *); -+ -+#endif /* CONFIG_COMPAT */ -+ -+#endif /* __KERNEL__ */ -+#endif /* _VX_DEVICE_CMD_H */ -diff -NurpP --minimal linux-2.6.32.1/include/linux/vserver/device_def.h linux-2.6.32.1-vs2.3.0.36.27/include/linux/vserver/device_def.h ---- linux-2.6.32.1/include/linux/vserver/device_def.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/include/linux/vserver/device_def.h 2009-12-03 20:04:56.000000000 +0100 -@@ -0,0 +1,17 @@ -+#ifndef _VX_DEVICE_DEF_H -+#define _VX_DEVICE_DEF_H -+ -+#include -+ -+struct vx_dmap_target { -+ dev_t target; -+ uint32_t flags; -+}; -+ -+struct _vx_device { -+#ifdef CONFIG_VSERVER_DEVICE -+ struct vx_dmap_target targets[2]; -+#endif -+}; -+ -+#endif /* _VX_DEVICE_DEF_H */ -diff -NurpP --minimal linux-2.6.32.1/include/linux/vserver/device.h linux-2.6.32.1-vs2.3.0.36.27/include/linux/vserver/device.h ---- linux-2.6.32.1/include/linux/vserver/device.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/include/linux/vserver/device.h 2009-12-03 20:04:56.000000000 +0100 -@@ -0,0 +1,15 @@ -+#ifndef _VX_DEVICE_H -+#define _VX_DEVICE_H -+ -+ -+#define DATTR_CREATE 0x00000001 -+#define DATTR_OPEN 0x00000002 -+ -+#define DATTR_REMAP 0x00000010 -+ -+#define DATTR_MASK 0x00000013 -+ -+ -+#else /* _VX_DEVICE_H */ -+#warning duplicate inclusion -+#endif /* _VX_DEVICE_H */ -diff -NurpP --minimal linux-2.6.32.1/include/linux/vserver/dlimit_cmd.h linux-2.6.32.1-vs2.3.0.36.27/include/linux/vserver/dlimit_cmd.h ---- linux-2.6.32.1/include/linux/vserver/dlimit_cmd.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/include/linux/vserver/dlimit_cmd.h 2009-12-10 16:43:43.000000000 +0100 -@@ -0,0 +1,109 @@ -+#ifndef _VX_DLIMIT_CMD_H -+#define _VX_DLIMIT_CMD_H -+ -+ -+/* dlimit vserver commands */ -+ -+#define VCMD_add_dlimit VC_CMD(DLIMIT, 1, 0) -+#define VCMD_rem_dlimit VC_CMD(DLIMIT, 2, 0) -+ -+#define VCMD_set_dlimit VC_CMD(DLIMIT, 5, 0) -+#define VCMD_get_dlimit VC_CMD(DLIMIT, 6, 0) -+ -+struct vcmd_ctx_dlimit_base_v0 { -+ const char __user *name; -+ uint32_t flags; -+}; -+ -+struct vcmd_ctx_dlimit_v0 { -+ const char __user *name; -+ uint32_t space_used; /* used space in kbytes */ -+ uint32_t space_total; /* maximum space in kbytes */ -+ uint32_t inodes_used; /* used inodes */ -+ uint32_t inodes_total; /* maximum inodes */ -+ uint32_t reserved; /* reserved for root in % */ -+ uint32_t flags; -+}; -+ -+#define CDLIM_UNSET ((uint32_t)0UL) -+#define CDLIM_INFINITY ((uint32_t)~0UL) -+#define CDLIM_KEEP ((uint32_t)~1UL) -+ -+#define DLIME_UNIT 0 -+#define DLIME_KILO 1 -+#define DLIME_MEGA 2 -+#define DLIME_GIGA 3 -+ -+#define DLIMF_SHIFT 0x10 -+ -+#define DLIMS_USED 0 -+#define DLIMS_TOTAL 2 -+ -+static inline -+uint64_t dlimit_space_32to64(uint32_t val, uint32_t flags, int shift) -+{ -+ int exp = (flags & DLIMF_SHIFT) ? -+ (flags >> shift) & DLIME_GIGA : DLIME_KILO; -+ return ((uint64_t)val) << (10 * exp); -+} -+ -+static inline -+uint32_t dlimit_space_64to32(uint64_t val, uint32_t *flags, int shift) -+{ -+ int exp = 0; -+ -+ if (*flags & DLIMF_SHIFT) { -+ while (val > (1LL << 32) && (exp < 3)) { -+ val >>= 10; -+ exp++; -+ } -+ *flags &= ~(DLIME_GIGA << shift); -+ *flags |= exp << shift; -+ } else -+ val >>= 10; -+ return val; -+} -+ -+#ifdef __KERNEL__ -+ -+#ifdef CONFIG_COMPAT -+ -+#include -+ -+struct vcmd_ctx_dlimit_base_v0_x32 { -+ compat_uptr_t name_ptr; -+ uint32_t flags; -+}; -+ -+struct vcmd_ctx_dlimit_v0_x32 { -+ compat_uptr_t name_ptr; -+ uint32_t space_used; /* used space in kbytes */ -+ uint32_t space_total; /* maximum space in kbytes */ -+ uint32_t inodes_used; /* used inodes */ -+ uint32_t inodes_total; /* maximum inodes */ -+ uint32_t reserved; /* reserved for root in % */ -+ uint32_t flags; -+}; -+ -+#endif /* CONFIG_COMPAT */ -+ -+#include -+ -+extern int vc_add_dlimit(uint32_t, void __user *); -+extern int vc_rem_dlimit(uint32_t, void __user *); -+ -+extern int vc_set_dlimit(uint32_t, void __user *); -+extern int vc_get_dlimit(uint32_t, void __user *); -+ -+#ifdef CONFIG_COMPAT -+ -+extern int vc_add_dlimit_x32(uint32_t, void __user *); -+extern int vc_rem_dlimit_x32(uint32_t, void __user *); -+ -+extern int vc_set_dlimit_x32(uint32_t, void __user *); -+extern int vc_get_dlimit_x32(uint32_t, void __user *); -+ -+#endif /* CONFIG_COMPAT */ -+ -+#endif /* __KERNEL__ */ -+#endif /* _VX_DLIMIT_CMD_H */ -diff -NurpP --minimal linux-2.6.32.1/include/linux/vserver/dlimit.h linux-2.6.32.1-vs2.3.0.36.27/include/linux/vserver/dlimit.h ---- linux-2.6.32.1/include/linux/vserver/dlimit.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/include/linux/vserver/dlimit.h 2009-12-03 20:04:56.000000000 +0100 -@@ -0,0 +1,54 @@ -+#ifndef _VX_DLIMIT_H -+#define _VX_DLIMIT_H -+ -+#include "switch.h" -+ -+ -+#ifdef __KERNEL__ -+ -+/* keep in sync with CDLIM_INFINITY */ -+ -+#define DLIM_INFINITY (~0ULL) -+ -+#include -+#include -+ -+struct super_block; -+ -+struct dl_info { -+ struct hlist_node dl_hlist; /* linked list of contexts */ -+ struct rcu_head dl_rcu; /* the rcu head */ -+ tag_t dl_tag; /* context tag */ -+ atomic_t dl_usecnt; /* usage count */ -+ atomic_t dl_refcnt; /* reference count */ -+ -+ struct super_block *dl_sb; /* associated superblock */ -+ -+ spinlock_t dl_lock; /* protect the values */ -+ -+ unsigned long long dl_space_used; /* used space in bytes */ -+ unsigned long long dl_space_total; /* maximum space in bytes */ -+ unsigned long dl_inodes_used; /* used inodes */ -+ unsigned long dl_inodes_total; /* maximum inodes */ -+ -+ unsigned int dl_nrlmult; /* non root limit mult */ -+}; -+ -+struct rcu_head; -+ -+extern void rcu_free_dl_info(struct rcu_head *); -+extern void unhash_dl_info(struct dl_info *); -+ -+extern struct dl_info *locate_dl_info(struct super_block *, tag_t); -+ -+ -+struct kstatfs; -+ -+extern void vx_vsi_statfs(struct super_block *, struct kstatfs *); -+ -+typedef uint64_t dlsize_t; -+ -+#endif /* __KERNEL__ */ -+#else /* _VX_DLIMIT_H */ -+#warning duplicate inclusion -+#endif /* _VX_DLIMIT_H */ -diff -NurpP --minimal linux-2.6.32.1/include/linux/vserver/global.h linux-2.6.32.1-vs2.3.0.36.27/include/linux/vserver/global.h ---- linux-2.6.32.1/include/linux/vserver/global.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/include/linux/vserver/global.h 2009-12-03 20:04:56.000000000 +0100 -@@ -0,0 +1,19 @@ -+#ifndef _VX_GLOBAL_H -+#define _VX_GLOBAL_H -+ -+ -+extern atomic_t vx_global_ctotal; -+extern atomic_t vx_global_cactive; -+ -+extern atomic_t nx_global_ctotal; -+extern atomic_t nx_global_cactive; -+ -+extern atomic_t vs_global_nsproxy; -+extern atomic_t vs_global_fs; -+extern atomic_t vs_global_mnt_ns; -+extern atomic_t vs_global_uts_ns; -+extern atomic_t vs_global_user_ns; -+extern atomic_t vs_global_pid_ns; -+ -+ -+#endif /* _VX_GLOBAL_H */ -diff -NurpP --minimal linux-2.6.32.1/include/linux/vserver/history.h linux-2.6.32.1-vs2.3.0.36.27/include/linux/vserver/history.h ---- linux-2.6.32.1/include/linux/vserver/history.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/include/linux/vserver/history.h 2009-12-03 20:04:56.000000000 +0100 -@@ -0,0 +1,197 @@ -+#ifndef _VX_HISTORY_H -+#define _VX_HISTORY_H -+ -+ -+enum { -+ VXH_UNUSED = 0, -+ VXH_THROW_OOPS = 1, -+ -+ VXH_GET_VX_INFO, -+ VXH_PUT_VX_INFO, -+ VXH_INIT_VX_INFO, -+ VXH_SET_VX_INFO, -+ VXH_CLR_VX_INFO, -+ VXH_CLAIM_VX_INFO, -+ VXH_RELEASE_VX_INFO, -+ VXH_ALLOC_VX_INFO, -+ VXH_DEALLOC_VX_INFO, -+ VXH_HASH_VX_INFO, -+ VXH_UNHASH_VX_INFO, -+ VXH_LOC_VX_INFO, -+ VXH_LOOKUP_VX_INFO, -+ VXH_CREATE_VX_INFO, -+}; -+ -+struct _vxhe_vxi { -+ struct vx_info *ptr; -+ unsigned xid; -+ unsigned usecnt; -+ unsigned tasks; -+}; -+ -+struct _vxhe_set_clr { -+ void *data; -+}; -+ -+struct _vxhe_loc_lookup { -+ unsigned arg; -+}; -+ -+struct _vx_hist_entry { -+ void *loc; -+ unsigned short seq; -+ unsigned short type; -+ struct _vxhe_vxi vxi; -+ union { -+ struct _vxhe_set_clr sc; -+ struct _vxhe_loc_lookup ll; -+ }; -+}; -+ -+#ifdef CONFIG_VSERVER_HISTORY -+ -+extern unsigned volatile int vxh_active; -+ -+struct _vx_hist_entry *vxh_advance(void *loc); -+ -+ -+static inline -+void __vxh_copy_vxi(struct _vx_hist_entry *entry, struct vx_info *vxi) -+{ -+ entry->vxi.ptr = vxi; -+ if (vxi) { -+ entry->vxi.usecnt = atomic_read(&vxi->vx_usecnt); -+ entry->vxi.tasks = atomic_read(&vxi->vx_tasks); -+ entry->vxi.xid = vxi->vx_id; -+ } -+} -+ -+ -+#define __HERE__ current_text_addr() -+ -+#define __VXH_BODY(__type, __data, __here) \ -+ struct _vx_hist_entry *entry; \ -+ \ -+ preempt_disable(); \ -+ entry = vxh_advance(__here); \ -+ __data; \ -+ entry->type = __type; \ -+ preempt_enable(); -+ -+ -+ /* pass vxi only */ -+ -+#define __VXH_SMPL \ -+ __vxh_copy_vxi(entry, vxi) -+ -+static inline -+void __vxh_smpl(struct vx_info *vxi, int __type, void *__here) -+{ -+ __VXH_BODY(__type, __VXH_SMPL, __here) -+} -+ -+ /* pass vxi and data (void *) */ -+ -+#define __VXH_DATA \ -+ __vxh_copy_vxi(entry, vxi); \ -+ entry->sc.data = data -+ -+static inline -+void __vxh_data(struct vx_info *vxi, void *data, -+ int __type, void *__here) -+{ -+ __VXH_BODY(__type, __VXH_DATA, __here) -+} -+ -+ /* pass vxi and arg (long) */ -+ -+#define __VXH_LONG \ -+ __vxh_copy_vxi(entry, vxi); \ -+ entry->ll.arg = arg -+ -+static inline -+void __vxh_long(struct vx_info *vxi, long arg, -+ int __type, void *__here) -+{ -+ __VXH_BODY(__type, __VXH_LONG, __here) -+} -+ -+ -+static inline -+void __vxh_throw_oops(void *__here) -+{ -+ __VXH_BODY(VXH_THROW_OOPS, {}, __here); -+ /* prevent further acquisition */ -+ vxh_active = 0; -+} -+ -+ -+#define vxh_throw_oops() __vxh_throw_oops(__HERE__); -+ -+#define __vxh_get_vx_info(v, h) __vxh_smpl(v, VXH_GET_VX_INFO, h); -+#define __vxh_put_vx_info(v, h) __vxh_smpl(v, VXH_PUT_VX_INFO, h); -+ -+#define __vxh_init_vx_info(v, d, h) \ -+ __vxh_data(v, d, VXH_INIT_VX_INFO, h); -+#define __vxh_set_vx_info(v, d, h) \ -+ __vxh_data(v, d, VXH_SET_VX_INFO, h); -+#define __vxh_clr_vx_info(v, d, h) \ -+ __vxh_data(v, d, VXH_CLR_VX_INFO, h); -+ -+#define __vxh_claim_vx_info(v, d, h) \ -+ __vxh_data(v, d, VXH_CLAIM_VX_INFO, h); -+#define __vxh_release_vx_info(v, d, h) \ -+ __vxh_data(v, d, VXH_RELEASE_VX_INFO, h); -+ -+#define vxh_alloc_vx_info(v) \ -+ __vxh_smpl(v, VXH_ALLOC_VX_INFO, __HERE__); -+#define vxh_dealloc_vx_info(v) \ -+ __vxh_smpl(v, VXH_DEALLOC_VX_INFO, __HERE__); -+ -+#define vxh_hash_vx_info(v) \ -+ __vxh_smpl(v, VXH_HASH_VX_INFO, __HERE__); -+#define vxh_unhash_vx_info(v) \ -+ __vxh_smpl(v, VXH_UNHASH_VX_INFO, __HERE__); -+ -+#define vxh_loc_vx_info(v, l) \ -+ __vxh_long(v, l, VXH_LOC_VX_INFO, __HERE__); -+#define vxh_lookup_vx_info(v, l) \ -+ __vxh_long(v, l, VXH_LOOKUP_VX_INFO, __HERE__); -+#define vxh_create_vx_info(v, l) \ -+ __vxh_long(v, l, VXH_CREATE_VX_INFO, __HERE__); -+ -+extern void vxh_dump_history(void); -+ -+ -+#else /* CONFIG_VSERVER_HISTORY */ -+ -+#define __HERE__ 0 -+ -+#define vxh_throw_oops() do { } while (0) -+ -+#define __vxh_get_vx_info(v, h) do { } while (0) -+#define __vxh_put_vx_info(v, h) do { } while (0) -+ -+#define __vxh_init_vx_info(v, d, h) do { } while (0) -+#define __vxh_set_vx_info(v, d, h) do { } while (0) -+#define __vxh_clr_vx_info(v, d, h) do { } while (0) -+ -+#define __vxh_claim_vx_info(v, d, h) do { } while (0) -+#define __vxh_release_vx_info(v, d, h) do { } while (0) -+ -+#define vxh_alloc_vx_info(v) do { } while (0) -+#define vxh_dealloc_vx_info(v) do { } while (0) -+ -+#define vxh_hash_vx_info(v) do { } while (0) -+#define vxh_unhash_vx_info(v) do { } while (0) -+ -+#define vxh_loc_vx_info(v, l) do { } while (0) -+#define vxh_lookup_vx_info(v, l) do { } while (0) -+#define vxh_create_vx_info(v, l) do { } while (0) -+ -+#define vxh_dump_history() do { } while (0) -+ -+ -+#endif /* CONFIG_VSERVER_HISTORY */ -+ -+#endif /* _VX_HISTORY_H */ -diff -NurpP --minimal linux-2.6.32.1/include/linux/vserver/inode_cmd.h linux-2.6.32.1-vs2.3.0.36.27/include/linux/vserver/inode_cmd.h ---- linux-2.6.32.1/include/linux/vserver/inode_cmd.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/include/linux/vserver/inode_cmd.h 2009-12-03 20:04:56.000000000 +0100 -@@ -0,0 +1,59 @@ -+#ifndef _VX_INODE_CMD_H -+#define _VX_INODE_CMD_H -+ -+ -+/* inode vserver commands */ -+ -+#define VCMD_get_iattr VC_CMD(INODE, 1, 1) -+#define VCMD_set_iattr VC_CMD(INODE, 2, 1) -+ -+#define VCMD_fget_iattr VC_CMD(INODE, 3, 0) -+#define VCMD_fset_iattr VC_CMD(INODE, 4, 0) -+ -+struct vcmd_ctx_iattr_v1 { -+ const char __user *name; -+ uint32_t tag; -+ uint32_t flags; -+ uint32_t mask; -+}; -+ -+struct vcmd_ctx_fiattr_v0 { -+ uint32_t tag; -+ uint32_t flags; -+ uint32_t mask; -+}; -+ -+ -+#ifdef __KERNEL__ -+ -+ -+#ifdef CONFIG_COMPAT -+ -+#include -+ -+struct vcmd_ctx_iattr_v1_x32 { -+ compat_uptr_t name_ptr; -+ uint32_t tag; -+ uint32_t flags; -+ uint32_t mask; -+}; -+ -+#endif /* CONFIG_COMPAT */ -+ -+#include -+ -+extern int vc_get_iattr(void __user *); -+extern int vc_set_iattr(void __user *); -+ -+extern int vc_fget_iattr(uint32_t, void __user *); -+extern int vc_fset_iattr(uint32_t, void __user *); -+ -+#ifdef CONFIG_COMPAT -+ -+extern int vc_get_iattr_x32(void __user *); -+extern int vc_set_iattr_x32(void __user *); -+ -+#endif /* CONFIG_COMPAT */ -+ -+#endif /* __KERNEL__ */ -+#endif /* _VX_INODE_CMD_H */ -diff -NurpP --minimal linux-2.6.32.1/include/linux/vserver/inode.h linux-2.6.32.1-vs2.3.0.36.27/include/linux/vserver/inode.h ---- linux-2.6.32.1/include/linux/vserver/inode.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/include/linux/vserver/inode.h 2009-12-03 20:04:56.000000000 +0100 -@@ -0,0 +1,39 @@ -+#ifndef _VX_INODE_H -+#define _VX_INODE_H -+ -+ -+#define IATTR_TAG 0x01000000 -+ -+#define IATTR_ADMIN 0x00000001 -+#define IATTR_WATCH 0x00000002 -+#define IATTR_HIDE 0x00000004 -+#define IATTR_FLAGS 0x00000007 -+ -+#define IATTR_BARRIER 0x00010000 -+#define IATTR_IXUNLINK 0x00020000 -+#define IATTR_IMMUTABLE 0x00040000 -+#define IATTR_COW 0x00080000 -+ -+#ifdef __KERNEL__ -+ -+ -+#ifdef CONFIG_VSERVER_PROC_SECURE -+#define IATTR_PROC_DEFAULT ( IATTR_ADMIN | IATTR_HIDE ) -+#define IATTR_PROC_SYMLINK ( IATTR_ADMIN ) -+#else -+#define IATTR_PROC_DEFAULT ( IATTR_ADMIN ) -+#define IATTR_PROC_SYMLINK ( IATTR_ADMIN ) -+#endif -+ -+#define vx_hide_check(c, m) (((m) & IATTR_HIDE) ? vx_check(c, m) : 1) -+ -+#endif /* __KERNEL__ */ -+ -+/* inode ioctls */ -+ -+#define FIOC_GETXFLG _IOR('x', 5, long) -+#define FIOC_SETXFLG _IOW('x', 6, long) -+ -+#else /* _VX_INODE_H */ -+#warning duplicate inclusion -+#endif /* _VX_INODE_H */ -diff -NurpP --minimal linux-2.6.32.1/include/linux/vserver/Kbuild linux-2.6.32.1-vs2.3.0.36.27/include/linux/vserver/Kbuild ---- linux-2.6.32.1/include/linux/vserver/Kbuild 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/include/linux/vserver/Kbuild 2009-12-03 20:04:56.000000000 +0100 -@@ -0,0 +1,8 @@ -+ -+unifdef-y += context_cmd.h network_cmd.h space_cmd.h \ -+ cacct_cmd.h cvirt_cmd.h limit_cmd.h dlimit_cmd.h \ -+ inode_cmd.h tag_cmd.h sched_cmd.h signal_cmd.h \ -+ debug_cmd.h device_cmd.h -+ -+unifdef-y += switch.h network.h monitor.h inode.h device.h -+ -diff -NurpP --minimal linux-2.6.32.1/include/linux/vserver/limit_cmd.h linux-2.6.32.1-vs2.3.0.36.27/include/linux/vserver/limit_cmd.h ---- linux-2.6.32.1/include/linux/vserver/limit_cmd.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/include/linux/vserver/limit_cmd.h 2009-12-03 20:04:56.000000000 +0100 -@@ -0,0 +1,71 @@ -+#ifndef _VX_LIMIT_CMD_H -+#define _VX_LIMIT_CMD_H -+ -+ -+/* rlimit vserver commands */ -+ -+#define VCMD_get_rlimit VC_CMD(RLIMIT, 1, 0) -+#define VCMD_set_rlimit VC_CMD(RLIMIT, 2, 0) -+#define VCMD_get_rlimit_mask VC_CMD(RLIMIT, 3, 0) -+#define VCMD_reset_hits VC_CMD(RLIMIT, 7, 0) -+#define VCMD_reset_minmax VC_CMD(RLIMIT, 9, 0) -+ -+struct vcmd_ctx_rlimit_v0 { -+ uint32_t id; -+ uint64_t minimum; -+ uint64_t softlimit; -+ uint64_t maximum; -+}; -+ -+struct vcmd_ctx_rlimit_mask_v0 { -+ uint32_t minimum; -+ uint32_t softlimit; -+ uint32_t maximum; -+}; -+ -+#define VCMD_rlimit_stat VC_CMD(VSTAT, 1, 0) -+ -+struct vcmd_rlimit_stat_v0 { -+ uint32_t id; -+ uint32_t hits; -+ uint64_t value; -+ uint64_t minimum; -+ uint64_t maximum; -+}; -+ -+#define CRLIM_UNSET (0ULL) -+#define CRLIM_INFINITY (~0ULL) -+#define CRLIM_KEEP (~1ULL) -+ -+#ifdef __KERNEL__ -+ -+#ifdef CONFIG_IA32_EMULATION -+ -+struct vcmd_ctx_rlimit_v0_x32 { -+ uint32_t id; -+ uint64_t minimum; -+ uint64_t softlimit; -+ uint64_t maximum; -+} __attribute__ ((packed)); -+ -+#endif /* CONFIG_IA32_EMULATION */ -+ -+#include -+ -+extern int vc_get_rlimit_mask(uint32_t, void __user *); -+extern int vc_get_rlimit(struct vx_info *, void __user *); -+extern int vc_set_rlimit(struct vx_info *, void __user *); -+extern int vc_reset_hits(struct vx_info *, void __user *); -+extern int vc_reset_minmax(struct vx_info *, void __user *); -+ -+extern int vc_rlimit_stat(struct vx_info *, void __user *); -+ -+#ifdef CONFIG_IA32_EMULATION -+ -+extern int vc_get_rlimit_x32(struct vx_info *, void __user *); -+extern int vc_set_rlimit_x32(struct vx_info *, void __user *); -+ -+#endif /* CONFIG_IA32_EMULATION */ -+ -+#endif /* __KERNEL__ */ -+#endif /* _VX_LIMIT_CMD_H */ -diff -NurpP --minimal linux-2.6.32.1/include/linux/vserver/limit_def.h linux-2.6.32.1-vs2.3.0.36.27/include/linux/vserver/limit_def.h ---- linux-2.6.32.1/include/linux/vserver/limit_def.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/include/linux/vserver/limit_def.h 2009-12-03 20:04:56.000000000 +0100 -@@ -0,0 +1,47 @@ -+#ifndef _VX_LIMIT_DEF_H -+#define _VX_LIMIT_DEF_H -+ -+#include -+#include -+ -+#include "limit.h" -+ -+ -+struct _vx_res_limit { -+ rlim_t soft; /* Context soft limit */ -+ rlim_t hard; /* Context hard limit */ -+ -+ rlim_atomic_t rcur; /* Current value */ -+ rlim_t rmin; /* Context minimum */ -+ rlim_t rmax; /* Context maximum */ -+ -+ atomic_t lhit; /* Limit hits */ -+}; -+ -+/* context sub struct */ -+ -+struct _vx_limit { -+ struct _vx_res_limit res[NUM_LIMITS]; -+}; -+ -+#ifdef CONFIG_VSERVER_DEBUG -+ -+static inline void __dump_vx_limit(struct _vx_limit *limit) -+{ -+ int i; -+ -+ printk("\t_vx_limit:"); -+ for (i = 0; i < NUM_LIMITS; i++) { -+ printk("\t [%2d] = %8lu %8lu/%8lu, %8ld/%8ld, %8d\n", -+ i, (unsigned long)__rlim_get(limit, i), -+ (unsigned long)__rlim_rmin(limit, i), -+ (unsigned long)__rlim_rmax(limit, i), -+ (long)__rlim_soft(limit, i), -+ (long)__rlim_hard(limit, i), -+ atomic_read(&__rlim_lhit(limit, i))); -+ } -+} -+ -+#endif -+ -+#endif /* _VX_LIMIT_DEF_H */ -diff -NurpP --minimal linux-2.6.32.1/include/linux/vserver/limit.h linux-2.6.32.1-vs2.3.0.36.27/include/linux/vserver/limit.h ---- linux-2.6.32.1/include/linux/vserver/limit.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/include/linux/vserver/limit.h 2009-12-03 20:04:56.000000000 +0100 -@@ -0,0 +1,70 @@ -+#ifndef _VX_LIMIT_H -+#define _VX_LIMIT_H -+ -+#define VLIMIT_NSOCK 16 -+#define VLIMIT_OPENFD 17 -+#define VLIMIT_ANON 18 -+#define VLIMIT_SHMEM 19 -+#define VLIMIT_SEMARY 20 -+#define VLIMIT_NSEMS 21 -+#define VLIMIT_DENTRY 22 -+#define VLIMIT_MAPPED 23 -+ -+ -+#ifdef __KERNEL__ -+ -+#define VLIM_NOCHECK ((1L << VLIMIT_DENTRY) | (1L << RLIMIT_RSS)) -+ -+/* keep in sync with CRLIM_INFINITY */ -+ -+#define VLIM_INFINITY (~0ULL) -+ -+#include -+#include -+ -+#ifndef RLIM_INFINITY -+#warning RLIM_INFINITY is undefined -+#endif -+ -+#define __rlim_val(l, r, v) ((l)->res[r].v) -+ -+#define __rlim_soft(l, r) __rlim_val(l, r, soft) -+#define __rlim_hard(l, r) __rlim_val(l, r, hard) -+ -+#define __rlim_rcur(l, r) __rlim_val(l, r, rcur) -+#define __rlim_rmin(l, r) __rlim_val(l, r, rmin) -+#define __rlim_rmax(l, r) __rlim_val(l, r, rmax) -+ -+#define __rlim_lhit(l, r) __rlim_val(l, r, lhit) -+#define __rlim_hit(l, r) atomic_inc(&__rlim_lhit(l, r)) -+ -+typedef atomic_long_t rlim_atomic_t; -+typedef unsigned long rlim_t; -+ -+#define __rlim_get(l, r) atomic_long_read(&__rlim_rcur(l, r)) -+#define __rlim_set(l, r, v) atomic_long_set(&__rlim_rcur(l, r), v) -+#define __rlim_inc(l, r) atomic_long_inc(&__rlim_rcur(l, r)) -+#define __rlim_dec(l, r) atomic_long_dec(&__rlim_rcur(l, r)) -+#define __rlim_add(l, r, v) atomic_long_add(v, &__rlim_rcur(l, r)) -+#define __rlim_sub(l, r, v) atomic_long_sub(v, &__rlim_rcur(l, r)) -+ -+ -+#if (RLIM_INFINITY == VLIM_INFINITY) -+#define VX_VLIM(r) ((long long)(long)(r)) -+#define VX_RLIM(v) ((rlim_t)(v)) -+#else -+#define VX_VLIM(r) (((r) == RLIM_INFINITY) \ -+ ? VLIM_INFINITY : (long long)(r)) -+#define VX_RLIM(v) (((v) == VLIM_INFINITY) \ -+ ? RLIM_INFINITY : (rlim_t)(v)) -+#endif -+ -+struct sysinfo; -+ -+void vx_vsi_meminfo(struct sysinfo *); -+void vx_vsi_swapinfo(struct sysinfo *); -+ -+#define NUM_LIMITS 24 -+ -+#endif /* __KERNEL__ */ -+#endif /* _VX_LIMIT_H */ -diff -NurpP --minimal linux-2.6.32.1/include/linux/vserver/limit_int.h linux-2.6.32.1-vs2.3.0.36.27/include/linux/vserver/limit_int.h ---- linux-2.6.32.1/include/linux/vserver/limit_int.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/include/linux/vserver/limit_int.h 2009-12-03 20:04:56.000000000 +0100 -@@ -0,0 +1,198 @@ -+#ifndef _VX_LIMIT_INT_H -+#define _VX_LIMIT_INT_H -+ -+#include "context.h" -+ -+#ifdef __KERNEL__ -+ -+#define VXD_RCRES_COND(r) VXD_CBIT(cres, r) -+#define VXD_RLIMIT_COND(r) VXD_CBIT(limit, r) -+ -+extern const char *vlimit_name[NUM_LIMITS]; -+ -+static inline void __vx_acc_cres(struct vx_info *vxi, -+ int res, int dir, void *_data, char *_file, int _line) -+{ -+ if (VXD_RCRES_COND(res)) -+ vxlprintk(1, "vx_acc_cres[%5d,%s,%2d]: %5ld%s (%p)", -+ (vxi ? vxi->vx_id : -1), vlimit_name[res], res, -+ (vxi ? (long)__rlim_get(&vxi->limit, res) : 0), -+ (dir > 0) ? "++" : "--", _data, _file, _line); -+ if (!vxi) -+ return; -+ -+ if (dir > 0) -+ __rlim_inc(&vxi->limit, res); -+ else -+ __rlim_dec(&vxi->limit, res); -+} -+ -+static inline void __vx_add_cres(struct vx_info *vxi, -+ int res, int amount, void *_data, char *_file, int _line) -+{ -+ if (VXD_RCRES_COND(res)) -+ vxlprintk(1, "vx_add_cres[%5d,%s,%2d]: %5ld += %5d (%p)", -+ (vxi ? vxi->vx_id : -1), vlimit_name[res], res, -+ (vxi ? (long)__rlim_get(&vxi->limit, res) : 0), -+ amount, _data, _file, _line); -+ if (amount == 0) -+ return; -+ if (!vxi) -+ return; -+ __rlim_add(&vxi->limit, res, amount); -+} -+ -+static inline -+int __vx_cres_adjust_max(struct _vx_limit *limit, int res, rlim_t value) -+{ -+ int cond = (value > __rlim_rmax(limit, res)); -+ -+ if (cond) -+ __rlim_rmax(limit, res) = value; -+ return cond; -+} -+ -+static inline -+int __vx_cres_adjust_min(struct _vx_limit *limit, int res, rlim_t value) -+{ -+ int cond = (value < __rlim_rmin(limit, res)); -+ -+ if (cond) -+ __rlim_rmin(limit, res) = value; -+ return cond; -+} -+ -+static inline -+void __vx_cres_fixup(struct _vx_limit *limit, int res, rlim_t value) -+{ -+ if (!__vx_cres_adjust_max(limit, res, value)) -+ __vx_cres_adjust_min(limit, res, value); -+} -+ -+ -+/* return values: -+ +1 ... no limit hit -+ -1 ... over soft limit -+ 0 ... over hard limit */ -+ -+static inline int __vx_cres_avail(struct vx_info *vxi, -+ int res, int num, char *_file, int _line) -+{ -+ struct _vx_limit *limit; -+ rlim_t value; -+ -+ if (VXD_RLIMIT_COND(res)) -+ vxlprintk(1, "vx_cres_avail[%5d,%s,%2d]: %5ld/%5ld > %5ld + %5d", -+ (vxi ? vxi->vx_id : -1), vlimit_name[res], res, -+ (vxi ? (long)__rlim_soft(&vxi->limit, res) : -1), -+ (vxi ? (long)__rlim_hard(&vxi->limit, res) : -1), -+ (vxi ? (long)__rlim_get(&vxi->limit, res) : 0), -+ num, _file, _line); -+ if (!vxi) -+ return 1; -+ -+ limit = &vxi->limit; -+ value = __rlim_get(limit, res); -+ -+ if (!__vx_cres_adjust_max(limit, res, value)) -+ __vx_cres_adjust_min(limit, res, value); -+ -+ if (num == 0) -+ return 1; -+ -+ if (__rlim_soft(limit, res) == RLIM_INFINITY) -+ return -1; -+ if (value + num <= __rlim_soft(limit, res)) -+ return -1; -+ -+ if (__rlim_hard(limit, res) == RLIM_INFINITY) -+ return 1; -+ if (value + num <= __rlim_hard(limit, res)) -+ return 1; -+ -+ __rlim_hit(limit, res); -+ return 0; -+} -+ -+ -+static const int VLA_RSS[] = { RLIMIT_RSS, VLIMIT_ANON, VLIMIT_MAPPED, 0 }; -+ -+static inline -+rlim_t __vx_cres_array_sum(struct _vx_limit *limit, const int *array) -+{ -+ rlim_t value, sum = 0; -+ int res; -+ -+ while ((res = *array++)) { -+ value = __rlim_get(limit, res); -+ __vx_cres_fixup(limit, res, value); -+ sum += value; -+ } -+ return sum; -+} -+ -+static inline -+rlim_t __vx_cres_array_fixup(struct _vx_limit *limit, const int *array) -+{ -+ rlim_t value = __vx_cres_array_sum(limit, array + 1); -+ int res = *array; -+ -+ if (value == __rlim_get(limit, res)) -+ return value; -+ -+ __rlim_set(limit, res, value); -+ /* now adjust min/max */ -+ if (!__vx_cres_adjust_max(limit, res, value)) -+ __vx_cres_adjust_min(limit, res, value); -+ -+ return value; -+} -+ -+static inline int __vx_cres_array_avail(struct vx_info *vxi, -+ const int *array, int num, char *_file, int _line) -+{ -+ struct _vx_limit *limit; -+ rlim_t value = 0; -+ int res; -+ -+ if (num == 0) -+ return 1; -+ if (!vxi) -+ return 1; -+ -+ limit = &vxi->limit; -+ res = *array; -+ value = __vx_cres_array_sum(limit, array + 1); -+ -+ __rlim_set(limit, res, value); -+ __vx_cres_fixup(limit, res, value); -+ -+ return __vx_cres_avail(vxi, res, num, _file, _line); -+} -+ -+ -+static inline void vx_limit_fixup(struct _vx_limit *limit, int id) -+{ -+ rlim_t value; -+ int res; -+ -+ /* complex resources first */ -+ if ((id < 0) || (id == RLIMIT_RSS)) -+ __vx_cres_array_fixup(limit, VLA_RSS); -+ -+ for (res = 0; res < NUM_LIMITS; res++) { -+ if ((id > 0) && (res != id)) -+ continue; -+ -+ value = __rlim_get(limit, res); -+ __vx_cres_fixup(limit, res, value); -+ -+ /* not supposed to happen, maybe warn? */ -+ if (__rlim_rmax(limit, res) > __rlim_hard(limit, res)) -+ __rlim_rmax(limit, res) = __rlim_hard(limit, res); -+ } -+} -+ -+ -+#endif /* __KERNEL__ */ -+#endif /* _VX_LIMIT_INT_H */ -diff -NurpP --minimal linux-2.6.32.1/include/linux/vserver/monitor.h linux-2.6.32.1-vs2.3.0.36.27/include/linux/vserver/monitor.h ---- linux-2.6.32.1/include/linux/vserver/monitor.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/include/linux/vserver/monitor.h 2009-12-03 20:04:56.000000000 +0100 -@@ -0,0 +1,96 @@ -+#ifndef _VX_MONITOR_H -+#define _VX_MONITOR_H -+ -+#include -+ -+enum { -+ VXM_UNUSED = 0, -+ -+ VXM_SYNC = 0x10, -+ -+ VXM_UPDATE = 0x20, -+ VXM_UPDATE_1, -+ VXM_UPDATE_2, -+ -+ VXM_RQINFO_1 = 0x24, -+ VXM_RQINFO_2, -+ -+ VXM_ACTIVATE = 0x40, -+ VXM_DEACTIVATE, -+ VXM_IDLE, -+ -+ VXM_HOLD = 0x44, -+ VXM_UNHOLD, -+ -+ VXM_MIGRATE = 0x48, -+ VXM_RESCHED, -+ -+ /* all other bits are flags */ -+ VXM_SCHED = 0x80, -+}; -+ -+struct _vxm_update_1 { -+ uint32_t tokens_max; -+ uint32_t fill_rate; -+ uint32_t interval; -+}; -+ -+struct _vxm_update_2 { -+ uint32_t tokens_min; -+ uint32_t fill_rate; -+ uint32_t interval; -+}; -+ -+struct _vxm_rqinfo_1 { -+ uint16_t running; -+ uint16_t onhold; -+ uint16_t iowait; -+ uint16_t uintr; -+ uint32_t idle_tokens; -+}; -+ -+struct _vxm_rqinfo_2 { -+ uint32_t norm_time; -+ uint32_t idle_time; -+ uint32_t idle_skip; -+}; -+ -+struct _vxm_sched { -+ uint32_t tokens; -+ uint32_t norm_time; -+ uint32_t idle_time; -+}; -+ -+struct _vxm_task { -+ uint16_t pid; -+ uint16_t state; -+}; -+ -+struct _vxm_event { -+ uint32_t jif; -+ union { -+ uint32_t seq; -+ uint32_t sec; -+ }; -+ union { -+ uint32_t tokens; -+ uint32_t nsec; -+ struct _vxm_task tsk; -+ }; -+}; -+ -+struct _vx_mon_entry { -+ uint16_t type; -+ uint16_t xid; -+ union { -+ struct _vxm_event ev; -+ struct _vxm_sched sd; -+ struct _vxm_update_1 u1; -+ struct _vxm_update_2 u2; -+ struct _vxm_rqinfo_1 q1; -+ struct _vxm_rqinfo_2 q2; -+ }; -+}; -+ -+ -+#endif /* _VX_MONITOR_H */ -diff -NurpP --minimal linux-2.6.32.1/include/linux/vserver/network_cmd.h linux-2.6.32.1-vs2.3.0.36.27/include/linux/vserver/network_cmd.h ---- linux-2.6.32.1/include/linux/vserver/network_cmd.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/include/linux/vserver/network_cmd.h 2009-12-03 20:04:56.000000000 +0100 -@@ -0,0 +1,150 @@ -+#ifndef _VX_NETWORK_CMD_H -+#define _VX_NETWORK_CMD_H -+ -+ -+/* vinfo commands */ -+ -+#define VCMD_task_nid VC_CMD(VINFO, 2, 0) -+ -+#ifdef __KERNEL__ -+extern int vc_task_nid(uint32_t); -+ -+#endif /* __KERNEL__ */ -+ -+#define VCMD_nx_info VC_CMD(VINFO, 6, 0) -+ -+struct vcmd_nx_info_v0 { -+ uint32_t nid; -+ /* more to come */ -+}; -+ -+#ifdef __KERNEL__ -+extern int vc_nx_info(struct nx_info *, void __user *); -+ -+#endif /* __KERNEL__ */ -+ -+#include -+#include -+ -+#define VCMD_net_create_v0 VC_CMD(VNET, 1, 0) -+#define VCMD_net_create VC_CMD(VNET, 1, 1) -+ -+struct vcmd_net_create { -+ uint64_t flagword; -+}; -+ -+#define VCMD_net_migrate VC_CMD(NETMIG, 1, 0) -+ -+#define VCMD_net_add VC_CMD(NETALT, 1, 0) -+#define VCMD_net_remove VC_CMD(NETALT, 2, 0) -+ -+struct vcmd_net_addr_v0 { -+ uint16_t type; -+ uint16_t count; -+ struct in_addr ip[4]; -+ struct in_addr mask[4]; -+}; -+ -+#define VCMD_net_add_ipv4 VC_CMD(NETALT, 1, 1) -+#define VCMD_net_remove_ipv4 VC_CMD(NETALT, 2, 1) -+ -+struct vcmd_net_addr_ipv4_v1 { -+ uint16_t type; -+ uint16_t flags; -+ struct in_addr ip; -+ struct in_addr mask; -+}; -+ -+#define VCMD_net_add_ipv6 VC_CMD(NETALT, 3, 1) -+#define VCMD_net_remove_ipv6 VC_CMD(NETALT, 4, 1) -+ -+struct vcmd_net_addr_ipv6_v1 { -+ uint16_t type; -+ uint16_t flags; -+ uint32_t prefix; -+ struct in6_addr ip; -+ struct in6_addr mask; -+}; -+ -+#define VCMD_add_match_ipv4 VC_CMD(NETALT, 5, 0) -+#define VCMD_get_match_ipv4 VC_CMD(NETALT, 6, 0) -+ -+struct vcmd_match_ipv4_v0 { -+ uint16_t type; -+ uint16_t flags; -+ uint16_t parent; -+ uint16_t prefix; -+ struct in_addr ip; -+ struct in_addr ip2; -+ struct in_addr mask; -+}; -+ -+#define VCMD_add_match_ipv6 VC_CMD(NETALT, 7, 0) -+#define VCMD_get_match_ipv6 VC_CMD(NETALT, 8, 0) -+ -+struct vcmd_match_ipv6_v0 { -+ uint16_t type; -+ uint16_t flags; -+ uint16_t parent; -+ uint16_t prefix; -+ struct in6_addr ip; -+ struct in6_addr ip2; -+ struct in6_addr mask; -+}; -+ -+ -+#ifdef __KERNEL__ -+extern int vc_net_create(uint32_t, void __user *); -+extern int vc_net_migrate(struct nx_info *, void __user *); -+ -+extern int vc_net_add(struct nx_info *, void __user *); -+extern int vc_net_remove(struct nx_info *, void __user *); -+ -+extern int vc_net_add_ipv4(struct nx_info *, void __user *); -+extern int vc_net_remove_ipv4(struct nx_info *, void __user *); -+ -+extern int vc_net_add_ipv6(struct nx_info *, void __user *); -+extern int vc_net_remove_ipv6(struct nx_info *, void __user *); -+ -+extern int vc_add_match_ipv4(struct nx_info *, void __user *); -+extern int vc_get_match_ipv4(struct nx_info *, void __user *); -+ -+extern int vc_add_match_ipv6(struct nx_info *, void __user *); -+extern int vc_get_match_ipv6(struct nx_info *, void __user *); -+ -+#endif /* __KERNEL__ */ -+ -+ -+/* flag commands */ -+ -+#define VCMD_get_nflags VC_CMD(FLAGS, 5, 0) -+#define VCMD_set_nflags VC_CMD(FLAGS, 6, 0) -+ -+struct vcmd_net_flags_v0 { -+ uint64_t flagword; -+ uint64_t mask; -+}; -+ -+#ifdef __KERNEL__ -+extern int vc_get_nflags(struct nx_info *, void __user *); -+extern int vc_set_nflags(struct nx_info *, void __user *); -+ -+#endif /* __KERNEL__ */ -+ -+ -+/* network caps commands */ -+ -+#define VCMD_get_ncaps VC_CMD(FLAGS, 7, 0) -+#define VCMD_set_ncaps VC_CMD(FLAGS, 8, 0) -+ -+struct vcmd_net_caps_v0 { -+ uint64_t ncaps; -+ uint64_t cmask; -+}; -+ -+#ifdef __KERNEL__ -+extern int vc_get_ncaps(struct nx_info *, void __user *); -+extern int vc_set_ncaps(struct nx_info *, void __user *); -+ -+#endif /* __KERNEL__ */ -+#endif /* _VX_CONTEXT_CMD_H */ -diff -NurpP --minimal linux-2.6.32.1/include/linux/vserver/network.h linux-2.6.32.1-vs2.3.0.36.27/include/linux/vserver/network.h ---- linux-2.6.32.1/include/linux/vserver/network.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/include/linux/vserver/network.h 2009-12-03 20:04:56.000000000 +0100 -@@ -0,0 +1,146 @@ -+#ifndef _VX_NETWORK_H -+#define _VX_NETWORK_H -+ -+#include -+ -+ -+#define MAX_N_CONTEXT 65535 /* Arbitrary limit */ -+ -+ -+/* network flags */ -+ -+#define NXF_INFO_PRIVATE 0x00000008 -+ -+#define NXF_SINGLE_IP 0x00000100 -+#define NXF_LBACK_REMAP 0x00000200 -+#define NXF_LBACK_ALLOW 0x00000400 -+ -+#define NXF_HIDE_NETIF 0x02000000 -+#define NXF_HIDE_LBACK 0x04000000 -+ -+#define NXF_STATE_SETUP (1ULL << 32) -+#define NXF_STATE_ADMIN (1ULL << 34) -+ -+#define NXF_SC_HELPER (1ULL << 36) -+#define NXF_PERSISTENT (1ULL << 38) -+ -+#define NXF_ONE_TIME (0x0005ULL << 32) -+ -+ -+#define NXF_INIT_SET (__nxf_init_set()) -+ -+static inline uint64_t __nxf_init_set(void) { -+ return NXF_STATE_ADMIN -+#ifdef CONFIG_VSERVER_AUTO_LBACK -+ | NXF_LBACK_REMAP -+ | NXF_HIDE_LBACK -+#endif -+#ifdef CONFIG_VSERVER_AUTO_SINGLE -+ | NXF_SINGLE_IP -+#endif -+ | NXF_HIDE_NETIF; -+} -+ -+ -+/* network caps */ -+ -+#define NXC_TUN_CREATE 0x00000001 -+ -+#define NXC_RAW_ICMP 0x00000100 -+ -+ -+/* address types */ -+ -+#define NXA_TYPE_IPV4 0x0001 -+#define NXA_TYPE_IPV6 0x0002 -+ -+#define NXA_TYPE_NONE 0x0000 -+#define NXA_TYPE_ANY 0x00FF -+ -+#define NXA_TYPE_ADDR 0x0010 -+#define NXA_TYPE_MASK 0x0020 -+#define NXA_TYPE_RANGE 0x0040 -+ -+#define NXA_MASK_ALL (NXA_TYPE_ADDR | NXA_TYPE_MASK | NXA_TYPE_RANGE) -+ -+#define NXA_MOD_BCAST 0x0100 -+#define NXA_MOD_LBACK 0x0200 -+ -+#define NXA_LOOPBACK 0x1000 -+ -+#define NXA_MASK_BIND (NXA_MASK_ALL | NXA_MOD_BCAST | NXA_MOD_LBACK) -+#define NXA_MASK_SHOW (NXA_MASK_ALL | NXA_LOOPBACK) -+ -+#ifdef __KERNEL__ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+struct nx_addr_v4 { -+ struct nx_addr_v4 *next; -+ struct in_addr ip[2]; -+ struct in_addr mask; -+ uint16_t type; -+ uint16_t flags; -+}; -+ -+struct nx_addr_v6 { -+ struct nx_addr_v6 *next; -+ struct in6_addr ip; -+ struct in6_addr mask; -+ uint32_t prefix; -+ uint16_t type; -+ uint16_t flags; -+}; -+ -+struct nx_info { -+ struct hlist_node nx_hlist; /* linked list of nxinfos */ -+ nid_t nx_id; /* vnet id */ -+ atomic_t nx_usecnt; /* usage count */ -+ atomic_t nx_tasks; /* tasks count */ -+ int nx_state; /* context state */ -+ -+ uint64_t nx_flags; /* network flag word */ -+ uint64_t nx_ncaps; /* network capabilities */ -+ -+ struct in_addr v4_lback; /* Loopback address */ -+ struct in_addr v4_bcast; /* Broadcast address */ -+ struct nx_addr_v4 v4; /* First/Single ipv4 address */ -+#ifdef CONFIG_IPV6 -+ struct nx_addr_v6 v6; /* First/Single ipv6 address */ -+#endif -+ char nx_name[65]; /* network context name */ -+}; -+ -+ -+/* status flags */ -+ -+#define NXS_HASHED 0x0001 -+#define NXS_SHUTDOWN 0x0100 -+#define NXS_RELEASED 0x8000 -+ -+extern struct nx_info *lookup_nx_info(int); -+ -+extern int get_nid_list(int, unsigned int *, int); -+extern int nid_is_hashed(nid_t); -+ -+extern int nx_migrate_task(struct task_struct *, struct nx_info *); -+ -+extern long vs_net_change(struct nx_info *, unsigned int); -+ -+struct sock; -+ -+ -+#define NX_IPV4(n) ((n)->v4.type != NXA_TYPE_NONE) -+#ifdef CONFIG_IPV6 -+#define NX_IPV6(n) ((n)->v6.type != NXA_TYPE_NONE) -+#else -+#define NX_IPV6(n) (0) -+#endif -+ -+#endif /* __KERNEL__ */ -+#endif /* _VX_NETWORK_H */ -diff -NurpP --minimal linux-2.6.32.1/include/linux/vserver/percpu.h linux-2.6.32.1-vs2.3.0.36.27/include/linux/vserver/percpu.h ---- linux-2.6.32.1/include/linux/vserver/percpu.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/include/linux/vserver/percpu.h 2009-12-03 20:04:56.000000000 +0100 -@@ -0,0 +1,14 @@ -+#ifndef _VX_PERCPU_H -+#define _VX_PERCPU_H -+ -+#include "cvirt_def.h" -+#include "sched_def.h" -+ -+struct _vx_percpu { -+ struct _vx_cvirt_pc cvirt; -+ struct _vx_sched_pc sched; -+}; -+ -+#define PERCPU_PERCTX (sizeof(struct _vx_percpu)) -+ -+#endif /* _VX_PERCPU_H */ -diff -NurpP --minimal linux-2.6.32.1/include/linux/vserver/pid.h linux-2.6.32.1-vs2.3.0.36.27/include/linux/vserver/pid.h ---- linux-2.6.32.1/include/linux/vserver/pid.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/include/linux/vserver/pid.h 2009-12-03 20:04:56.000000000 +0100 -@@ -0,0 +1,51 @@ -+#ifndef _VSERVER_PID_H -+#define _VSERVER_PID_H -+ -+/* pid faking stuff */ -+ -+#define vx_info_map_pid(v, p) \ -+ __vx_info_map_pid((v), (p), __func__, __FILE__, __LINE__) -+#define vx_info_map_tgid(v,p) vx_info_map_pid(v,p) -+#define vx_map_pid(p) vx_info_map_pid(current_vx_info(), p) -+#define vx_map_tgid(p) vx_map_pid(p) -+ -+static inline int __vx_info_map_pid(struct vx_info *vxi, int pid, -+ const char *func, const char *file, int line) -+{ -+ if (vx_info_flags(vxi, VXF_INFO_INIT, 0)) { -+ vxfprintk(VXD_CBIT(cvirt, 2), -+ "vx_map_tgid: %p/%llx: %d -> %d", -+ vxi, (long long)vxi->vx_flags, pid, -+ (pid && pid == vxi->vx_initpid) ? 1 : pid, -+ func, file, line); -+ if (pid == 0) -+ return 0; -+ if (pid == vxi->vx_initpid) -+ return 1; -+ } -+ return pid; -+} -+ -+#define vx_info_rmap_pid(v, p) \ -+ __vx_info_rmap_pid((v), (p), __func__, __FILE__, __LINE__) -+#define vx_rmap_pid(p) vx_info_rmap_pid(current_vx_info(), p) -+#define vx_rmap_tgid(p) vx_rmap_pid(p) -+ -+static inline int __vx_info_rmap_pid(struct vx_info *vxi, int pid, -+ const char *func, const char *file, int line) -+{ -+ if (vx_info_flags(vxi, VXF_INFO_INIT, 0)) { -+ vxfprintk(VXD_CBIT(cvirt, 2), -+ "vx_rmap_tgid: %p/%llx: %d -> %d", -+ vxi, (long long)vxi->vx_flags, pid, -+ (pid == 1) ? vxi->vx_initpid : pid, -+ func, file, line); -+ if ((pid == 1) && vxi->vx_initpid) -+ return vxi->vx_initpid; -+ if (pid == vxi->vx_initpid) -+ return ~0U; -+ } -+ return pid; -+} -+ -+#endif -diff -NurpP --minimal linux-2.6.32.1/include/linux/vserver/sched_cmd.h linux-2.6.32.1-vs2.3.0.36.27/include/linux/vserver/sched_cmd.h ---- linux-2.6.32.1/include/linux/vserver/sched_cmd.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/include/linux/vserver/sched_cmd.h 2009-12-03 20:04:56.000000000 +0100 -@@ -0,0 +1,108 @@ -+#ifndef _VX_SCHED_CMD_H -+#define _VX_SCHED_CMD_H -+ -+ -+/* sched vserver commands */ -+ -+#define VCMD_set_sched_v2 VC_CMD(SCHED, 1, 2) -+#define VCMD_set_sched_v3 VC_CMD(SCHED, 1, 3) -+#define VCMD_set_sched_v4 VC_CMD(SCHED, 1, 4) -+ -+struct vcmd_set_sched_v2 { -+ int32_t fill_rate; -+ int32_t interval; -+ int32_t tokens; -+ int32_t tokens_min; -+ int32_t tokens_max; -+ uint64_t cpu_mask; -+}; -+ -+struct vcmd_set_sched_v3 { -+ uint32_t set_mask; -+ int32_t fill_rate; -+ int32_t interval; -+ int32_t tokens; -+ int32_t tokens_min; -+ int32_t tokens_max; -+ int32_t priority_bias; -+}; -+ -+struct vcmd_set_sched_v4 { -+ uint32_t set_mask; -+ int32_t fill_rate; -+ int32_t interval; -+ int32_t tokens; -+ int32_t tokens_min; -+ int32_t tokens_max; -+ int32_t prio_bias; -+ int32_t cpu_id; -+ int32_t bucket_id; -+}; -+ -+#define VCMD_set_sched VC_CMD(SCHED, 1, 5) -+#define VCMD_get_sched VC_CMD(SCHED, 2, 5) -+ -+struct vcmd_sched_v5 { -+ uint32_t mask; -+ int32_t cpu_id; -+ int32_t bucket_id; -+ int32_t fill_rate[2]; -+ int32_t interval[2]; -+ int32_t tokens; -+ int32_t tokens_min; -+ int32_t tokens_max; -+ int32_t prio_bias; -+}; -+ -+#define VXSM_FILL_RATE 0x0001 -+#define VXSM_INTERVAL 0x0002 -+#define VXSM_FILL_RATE2 0x0004 -+#define VXSM_INTERVAL2 0x0008 -+#define VXSM_TOKENS 0x0010 -+#define VXSM_TOKENS_MIN 0x0020 -+#define VXSM_TOKENS_MAX 0x0040 -+#define VXSM_PRIO_BIAS 0x0100 -+ -+#define VXSM_IDLE_TIME 0x0200 -+#define VXSM_FORCE 0x0400 -+ -+#define VXSM_V3_MASK 0x0173 -+#define VXSM_SET_MASK 0x01FF -+ -+#define VXSM_CPU_ID 0x1000 -+#define VXSM_BUCKET_ID 0x2000 -+ -+#define VXSM_MSEC 0x4000 -+ -+#define SCHED_KEEP (-2) /* only for v2 */ -+ -+#ifdef __KERNEL__ -+ -+#include -+ -+extern int vc_set_sched_v2(struct vx_info *, void __user *); -+extern int vc_set_sched_v3(struct vx_info *, void __user *); -+extern int vc_set_sched_v4(struct vx_info *, void __user *); -+extern int vc_set_sched(struct vx_info *, void __user *); -+extern int vc_get_sched(struct vx_info *, void __user *); -+ -+#endif /* __KERNEL__ */ -+ -+#define VCMD_sched_info VC_CMD(SCHED, 3, 0) -+ -+struct vcmd_sched_info { -+ int32_t cpu_id; -+ int32_t bucket_id; -+ uint64_t user_msec; -+ uint64_t sys_msec; -+ uint64_t hold_msec; -+ uint32_t token_usec; -+ int32_t vavavoom; -+}; -+ -+#ifdef __KERNEL__ -+ -+extern int vc_sched_info(struct vx_info *, void __user *); -+ -+#endif /* __KERNEL__ */ -+#endif /* _VX_SCHED_CMD_H */ -diff -NurpP --minimal linux-2.6.32.1/include/linux/vserver/sched_def.h linux-2.6.32.1-vs2.3.0.36.27/include/linux/vserver/sched_def.h ---- linux-2.6.32.1/include/linux/vserver/sched_def.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/include/linux/vserver/sched_def.h 2009-12-03 20:04:56.000000000 +0100 -@@ -0,0 +1,68 @@ -+#ifndef _VX_SCHED_DEF_H -+#define _VX_SCHED_DEF_H -+ -+#include -+#include -+#include -+#include -+#include -+ -+ -+/* context sub struct */ -+ -+struct _vx_sched { -+ spinlock_t tokens_lock; /* lock for token bucket */ -+ -+ int tokens; /* number of CPU tokens */ -+ int fill_rate[2]; /* Fill rate: add X tokens... */ -+ int interval[2]; /* Divisor: per Y jiffies */ -+ int tokens_min; /* Limit: minimum for unhold */ -+ int tokens_max; /* Limit: no more than N tokens */ -+ -+ int prio_bias; /* bias offset for priority */ -+ -+ unsigned update_mask; /* which features should be updated */ -+ cpumask_t update; /* CPUs which should update */ -+}; -+ -+struct _vx_sched_pc { -+ int tokens; /* number of CPU tokens */ -+ int flags; /* bucket flags */ -+ -+ int fill_rate[2]; /* Fill rate: add X tokens... */ -+ int interval[2]; /* Divisor: per Y jiffies */ -+ int tokens_min; /* Limit: minimum for unhold */ -+ int tokens_max; /* Limit: no more than N tokens */ -+ -+ int prio_bias; /* bias offset for priority */ -+ int vavavoom; /* last calculated vavavoom */ -+ -+ unsigned long norm_time; /* last time accounted */ -+ unsigned long idle_time; /* non linear time for fair sched */ -+ unsigned long token_time; /* token time for accounting */ -+ unsigned long onhold; /* jiffies when put on hold */ -+ -+ uint64_t user_ticks; /* token tick events */ -+ uint64_t sys_ticks; /* token tick events */ -+ uint64_t hold_ticks; /* token ticks paused */ -+}; -+ -+ -+#define VXSF_ONHOLD 0x0001 -+#define VXSF_IDLE_TIME 0x0100 -+ -+#ifdef CONFIG_VSERVER_DEBUG -+ -+static inline void __dump_vx_sched(struct _vx_sched *sched) -+{ -+ printk("\t_vx_sched:\n"); -+ printk("\t tokens: %4d/%4d, %4d/%4d, %4d, %4d\n", -+ sched->fill_rate[0], sched->interval[0], -+ sched->fill_rate[1], sched->interval[1], -+ sched->tokens_min, sched->tokens_max); -+ printk("\t priority = %4d\n", sched->prio_bias); -+} -+ -+#endif -+ -+#endif /* _VX_SCHED_DEF_H */ -diff -NurpP --minimal linux-2.6.32.1/include/linux/vserver/sched.h linux-2.6.32.1-vs2.3.0.36.27/include/linux/vserver/sched.h ---- linux-2.6.32.1/include/linux/vserver/sched.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/include/linux/vserver/sched.h 2009-12-03 20:04:56.000000000 +0100 -@@ -0,0 +1,26 @@ -+#ifndef _VX_SCHED_H -+#define _VX_SCHED_H -+ -+ -+#ifdef __KERNEL__ -+ -+struct timespec; -+ -+void vx_vsi_uptime(struct timespec *, struct timespec *); -+ -+ -+struct vx_info; -+ -+void vx_update_load(struct vx_info *); -+ -+ -+int vx_tokens_recalc(struct _vx_sched_pc *, -+ unsigned long *, unsigned long *, int [2]); -+ -+void vx_update_sched_param(struct _vx_sched *sched, -+ struct _vx_sched_pc *sched_pc); -+ -+#endif /* __KERNEL__ */ -+#else /* _VX_SCHED_H */ -+#warning duplicate inclusion -+#endif /* _VX_SCHED_H */ -diff -NurpP --minimal linux-2.6.32.1/include/linux/vserver/signal_cmd.h linux-2.6.32.1-vs2.3.0.36.27/include/linux/vserver/signal_cmd.h ---- linux-2.6.32.1/include/linux/vserver/signal_cmd.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/include/linux/vserver/signal_cmd.h 2009-12-03 20:04:56.000000000 +0100 -@@ -0,0 +1,43 @@ -+#ifndef _VX_SIGNAL_CMD_H -+#define _VX_SIGNAL_CMD_H -+ -+ -+/* signalling vserver commands */ -+ -+#define VCMD_ctx_kill VC_CMD(PROCTRL, 1, 0) -+#define VCMD_wait_exit VC_CMD(EVENT, 99, 0) -+ -+struct vcmd_ctx_kill_v0 { -+ int32_t pid; -+ int32_t sig; -+}; -+ -+struct vcmd_wait_exit_v0 { -+ int32_t reboot_cmd; -+ int32_t exit_code; -+}; -+ -+#ifdef __KERNEL__ -+ -+extern int vc_ctx_kill(struct vx_info *, void __user *); -+extern int vc_wait_exit(struct vx_info *, void __user *); -+ -+#endif /* __KERNEL__ */ -+ -+/* process alteration commands */ -+ -+#define VCMD_get_pflags VC_CMD(PROCALT, 5, 0) -+#define VCMD_set_pflags VC_CMD(PROCALT, 6, 0) -+ -+struct vcmd_pflags_v0 { -+ uint32_t flagword; -+ uint32_t mask; -+}; -+ -+#ifdef __KERNEL__ -+ -+extern int vc_get_pflags(uint32_t pid, void __user *); -+extern int vc_set_pflags(uint32_t pid, void __user *); -+ -+#endif /* __KERNEL__ */ -+#endif /* _VX_SIGNAL_CMD_H */ -diff -NurpP --minimal linux-2.6.32.1/include/linux/vserver/signal.h linux-2.6.32.1-vs2.3.0.36.27/include/linux/vserver/signal.h ---- linux-2.6.32.1/include/linux/vserver/signal.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/include/linux/vserver/signal.h 2009-12-03 20:04:56.000000000 +0100 -@@ -0,0 +1,14 @@ -+#ifndef _VX_SIGNAL_H -+#define _VX_SIGNAL_H -+ -+ -+#ifdef __KERNEL__ -+ -+struct vx_info; -+ -+int vx_info_kill(struct vx_info *, int, int); -+ -+#endif /* __KERNEL__ */ -+#else /* _VX_SIGNAL_H */ -+#warning duplicate inclusion -+#endif /* _VX_SIGNAL_H */ -diff -NurpP --minimal linux-2.6.32.1/include/linux/vserver/space_cmd.h linux-2.6.32.1-vs2.3.0.36.27/include/linux/vserver/space_cmd.h ---- linux-2.6.32.1/include/linux/vserver/space_cmd.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/include/linux/vserver/space_cmd.h 2009-12-03 20:04:56.000000000 +0100 -@@ -0,0 +1,38 @@ -+#ifndef _VX_SPACE_CMD_H -+#define _VX_SPACE_CMD_H -+ -+ -+#define VCMD_enter_space_v0 VC_CMD(PROCALT, 1, 0) -+#define VCMD_enter_space_v1 VC_CMD(PROCALT, 1, 1) -+#define VCMD_enter_space VC_CMD(PROCALT, 1, 2) -+ -+#define VCMD_set_space_v0 VC_CMD(PROCALT, 3, 0) -+#define VCMD_set_space_v1 VC_CMD(PROCALT, 3, 1) -+#define VCMD_set_space VC_CMD(PROCALT, 3, 2) -+ -+#define VCMD_get_space_mask_v0 VC_CMD(PROCALT, 4, 0) -+ -+#define VCMD_get_space_mask VC_CMD(VSPACE, 0, 1) -+#define VCMD_get_space_default VC_CMD(VSPACE, 1, 0) -+ -+ -+struct vcmd_space_mask_v1 { -+ uint64_t mask; -+}; -+ -+struct vcmd_space_mask_v2 { -+ uint64_t mask; -+ uint32_t index; -+}; -+ -+ -+#ifdef __KERNEL__ -+ -+extern int vc_enter_space_v1(struct vx_info *, void __user *); -+extern int vc_set_space_v1(struct vx_info *, void __user *); -+extern int vc_enter_space(struct vx_info *, void __user *); -+extern int vc_set_space(struct vx_info *, void __user *); -+extern int vc_get_space_mask(void __user *, int); -+ -+#endif /* __KERNEL__ */ -+#endif /* _VX_SPACE_CMD_H */ -diff -NurpP --minimal linux-2.6.32.1/include/linux/vserver/space.h linux-2.6.32.1-vs2.3.0.36.27/include/linux/vserver/space.h ---- linux-2.6.32.1/include/linux/vserver/space.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/include/linux/vserver/space.h 2009-12-03 20:04:56.000000000 +0100 -@@ -0,0 +1,12 @@ -+#ifndef _VX_SPACE_H -+#define _VX_SPACE_H -+ -+#include -+ -+struct vx_info; -+ -+int vx_set_space(struct vx_info *vxi, unsigned long mask, unsigned index); -+ -+#else /* _VX_SPACE_H */ -+#warning duplicate inclusion -+#endif /* _VX_SPACE_H */ -diff -NurpP --minimal linux-2.6.32.1/include/linux/vserver/switch.h linux-2.6.32.1-vs2.3.0.36.27/include/linux/vserver/switch.h ---- linux-2.6.32.1/include/linux/vserver/switch.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/include/linux/vserver/switch.h 2009-12-03 20:04:56.000000000 +0100 -@@ -0,0 +1,98 @@ -+#ifndef _VX_SWITCH_H -+#define _VX_SWITCH_H -+ -+#include -+ -+ -+#define VC_CATEGORY(c) (((c) >> 24) & 0x3F) -+#define VC_COMMAND(c) (((c) >> 16) & 0xFF) -+#define VC_VERSION(c) ((c) & 0xFFF) -+ -+#define VC_CMD(c, i, v) ((((VC_CAT_ ## c) & 0x3F) << 24) \ -+ | (((i) & 0xFF) << 16) | ((v) & 0xFFF)) -+ -+/* -+ -+ Syscall Matrix V2.8 -+ -+ |VERSION|CREATE |MODIFY |MIGRATE|CONTROL|EXPERIM| |SPECIAL|SPECIAL| -+ |STATS |DESTROY|ALTER |CHANGE |LIMIT |TEST | | | | -+ |INFO |SETUP | |MOVE | | | | | | -+ -------+-------+-------+-------+-------+-------+-------+ +-------+-------+ -+ SYSTEM |VERSION|VSETUP |VHOST | | | | |DEVICE | | -+ HOST | 00| 01| 02| 03| 04| 05| | 06| 07| -+ -------+-------+-------+-------+-------+-------+-------+ +-------+-------+ -+ CPU | |VPROC |PROCALT|PROCMIG|PROCTRL| | |SCHED. | | -+ PROCESS| 08| 09| 10| 11| 12| 13| | 14| 15| -+ -------+-------+-------+-------+-------+-------+-------+ +-------+-------+ -+ MEMORY | | | | |MEMCTRL| | |SWAP | | -+ | 16| 17| 18| 19| 20| 21| | 22| 23| -+ -------+-------+-------+-------+-------+-------+-------+ +-------+-------+ -+ NETWORK| |VNET |NETALT |NETMIG |NETCTL | | |SERIAL | | -+ | 24| 25| 26| 27| 28| 29| | 30| 31| -+ -------+-------+-------+-------+-------+-------+-------+ +-------+-------+ -+ DISK | | | |TAGMIG |DLIMIT | | |INODE | | -+ VFS | 32| 33| 34| 35| 36| 37| | 38| 39| -+ -------+-------+-------+-------+-------+-------+-------+ +-------+-------+ -+ OTHER |VSTAT | | | | | | |VINFO | | -+ | 40| 41| 42| 43| 44| 45| | 46| 47| -+ =======+=======+=======+=======+=======+=======+=======+ +=======+=======+ -+ SPECIAL|EVENT | | | |FLAGS | | |VSPACE | | -+ | 48| 49| 50| 51| 52| 53| | 54| 55| -+ -------+-------+-------+-------+-------+-------+-------+ +-------+-------+ -+ SPECIAL|DEBUG | | | |RLIMIT |SYSCALL| | |COMPAT | -+ | 56| 57| 58| 59| 60|TEST 61| | 62| 63| -+ -------+-------+-------+-------+-------+-------+-------+ +-------+-------+ -+ -+*/ -+ -+#define VC_CAT_VERSION 0 -+ -+#define VC_CAT_VSETUP 1 -+#define VC_CAT_VHOST 2 -+ -+#define VC_CAT_DEVICE 6 -+ -+#define VC_CAT_VPROC 9 -+#define VC_CAT_PROCALT 10 -+#define VC_CAT_PROCMIG 11 -+#define VC_CAT_PROCTRL 12 -+ -+#define VC_CAT_SCHED 14 -+#define VC_CAT_MEMCTRL 20 -+ -+#define VC_CAT_VNET 25 -+#define VC_CAT_NETALT 26 -+#define VC_CAT_NETMIG 27 -+#define VC_CAT_NETCTRL 28 -+ -+#define VC_CAT_TAGMIG 35 -+#define VC_CAT_DLIMIT 36 -+#define VC_CAT_INODE 38 -+ -+#define VC_CAT_VSTAT 40 -+#define VC_CAT_VINFO 46 -+#define VC_CAT_EVENT 48 -+ -+#define VC_CAT_FLAGS 52 -+#define VC_CAT_VSPACE 54 -+#define VC_CAT_DEBUG 56 -+#define VC_CAT_RLIMIT 60 -+ -+#define VC_CAT_SYSTEST 61 -+#define VC_CAT_COMPAT 63 -+ -+/* query version */ -+ -+#define VCMD_get_version VC_CMD(VERSION, 0, 0) -+#define VCMD_get_vci VC_CMD(VERSION, 1, 0) -+ -+ -+#ifdef __KERNEL__ -+ -+#include -+ -+#endif /* __KERNEL__ */ -+ -+#endif /* _VX_SWITCH_H */ -+ -diff -NurpP --minimal linux-2.6.32.1/include/linux/vserver/tag_cmd.h linux-2.6.32.1-vs2.3.0.36.27/include/linux/vserver/tag_cmd.h ---- linux-2.6.32.1/include/linux/vserver/tag_cmd.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/include/linux/vserver/tag_cmd.h 2009-12-03 20:04:56.000000000 +0100 -@@ -0,0 +1,22 @@ -+#ifndef _VX_TAG_CMD_H -+#define _VX_TAG_CMD_H -+ -+ -+/* vinfo commands */ -+ -+#define VCMD_task_tag VC_CMD(VINFO, 3, 0) -+ -+#ifdef __KERNEL__ -+extern int vc_task_tag(uint32_t); -+ -+#endif /* __KERNEL__ */ -+ -+/* context commands */ -+ -+#define VCMD_tag_migrate VC_CMD(TAGMIG, 1, 0) -+ -+#ifdef __KERNEL__ -+extern int vc_tag_migrate(uint32_t); -+ -+#endif /* __KERNEL__ */ -+#endif /* _VX_TAG_CMD_H */ -diff -NurpP --minimal linux-2.6.32.1/include/linux/vserver/tag.h linux-2.6.32.1-vs2.3.0.36.27/include/linux/vserver/tag.h ---- linux-2.6.32.1/include/linux/vserver/tag.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/include/linux/vserver/tag.h 2009-12-03 20:04:56.000000000 +0100 -@@ -0,0 +1,143 @@ -+#ifndef _DX_TAG_H -+#define _DX_TAG_H -+ -+#include -+ -+ -+#define DX_TAG(in) (IS_TAGGED(in)) -+ -+ -+#ifdef CONFIG_TAG_NFSD -+#define DX_TAG_NFSD 1 -+#else -+#define DX_TAG_NFSD 0 -+#endif -+ -+ -+#ifdef CONFIG_TAGGING_NONE -+ -+#define MAX_UID 0xFFFFFFFF -+#define MAX_GID 0xFFFFFFFF -+ -+#define INOTAG_TAG(cond, uid, gid, tag) (0) -+ -+#define TAGINO_UID(cond, uid, tag) (uid) -+#define TAGINO_GID(cond, gid, tag) (gid) -+ -+#endif -+ -+ -+#ifdef CONFIG_TAGGING_GID16 -+ -+#define MAX_UID 0xFFFFFFFF -+#define MAX_GID 0x0000FFFF -+ -+#define INOTAG_TAG(cond, uid, gid, tag) \ -+ ((cond) ? (((gid) >> 16) & 0xFFFF) : 0) -+ -+#define TAGINO_UID(cond, uid, tag) (uid) -+#define TAGINO_GID(cond, gid, tag) \ -+ ((cond) ? (((gid) & 0xFFFF) | ((tag) << 16)) : (gid)) -+ -+#endif -+ -+ -+#ifdef CONFIG_TAGGING_ID24 -+ -+#define MAX_UID 0x00FFFFFF -+#define MAX_GID 0x00FFFFFF -+ -+#define INOTAG_TAG(cond, uid, gid, tag) \ -+ ((cond) ? ((((uid) >> 16) & 0xFF00) | (((gid) >> 24) & 0xFF)) : 0) -+ -+#define TAGINO_UID(cond, uid, tag) \ -+ ((cond) ? (((uid) & 0xFFFFFF) | (((tag) & 0xFF00) << 16)) : (uid)) -+#define TAGINO_GID(cond, gid, tag) \ -+ ((cond) ? (((gid) & 0xFFFFFF) | (((tag) & 0x00FF) << 24)) : (gid)) -+ -+#endif -+ -+ -+#ifdef CONFIG_TAGGING_UID16 -+ -+#define MAX_UID 0x0000FFFF -+#define MAX_GID 0xFFFFFFFF -+ -+#define INOTAG_TAG(cond, uid, gid, tag) \ -+ ((cond) ? (((uid) >> 16) & 0xFFFF) : 0) -+ -+#define TAGINO_UID(cond, uid, tag) \ -+ ((cond) ? (((uid) & 0xFFFF) | ((tag) << 16)) : (uid)) -+#define TAGINO_GID(cond, gid, tag) (gid) -+ -+#endif -+ -+ -+#ifdef CONFIG_TAGGING_INTERN -+ -+#define MAX_UID 0xFFFFFFFF -+#define MAX_GID 0xFFFFFFFF -+ -+#define INOTAG_TAG(cond, uid, gid, tag) \ -+ ((cond) ? (tag) : 0) -+ -+#define TAGINO_UID(cond, uid, tag) (uid) -+#define TAGINO_GID(cond, gid, tag) (gid) -+ -+#endif -+ -+ -+#ifndef CONFIG_TAGGING_NONE -+#define dx_current_fstag(sb) \ -+ ((sb)->s_flags & MS_TAGGED ? dx_current_tag() : 0) -+#else -+#define dx_current_fstag(sb) (0) -+#endif -+ -+#ifndef CONFIG_TAGGING_INTERN -+#define TAGINO_TAG(cond, tag) (0) -+#else -+#define TAGINO_TAG(cond, tag) ((cond) ? (tag) : 0) -+#endif -+ -+#define INOTAG_UID(cond, uid, gid) \ -+ ((cond) ? ((uid) & MAX_UID) : (uid)) -+#define INOTAG_GID(cond, uid, gid) \ -+ ((cond) ? ((gid) & MAX_GID) : (gid)) -+ -+ -+static inline uid_t dx_map_uid(uid_t uid) -+{ -+ if ((uid > MAX_UID) && (uid != -1)) -+ uid = -2; -+ return (uid & MAX_UID); -+} -+ -+static inline gid_t dx_map_gid(gid_t gid) -+{ -+ if ((gid > MAX_GID) && (gid != -1)) -+ gid = -2; -+ return (gid & MAX_GID); -+} -+ -+struct peer_tag { -+ int32_t xid; -+ int32_t nid; -+}; -+ -+#define dx_notagcheck(sb) ((sb) && ((sb)->s_flags & MS_NOTAGCHECK)) -+ -+int dx_parse_tag(char *string, tag_t *tag, int remove, int *mnt_flags, -+ unsigned long *flags); -+ -+#ifdef CONFIG_PROPAGATE -+ -+void __dx_propagate_tag(struct nameidata *nd, struct inode *inode); -+ -+#define dx_propagate_tag(n, i) __dx_propagate_tag(n, i) -+ -+#else -+#define dx_propagate_tag(n, i) do { } while (0) -+#endif -+ -+#endif /* _DX_TAG_H */ -diff -NurpP --minimal linux-2.6.32.1/include/linux/vs_inet6.h linux-2.6.32.1-vs2.3.0.36.27/include/linux/vs_inet6.h ---- linux-2.6.32.1/include/linux/vs_inet6.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/include/linux/vs_inet6.h 2009-12-03 20:04:56.000000000 +0100 -@@ -0,0 +1,246 @@ -+#ifndef _VS_INET6_H -+#define _VS_INET6_H -+ -+#include "vserver/base.h" -+#include "vserver/network.h" -+#include "vserver/debug.h" -+ -+#include -+ -+#define NXAV6(a) &(a)->ip, &(a)->mask, (a)->prefix, (a)->type -+#define NXAV6_FMT "[%pI6/%pI6/%d:%04x]" -+ -+ -+#ifdef CONFIG_IPV6 -+ -+static inline -+int v6_addr_match(struct nx_addr_v6 *nxa, -+ const struct in6_addr *addr, uint16_t mask) -+{ -+ int ret = 0; -+ -+ switch (nxa->type & mask) { -+ case NXA_TYPE_MASK: -+ ret = ipv6_masked_addr_cmp(&nxa->ip, &nxa->mask, addr); -+ break; -+ case NXA_TYPE_ADDR: -+ ret = ipv6_addr_equal(&nxa->ip, addr); -+ break; -+ case NXA_TYPE_ANY: -+ ret = 1; -+ break; -+ } -+ vxdprintk(VXD_CBIT(net, 0), -+ "v6_addr_match(%p" NXAV6_FMT ",%pI6,%04x) = %d", -+ nxa, NXAV6(nxa), addr, mask, ret); -+ return ret; -+} -+ -+static inline -+int v6_addr_in_nx_info(struct nx_info *nxi, -+ const struct in6_addr *addr, uint16_t mask) -+{ -+ struct nx_addr_v6 *nxa; -+ int ret = 1; -+ -+ if (!nxi) -+ goto out; -+ for (nxa = &nxi->v6; nxa; nxa = nxa->next) -+ if (v6_addr_match(nxa, addr, mask)) -+ goto out; -+ ret = 0; -+out: -+ vxdprintk(VXD_CBIT(net, 0), -+ "v6_addr_in_nx_info(%p[#%u],%pI6,%04x) = %d", -+ nxi, nxi ? nxi->nx_id : 0, addr, mask, ret); -+ return ret; -+} -+ -+static inline -+int v6_nx_addr_match(struct nx_addr_v6 *nxa, struct nx_addr_v6 *addr, uint16_t mask) -+{ -+ /* FIXME: needs full range checks */ -+ return v6_addr_match(nxa, &addr->ip, mask); -+} -+ -+static inline -+int v6_nx_addr_in_nx_info(struct nx_info *nxi, struct nx_addr_v6 *nxa, uint16_t mask) -+{ -+ struct nx_addr_v6 *ptr; -+ -+ for (ptr = &nxi->v6; ptr; ptr = ptr->next) -+ if (v6_nx_addr_match(ptr, nxa, mask)) -+ return 1; -+ return 0; -+} -+ -+ -+/* -+ * Check if a given address matches for a socket -+ * -+ * nxi: the socket's nx_info if any -+ * addr: to be verified address -+ */ -+static inline -+int v6_sock_addr_match ( -+ struct nx_info *nxi, -+ struct inet_sock *inet, -+ struct in6_addr *addr) -+{ -+ struct sock *sk = &inet->sk; -+ struct in6_addr *saddr = inet6_rcv_saddr(sk); -+ -+ if (!ipv6_addr_any(addr) && -+ ipv6_addr_equal(saddr, addr)) -+ return 1; -+ if (ipv6_addr_any(saddr)) -+ return v6_addr_in_nx_info(nxi, addr, -1); -+ return 0; -+} -+ -+/* -+ * check if address is covered by socket -+ * -+ * sk: the socket to check against -+ * addr: the address in question (must be != 0) -+ */ -+ -+static inline -+int __v6_addr_match_socket(const struct sock *sk, struct nx_addr_v6 *nxa) -+{ -+ struct nx_info *nxi = sk->sk_nx_info; -+ struct in6_addr *saddr = inet6_rcv_saddr(sk); -+ -+ vxdprintk(VXD_CBIT(net, 5), -+ "__v6_addr_in_socket(%p," NXAV6_FMT ") %p:%pI6 %p;%lx", -+ sk, NXAV6(nxa), nxi, saddr, sk->sk_socket, -+ (sk->sk_socket?sk->sk_socket->flags:0)); -+ -+ if (!ipv6_addr_any(saddr)) { /* direct address match */ -+ return v6_addr_match(nxa, saddr, -1); -+ } else if (nxi) { /* match against nx_info */ -+ return v6_nx_addr_in_nx_info(nxi, nxa, -1); -+ } else { /* unrestricted any socket */ -+ return 1; -+ } -+} -+ -+ -+/* inet related checks and helpers */ -+ -+ -+struct in_ifaddr; -+struct net_device; -+struct sock; -+ -+ -+#include -+#include -+#include -+ -+ -+int dev_in_nx_info(struct net_device *, struct nx_info *); -+int v6_dev_in_nx_info(struct net_device *, struct nx_info *); -+int nx_v6_addr_conflict(struct nx_info *, struct nx_info *); -+ -+ -+ -+static inline -+int v6_ifa_in_nx_info(struct inet6_ifaddr *ifa, struct nx_info *nxi) -+{ -+ if (!nxi) -+ return 1; -+ if (!ifa) -+ return 0; -+ return v6_addr_in_nx_info(nxi, &ifa->addr, -1); -+} -+ -+static inline -+int nx_v6_ifa_visible(struct nx_info *nxi, struct inet6_ifaddr *ifa) -+{ -+ vxdprintk(VXD_CBIT(net, 1), "nx_v6_ifa_visible(%p[#%u],%p) %d", -+ nxi, nxi ? nxi->nx_id : 0, ifa, -+ nxi ? v6_ifa_in_nx_info(ifa, nxi) : 0); -+ -+ if (!nx_info_flags(nxi, NXF_HIDE_NETIF, 0)) -+ return 1; -+ if (v6_ifa_in_nx_info(ifa, nxi)) -+ return 1; -+ return 0; -+} -+ -+ -+struct nx_v6_sock_addr { -+ struct in6_addr saddr; /* Address used for validation */ -+ struct in6_addr baddr; /* Address used for socket bind */ -+}; -+ -+static inline -+int v6_map_sock_addr(struct inet_sock *inet, struct sockaddr_in6 *addr, -+ struct nx_v6_sock_addr *nsa) -+{ -+ // struct sock *sk = &inet->sk; -+ // struct nx_info *nxi = sk->sk_nx_info; -+ struct in6_addr saddr = addr->sin6_addr; -+ struct in6_addr baddr = saddr; -+ -+ nsa->saddr = saddr; -+ nsa->baddr = baddr; -+ return 0; -+} -+ -+static inline -+void v6_set_sock_addr(struct inet_sock *inet, struct nx_v6_sock_addr *nsa) -+{ -+ // struct sock *sk = &inet->sk; -+ // struct in6_addr *saddr = inet6_rcv_saddr(sk); -+ -+ // *saddr = nsa->baddr; -+ // inet->saddr = nsa->baddr; -+} -+ -+static inline -+int nx_info_has_v6(struct nx_info *nxi) -+{ -+ if (!nxi) -+ return 1; -+ if (NX_IPV6(nxi)) -+ return 1; -+ return 0; -+} -+ -+#else /* CONFIG_IPV6 */ -+ -+static inline -+int nx_v6_dev_visible(struct nx_info *n, struct net_device *d) -+{ -+ return 1; -+} -+ -+ -+static inline -+int nx_v6_addr_conflict(struct nx_info *n, uint32_t a, const struct sock *s) -+{ -+ return 1; -+} -+ -+static inline -+int v6_ifa_in_nx_info(struct in_ifaddr *a, struct nx_info *n) -+{ -+ return 1; -+} -+ -+static inline -+int nx_info_has_v6(struct nx_info *nxi) -+{ -+ return 0; -+} -+ -+#endif /* CONFIG_IPV6 */ -+ -+#define current_nx_info_has_v6() \ -+ nx_info_has_v6(current_nx_info()) -+ -+#else -+#warning duplicate inclusion -+#endif -diff -NurpP --minimal linux-2.6.32.1/include/linux/vs_inet.h linux-2.6.32.1-vs2.3.0.36.27/include/linux/vs_inet.h ---- linux-2.6.32.1/include/linux/vs_inet.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/include/linux/vs_inet.h 2009-12-03 20:04:56.000000000 +0100 -@@ -0,0 +1,342 @@ -+#ifndef _VS_INET_H -+#define _VS_INET_H -+ -+#include "vserver/base.h" -+#include "vserver/network.h" -+#include "vserver/debug.h" -+ -+#define IPI_LOOPBACK htonl(INADDR_LOOPBACK) -+ -+#define NXAV4(a) NIPQUAD((a)->ip[0]), NIPQUAD((a)->ip[1]), \ -+ NIPQUAD((a)->mask), (a)->type -+#define NXAV4_FMT "[" NIPQUAD_FMT "-" NIPQUAD_FMT "/" NIPQUAD_FMT ":%04x]" -+ -+ -+static inline -+int v4_addr_match(struct nx_addr_v4 *nxa, __be32 addr, uint16_t tmask) -+{ -+ __be32 ip = nxa->ip[0].s_addr; -+ __be32 mask = nxa->mask.s_addr; -+ __be32 bcast = ip | ~mask; -+ int ret = 0; -+ -+ switch (nxa->type & tmask) { -+ case NXA_TYPE_MASK: -+ ret = (ip == (addr & mask)); -+ break; -+ case NXA_TYPE_ADDR: -+ ret = 3; -+ if (addr == ip) -+ break; -+ /* fall through to broadcast */ -+ case NXA_MOD_BCAST: -+ ret = ((tmask & NXA_MOD_BCAST) && (addr == bcast)); -+ break; -+ case NXA_TYPE_RANGE: -+ ret = ((nxa->ip[0].s_addr <= addr) && -+ (nxa->ip[1].s_addr > addr)); -+ break; -+ case NXA_TYPE_ANY: -+ ret = 2; -+ break; -+ } -+ -+ vxdprintk(VXD_CBIT(net, 0), -+ "v4_addr_match(%p" NXAV4_FMT "," NIPQUAD_FMT ",%04x) = %d", -+ nxa, NXAV4(nxa), NIPQUAD(addr), tmask, ret); -+ return ret; -+} -+ -+static inline -+int v4_addr_in_nx_info(struct nx_info *nxi, __be32 addr, uint16_t tmask) -+{ -+ struct nx_addr_v4 *nxa; -+ int ret = 1; -+ -+ if (!nxi) -+ goto out; -+ -+ ret = 2; -+ /* allow 127.0.0.1 when remapping lback */ -+ if ((tmask & NXA_LOOPBACK) && -+ (addr == IPI_LOOPBACK) && -+ nx_info_flags(nxi, NXF_LBACK_REMAP, 0)) -+ goto out; -+ ret = 3; -+ /* check for lback address */ -+ if ((tmask & NXA_MOD_LBACK) && -+ (nxi->v4_lback.s_addr == addr)) -+ goto out; -+ ret = 4; -+ /* check for broadcast address */ -+ if ((tmask & NXA_MOD_BCAST) && -+ (nxi->v4_bcast.s_addr == addr)) -+ goto out; -+ ret = 5; -+ /* check for v4 addresses */ -+ for (nxa = &nxi->v4; nxa; nxa = nxa->next) -+ if (v4_addr_match(nxa, addr, tmask)) -+ goto out; -+ ret = 0; -+out: -+ vxdprintk(VXD_CBIT(net, 0), -+ "v4_addr_in_nx_info(%p[#%u]," NIPQUAD_FMT ",%04x) = %d", -+ nxi, nxi ? nxi->nx_id : 0, NIPQUAD(addr), tmask, ret); -+ return ret; -+} -+ -+static inline -+int v4_nx_addr_match(struct nx_addr_v4 *nxa, struct nx_addr_v4 *addr, uint16_t mask) -+{ -+ /* FIXME: needs full range checks */ -+ return v4_addr_match(nxa, addr->ip[0].s_addr, mask); -+} -+ -+static inline -+int v4_nx_addr_in_nx_info(struct nx_info *nxi, struct nx_addr_v4 *nxa, uint16_t mask) -+{ -+ struct nx_addr_v4 *ptr; -+ -+ for (ptr = &nxi->v4; ptr; ptr = ptr->next) -+ if (v4_nx_addr_match(ptr, nxa, mask)) -+ return 1; -+ return 0; -+} -+ -+#include -+ -+/* -+ * Check if a given address matches for a socket -+ * -+ * nxi: the socket's nx_info if any -+ * addr: to be verified address -+ */ -+static inline -+int v4_sock_addr_match ( -+ struct nx_info *nxi, -+ struct inet_sock *inet, -+ __be32 addr) -+{ -+ __be32 saddr = inet->rcv_saddr; -+ __be32 bcast = nxi ? nxi->v4_bcast.s_addr : INADDR_BROADCAST; -+ -+ if (addr && (saddr == addr || bcast == addr)) -+ return 1; -+ if (!saddr) -+ return v4_addr_in_nx_info(nxi, addr, NXA_MASK_BIND); -+ return 0; -+} -+ -+ -+/* inet related checks and helpers */ -+ -+ -+struct in_ifaddr; -+struct net_device; -+struct sock; -+ -+#ifdef CONFIG_INET -+ -+#include -+#include -+#include -+#include -+ -+ -+int dev_in_nx_info(struct net_device *, struct nx_info *); -+int v4_dev_in_nx_info(struct net_device *, struct nx_info *); -+int nx_v4_addr_conflict(struct nx_info *, struct nx_info *); -+ -+ -+/* -+ * check if address is covered by socket -+ * -+ * sk: the socket to check against -+ * addr: the address in question (must be != 0) -+ */ -+ -+static inline -+int __v4_addr_match_socket(const struct sock *sk, struct nx_addr_v4 *nxa) -+{ -+ struct nx_info *nxi = sk->sk_nx_info; -+ __be32 saddr = inet_rcv_saddr(sk); -+ -+ vxdprintk(VXD_CBIT(net, 5), -+ "__v4_addr_in_socket(%p," NXAV4_FMT ") %p:" NIPQUAD_FMT " %p;%lx", -+ sk, NXAV4(nxa), nxi, NIPQUAD(saddr), sk->sk_socket, -+ (sk->sk_socket?sk->sk_socket->flags:0)); -+ -+ if (saddr) { /* direct address match */ -+ return v4_addr_match(nxa, saddr, -1); -+ } else if (nxi) { /* match against nx_info */ -+ return v4_nx_addr_in_nx_info(nxi, nxa, -1); -+ } else { /* unrestricted any socket */ -+ return 1; -+ } -+} -+ -+ -+ -+static inline -+int nx_dev_visible(struct nx_info *nxi, struct net_device *dev) -+{ -+ vxdprintk(VXD_CBIT(net, 1), "nx_dev_visible(%p[#%u],%p »%s«) %d", -+ nxi, nxi ? nxi->nx_id : 0, dev, dev->name, -+ nxi ? dev_in_nx_info(dev, nxi) : 0); -+ -+ if (!nx_info_flags(nxi, NXF_HIDE_NETIF, 0)) -+ return 1; -+ if (dev_in_nx_info(dev, nxi)) -+ return 1; -+ return 0; -+} -+ -+ -+static inline -+int v4_ifa_in_nx_info(struct in_ifaddr *ifa, struct nx_info *nxi) -+{ -+ if (!nxi) -+ return 1; -+ if (!ifa) -+ return 0; -+ return v4_addr_in_nx_info(nxi, ifa->ifa_local, NXA_MASK_SHOW); -+} -+ -+static inline -+int nx_v4_ifa_visible(struct nx_info *nxi, struct in_ifaddr *ifa) -+{ -+ vxdprintk(VXD_CBIT(net, 1), "nx_v4_ifa_visible(%p[#%u],%p) %d", -+ nxi, nxi ? nxi->nx_id : 0, ifa, -+ nxi ? v4_ifa_in_nx_info(ifa, nxi) : 0); -+ -+ if (!nx_info_flags(nxi, NXF_HIDE_NETIF, 0)) -+ return 1; -+ if (v4_ifa_in_nx_info(ifa, nxi)) -+ return 1; -+ return 0; -+} -+ -+ -+struct nx_v4_sock_addr { -+ __be32 saddr; /* Address used for validation */ -+ __be32 baddr; /* Address used for socket bind */ -+}; -+ -+static inline -+int v4_map_sock_addr(struct inet_sock *inet, struct sockaddr_in *addr, -+ struct nx_v4_sock_addr *nsa) -+{ -+ struct sock *sk = &inet->sk; -+ struct nx_info *nxi = sk->sk_nx_info; -+ __be32 saddr = addr->sin_addr.s_addr; -+ __be32 baddr = saddr; -+ -+ vxdprintk(VXD_CBIT(net, 3), -+ "inet_bind(%p)* %p,%p;%lx " NIPQUAD_FMT, -+ sk, sk->sk_nx_info, sk->sk_socket, -+ (sk->sk_socket ? sk->sk_socket->flags : 0), -+ NIPQUAD(saddr)); -+ -+ if (nxi) { -+ if (saddr == INADDR_ANY) { -+ if (nx_info_flags(nxi, NXF_SINGLE_IP, 0)) -+ baddr = nxi->v4.ip[0].s_addr; -+ } else if (saddr == IPI_LOOPBACK) { -+ if (nx_info_flags(nxi, NXF_LBACK_REMAP, 0)) -+ baddr = nxi->v4_lback.s_addr; -+ } else { /* normal address bind */ -+ if (!v4_addr_in_nx_info(nxi, saddr, NXA_MASK_BIND)) -+ return -EADDRNOTAVAIL; -+ } -+ } -+ -+ vxdprintk(VXD_CBIT(net, 3), -+ "inet_bind(%p) " NIPQUAD_FMT ", " NIPQUAD_FMT, -+ sk, NIPQUAD(saddr), NIPQUAD(baddr)); -+ -+ nsa->saddr = saddr; -+ nsa->baddr = baddr; -+ return 0; -+} -+ -+static inline -+void v4_set_sock_addr(struct inet_sock *inet, struct nx_v4_sock_addr *nsa) -+{ -+ inet->saddr = nsa->baddr; -+ inet->rcv_saddr = nsa->baddr; -+} -+ -+ -+/* -+ * helper to simplify inet_lookup_listener -+ * -+ * nxi: the socket's nx_info if any -+ * addr: to be verified address -+ * saddr: socket address -+ */ -+static inline int v4_inet_addr_match ( -+ struct nx_info *nxi, -+ __be32 addr, -+ __be32 saddr) -+{ -+ if (addr && (saddr == addr)) -+ return 1; -+ if (!saddr) -+ return nxi ? v4_addr_in_nx_info(nxi, addr, NXA_MASK_BIND) : 1; -+ return 0; -+} -+ -+static inline __be32 nx_map_sock_lback(struct nx_info *nxi, __be32 addr) -+{ -+ if (nx_info_flags(nxi, NXF_HIDE_LBACK, 0) && -+ (addr == nxi->v4_lback.s_addr)) -+ return IPI_LOOPBACK; -+ return addr; -+} -+ -+static inline -+int nx_info_has_v4(struct nx_info *nxi) -+{ -+ if (!nxi) -+ return 1; -+ if (NX_IPV4(nxi)) -+ return 1; -+ if (nx_info_flags(nxi, NXF_LBACK_REMAP, 0)) -+ return 1; -+ return 0; -+} -+ -+#else /* CONFIG_INET */ -+ -+static inline -+int nx_dev_visible(struct nx_info *n, struct net_device *d) -+{ -+ return 1; -+} -+ -+static inline -+int nx_v4_addr_conflict(struct nx_info *n, uint32_t a, const struct sock *s) -+{ -+ return 1; -+} -+ -+static inline -+int v4_ifa_in_nx_info(struct in_ifaddr *a, struct nx_info *n) -+{ -+ return 1; -+} -+ -+static inline -+int nx_info_has_v4(struct nx_info *nxi) -+{ -+ return 0; -+} -+ -+#endif /* CONFIG_INET */ -+ -+#define current_nx_info_has_v4() \ -+ nx_info_has_v4(current_nx_info()) -+ -+#else -+// #warning duplicate inclusion -+#endif -diff -NurpP --minimal linux-2.6.32.1/include/linux/vs_limit.h linux-2.6.32.1-vs2.3.0.36.27/include/linux/vs_limit.h ---- linux-2.6.32.1/include/linux/vs_limit.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/include/linux/vs_limit.h 2009-12-03 20:04:56.000000000 +0100 -@@ -0,0 +1,140 @@ -+#ifndef _VS_LIMIT_H -+#define _VS_LIMIT_H -+ -+#include "vserver/limit.h" -+#include "vserver/base.h" -+#include "vserver/context.h" -+#include "vserver/debug.h" -+#include "vserver/context.h" -+#include "vserver/limit_int.h" -+ -+ -+#define vx_acc_cres(v, d, p, r) \ -+ __vx_acc_cres(v, r, d, p, __FILE__, __LINE__) -+ -+#define vx_acc_cres_cond(x, d, p, r) \ -+ __vx_acc_cres(((x) == vx_current_xid()) ? current_vx_info() : 0, \ -+ r, d, p, __FILE__, __LINE__) -+ -+ -+#define vx_add_cres(v, a, p, r) \ -+ __vx_add_cres(v, r, a, p, __FILE__, __LINE__) -+#define vx_sub_cres(v, a, p, r) vx_add_cres(v, -(a), p, r) -+ -+#define vx_add_cres_cond(x, a, p, r) \ -+ __vx_add_cres(((x) == vx_current_xid()) ? current_vx_info() : 0, \ -+ r, a, p, __FILE__, __LINE__) -+#define vx_sub_cres_cond(x, a, p, r) vx_add_cres_cond(x, -(a), p, r) -+ -+ -+/* process and file limits */ -+ -+#define vx_nproc_inc(p) \ -+ vx_acc_cres((p)->vx_info, 1, p, RLIMIT_NPROC) -+ -+#define vx_nproc_dec(p) \ -+ vx_acc_cres((p)->vx_info,-1, p, RLIMIT_NPROC) -+ -+#define vx_files_inc(f) \ -+ vx_acc_cres_cond((f)->f_xid, 1, f, RLIMIT_NOFILE) -+ -+#define vx_files_dec(f) \ -+ vx_acc_cres_cond((f)->f_xid,-1, f, RLIMIT_NOFILE) -+ -+#define vx_locks_inc(l) \ -+ vx_acc_cres_cond((l)->fl_xid, 1, l, RLIMIT_LOCKS) -+ -+#define vx_locks_dec(l) \ -+ vx_acc_cres_cond((l)->fl_xid,-1, l, RLIMIT_LOCKS) -+ -+#define vx_openfd_inc(f) \ -+ vx_acc_cres(current_vx_info(), 1, (void *)(long)(f), VLIMIT_OPENFD) -+ -+#define vx_openfd_dec(f) \ -+ vx_acc_cres(current_vx_info(),-1, (void *)(long)(f), VLIMIT_OPENFD) -+ -+ -+#define vx_cres_avail(v, n, r) \ -+ __vx_cres_avail(v, r, n, __FILE__, __LINE__) -+ -+ -+#define vx_nproc_avail(n) \ -+ vx_cres_avail(current_vx_info(), n, RLIMIT_NPROC) -+ -+#define vx_files_avail(n) \ -+ vx_cres_avail(current_vx_info(), n, RLIMIT_NOFILE) -+ -+#define vx_locks_avail(n) \ -+ vx_cres_avail(current_vx_info(), n, RLIMIT_LOCKS) -+ -+#define vx_openfd_avail(n) \ -+ vx_cres_avail(current_vx_info(), n, VLIMIT_OPENFD) -+ -+ -+/* dentry limits */ -+ -+#define vx_dentry_inc(d) do { \ -+ if (atomic_read(&d->d_count) == 1) \ -+ vx_acc_cres(current_vx_info(), 1, d, VLIMIT_DENTRY); \ -+ } while (0) -+ -+#define vx_dentry_dec(d) do { \ -+ if (atomic_read(&d->d_count) == 0) \ -+ vx_acc_cres(current_vx_info(),-1, d, VLIMIT_DENTRY); \ -+ } while (0) -+ -+#define vx_dentry_avail(n) \ -+ vx_cres_avail(current_vx_info(), n, VLIMIT_DENTRY) -+ -+ -+/* socket limits */ -+ -+#define vx_sock_inc(s) \ -+ vx_acc_cres((s)->sk_vx_info, 1, s, VLIMIT_NSOCK) -+ -+#define vx_sock_dec(s) \ -+ vx_acc_cres((s)->sk_vx_info,-1, s, VLIMIT_NSOCK) -+ -+#define vx_sock_avail(n) \ -+ vx_cres_avail(current_vx_info(), n, VLIMIT_NSOCK) -+ -+ -+/* ipc resource limits */ -+ -+#define vx_ipcmsg_add(v, u, a) \ -+ vx_add_cres(v, a, u, RLIMIT_MSGQUEUE) -+ -+#define vx_ipcmsg_sub(v, u, a) \ -+ vx_sub_cres(v, a, u, RLIMIT_MSGQUEUE) -+ -+#define vx_ipcmsg_avail(v, a) \ -+ vx_cres_avail(v, a, RLIMIT_MSGQUEUE) -+ -+ -+#define vx_ipcshm_add(v, k, a) \ -+ vx_add_cres(v, a, (void *)(long)(k), VLIMIT_SHMEM) -+ -+#define vx_ipcshm_sub(v, k, a) \ -+ vx_sub_cres(v, a, (void *)(long)(k), VLIMIT_SHMEM) -+ -+#define vx_ipcshm_avail(v, a) \ -+ vx_cres_avail(v, a, VLIMIT_SHMEM) -+ -+ -+#define vx_semary_inc(a) \ -+ vx_acc_cres(current_vx_info(), 1, a, VLIMIT_SEMARY) -+ -+#define vx_semary_dec(a) \ -+ vx_acc_cres(current_vx_info(), -1, a, VLIMIT_SEMARY) -+ -+ -+#define vx_nsems_add(a,n) \ -+ vx_add_cres(current_vx_info(), n, a, VLIMIT_NSEMS) -+ -+#define vx_nsems_sub(a,n) \ -+ vx_sub_cres(current_vx_info(), n, a, VLIMIT_NSEMS) -+ -+ -+#else -+#warning duplicate inclusion -+#endif -diff -NurpP --minimal linux-2.6.32.1/include/linux/vs_memory.h linux-2.6.32.1-vs2.3.0.36.27/include/linux/vs_memory.h ---- linux-2.6.32.1/include/linux/vs_memory.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/include/linux/vs_memory.h 2009-12-03 20:04:56.000000000 +0100 -@@ -0,0 +1,159 @@ -+#ifndef _VS_MEMORY_H -+#define _VS_MEMORY_H -+ -+#include "vserver/limit.h" -+#include "vserver/base.h" -+#include "vserver/context.h" -+#include "vserver/debug.h" -+#include "vserver/context.h" -+#include "vserver/limit_int.h" -+ -+ -+#define __acc_add_long(a, v) (*(v) += (a)) -+#define __acc_inc_long(v) (++*(v)) -+#define __acc_dec_long(v) (--*(v)) -+ -+#if NR_CPUS >= CONFIG_SPLIT_PTLOCK_CPUS -+#define __acc_add_atomic(a, v) atomic_long_add(a, v) -+#define __acc_inc_atomic(v) atomic_long_inc(v) -+#define __acc_dec_atomic(v) atomic_long_dec(v) -+#else /* NR_CPUS < CONFIG_SPLIT_PTLOCK_CPUS */ -+#define __acc_add_atomic(a, v) __acc_add_long(a, v) -+#define __acc_inc_atomic(v) __acc_inc_long(v) -+#define __acc_dec_atomic(v) __acc_dec_long(v) -+#endif /* NR_CPUS < CONFIG_SPLIT_PTLOCK_CPUS */ -+ -+ -+#define vx_acc_page(m, d, v, r) do { \ -+ if ((d) > 0) \ -+ __acc_inc_long(&(m)->v); \ -+ else \ -+ __acc_dec_long(&(m)->v); \ -+ __vx_acc_cres(m->mm_vx_info, r, d, m, __FILE__, __LINE__); \ -+} while (0) -+ -+#define vx_acc_page_atomic(m, d, v, r) do { \ -+ if ((d) > 0) \ -+ __acc_inc_atomic(&(m)->v); \ -+ else \ -+ __acc_dec_atomic(&(m)->v); \ -+ __vx_acc_cres(m->mm_vx_info, r, d, m, __FILE__, __LINE__); \ -+} while (0) -+ -+ -+#define vx_acc_pages(m, p, v, r) do { \ -+ unsigned long __p = (p); \ -+ __acc_add_long(__p, &(m)->v); \ -+ __vx_add_cres(m->mm_vx_info, r, __p, m, __FILE__, __LINE__); \ -+} while (0) -+ -+#define vx_acc_pages_atomic(m, p, v, r) do { \ -+ unsigned long __p = (p); \ -+ __acc_add_atomic(__p, &(m)->v); \ -+ __vx_add_cres(m->mm_vx_info, r, __p, m, __FILE__, __LINE__); \ -+} while (0) -+ -+ -+ -+#define vx_acc_vmpage(m, d) \ -+ vx_acc_page(m, d, total_vm, RLIMIT_AS) -+#define vx_acc_vmlpage(m, d) \ -+ vx_acc_page(m, d, locked_vm, RLIMIT_MEMLOCK) -+#define vx_acc_file_rsspage(m, d) \ -+ vx_acc_page_atomic(m, d, _file_rss, VLIMIT_MAPPED) -+#define vx_acc_anon_rsspage(m, d) \ -+ vx_acc_page_atomic(m, d, _anon_rss, VLIMIT_ANON) -+ -+#define vx_acc_vmpages(m, p) \ -+ vx_acc_pages(m, p, total_vm, RLIMIT_AS) -+#define vx_acc_vmlpages(m, p) \ -+ vx_acc_pages(m, p, locked_vm, RLIMIT_MEMLOCK) -+#define vx_acc_file_rsspages(m, p) \ -+ vx_acc_pages_atomic(m, p, _file_rss, VLIMIT_MAPPED) -+#define vx_acc_anon_rsspages(m, p) \ -+ vx_acc_pages_atomic(m, p, _anon_rss, VLIMIT_ANON) -+ -+#define vx_pages_add(s, r, p) __vx_add_cres(s, r, p, 0, __FILE__, __LINE__) -+#define vx_pages_sub(s, r, p) vx_pages_add(s, r, -(p)) -+ -+#define vx_vmpages_inc(m) vx_acc_vmpage(m, 1) -+#define vx_vmpages_dec(m) vx_acc_vmpage(m, -1) -+#define vx_vmpages_add(m, p) vx_acc_vmpages(m, p) -+#define vx_vmpages_sub(m, p) vx_acc_vmpages(m, -(p)) -+ -+#define vx_vmlocked_inc(m) vx_acc_vmlpage(m, 1) -+#define vx_vmlocked_dec(m) vx_acc_vmlpage(m, -1) -+#define vx_vmlocked_add(m, p) vx_acc_vmlpages(m, p) -+#define vx_vmlocked_sub(m, p) vx_acc_vmlpages(m, -(p)) -+ -+#define vx_file_rsspages_inc(m) vx_acc_file_rsspage(m, 1) -+#define vx_file_rsspages_dec(m) vx_acc_file_rsspage(m, -1) -+#define vx_file_rsspages_add(m, p) vx_acc_file_rsspages(m, p) -+#define vx_file_rsspages_sub(m, p) vx_acc_file_rsspages(m, -(p)) -+ -+#define vx_anon_rsspages_inc(m) vx_acc_anon_rsspage(m, 1) -+#define vx_anon_rsspages_dec(m) vx_acc_anon_rsspage(m, -1) -+#define vx_anon_rsspages_add(m, p) vx_acc_anon_rsspages(m, p) -+#define vx_anon_rsspages_sub(m, p) vx_acc_anon_rsspages(m, -(p)) -+ -+ -+#define vx_pages_avail(m, p, r) \ -+ __vx_cres_avail((m)->mm_vx_info, r, p, __FILE__, __LINE__) -+ -+#define vx_vmpages_avail(m, p) vx_pages_avail(m, p, RLIMIT_AS) -+#define vx_vmlocked_avail(m, p) vx_pages_avail(m, p, RLIMIT_MEMLOCK) -+#define vx_anon_avail(m, p) vx_pages_avail(m, p, VLIMIT_ANON) -+#define vx_mapped_avail(m, p) vx_pages_avail(m, p, VLIMIT_MAPPED) -+ -+#define vx_rss_avail(m, p) \ -+ __vx_cres_array_avail((m)->mm_vx_info, VLA_RSS, p, __FILE__, __LINE__) -+ -+ -+enum { -+ VXPT_UNKNOWN = 0, -+ VXPT_ANON, -+ VXPT_NONE, -+ VXPT_FILE, -+ VXPT_SWAP, -+ VXPT_WRITE -+}; -+ -+#if 0 -+#define vx_page_fault(mm, vma, type, ret) -+#else -+ -+static inline -+void __vx_page_fault(struct mm_struct *mm, -+ struct vm_area_struct *vma, int type, int ret) -+{ -+ struct vx_info *vxi = mm->mm_vx_info; -+ int what; -+/* -+ static char *page_type[6] = -+ { "UNKNOWN", "ANON", "NONE", "FILE", "SWAP", "WRITE" }; -+ static char *page_what[4] = -+ { "FAULT_OOM", "FAULT_SIGBUS", "FAULT_MINOR", "FAULT_MAJOR" }; -+*/ -+ -+ if (!vxi) -+ return; -+ -+ what = (ret & 0x3); -+ -+/* printk("[%d] page[%d][%d] %2x %s %s\n", vxi->vx_id, -+ type, what, ret, page_type[type], page_what[what]); -+*/ -+ if (ret & VM_FAULT_WRITE) -+ what |= 0x4; -+ atomic_inc(&vxi->cacct.page[type][what]); -+} -+ -+#define vx_page_fault(mm, vma, type, ret) __vx_page_fault(mm, vma, type, ret) -+#endif -+ -+ -+extern unsigned long vx_badness(struct task_struct *task, struct mm_struct *mm); -+ -+#else -+#warning duplicate inclusion -+#endif -diff -NurpP --minimal linux-2.6.32.1/include/linux/vs_network.h linux-2.6.32.1-vs2.3.0.36.27/include/linux/vs_network.h ---- linux-2.6.32.1/include/linux/vs_network.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/include/linux/vs_network.h 2009-12-03 20:04:56.000000000 +0100 -@@ -0,0 +1,169 @@ -+#ifndef _NX_VS_NETWORK_H -+#define _NX_VS_NETWORK_H -+ -+#include "vserver/context.h" -+#include "vserver/network.h" -+#include "vserver/base.h" -+#include "vserver/check.h" -+#include "vserver/debug.h" -+ -+#include -+ -+ -+#define get_nx_info(i) __get_nx_info(i, __FILE__, __LINE__) -+ -+static inline struct nx_info *__get_nx_info(struct nx_info *nxi, -+ const char *_file, int _line) -+{ -+ if (!nxi) -+ return NULL; -+ -+ vxlprintk(VXD_CBIT(nid, 2), "get_nx_info(%p[#%d.%d])", -+ nxi, nxi ? nxi->nx_id : 0, -+ nxi ? atomic_read(&nxi->nx_usecnt) : 0, -+ _file, _line); -+ -+ atomic_inc(&nxi->nx_usecnt); -+ return nxi; -+} -+ -+ -+extern void free_nx_info(struct nx_info *); -+ -+#define put_nx_info(i) __put_nx_info(i, __FILE__, __LINE__) -+ -+static inline void __put_nx_info(struct nx_info *nxi, const char *_file, int _line) -+{ -+ if (!nxi) -+ return; -+ -+ vxlprintk(VXD_CBIT(nid, 2), "put_nx_info(%p[#%d.%d])", -+ nxi, nxi ? nxi->nx_id : 0, -+ nxi ? atomic_read(&nxi->nx_usecnt) : 0, -+ _file, _line); -+ -+ if (atomic_dec_and_test(&nxi->nx_usecnt)) -+ free_nx_info(nxi); -+} -+ -+ -+#define init_nx_info(p, i) __init_nx_info(p, i, __FILE__, __LINE__) -+ -+static inline void __init_nx_info(struct nx_info **nxp, struct nx_info *nxi, -+ const char *_file, int _line) -+{ -+ if (nxi) { -+ vxlprintk(VXD_CBIT(nid, 3), -+ "init_nx_info(%p[#%d.%d])", -+ nxi, nxi ? nxi->nx_id : 0, -+ nxi ? atomic_read(&nxi->nx_usecnt) : 0, -+ _file, _line); -+ -+ atomic_inc(&nxi->nx_usecnt); -+ } -+ *nxp = nxi; -+} -+ -+ -+#define set_nx_info(p, i) __set_nx_info(p, i, __FILE__, __LINE__) -+ -+static inline void __set_nx_info(struct nx_info **nxp, struct nx_info *nxi, -+ const char *_file, int _line) -+{ -+ struct nx_info *nxo; -+ -+ if (!nxi) -+ return; -+ -+ vxlprintk(VXD_CBIT(nid, 3), "set_nx_info(%p[#%d.%d])", -+ nxi, nxi ? nxi->nx_id : 0, -+ nxi ? atomic_read(&nxi->nx_usecnt) : 0, -+ _file, _line); -+ -+ atomic_inc(&nxi->nx_usecnt); -+ nxo = xchg(nxp, nxi); -+ BUG_ON(nxo); -+} -+ -+#define clr_nx_info(p) __clr_nx_info(p, __FILE__, __LINE__) -+ -+static inline void __clr_nx_info(struct nx_info **nxp, -+ const char *_file, int _line) -+{ -+ struct nx_info *nxo; -+ -+ nxo = xchg(nxp, NULL); -+ if (!nxo) -+ return; -+ -+ vxlprintk(VXD_CBIT(nid, 3), "clr_nx_info(%p[#%d.%d])", -+ nxo, nxo ? nxo->nx_id : 0, -+ nxo ? atomic_read(&nxo->nx_usecnt) : 0, -+ _file, _line); -+ -+ if (atomic_dec_and_test(&nxo->nx_usecnt)) -+ free_nx_info(nxo); -+} -+ -+ -+#define claim_nx_info(v, p) __claim_nx_info(v, p, __FILE__, __LINE__) -+ -+static inline void __claim_nx_info(struct nx_info *nxi, -+ struct task_struct *task, const char *_file, int _line) -+{ -+ vxlprintk(VXD_CBIT(nid, 3), "claim_nx_info(%p[#%d.%d.%d]) %p", -+ nxi, nxi ? nxi->nx_id : 0, -+ nxi?atomic_read(&nxi->nx_usecnt):0, -+ nxi?atomic_read(&nxi->nx_tasks):0, -+ task, _file, _line); -+ -+ atomic_inc(&nxi->nx_tasks); -+} -+ -+ -+extern void unhash_nx_info(struct nx_info *); -+ -+#define release_nx_info(v, p) __release_nx_info(v, p, __FILE__, __LINE__) -+ -+static inline void __release_nx_info(struct nx_info *nxi, -+ struct task_struct *task, const char *_file, int _line) -+{ -+ vxlprintk(VXD_CBIT(nid, 3), "release_nx_info(%p[#%d.%d.%d]) %p", -+ nxi, nxi ? nxi->nx_id : 0, -+ nxi ? atomic_read(&nxi->nx_usecnt) : 0, -+ nxi ? atomic_read(&nxi->nx_tasks) : 0, -+ task, _file, _line); -+ -+ might_sleep(); -+ -+ if (atomic_dec_and_test(&nxi->nx_tasks)) -+ unhash_nx_info(nxi); -+} -+ -+ -+#define task_get_nx_info(i) __task_get_nx_info(i, __FILE__, __LINE__) -+ -+static __inline__ struct nx_info *__task_get_nx_info(struct task_struct *p, -+ const char *_file, int _line) -+{ -+ struct nx_info *nxi; -+ -+ task_lock(p); -+ vxlprintk(VXD_CBIT(nid, 5), "task_get_nx_info(%p)", -+ p, _file, _line); -+ nxi = __get_nx_info(p->nx_info, _file, _line); -+ task_unlock(p); -+ return nxi; -+} -+ -+ -+static inline void exit_nx_info(struct task_struct *p) -+{ -+ if (p->nx_info) -+ release_nx_info(p->nx_info, p); -+} -+ -+ -+#else -+#warning duplicate inclusion -+#endif -diff -NurpP --minimal linux-2.6.32.1/include/linux/vs_pid.h linux-2.6.32.1-vs2.3.0.36.27/include/linux/vs_pid.h ---- linux-2.6.32.1/include/linux/vs_pid.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/include/linux/vs_pid.h 2009-12-03 20:04:56.000000000 +0100 -@@ -0,0 +1,95 @@ -+#ifndef _VS_PID_H -+#define _VS_PID_H -+ -+#include "vserver/base.h" -+#include "vserver/check.h" -+#include "vserver/context.h" -+#include "vserver/debug.h" -+#include "vserver/pid.h" -+#include -+ -+ -+#define VXF_FAKE_INIT (VXF_INFO_INIT | VXF_STATE_INIT) -+ -+static inline -+int vx_proc_task_visible(struct task_struct *task) -+{ -+ if ((task->pid == 1) && -+ !vx_flags(VXF_FAKE_INIT, VXF_FAKE_INIT)) -+ /* show a blend through init */ -+ goto visible; -+ if (vx_check(vx_task_xid(task), VS_WATCH | VS_IDENT)) -+ goto visible; -+ return 0; -+visible: -+ return 1; -+} -+ -+#define find_task_by_real_pid(pid) find_task_by_pid_ns(pid, &init_pid_ns) -+ -+#if 0 -+ -+static inline -+struct task_struct *vx_find_proc_task_by_pid(int pid) -+{ -+ struct task_struct *task = find_task_by_real_pid(pid); -+ -+ if (task && !vx_proc_task_visible(task)) { -+ vxdprintk(VXD_CBIT(misc, 6), -+ "dropping task (find) %p[#%u,%u] for %p[#%u,%u]", -+ task, task->xid, task->pid, -+ current, current->xid, current->pid); -+ task = NULL; -+ } -+ return task; -+} -+ -+#endif -+ -+static inline -+struct task_struct *vx_get_proc_task(struct inode *inode, struct pid *pid) -+{ -+ struct task_struct *task = get_pid_task(pid, PIDTYPE_PID); -+ -+ if (task && !vx_proc_task_visible(task)) { -+ vxdprintk(VXD_CBIT(misc, 6), -+ "dropping task (get) %p[#%u,%u] for %p[#%u,%u]", -+ task, task->xid, task->pid, -+ current, current->xid, current->pid); -+ put_task_struct(task); -+ task = NULL; -+ } -+ return task; -+} -+ -+#if 0 -+ -+static inline -+struct task_struct *vx_child_reaper(struct task_struct *p) -+{ -+ struct vx_info *vxi = p->vx_info; -+ struct task_struct *reaper = child_reaper(p); -+ -+ if (!vxi) -+ goto out; -+ -+ BUG_ON(!p->vx_info->vx_reaper); -+ -+ /* child reaper for the guest reaper */ -+ if (vxi->vx_reaper == p) -+ goto out; -+ -+ reaper = vxi->vx_reaper; -+out: -+ vxdprintk(VXD_CBIT(xid, 7), -+ "vx_child_reaper(%p[#%u,%u]) = %p[#%u,%u]", -+ p, p->xid, p->pid, reaper, reaper->xid, reaper->pid); -+ return reaper; -+} -+ -+#endif -+ -+ -+#else -+#warning duplicate inclusion -+#endif -diff -NurpP --minimal linux-2.6.32.1/include/linux/vs_sched.h linux-2.6.32.1-vs2.3.0.36.27/include/linux/vs_sched.h ---- linux-2.6.32.1/include/linux/vs_sched.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/include/linux/vs_sched.h 2009-12-03 20:04:56.000000000 +0100 -@@ -0,0 +1,110 @@ -+#ifndef _VS_SCHED_H -+#define _VS_SCHED_H -+ -+#include "vserver/base.h" -+#include "vserver/context.h" -+#include "vserver/sched.h" -+ -+ -+#define VAVAVOOM_RATIO 50 -+ -+#define MAX_PRIO_BIAS 20 -+#define MIN_PRIO_BIAS -20 -+ -+ -+#ifdef CONFIG_VSERVER_HARDCPU -+ -+/* -+ * effective_prio - return the priority that is based on the static -+ * priority but is modified by bonuses/penalties. -+ * -+ * We scale the actual sleep average [0 .... MAX_SLEEP_AVG] -+ * into a -4 ... 0 ... +4 bonus/penalty range. -+ * -+ * Additionally, we scale another amount based on the number of -+ * CPU tokens currently held by the context, if the process is -+ * part of a context (and the appropriate SCHED flag is set). -+ * This ranges from -5 ... 0 ... +15, quadratically. -+ * -+ * So, the total bonus is -9 .. 0 .. +19 -+ * We use ~50% of the full 0...39 priority range so that: -+ * -+ * 1) nice +19 interactive tasks do not preempt nice 0 CPU hogs. -+ * 2) nice -20 CPU hogs do not get preempted by nice 0 tasks. -+ * unless that context is far exceeding its CPU allocation. -+ * -+ * Both properties are important to certain workloads. -+ */ -+static inline -+int vx_effective_vavavoom(struct _vx_sched_pc *sched_pc, int max_prio) -+{ -+ int vavavoom, max; -+ -+ /* lots of tokens = lots of vavavoom -+ * no tokens = no vavavoom */ -+ if ((vavavoom = sched_pc->tokens) >= 0) { -+ max = sched_pc->tokens_max; -+ vavavoom = max - vavavoom; -+ max = max * max; -+ vavavoom = max_prio * VAVAVOOM_RATIO / 100 -+ * (vavavoom*vavavoom - (max >> 2)) / max; -+ return vavavoom; -+ } -+ return 0; -+} -+ -+ -+static inline -+int vx_adjust_prio(struct task_struct *p, int prio, int max_user) -+{ -+ struct vx_info *vxi = p->vx_info; -+ struct _vx_sched_pc *sched_pc; -+ -+ if (!vxi) -+ return prio; -+ -+ sched_pc = &vx_cpu(vxi, sched_pc); -+ if (vx_info_flags(vxi, VXF_SCHED_PRIO, 0)) { -+ int vavavoom = vx_effective_vavavoom(sched_pc, max_user); -+ -+ sched_pc->vavavoom = vavavoom; -+ prio += vavavoom; -+ } -+ prio += sched_pc->prio_bias; -+ return prio; -+} -+ -+#else /* !CONFIG_VSERVER_HARDCPU */ -+ -+static inline -+int vx_adjust_prio(struct task_struct *p, int prio, int max_user) -+{ -+ struct vx_info *vxi = p->vx_info; -+ -+ if (vxi) -+ prio += vx_cpu(vxi, sched_pc).prio_bias; -+ return prio; -+} -+ -+#endif /* CONFIG_VSERVER_HARDCPU */ -+ -+ -+static inline void vx_account_user(struct vx_info *vxi, -+ cputime_t cputime, int nice) -+{ -+ if (!vxi) -+ return; -+ vx_cpu(vxi, sched_pc).user_ticks += cputime; -+} -+ -+static inline void vx_account_system(struct vx_info *vxi, -+ cputime_t cputime, int idle) -+{ -+ if (!vxi) -+ return; -+ vx_cpu(vxi, sched_pc).sys_ticks += cputime; -+} -+ -+#else -+#warning duplicate inclusion -+#endif -diff -NurpP --minimal linux-2.6.32.1/include/linux/vs_socket.h linux-2.6.32.1-vs2.3.0.36.27/include/linux/vs_socket.h ---- linux-2.6.32.1/include/linux/vs_socket.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/include/linux/vs_socket.h 2009-12-03 20:04:56.000000000 +0100 -@@ -0,0 +1,67 @@ -+#ifndef _VS_SOCKET_H -+#define _VS_SOCKET_H -+ -+#include "vserver/debug.h" -+#include "vserver/base.h" -+#include "vserver/cacct.h" -+#include "vserver/context.h" -+#include "vserver/tag.h" -+ -+ -+/* socket accounting */ -+ -+#include -+ -+static inline int vx_sock_type(int family) -+{ -+ switch (family) { -+ case PF_UNSPEC: -+ return VXA_SOCK_UNSPEC; -+ case PF_UNIX: -+ return VXA_SOCK_UNIX; -+ case PF_INET: -+ return VXA_SOCK_INET; -+ case PF_INET6: -+ return VXA_SOCK_INET6; -+ case PF_PACKET: -+ return VXA_SOCK_PACKET; -+ default: -+ return VXA_SOCK_OTHER; -+ } -+} -+ -+#define vx_acc_sock(v, f, p, s) \ -+ __vx_acc_sock(v, f, p, s, __FILE__, __LINE__) -+ -+static inline void __vx_acc_sock(struct vx_info *vxi, -+ int family, int pos, int size, char *file, int line) -+{ -+ if (vxi) { -+ int type = vx_sock_type(family); -+ -+ atomic_long_inc(&vxi->cacct.sock[type][pos].count); -+ atomic_long_add(size, &vxi->cacct.sock[type][pos].total); -+ } -+} -+ -+#define vx_sock_recv(sk, s) \ -+ vx_acc_sock((sk)->sk_vx_info, (sk)->sk_family, 0, s) -+#define vx_sock_send(sk, s) \ -+ vx_acc_sock((sk)->sk_vx_info, (sk)->sk_family, 1, s) -+#define vx_sock_fail(sk, s) \ -+ vx_acc_sock((sk)->sk_vx_info, (sk)->sk_family, 2, s) -+ -+ -+#define sock_vx_init(s) do { \ -+ (s)->sk_xid = 0; \ -+ (s)->sk_vx_info = NULL; \ -+ } while (0) -+ -+#define sock_nx_init(s) do { \ -+ (s)->sk_nid = 0; \ -+ (s)->sk_nx_info = NULL; \ -+ } while (0) -+ -+#else -+#warning duplicate inclusion -+#endif -diff -NurpP --minimal linux-2.6.32.1/include/linux/vs_tag.h linux-2.6.32.1-vs2.3.0.36.27/include/linux/vs_tag.h ---- linux-2.6.32.1/include/linux/vs_tag.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/include/linux/vs_tag.h 2009-12-03 20:04:56.000000000 +0100 -@@ -0,0 +1,47 @@ -+#ifndef _VS_TAG_H -+#define _VS_TAG_H -+ -+#include -+ -+/* check conditions */ -+ -+#define DX_ADMIN 0x0001 -+#define DX_WATCH 0x0002 -+#define DX_HOSTID 0x0008 -+ -+#define DX_IDENT 0x0010 -+ -+#define DX_ARG_MASK 0x0010 -+ -+ -+#define dx_task_tag(t) ((t)->tag) -+ -+#define dx_current_tag() dx_task_tag(current) -+ -+#define dx_check(c, m) __dx_check(dx_current_tag(), c, m) -+ -+#define dx_weak_check(c, m) ((m) ? dx_check(c, m) : 1) -+ -+ -+/* -+ * check current context for ADMIN/WATCH and -+ * optionally against supplied argument -+ */ -+static inline int __dx_check(tag_t cid, tag_t id, unsigned int mode) -+{ -+ if (mode & DX_ARG_MASK) { -+ if ((mode & DX_IDENT) && (id == cid)) -+ return 1; -+ } -+ return (((mode & DX_ADMIN) && (cid == 0)) || -+ ((mode & DX_WATCH) && (cid == 1)) || -+ ((mode & DX_HOSTID) && (id == 0))); -+} -+ -+struct inode; -+int dx_permission(const struct inode *inode, int mask); -+ -+ -+#else -+#warning duplicate inclusion -+#endif -diff -NurpP --minimal linux-2.6.32.1/include/linux/vs_time.h linux-2.6.32.1-vs2.3.0.36.27/include/linux/vs_time.h ---- linux-2.6.32.1/include/linux/vs_time.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/include/linux/vs_time.h 2009-12-03 20:04:56.000000000 +0100 -@@ -0,0 +1,19 @@ -+#ifndef _VS_TIME_H -+#define _VS_TIME_H -+ -+ -+/* time faking stuff */ -+ -+#ifdef CONFIG_VSERVER_VTIME -+ -+extern void vx_gettimeofday(struct timeval *tv); -+extern int vx_settimeofday(struct timespec *ts); -+ -+#else -+#define vx_gettimeofday(t) do_gettimeofday(t) -+#define vx_settimeofday(t) do_settimeofday(t) -+#endif -+ -+#else -+#warning duplicate inclusion -+#endif -diff -NurpP --minimal linux-2.6.32.1/include/net/addrconf.h linux-2.6.32.1-vs2.3.0.36.27/include/net/addrconf.h ---- linux-2.6.32.1/include/net/addrconf.h 2009-12-03 20:02:57.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/include/net/addrconf.h 2009-12-03 20:04:56.000000000 +0100 -@@ -84,7 +84,8 @@ extern int ipv6_dev_get_saddr(struct n - struct net_device *dev, - const struct in6_addr *daddr, - unsigned int srcprefs, -- struct in6_addr *saddr); -+ struct in6_addr *saddr, -+ struct nx_info *nxi); - extern int ipv6_get_lladdr(struct net_device *dev, - struct in6_addr *addr, - unsigned char banned_flags); -diff -NurpP --minimal linux-2.6.32.1/include/net/af_unix.h linux-2.6.32.1-vs2.3.0.36.27/include/net/af_unix.h ---- linux-2.6.32.1/include/net/af_unix.h 2008-12-25 00:26:37.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/include/net/af_unix.h 2009-12-03 20:04:56.000000000 +0100 -@@ -4,6 +4,7 @@ - #include - #include - #include -+#include - #include - - extern void unix_inflight(struct file *fp); -diff -NurpP --minimal linux-2.6.32.1/include/net/inet_timewait_sock.h linux-2.6.32.1-vs2.3.0.36.27/include/net/inet_timewait_sock.h ---- linux-2.6.32.1/include/net/inet_timewait_sock.h 2009-12-03 20:02:57.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/include/net/inet_timewait_sock.h 2009-12-03 20:04:56.000000000 +0100 -@@ -117,6 +117,10 @@ struct inet_timewait_sock { - #define tw_hash __tw_common.skc_hash - #define tw_prot __tw_common.skc_prot - #define tw_net __tw_common.skc_net -+#define tw_xid __tw_common.skc_xid -+#define tw_vx_info __tw_common.skc_vx_info -+#define tw_nid __tw_common.skc_nid -+#define tw_nx_info __tw_common.skc_nx_info - int tw_timeout; - volatile unsigned char tw_substate; - /* 3 bits hole, try to pack */ -diff -NurpP --minimal linux-2.6.32.1/include/net/route.h linux-2.6.32.1-vs2.3.0.36.27/include/net/route.h ---- linux-2.6.32.1/include/net/route.h 2009-09-10 15:26:27.000000000 +0200 -+++ linux-2.6.32.1-vs2.3.0.36.27/include/net/route.h 2009-12-03 20:04:56.000000000 +0100 -@@ -135,6 +135,9 @@ static inline void ip_rt_put(struct rtab - dst_release(&rt->u.dst); - } - -+#include -+#include -+ - #define IPTOS_RT_MASK (IPTOS_TOS_MASK & ~3) - - extern const __u8 ip_tos2prio[16]; -@@ -144,6 +147,9 @@ static inline char rt_tos2priority(u8 to - return ip_tos2prio[IPTOS_TOS(tos)>>1]; - } - -+extern int ip_v4_find_src(struct net *net, struct nx_info *, -+ struct rtable **, struct flowi *); -+ - static inline int ip_route_connect(struct rtable **rp, __be32 dst, - __be32 src, u32 tos, int oif, u8 protocol, - __be16 sport, __be16 dport, struct sock *sk, -@@ -161,11 +167,24 @@ static inline int ip_route_connect(struc - - int err; - struct net *net = sock_net(sk); -+ struct nx_info *nx_info = current_nx_info(); - - if (inet_sk(sk)->transparent) - fl.flags |= FLOWI_FLAG_ANYSRC; - -- if (!dst || !src) { -+ if (sk) -+ nx_info = sk->sk_nx_info; -+ -+ vxdprintk(VXD_CBIT(net, 4), -+ "ip_route_connect(%p) %p,%p;%lx", -+ sk, nx_info, sk->sk_socket, -+ (sk->sk_socket?sk->sk_socket->flags:0)); -+ -+ err = ip_v4_find_src(net, nx_info, rp, &fl); -+ if (err) -+ return err; -+ -+ if (!fl.fl4_dst || !fl.fl4_src) { - err = __ip_route_output_key(net, rp, &fl); - if (err) - return err; -diff -NurpP --minimal linux-2.6.32.1/include/net/sock.h linux-2.6.32.1-vs2.3.0.36.27/include/net/sock.h ---- linux-2.6.32.1/include/net/sock.h 2009-12-03 20:02:57.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/include/net/sock.h 2009-12-03 20:04:56.000000000 +0100 -@@ -139,6 +139,10 @@ struct sock_common { - #ifdef CONFIG_NET_NS - struct net *skc_net; - #endif -+ xid_t skc_xid; -+ struct vx_info *skc_vx_info; -+ nid_t skc_nid; -+ struct nx_info *skc_nx_info; - }; - - /** -@@ -225,6 +229,10 @@ struct sock { - #define sk_bind_node __sk_common.skc_bind_node - #define sk_prot __sk_common.skc_prot - #define sk_net __sk_common.skc_net -+#define sk_xid __sk_common.skc_xid -+#define sk_vx_info __sk_common.skc_vx_info -+#define sk_nid __sk_common.skc_nid -+#define sk_nx_info __sk_common.skc_nx_info - kmemcheck_bitfield_begin(flags); - unsigned int sk_shutdown : 2, - sk_no_check : 2, -diff -NurpP --minimal linux-2.6.32.1/init/Kconfig linux-2.6.32.1-vs2.3.0.36.27/init/Kconfig ---- linux-2.6.32.1/init/Kconfig 2009-12-03 20:02:57.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/init/Kconfig 2009-12-03 20:04:56.000000000 +0100 -@@ -477,6 +477,19 @@ config CGROUP_SCHED - - endchoice - -+config CFS_HARD_LIMITS -+ bool "Hard Limits for CFS Group Scheduler" -+ depends on EXPERIMENTAL -+ depends on FAIR_GROUP_SCHED && CGROUP_SCHED -+ default n -+ help -+ This option enables hard limiting of CPU time obtained by -+ a fair task group. Use this if you want to throttle a group of tasks -+ based on its CPU usage. For more details refer to -+ Documentation/scheduler/sched-cfs-hard-limits.txt -+ -+ Say N if unsure. -+ - menuconfig CGROUPS - boolean "Control Group support" - help -diff -NurpP --minimal linux-2.6.32.1/init/main.c linux-2.6.32.1-vs2.3.0.36.27/init/main.c ---- linux-2.6.32.1/init/main.c 2009-12-03 20:02:57.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/init/main.c 2009-12-03 20:04:56.000000000 +0100 -@@ -70,6 +70,7 @@ - #include - #include - #include -+#include - - #include - #include -diff -NurpP --minimal linux-2.6.32.1/ipc/mqueue.c linux-2.6.32.1-vs2.3.0.36.27/ipc/mqueue.c ---- linux-2.6.32.1/ipc/mqueue.c 2009-12-03 20:02:57.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/ipc/mqueue.c 2009-12-03 20:04:56.000000000 +0100 -@@ -33,6 +33,8 @@ - #include - #include - #include -+#include -+#include - - #include - #include "util.h" -@@ -66,6 +68,7 @@ struct mqueue_inode_info { - struct sigevent notify; - struct pid* notify_owner; - struct user_struct *user; /* user who created, for accounting */ -+ struct vx_info *vxi; - struct sock *notify_sock; - struct sk_buff *notify_cookie; - -@@ -125,6 +128,7 @@ static struct inode *mqueue_get_inode(st - if (S_ISREG(mode)) { - struct mqueue_inode_info *info; - struct task_struct *p = current; -+ struct vx_info *vxi = p->vx_info; - unsigned long mq_bytes, mq_msg_tblsz; - - inode->i_fop = &mqueue_file_operations; -@@ -139,6 +143,7 @@ static struct inode *mqueue_get_inode(st - info->notify_owner = NULL; - info->qsize = 0; - info->user = NULL; /* set when all is ok */ -+ info->vxi = NULL; - memset(&info->attr, 0, sizeof(info->attr)); - info->attr.mq_maxmsg = ipc_ns->mq_msg_max; - info->attr.mq_msgsize = ipc_ns->mq_msgsize_max; -@@ -153,22 +158,26 @@ static struct inode *mqueue_get_inode(st - spin_lock(&mq_lock); - if (u->mq_bytes + mq_bytes < u->mq_bytes || - u->mq_bytes + mq_bytes > -- p->signal->rlim[RLIMIT_MSGQUEUE].rlim_cur) { -+ p->signal->rlim[RLIMIT_MSGQUEUE].rlim_cur || -+ !vx_ipcmsg_avail(vxi, mq_bytes)) { - spin_unlock(&mq_lock); - goto out_inode; - } - u->mq_bytes += mq_bytes; -+ vx_ipcmsg_add(vxi, u, mq_bytes); - spin_unlock(&mq_lock); - - info->messages = kmalloc(mq_msg_tblsz, GFP_KERNEL); - if (!info->messages) { - spin_lock(&mq_lock); - u->mq_bytes -= mq_bytes; -+ vx_ipcmsg_sub(vxi, u, mq_bytes); - spin_unlock(&mq_lock); - goto out_inode; - } - /* all is ok */ - info->user = get_uid(u); -+ info->vxi = get_vx_info(vxi); - } else if (S_ISDIR(mode)) { - inc_nlink(inode); - /* Some things misbehave if size == 0 on a directory */ -@@ -269,8 +278,11 @@ static void mqueue_delete_inode(struct i - (info->attr.mq_maxmsg * info->attr.mq_msgsize)); - user = info->user; - if (user) { -+ struct vx_info *vxi = info->vxi; -+ - spin_lock(&mq_lock); - user->mq_bytes -= mq_bytes; -+ vx_ipcmsg_sub(vxi, user, mq_bytes); - /* - * get_ns_from_inode() ensures that the - * (ipc_ns = sb->s_fs_info) is either a valid ipc_ns -@@ -280,6 +292,7 @@ static void mqueue_delete_inode(struct i - if (ipc_ns) - ipc_ns->mq_queues_count--; - spin_unlock(&mq_lock); -+ put_vx_info(vxi); - free_uid(user); - } - if (ipc_ns) -diff -NurpP --minimal linux-2.6.32.1/ipc/msg.c linux-2.6.32.1-vs2.3.0.36.27/ipc/msg.c ---- linux-2.6.32.1/ipc/msg.c 2009-03-24 14:22:44.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/ipc/msg.c 2009-12-03 20:04:56.000000000 +0100 -@@ -38,6 +38,7 @@ - #include - #include - #include -+#include - - #include - #include -@@ -190,6 +191,7 @@ static int newque(struct ipc_namespace * - - msq->q_perm.mode = msgflg & S_IRWXUGO; - msq->q_perm.key = key; -+ msq->q_perm.xid = vx_current_xid(); - - msq->q_perm.security = NULL; - retval = security_msg_queue_alloc(msq); -diff -NurpP --minimal linux-2.6.32.1/ipc/namespace.c linux-2.6.32.1-vs2.3.0.36.27/ipc/namespace.c ---- linux-2.6.32.1/ipc/namespace.c 2009-09-10 15:26:27.000000000 +0200 -+++ linux-2.6.32.1-vs2.3.0.36.27/ipc/namespace.c 2009-12-03 20:04:56.000000000 +0100 -@@ -11,6 +11,8 @@ - #include - #include - #include -+#include -+#include - - #include "util.h" - -diff -NurpP --minimal linux-2.6.32.1/ipc/sem.c linux-2.6.32.1-vs2.3.0.36.27/ipc/sem.c ---- linux-2.6.32.1/ipc/sem.c 2009-09-10 15:26:27.000000000 +0200 -+++ linux-2.6.32.1-vs2.3.0.36.27/ipc/sem.c 2009-12-03 20:04:56.000000000 +0100 -@@ -83,6 +83,8 @@ - #include - #include - #include -+#include -+#include - - #include - #include "util.h" -@@ -255,6 +257,7 @@ static int newary(struct ipc_namespace * - - sma->sem_perm.mode = (semflg & S_IRWXUGO); - sma->sem_perm.key = key; -+ sma->sem_perm.xid = vx_current_xid(); - - sma->sem_perm.security = NULL; - retval = security_sem_alloc(sma); -@@ -270,6 +273,9 @@ static int newary(struct ipc_namespace * - return id; - } - ns->used_sems += nsems; -+ /* FIXME: obsoleted? */ -+ vx_semary_inc(sma); -+ vx_nsems_add(sma, nsems); - - sma->sem_base = (struct sem *) &sma[1]; - INIT_LIST_HEAD(&sma->sem_pending); -@@ -546,6 +552,9 @@ static void freeary(struct ipc_namespace - sem_unlock(sma); - - ns->used_sems -= sma->sem_nsems; -+ /* FIXME: obsoleted? */ -+ vx_nsems_sub(sma, sma->sem_nsems); -+ vx_semary_dec(sma); - security_sem_free(sma); - ipc_rcu_putref(sma); - } -diff -NurpP --minimal linux-2.6.32.1/ipc/shm.c linux-2.6.32.1-vs2.3.0.36.27/ipc/shm.c ---- linux-2.6.32.1/ipc/shm.c 2009-12-03 20:02:57.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/ipc/shm.c 2009-12-03 20:04:56.000000000 +0100 -@@ -40,6 +40,8 @@ - #include - #include - #include -+#include -+#include - - #include - -@@ -169,7 +171,12 @@ static void shm_open(struct vm_area_stru - */ - static void shm_destroy(struct ipc_namespace *ns, struct shmid_kernel *shp) - { -- ns->shm_tot -= (shp->shm_segsz + PAGE_SIZE - 1) >> PAGE_SHIFT; -+ struct vx_info *vxi = lookup_vx_info(shp->shm_perm.xid); -+ int numpages = (shp->shm_segsz + PAGE_SIZE - 1) >> PAGE_SHIFT; -+ -+ vx_ipcshm_sub(vxi, shp, numpages); -+ ns->shm_tot -= numpages; -+ - shm_rmid(ns, shp); - shm_unlock(shp); - if (!is_file_hugepages(shp->shm_file)) -@@ -179,6 +186,7 @@ static void shm_destroy(struct ipc_names - shp->mlock_user); - fput (shp->shm_file); - security_shm_free(shp); -+ put_vx_info(vxi); - ipc_rcu_putref(shp); - } - -@@ -349,11 +357,15 @@ static int newseg(struct ipc_namespace * - if (ns->shm_tot + numpages > ns->shm_ctlall) - return -ENOSPC; - -+ if (!vx_ipcshm_avail(current_vx_info(), numpages)) -+ return -ENOSPC; -+ - shp = ipc_rcu_alloc(sizeof(*shp)); - if (!shp) - return -ENOMEM; - - shp->shm_perm.key = key; -+ shp->shm_perm.xid = vx_current_xid(); - shp->shm_perm.mode = (shmflg & S_IRWXUGO); - shp->mlock_user = NULL; - -@@ -407,6 +419,7 @@ static int newseg(struct ipc_namespace * - ns->shm_tot += numpages; - error = shp->shm_perm.id; - shm_unlock(shp); -+ vx_ipcshm_add(current_vx_info(), key, numpages); - return error; - - no_id: -diff -NurpP --minimal linux-2.6.32.1/kernel/capability.c linux-2.6.32.1-vs2.3.0.36.27/kernel/capability.c ---- linux-2.6.32.1/kernel/capability.c 2009-03-24 14:22:44.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/kernel/capability.c 2009-12-03 20:04:56.000000000 +0100 -@@ -14,6 +14,7 @@ - #include - #include - #include -+#include - #include - #include "cred-internals.h" - -@@ -122,6 +123,7 @@ static int cap_validate_magic(cap_user_h - return 0; - } - -+ - /* - * The only thing that can change the capabilities of the current - * process is the current process. As such, we can't be in this code -@@ -289,6 +291,8 @@ error: - return ret; - } - -+#include -+ - /** - * capable - Determine if the current task has a superior capability in effect - * @cap: The capability to be tested for -@@ -301,6 +305,9 @@ error: - */ - int capable(int cap) - { -+ /* here for now so we don't require task locking */ -+ if (vs_check_bit(VXC_CAP_MASK, cap) && !vx_mcaps(1L << cap)) -+ return 0; - if (unlikely(!cap_valid(cap))) { - printk(KERN_CRIT "capable() called with invalid cap=%u\n", cap); - BUG(); -diff -NurpP --minimal linux-2.6.32.1/kernel/compat.c linux-2.6.32.1-vs2.3.0.36.27/kernel/compat.c ---- linux-2.6.32.1/kernel/compat.c 2009-09-10 15:26:27.000000000 +0200 -+++ linux-2.6.32.1-vs2.3.0.36.27/kernel/compat.c 2009-12-03 20:04:56.000000000 +0100 -@@ -902,7 +902,7 @@ asmlinkage long compat_sys_time(compat_t - compat_time_t i; - struct timeval tv; - -- do_gettimeofday(&tv); -+ vx_gettimeofday(&tv); - i = tv.tv_sec; - - if (tloc) { -@@ -927,7 +927,7 @@ asmlinkage long compat_sys_stime(compat_ - if (err) - return err; - -- do_settimeofday(&tv); -+ vx_settimeofday(&tv); - return 0; - } - -diff -NurpP --minimal linux-2.6.32.1/kernel/exit.c linux-2.6.32.1-vs2.3.0.36.27/kernel/exit.c ---- linux-2.6.32.1/kernel/exit.c 2009-12-03 20:02:57.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/kernel/exit.c 2009-12-03 20:04:56.000000000 +0100 -@@ -48,6 +48,10 @@ - #include - #include - #include -+#include -+#include -+#include -+#include - #include - - #include -@@ -488,9 +492,11 @@ static void close_files(struct files_str - filp_close(file, files); - cond_resched(); - } -+ vx_openfd_dec(i); - } - i++; - set >>= 1; -+ cond_resched(); - } - } - } -@@ -1011,11 +1017,16 @@ NORET_TYPE void do_exit(long code) - - validate_creds_for_do_exit(tsk); - -+ /* needs to stay after exit_notify() */ -+ exit_vx_info(tsk, code); -+ exit_nx_info(tsk); -+ - preempt_disable(); - exit_rcu(); - /* causes final put_task_struct in finish_task_switch(). */ - tsk->state = TASK_DEAD; - schedule(); -+ printk("bad task: %p [%lx]\n", current, current->state); - BUG(); - /* Avoid "noreturn function does return". */ - for (;;) -diff -NurpP --minimal linux-2.6.32.1/kernel/fork.c linux-2.6.32.1-vs2.3.0.36.27/kernel/fork.c ---- linux-2.6.32.1/kernel/fork.c 2009-12-03 20:02:57.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/kernel/fork.c 2009-12-03 20:04:56.000000000 +0100 -@@ -64,6 +64,10 @@ - #include - #include - #include -+#include -+#include -+#include -+#include - - #include - #include -@@ -151,6 +155,8 @@ void free_task(struct task_struct *tsk) - account_kernel_stack(tsk->stack, -1); - free_thread_info(tsk->stack); - rt_mutex_debug_task_free(tsk); -+ clr_vx_info(&tsk->vx_info); -+ clr_nx_info(&tsk->nx_info); - ftrace_graph_exit_task(tsk); - free_task_struct(tsk); - } -@@ -296,6 +302,8 @@ static int dup_mmap(struct mm_struct *mm - mm->free_area_cache = oldmm->mmap_base; - mm->cached_hole_size = ~0UL; - mm->map_count = 0; -+ __set_mm_counter(mm, file_rss, 0); -+ __set_mm_counter(mm, anon_rss, 0); - cpumask_clear(mm_cpumask(mm)); - mm->mm_rb = RB_ROOT; - rb_link = &mm->mm_rb.rb_node; -@@ -310,7 +318,7 @@ static int dup_mmap(struct mm_struct *mm - - if (mpnt->vm_flags & VM_DONTCOPY) { - long pages = vma_pages(mpnt); -- mm->total_vm -= pages; -+ vx_vmpages_sub(mm, pages); - vm_stat_account(mm, mpnt->vm_flags, mpnt->vm_file, - -pages); - continue; -@@ -452,8 +460,8 @@ static struct mm_struct * mm_init(struct - (current->mm->flags & MMF_INIT_MASK) : default_dump_filter; - mm->core_state = NULL; - mm->nr_ptes = 0; -- set_mm_counter(mm, file_rss, 0); -- set_mm_counter(mm, anon_rss, 0); -+ __set_mm_counter(mm, file_rss, 0); -+ __set_mm_counter(mm, anon_rss, 0); - spin_lock_init(&mm->page_table_lock); - mm->free_area_cache = TASK_UNMAPPED_BASE; - mm->cached_hole_size = ~0UL; -@@ -463,6 +471,7 @@ static struct mm_struct * mm_init(struct - if (likely(!mm_alloc_pgd(mm))) { - mm->def_flags = 0; - mmu_notifier_mm_init(mm); -+ set_vx_info(&mm->mm_vx_info, p->vx_info); - return mm; - } - -@@ -496,6 +505,7 @@ void __mmdrop(struct mm_struct *mm) - mm_free_pgd(mm); - destroy_context(mm); - mmu_notifier_mm_destroy(mm); -+ clr_vx_info(&mm->mm_vx_info); - free_mm(mm); - } - EXPORT_SYMBOL_GPL(__mmdrop); -@@ -631,6 +641,7 @@ struct mm_struct *dup_mm(struct task_str - goto fail_nomem; - - memcpy(mm, oldmm, sizeof(*mm)); -+ mm->mm_vx_info = NULL; - - /* Initializing for Swap token stuff */ - mm->token_priority = 0; -@@ -669,6 +680,7 @@ fail_nocontext: - * If init_new_context() failed, we cannot use mmput() to free the mm - * because it calls destroy_context() - */ -+ clr_vx_info(&mm->mm_vx_info); - mm_free_pgd(mm); - free_mm(mm); - return NULL; -@@ -980,6 +992,8 @@ static struct task_struct *copy_process( - int retval; - struct task_struct *p; - int cgroup_callbacks_done = 0; -+ struct vx_info *vxi; -+ struct nx_info *nxi; - - if ((clone_flags & (CLONE_NEWNS|CLONE_FS)) == (CLONE_NEWNS|CLONE_FS)) - return ERR_PTR(-EINVAL); -@@ -1026,12 +1040,28 @@ static struct task_struct *copy_process( - DEBUG_LOCKS_WARN_ON(!p->hardirqs_enabled); - DEBUG_LOCKS_WARN_ON(!p->softirqs_enabled); - #endif -+ init_vx_info(&p->vx_info, current_vx_info()); -+ init_nx_info(&p->nx_info, current_nx_info()); -+ -+ /* check vserver memory */ -+ if (p->mm && !(clone_flags & CLONE_VM)) { -+ if (vx_vmpages_avail(p->mm, p->mm->total_vm)) -+ vx_pages_add(p->vx_info, RLIMIT_AS, p->mm->total_vm); -+ else -+ goto bad_fork_free; -+ } -+ if (p->mm && vx_flags(VXF_FORK_RSS, 0)) { -+ if (!vx_rss_avail(p->mm, get_mm_counter(p->mm, file_rss))) -+ goto bad_fork_cleanup_vm; -+ } - retval = -EAGAIN; -+ if (!vx_nproc_avail(1)) -+ goto bad_fork_cleanup_vm; - if (atomic_read(&p->real_cred->user->processes) >= - p->signal->rlim[RLIMIT_NPROC].rlim_cur) { - if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RESOURCE) && - p->real_cred->user != INIT_USER) -- goto bad_fork_free; -+ goto bad_fork_cleanup_vm; - } - - retval = copy_creds(p, clone_flags); -@@ -1300,6 +1330,18 @@ static struct task_struct *copy_process( - - total_forks++; - spin_unlock(¤t->sighand->siglock); -+ -+ /* p is copy of current */ -+ vxi = p->vx_info; -+ if (vxi) { -+ claim_vx_info(vxi, p); -+ atomic_inc(&vxi->cvirt.nr_threads); -+ atomic_inc(&vxi->cvirt.total_forks); -+ vx_nproc_inc(p); -+ } -+ nxi = p->nx_info; -+ if (nxi) -+ claim_nx_info(nxi, p); - write_unlock_irq(&tasklist_lock); - proc_fork_connector(p); - cgroup_post_fork(p); -@@ -1341,6 +1383,9 @@ bad_fork_cleanup_cgroup: - bad_fork_cleanup_count: - atomic_dec(&p->cred->user->processes); - exit_creds(p); -+bad_fork_cleanup_vm: -+ if (p->mm && !(clone_flags & CLONE_VM)) -+ vx_pages_sub(p->vx_info, RLIMIT_AS, p->mm->total_vm); - bad_fork_free: - free_task(p); - fork_out: -diff -NurpP --minimal linux-2.6.32.1/kernel/kthread.c linux-2.6.32.1-vs2.3.0.36.27/kernel/kthread.c ---- linux-2.6.32.1/kernel/kthread.c 2009-12-03 20:02:58.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/kernel/kthread.c 2009-12-03 20:04:56.000000000 +0100 -@@ -14,6 +14,7 @@ - #include - #include - #include -+#include - #include - - static DEFINE_SPINLOCK(kthread_create_lock); -diff -NurpP --minimal linux-2.6.32.1/kernel/Makefile linux-2.6.32.1-vs2.3.0.36.27/kernel/Makefile ---- linux-2.6.32.1/kernel/Makefile 2009-12-03 20:02:57.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/kernel/Makefile 2009-12-03 20:04:56.000000000 +0100 -@@ -23,6 +23,7 @@ CFLAGS_REMOVE_cgroup-debug.o = -pg - CFLAGS_REMOVE_sched_clock.o = -pg - endif - -+obj-y += vserver/ - obj-$(CONFIG_FREEZER) += freezer.o - obj-$(CONFIG_PROFILING) += profile.o - obj-$(CONFIG_SYSCTL_SYSCALL_CHECK) += sysctl_check.o -diff -NurpP --minimal linux-2.6.32.1/kernel/nsproxy.c linux-2.6.32.1-vs2.3.0.36.27/kernel/nsproxy.c ---- linux-2.6.32.1/kernel/nsproxy.c 2009-09-10 15:26:28.000000000 +0200 -+++ linux-2.6.32.1-vs2.3.0.36.27/kernel/nsproxy.c 2009-12-03 20:04:56.000000000 +0100 -@@ -19,6 +19,8 @@ - #include - #include - #include -+#include -+#include - #include - #include - -@@ -31,8 +33,11 @@ static inline struct nsproxy *create_nsp - struct nsproxy *nsproxy; - - nsproxy = kmem_cache_alloc(nsproxy_cachep, GFP_KERNEL); -- if (nsproxy) -+ if (nsproxy) { - atomic_set(&nsproxy->count, 1); -+ atomic_inc(&vs_global_nsproxy); -+ } -+ vxdprintk(VXD_CBIT(space, 2), "create_nsproxy = %p[1]", nsproxy); - return nsproxy; - } - -@@ -41,41 +46,52 @@ static inline struct nsproxy *create_nsp - * Return the newly created nsproxy. Do not attach this to the task, - * leave it to the caller to do proper locking and attach it to task. - */ --static struct nsproxy *create_new_namespaces(unsigned long flags, -- struct task_struct *tsk, struct fs_struct *new_fs) -+static struct nsproxy *unshare_namespaces(unsigned long flags, -+ struct nsproxy *orig, struct fs_struct *new_fs) - { - struct nsproxy *new_nsp; - int err; - -+ vxdprintk(VXD_CBIT(space, 4), -+ "unshare_namespaces(0x%08lx,%p,%p)", -+ flags, orig, new_fs); -+ - new_nsp = create_nsproxy(); - if (!new_nsp) - return ERR_PTR(-ENOMEM); - -- new_nsp->mnt_ns = copy_mnt_ns(flags, tsk->nsproxy->mnt_ns, new_fs); -+ new_nsp->mnt_ns = copy_mnt_ns(flags, orig->mnt_ns, new_fs); - if (IS_ERR(new_nsp->mnt_ns)) { - err = PTR_ERR(new_nsp->mnt_ns); - goto out_ns; - } - -- new_nsp->uts_ns = copy_utsname(flags, tsk->nsproxy->uts_ns); -+ new_nsp->uts_ns = copy_utsname(flags, orig->uts_ns); - if (IS_ERR(new_nsp->uts_ns)) { - err = PTR_ERR(new_nsp->uts_ns); - goto out_uts; - } - -- new_nsp->ipc_ns = copy_ipcs(flags, tsk->nsproxy->ipc_ns); -+ new_nsp->ipc_ns = copy_ipcs(flags, orig->ipc_ns); - if (IS_ERR(new_nsp->ipc_ns)) { - err = PTR_ERR(new_nsp->ipc_ns); - goto out_ipc; - } - -- new_nsp->pid_ns = copy_pid_ns(flags, task_active_pid_ns(tsk)); -+ new_nsp->pid_ns = copy_pid_ns(flags, orig->pid_ns); - if (IS_ERR(new_nsp->pid_ns)) { - err = PTR_ERR(new_nsp->pid_ns); - goto out_pid; - } - -- new_nsp->net_ns = copy_net_ns(flags, tsk->nsproxy->net_ns); -+ /* disabled now? -+ new_nsp->user_ns = copy_user_ns(flags, orig->user_ns); -+ if (IS_ERR(new_nsp->user_ns)) { -+ err = PTR_ERR(new_nsp->user_ns); -+ goto out_user; -+ } */ -+ -+ new_nsp->net_ns = copy_net_ns(flags, orig->net_ns); - if (IS_ERR(new_nsp->net_ns)) { - err = PTR_ERR(new_nsp->net_ns); - goto out_net; -@@ -100,6 +116,38 @@ out_ns: - return ERR_PTR(err); - } - -+static struct nsproxy *create_new_namespaces(int flags, struct task_struct *tsk, -+ struct fs_struct *new_fs) -+{ -+ return unshare_namespaces(flags, tsk->nsproxy, new_fs); -+} -+ -+/* -+ * copies the nsproxy, setting refcount to 1, and grabbing a -+ * reference to all contained namespaces. -+ */ -+struct nsproxy *copy_nsproxy(struct nsproxy *orig) -+{ -+ struct nsproxy *ns = create_nsproxy(); -+ -+ if (ns) { -+ memcpy(ns, orig, sizeof(struct nsproxy)); -+ atomic_set(&ns->count, 1); -+ -+ if (ns->mnt_ns) -+ get_mnt_ns(ns->mnt_ns); -+ if (ns->uts_ns) -+ get_uts_ns(ns->uts_ns); -+ if (ns->ipc_ns) -+ get_ipc_ns(ns->ipc_ns); -+ if (ns->pid_ns) -+ get_pid_ns(ns->pid_ns); -+ if (ns->net_ns) -+ get_net(ns->net_ns); -+ } -+ return ns; -+} -+ - /* - * called from clone. This now handles copy for nsproxy and all - * namespaces therein. -@@ -107,9 +155,12 @@ out_ns: - int copy_namespaces(unsigned long flags, struct task_struct *tsk) - { - struct nsproxy *old_ns = tsk->nsproxy; -- struct nsproxy *new_ns; -+ struct nsproxy *new_ns = NULL; - int err = 0; - -+ vxdprintk(VXD_CBIT(space, 7), "copy_namespaces(0x%08lx,%p[%p])", -+ flags, tsk, old_ns); -+ - if (!old_ns) - return 0; - -@@ -119,7 +170,7 @@ int copy_namespaces(unsigned long flags, - CLONE_NEWPID | CLONE_NEWNET))) - return 0; - -- if (!capable(CAP_SYS_ADMIN)) { -+ if (!vx_can_unshare(CAP_SYS_ADMIN, flags)) { - err = -EPERM; - goto out; - } -@@ -146,6 +197,9 @@ int copy_namespaces(unsigned long flags, - - out: - put_nsproxy(old_ns); -+ vxdprintk(VXD_CBIT(space, 3), -+ "copy_namespaces(0x%08lx,%p[%p]) = %d [%p]", -+ flags, tsk, old_ns, err, new_ns); - return err; - } - -@@ -159,7 +213,9 @@ void free_nsproxy(struct nsproxy *ns) - put_ipc_ns(ns->ipc_ns); - if (ns->pid_ns) - put_pid_ns(ns->pid_ns); -- put_net(ns->net_ns); -+ if (ns->net_ns) -+ put_net(ns->net_ns); -+ atomic_dec(&vs_global_nsproxy); - kmem_cache_free(nsproxy_cachep, ns); - } - -@@ -172,11 +228,15 @@ int unshare_nsproxy_namespaces(unsigned - { - int err = 0; - -+ vxdprintk(VXD_CBIT(space, 4), -+ "unshare_nsproxy_namespaces(0x%08lx,[%p])", -+ unshare_flags, current->nsproxy); -+ - if (!(unshare_flags & (CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC | - CLONE_NEWNET))) - return 0; - -- if (!capable(CAP_SYS_ADMIN)) -+ if (!vx_can_unshare(CAP_SYS_ADMIN, unshare_flags)) - return -EPERM; - - *new_nsp = create_new_namespaces(unshare_flags, current, -diff -NurpP --minimal linux-2.6.32.1/kernel/pid.c linux-2.6.32.1-vs2.3.0.36.27/kernel/pid.c ---- linux-2.6.32.1/kernel/pid.c 2009-12-03 20:02:58.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/kernel/pid.c 2009-12-03 20:04:56.000000000 +0100 -@@ -36,6 +36,7 @@ - #include - #include - #include -+#include - - #define pid_hashfn(nr, ns) \ - hash_long((unsigned long)nr + (unsigned long)ns, pidhash_shift) -@@ -305,7 +306,7 @@ EXPORT_SYMBOL_GPL(find_pid_ns); - - struct pid *find_vpid(int nr) - { -- return find_pid_ns(nr, current->nsproxy->pid_ns); -+ return find_pid_ns(vx_rmap_pid(nr), current->nsproxy->pid_ns); - } - EXPORT_SYMBOL_GPL(find_vpid); - -@@ -365,6 +366,9 @@ void transfer_pid(struct task_struct *ol - struct task_struct *pid_task(struct pid *pid, enum pid_type type) - { - struct task_struct *result = NULL; -+ -+ if (type == PIDTYPE_REALPID) -+ type = PIDTYPE_PID; - if (pid) { - struct hlist_node *first; - first = rcu_dereference(pid->tasks[type].first); -@@ -380,7 +384,7 @@ EXPORT_SYMBOL(pid_task); - */ - struct task_struct *find_task_by_pid_ns(pid_t nr, struct pid_namespace *ns) - { -- return pid_task(find_pid_ns(nr, ns), PIDTYPE_PID); -+ return pid_task(find_pid_ns(vx_rmap_pid(nr), ns), PIDTYPE_PID); - } - - struct task_struct *find_task_by_vpid(pid_t vnr) -@@ -422,7 +426,7 @@ struct pid *find_get_pid(pid_t nr) - } - EXPORT_SYMBOL_GPL(find_get_pid); - --pid_t pid_nr_ns(struct pid *pid, struct pid_namespace *ns) -+pid_t pid_unmapped_nr_ns(struct pid *pid, struct pid_namespace *ns) - { - struct upid *upid; - pid_t nr = 0; -@@ -435,6 +439,11 @@ pid_t pid_nr_ns(struct pid *pid, struct - return nr; - } - -+pid_t pid_nr_ns(struct pid *pid, struct pid_namespace *ns) -+{ -+ return vx_map_pid(pid_unmapped_nr_ns(pid, ns)); -+} -+ - pid_t pid_vnr(struct pid *pid) - { - return pid_nr_ns(pid, current->nsproxy->pid_ns); -diff -NurpP --minimal linux-2.6.32.1/kernel/pid_namespace.c linux-2.6.32.1-vs2.3.0.36.27/kernel/pid_namespace.c ---- linux-2.6.32.1/kernel/pid_namespace.c 2009-12-03 20:02:58.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/kernel/pid_namespace.c 2009-12-03 20:04:56.000000000 +0100 -@@ -13,6 +13,7 @@ - #include - #include - #include -+#include - - #define BITS_PER_PAGE (PAGE_SIZE*8) - -@@ -86,6 +87,7 @@ static struct pid_namespace *create_pid_ - goto out_free_map; - - kref_init(&ns->kref); -+ atomic_inc(&vs_global_pid_ns); - ns->level = level; - ns->parent = get_pid_ns(parent_pid_ns); - -@@ -111,6 +113,7 @@ static void destroy_pid_namespace(struct - - for (i = 0; i < PIDMAP_ENTRIES; i++) - kfree(ns->pidmap[i].page); -+ atomic_dec(&vs_global_pid_ns); - kmem_cache_free(pid_ns_cachep, ns); - } - -diff -NurpP --minimal linux-2.6.32.1/kernel/posix-timers.c linux-2.6.32.1-vs2.3.0.36.27/kernel/posix-timers.c ---- linux-2.6.32.1/kernel/posix-timers.c 2009-12-03 20:02:58.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/kernel/posix-timers.c 2009-12-03 20:04:56.000000000 +0100 -@@ -46,6 +46,7 @@ - #include - #include - #include -+#include - - /* - * Management arrays for POSIX timers. Timers are kept in slab memory -@@ -363,6 +364,7 @@ int posix_timer_event(struct k_itimer *t - { - struct task_struct *task; - int shared, ret = -1; -+ - /* - * FIXME: if ->sigq is queued we can race with - * dequeue_signal()->do_schedule_next_timer(). -@@ -379,10 +381,18 @@ int posix_timer_event(struct k_itimer *t - rcu_read_lock(); - task = pid_task(timr->it_pid, PIDTYPE_PID); - if (task) { -+ struct vx_info_save vxis; -+ struct vx_info *vxi; -+ -+ vxi = get_vx_info(task->vx_info); -+ enter_vx_info(vxi, &vxis); - shared = !(timr->it_sigev_notify & SIGEV_THREAD_ID); - ret = send_sigqueue(timr->sigq, task, shared); -+ leave_vx_info(&vxis); -+ put_vx_info(vxi); - } - rcu_read_unlock(); -+ - /* If we failed to send the signal the timer stops. */ - return ret > 0; - } -diff -NurpP --minimal linux-2.6.32.1/kernel/printk.c linux-2.6.32.1-vs2.3.0.36.27/kernel/printk.c ---- linux-2.6.32.1/kernel/printk.c 2009-12-03 20:02:58.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/kernel/printk.c 2009-12-03 20:04:56.000000000 +0100 -@@ -33,6 +33,7 @@ - #include - #include - #include -+#include - - #include - -@@ -276,18 +277,13 @@ int do_syslog(int type, char __user *buf - unsigned i, j, limit, count; - int do_clear = 0; - char c; -- int error = 0; -+ int error; - - error = security_syslog(type); - if (error) - return error; - -- switch (type) { -- case 0: /* Close log */ -- break; -- case 1: /* Open log */ -- break; -- case 2: /* Read from log */ -+ if ((type >= 2) && (type <= 4)) { - error = -EINVAL; - if (!buf || len < 0) - goto out; -@@ -298,6 +294,16 @@ int do_syslog(int type, char __user *buf - error = -EFAULT; - goto out; - } -+ } -+ if (!vx_check(0, VS_ADMIN|VS_WATCH)) -+ return vx_do_syslog(type, buf, len); -+ -+ switch (type) { -+ case 0: /* Close log */ -+ break; -+ case 1: /* Open log */ -+ break; -+ case 2: /* Read from log */ - error = wait_event_interruptible(log_wait, - (log_start - log_end)); - if (error) -@@ -322,16 +328,6 @@ int do_syslog(int type, char __user *buf - do_clear = 1; - /* FALL THRU */ - case 3: /* Read last kernel messages */ -- error = -EINVAL; -- if (!buf || len < 0) -- goto out; -- error = 0; -- if (!len) -- goto out; -- if (!access_ok(VERIFY_WRITE, buf, len)) { -- error = -EFAULT; -- goto out; -- } - count = len; - if (count > log_buf_len) - count = log_buf_len; -diff -NurpP --minimal linux-2.6.32.1/kernel/ptrace.c linux-2.6.32.1-vs2.3.0.36.27/kernel/ptrace.c ---- linux-2.6.32.1/kernel/ptrace.c 2009-12-03 20:02:58.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/kernel/ptrace.c 2009-12-03 20:04:56.000000000 +0100 -@@ -22,6 +22,7 @@ - #include - #include - #include -+#include - - - /* -@@ -151,6 +152,11 @@ int __ptrace_may_access(struct task_stru - dumpable = get_dumpable(task->mm); - if (!dumpable && !capable(CAP_SYS_PTRACE)) - return -EPERM; -+ if (!vx_check(task->xid, VS_ADMIN_P|VS_IDENT)) -+ return -EPERM; -+ if (!vx_check(task->xid, VS_IDENT) && -+ !task_vx_flags(task, VXF_STATE_ADMIN, 0)) -+ return -EACCES; - - return security_ptrace_access_check(task, mode); - } -@@ -621,6 +627,10 @@ SYSCALL_DEFINE4(ptrace, long, request, l - goto out; - } - -+ ret = -EPERM; -+ if (!vx_check(vx_task_xid(child), VS_WATCH_P | VS_IDENT)) -+ goto out_put_task_struct; -+ - if (request == PTRACE_ATTACH) { - ret = ptrace_attach(child); - /* -diff -NurpP --minimal linux-2.6.32.1/kernel/sched.c linux-2.6.32.1-vs2.3.0.36.27/kernel/sched.c ---- linux-2.6.32.1/kernel/sched.c 2009-12-03 20:02:58.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/kernel/sched.c 2009-12-03 20:04:56.000000000 +0100 -@@ -71,6 +71,8 @@ - #include - #include - #include -+#include -+#include - - #include - #include -@@ -237,6 +239,15 @@ static DEFINE_MUTEX(sched_domains_mutex) - - #include - -+#if defined(CONFIG_FAIR_GROUP_SCHED) && defined(CONFIG_CFS_HARD_LIMITS) -+struct cfs_bandwidth { -+ spinlock_t cfs_runtime_lock; -+ ktime_t cfs_period; -+ u64 cfs_runtime; -+ struct hrtimer cfs_period_timer; -+}; -+#endif -+ - struct cfs_rq; - - static LIST_HEAD(task_groups); -@@ -257,6 +268,9 @@ struct task_group { - /* runqueue "owned" by this group on each cpu */ - struct cfs_rq **cfs_rq; - unsigned long shares; -+#ifdef CONFIG_CFS_HARD_LIMITS -+ struct cfs_bandwidth cfs_bandwidth; -+#endif - #endif - - #ifdef CONFIG_RT_GROUP_SCHED -@@ -446,6 +460,19 @@ struct cfs_rq { - unsigned long rq_weight; - #endif - #endif -+#ifdef CONFIG_CFS_HARD_LIMITS -+ /* set when the group is throttled on this cpu */ -+ int cfs_throttled; -+ -+ /* runtime currently consumed by the group on this rq */ -+ u64 cfs_time; -+ -+ /* runtime available to the group on this rq */ -+ u64 cfs_runtime; -+ -+ /* Protects the cfs runtime related fields of this cfs_rq */ -+ spinlock_t cfs_runtime_lock; -+#endif - }; - - /* Real-Time classes' related field in a runqueue: */ -@@ -1607,6 +1634,7 @@ static void update_group_shares_cpu(stru - } - } - -+static inline int cfs_rq_throttled(struct cfs_rq *cfs_rq); - /* - * Re-compute the task group their per cpu shares over the given domain. - * This needs to be done in a bottom-up fashion because the rq weight of a -@@ -1634,8 +1662,10 @@ static int tg_shares_up(struct task_grou - * If there are currently no tasks on the cpu pretend there - * is one of average load so that when a new task gets to - * run here it will not get delayed by group starvation. -+ * Also if the group is throttled on this cpu, pretend that -+ * it has no tasks. - */ -- if (!weight) -+ if (!weight || cfs_rq_throttled(tg->cfs_rq[i])) - weight = NICE_0_LOAD; - - rq_weight += weight; -@@ -1811,6 +1841,175 @@ static void cfs_rq_set_shares(struct cfs - - static void calc_load_account_active(struct rq *this_rq); - -+ -+#if defined(CONFIG_RT_GROUP_SCHED) || defined(CONFIG_FAIR_GROUP_SCHED) -+ -+#ifdef CONFIG_SMP -+static inline const struct cpumask *sched_bw_period_mask(void) -+{ -+ return cpu_rq(smp_processor_id())->rd->span; -+} -+#else /* !CONFIG_SMP */ -+static inline const struct cpumask *sched_bw_period_mask(void) -+{ -+ return cpu_online_mask; -+} -+#endif /* CONFIG_SMP */ -+ -+#else -+static inline const struct cpumask *sched_bw_period_mask(void) -+{ -+ return cpu_online_mask; -+} -+ -+#endif -+ -+#ifdef CONFIG_FAIR_GROUP_SCHED -+#ifdef CONFIG_CFS_HARD_LIMITS -+ -+/* -+ * Runtime allowed for a cfs group before it is hard limited. -+ * default: Infinite which means no hard limiting. -+ */ -+u64 sched_cfs_runtime = RUNTIME_INF; -+ -+/* -+ * period over which we hard limit the cfs group's bandwidth. -+ * default: 0.5s -+ */ -+u64 sched_cfs_period = 500000; -+ -+static inline u64 global_cfs_period(void) -+{ -+ return sched_cfs_period * NSEC_PER_USEC; -+} -+ -+static inline u64 global_cfs_runtime(void) -+{ -+ return RUNTIME_INF; -+} -+ -+void do_sched_cfs_period_timer(struct cfs_bandwidth *cfs_b); -+ -+static inline void cfs_rq_runtime_lock(struct cfs_rq *cfs_rq) -+{ -+ spin_lock(&cfs_rq->cfs_runtime_lock); -+} -+ -+static inline void cfs_rq_runtime_unlock(struct cfs_rq *cfs_rq) -+{ -+ spin_unlock(&cfs_rq->cfs_runtime_lock); -+} -+ -+/* -+ * Refresh the runtimes of the throttled groups. -+ * But nothing much to do now, will populate this in later patches. -+ */ -+static enum hrtimer_restart sched_cfs_period_timer(struct hrtimer *timer) -+{ -+ struct cfs_bandwidth *cfs_b = -+ container_of(timer, struct cfs_bandwidth, cfs_period_timer); -+ -+ do_sched_cfs_period_timer(cfs_b); -+ hrtimer_add_expires_ns(timer, ktime_to_ns(cfs_b->cfs_period)); -+ return HRTIMER_RESTART; -+} -+ -+/* -+ * TODO: Check if this kind of timer setup is sufficient for cfs or -+ * should we do what rt is doing. -+ */ -+static void start_cfs_bandwidth(struct task_group *tg) -+{ -+ struct cfs_bandwidth *cfs_b = &tg->cfs_bandwidth; -+ -+ /* -+ * Timer isn't setup for groups with infinite runtime -+ */ -+ if (cfs_b->cfs_runtime == RUNTIME_INF) -+ return; -+ -+ if (hrtimer_active(&cfs_b->cfs_period_timer)) -+ return; -+ -+ hrtimer_start_range_ns(&cfs_b->cfs_period_timer, cfs_b->cfs_period, -+ 0, HRTIMER_MODE_REL); -+} -+ -+static void init_cfs_bandwidth(struct task_group *tg) -+{ -+ struct cfs_bandwidth *cfs_b = &tg->cfs_bandwidth; -+ -+ cfs_b->cfs_period = ns_to_ktime(global_cfs_period()); -+ cfs_b->cfs_runtime = global_cfs_runtime(); -+ -+ spin_lock_init(&cfs_b->cfs_runtime_lock); -+ -+ hrtimer_init(&cfs_b->cfs_period_timer, -+ CLOCK_MONOTONIC, HRTIMER_MODE_REL); -+ cfs_b->cfs_period_timer.function = &sched_cfs_period_timer; -+} -+ -+static inline void destroy_cfs_bandwidth(struct task_group *tg) -+{ -+ hrtimer_cancel(&tg->cfs_bandwidth.cfs_period_timer); -+} -+ -+static void init_cfs_hard_limits(struct cfs_rq *cfs_rq, struct task_group *tg) -+{ -+ cfs_rq->cfs_time = 0; -+ cfs_rq->cfs_throttled = 0; -+ cfs_rq->cfs_runtime = tg->cfs_bandwidth.cfs_runtime; -+ spin_lock_init(&cfs_rq->cfs_runtime_lock); -+} -+ -+#else /* !CONFIG_CFS_HARD_LIMITS */ -+ -+static void init_cfs_bandwidth(struct task_group *tg) -+{ -+ return; -+} -+ -+static inline void destroy_cfs_bandwidth(struct task_group *tg) -+{ -+ return; -+} -+ -+static void init_cfs_hard_limits(struct cfs_rq *cfs_rq, struct task_group *tg) -+{ -+ return; -+} -+ -+static inline void cfs_rq_runtime_lock(struct cfs_rq *cfs_rq) -+{ -+ return; -+} -+ -+static inline void cfs_rq_runtime_unlock(struct cfs_rq *cfs_rq) -+{ -+ return; -+} -+ -+#endif /* CONFIG_CFS_HARD_LIMITS */ -+#else /* !CONFIG_FAIR_GROUP_SCHED */ -+ -+static inline void cfs_rq_runtime_lock(struct cfs_rq *cfs_rq) -+{ -+ return; -+} -+ -+static inline void cfs_rq_runtime_unlock(struct cfs_rq *cfs_rq) -+{ -+ return; -+} -+ -+static inline int cfs_rq_throttled(struct cfs_rq *cfs_rq) -+{ -+ return 0; -+} -+ -+#endif /* CONFIG_FAIR_GROUP_SCHED */ -+ - #include "sched_stats.h" - #include "sched_idletask.c" - #include "sched_fair.c" -@@ -2965,9 +3164,17 @@ EXPORT_SYMBOL(avenrun); - */ - void get_avenrun(unsigned long *loads, unsigned long offset, int shift) - { -- loads[0] = (avenrun[0] + offset) << shift; -- loads[1] = (avenrun[1] + offset) << shift; -- loads[2] = (avenrun[2] + offset) << shift; -+ if (vx_flags(VXF_VIRT_LOAD, 0)) { -+ struct vx_info *vxi = current_vx_info(); -+ -+ loads[0] = (vxi->cvirt.load[0] + offset) << shift; -+ loads[1] = (vxi->cvirt.load[1] + offset) << shift; -+ loads[2] = (vxi->cvirt.load[2] + offset) << shift; -+ } else { -+ loads[0] = (avenrun[0] + offset) << shift; -+ loads[1] = (avenrun[1] + offset) << shift; -+ loads[2] = (avenrun[2] + offset) << shift; -+ } - } - - static unsigned long -@@ -5006,16 +5213,19 @@ void account_user_time(struct task_struc - cputime_t cputime_scaled) - { - struct cpu_usage_stat *cpustat = &kstat_this_cpu.cpustat; -+ struct vx_info *vxi = p->vx_info; /* p is _always_ current */ - cputime64_t tmp; -+ int nice = (TASK_NICE(p) > 0); - - /* Add user time to process. */ - p->utime = cputime_add(p->utime, cputime); - p->utimescaled = cputime_add(p->utimescaled, cputime_scaled); -+ vx_account_user(vxi, cputime, nice); - account_group_user_time(p, cputime); - - /* Add user time to cpustat. */ - tmp = cputime_to_cputime64(cputime); -- if (TASK_NICE(p) > 0) -+ if (nice) - cpustat->nice = cputime64_add(cpustat->nice, tmp); - else - cpustat->user = cputime64_add(cpustat->user, tmp); -@@ -5061,6 +5271,7 @@ void account_system_time(struct task_str - cputime_t cputime, cputime_t cputime_scaled) - { - struct cpu_usage_stat *cpustat = &kstat_this_cpu.cpustat; -+ struct vx_info *vxi = p->vx_info; /* p is _always_ current */ - cputime64_t tmp; - - if ((p->flags & PF_VCPU) && (irq_count() - hardirq_offset == 0)) { -@@ -5071,6 +5282,7 @@ void account_system_time(struct task_str - /* Add system time to process. */ - p->stime = cputime_add(p->stime, cputime); - p->stimescaled = cputime_add(p->stimescaled, cputime_scaled); -+ vx_account_system(vxi, cputime, 0 /* do we have idle time? */); - account_group_system_time(p, cputime); - - /* Add system time to cpustat. */ -@@ -6106,7 +6318,7 @@ SYSCALL_DEFINE1(nice, int, increment) - nice = 19; - - if (increment < 0 && !can_nice(current, nice)) -- return -EPERM; -+ return vx_flags(VXF_IGNEG_NICE, 0) ? 0 : -EPERM; - - retval = security_task_setnice(current, nice); - if (retval) -@@ -9164,6 +9376,32 @@ static int update_sched_domains(struct n - } - #endif - -+#ifdef CONFIG_SMP -+static void disable_runtime(struct rq *rq) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&rq->lock, flags); -+#if defined(CONFIG_FAIR_GROUP_SCHED) && defined(CONFIG_CFS_HARD_LIMITS) -+ disable_runtime_cfs(rq); -+#endif -+ disable_runtime_rt(rq); -+ spin_unlock_irqrestore(&rq->lock, flags); -+} -+ -+static void enable_runtime(struct rq *rq) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&rq->lock, flags); -+#if defined(CONFIG_FAIR_GROUP_SCHED) && defined(CONFIG_CFS_HARD_LIMITS) -+ enable_runtime_cfs(rq); -+#endif -+ enable_runtime_rt(rq); -+ spin_unlock_irqrestore(&rq->lock, flags); -+} -+#endif -+ - static int update_runtime(struct notifier_block *nfb, - unsigned long action, void *hcpu) - { -@@ -9296,6 +9534,7 @@ static void init_tg_cfs_entry(struct tas - struct rq *rq = cpu_rq(cpu); - tg->cfs_rq[cpu] = cfs_rq; - init_cfs_rq(cfs_rq, rq); -+ init_cfs_hard_limits(cfs_rq, tg); - cfs_rq->tg = tg; - if (add) - list_add(&cfs_rq->leaf_cfs_rq_list, &rq->leaf_cfs_rq_list); -@@ -9425,6 +9664,10 @@ void __init sched_init(void) - #endif /* CONFIG_USER_SCHED */ - #endif /* CONFIG_RT_GROUP_SCHED */ - -+#ifdef CONFIG_FAIR_GROUP_SCHED -+ init_cfs_bandwidth(&init_task_group); -+#endif -+ - #ifdef CONFIG_GROUP_SCHED - list_add(&init_task_group.list, &task_groups); - INIT_LIST_HEAD(&init_task_group.children); -@@ -9451,6 +9694,7 @@ void __init sched_init(void) - init_cfs_rq(&rq->cfs, rq); - init_rt_rq(&rq->rt, rq); - #ifdef CONFIG_FAIR_GROUP_SCHED -+ init_cfs_hard_limits(&rq->cfs, &init_task_group); - init_task_group.shares = init_task_group_load; - INIT_LIST_HEAD(&rq->leaf_cfs_rq_list); - #ifdef CONFIG_CGROUP_SCHED -@@ -9726,6 +9970,7 @@ static void free_fair_sched_group(struct - { - int i; - -+ destroy_cfs_bandwidth(tg); - for_each_possible_cpu(i) { - if (tg->cfs_rq) - kfree(tg->cfs_rq[i]); -@@ -9752,6 +9997,7 @@ int alloc_fair_sched_group(struct task_g - if (!tg->se) - goto err; - -+ init_cfs_bandwidth(tg); - tg->shares = NICE_0_LOAD; - - for_each_possible_cpu(i) { -@@ -10475,6 +10721,100 @@ static u64 cpu_shares_read_u64(struct cg - - return (u64) tg->shares; - } -+ -+#ifdef CONFIG_CFS_HARD_LIMITS -+ -+static int tg_set_cfs_bandwidth(struct task_group *tg, -+ u64 cfs_period, u64 cfs_runtime) -+{ -+ int i; -+ -+ spin_lock_irq(&tg->cfs_bandwidth.cfs_runtime_lock); -+ tg->cfs_bandwidth.cfs_period = ns_to_ktime(cfs_period); -+ tg->cfs_bandwidth.cfs_runtime = cfs_runtime; -+ -+ for_each_possible_cpu(i) { -+ struct cfs_rq *cfs_rq = tg->cfs_rq[i]; -+ -+ cfs_rq_runtime_lock(cfs_rq); -+ cfs_rq->cfs_runtime = cfs_runtime; -+ cfs_rq_runtime_unlock(cfs_rq); -+ } -+ -+ start_cfs_bandwidth(tg); -+ spin_unlock_irq(&tg->cfs_bandwidth.cfs_runtime_lock); -+ return 0; -+} -+ -+int tg_set_cfs_runtime(struct task_group *tg, long cfs_runtime_us) -+{ -+ u64 cfs_runtime, cfs_period; -+ -+ cfs_period = ktime_to_ns(tg->cfs_bandwidth.cfs_period); -+ cfs_runtime = (u64)cfs_runtime_us * NSEC_PER_USEC; -+ if (cfs_runtime_us < 0) -+ cfs_runtime = RUNTIME_INF; -+ -+ return tg_set_cfs_bandwidth(tg, cfs_period, cfs_runtime); -+} -+ -+long tg_get_cfs_runtime(struct task_group *tg) -+{ -+ u64 cfs_runtime_us; -+ -+ if (tg->cfs_bandwidth.cfs_runtime == RUNTIME_INF) -+ return -1; -+ -+ cfs_runtime_us = tg->cfs_bandwidth.cfs_runtime; -+ do_div(cfs_runtime_us, NSEC_PER_USEC); -+ return cfs_runtime_us; -+} -+ -+int tg_set_cfs_period(struct task_group *tg, long cfs_period_us) -+{ -+ u64 cfs_runtime, cfs_period; -+ -+ cfs_period = (u64)cfs_period_us * NSEC_PER_USEC; -+ cfs_runtime = tg->cfs_bandwidth.cfs_runtime; -+ -+ if (cfs_period == 0) -+ return -EINVAL; -+ -+ return tg_set_cfs_bandwidth(tg, cfs_period, cfs_runtime); -+} -+ -+long tg_get_cfs_period(struct task_group *tg) -+{ -+ u64 cfs_period_us; -+ -+ cfs_period_us = ktime_to_ns(tg->cfs_bandwidth.cfs_period); -+ do_div(cfs_period_us, NSEC_PER_USEC); -+ return cfs_period_us; -+} -+ -+static s64 cpu_cfs_runtime_read_s64(struct cgroup *cgrp, struct cftype *cft) -+{ -+ return tg_get_cfs_runtime(cgroup_tg(cgrp)); -+} -+ -+static int cpu_cfs_runtime_write_s64(struct cgroup *cgrp, struct cftype *cftype, -+ s64 cfs_runtime_us) -+{ -+ return tg_set_cfs_runtime(cgroup_tg(cgrp), cfs_runtime_us); -+} -+ -+static u64 cpu_cfs_period_read_u64(struct cgroup *cgrp, struct cftype *cft) -+{ -+ return tg_get_cfs_period(cgroup_tg(cgrp)); -+} -+ -+static int cpu_cfs_period_write_u64(struct cgroup *cgrp, struct cftype *cftype, -+ u64 cfs_period_us) -+{ -+ return tg_set_cfs_period(cgroup_tg(cgrp), cfs_period_us); -+} -+ -+#endif /* CONFIG_CFS_HARD_LIMITS */ - #endif /* CONFIG_FAIR_GROUP_SCHED */ - - #ifdef CONFIG_RT_GROUP_SCHED -@@ -10508,6 +10848,18 @@ static struct cftype cpu_files[] = { - .read_u64 = cpu_shares_read_u64, - .write_u64 = cpu_shares_write_u64, - }, -+#ifdef CONFIG_CFS_HARD_LIMITS -+ { -+ .name = "cfs_runtime_us", -+ .read_s64 = cpu_cfs_runtime_read_s64, -+ .write_s64 = cpu_cfs_runtime_write_s64, -+ }, -+ { -+ .name = "cfs_period_us", -+ .read_u64 = cpu_cfs_period_read_u64, -+ .write_u64 = cpu_cfs_period_write_u64, -+ }, -+#endif /* CONFIG_CFS_HARD_LIMITS */ - #endif - #ifdef CONFIG_RT_GROUP_SCHED - { -diff -NurpP --minimal linux-2.6.32.1/kernel/sched_debug.c linux-2.6.32.1-vs2.3.0.36.27/kernel/sched_debug.c ---- linux-2.6.32.1/kernel/sched_debug.c 2009-12-03 20:02:58.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/kernel/sched_debug.c 2009-12-03 20:04:56.000000000 +0100 -@@ -80,6 +80,11 @@ static void print_cfs_group_stats(struct - PN(se->wait_max); - PN(se->wait_sum); - P(se->wait_count); -+#ifdef CONFIG_CFS_HARD_LIMITS -+ PN(se->throttle_max); -+ PN(se->throttle_sum); -+ P(se->throttle_count); -+#endif - #endif - P(se->load.weight); - #undef PN -@@ -214,6 +219,16 @@ void print_cfs_rq(struct seq_file *m, in - #ifdef CONFIG_SMP - SEQ_printf(m, " .%-30s: %lu\n", "shares", cfs_rq->shares); - #endif -+#ifdef CONFIG_CFS_HARD_LIMITS -+ spin_lock_irqsave(&rq->lock, flags); -+ SEQ_printf(m, " .%-30s: %d\n", "cfs_throttled", -+ cfs_rq->cfs_throttled); -+ SEQ_printf(m, " .%-30s: %Ld.%06ld\n", "cfs_time", -+ SPLIT_NS(cfs_rq->cfs_time)); -+ SEQ_printf(m, " .%-30s: %Ld.%06ld\n", "cfs_runtime", -+ SPLIT_NS(cfs_rq->cfs_runtime)); -+ spin_unlock_irqrestore(&rq->lock, flags); -+#endif /* CONFIG_CFS_HARD_LIMITS */ - print_cfs_group_stats(m, cpu, cfs_rq->tg); - #endif - } -@@ -310,7 +325,7 @@ static int sched_debug_show(struct seq_f - u64 now = ktime_to_ns(ktime_get()); - int cpu; - -- SEQ_printf(m, "Sched Debug Version: v0.09, %s %.*s\n", -+ SEQ_printf(m, "Sched Debug Version: v0.10, %s %.*s\n", - init_utsname()->release, - (int)strcspn(init_utsname()->version, " "), - init_utsname()->version); -diff -NurpP --minimal linux-2.6.32.1/kernel/sched_fair.c linux-2.6.32.1-vs2.3.0.36.27/kernel/sched_fair.c ---- linux-2.6.32.1/kernel/sched_fair.c 2009-12-03 20:02:58.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/kernel/sched_fair.c 2009-12-03 20:04:56.000000000 +0100 -@@ -189,7 +189,308 @@ find_matching_se(struct sched_entity **s - } - } - --#else /* !CONFIG_FAIR_GROUP_SCHED */ -+#ifdef CONFIG_CFS_HARD_LIMITS -+ -+static inline void update_stats_throttle_start(struct cfs_rq *cfs_rq, -+ struct sched_entity *se) -+{ -+ schedstat_set(se->throttle_start, rq_of(cfs_rq)->clock); -+} -+ -+static inline void update_stats_throttle_end(struct cfs_rq *cfs_rq, -+ struct sched_entity *se) -+{ -+ schedstat_set(se->throttle_max, max(se->throttle_max, -+ rq_of(cfs_rq)->clock - se->throttle_start)); -+ schedstat_set(se->throttle_count, se->throttle_count + 1); -+ schedstat_set(se->throttle_sum, se->throttle_sum + -+ rq_of(cfs_rq)->clock - se->throttle_start); -+ schedstat_set(se->throttle_start, 0); -+} -+ -+static inline -+struct cfs_rq *sched_cfs_period_cfs_rq(struct cfs_bandwidth *cfs_b, int cpu) -+{ -+ return container_of(cfs_b, struct task_group, -+ cfs_bandwidth)->cfs_rq[cpu]; -+} -+ -+static inline int cfs_rq_throttled(struct cfs_rq *cfs_rq) -+{ -+ return cfs_rq->cfs_throttled; -+} -+ -+#ifdef CONFIG_SMP -+/* -+ * Ensure this RQ takes back all the runtime it lend to its neighbours. -+ */ -+static void disable_runtime_cfs(struct rq *rq) -+{ -+ struct root_domain *rd = rq->rd; -+ struct cfs_rq *cfs_rq; -+ -+ if (unlikely(!scheduler_running)) -+ return; -+ -+ for_each_leaf_cfs_rq(rq, cfs_rq) { -+ struct cfs_bandwidth *cfs_b = &cfs_rq->tg->cfs_bandwidth; -+ s64 want; -+ int i; -+ -+ spin_lock(&cfs_b->cfs_runtime_lock); -+ spin_lock(&cfs_rq->cfs_runtime_lock); -+ -+ /* -+ * Either we're all are infinity and nobody needs to borrow, -+ * or we're already disabled and this have nothing to do, or -+ * we have exactly the right amount of runtime to take out. -+ */ -+ if (cfs_rq->cfs_runtime == RUNTIME_INF || -+ cfs_rq->cfs_runtime == cfs_b->cfs_runtime) -+ goto balanced; -+ spin_unlock(&cfs_rq->cfs_runtime_lock); -+ -+ /* -+ * Calculate the difference between what we started out with -+ * and what we current have, that's the amount of runtime -+ * we lend and now have to reclaim. -+ */ -+ want = cfs_b->cfs_runtime - cfs_rq->cfs_runtime; -+ -+ /* -+ * Greedy reclaim, take back as much as possible. -+ */ -+ for_each_cpu(i, rd->span) { -+ struct cfs_rq *iter = sched_cfs_period_cfs_rq(cfs_b, i); -+ s64 diff; -+ -+ /* -+ * Can't reclaim from ourselves or disabled runqueues. -+ */ -+ if (iter == cfs_rq || iter->cfs_runtime == RUNTIME_INF) -+ continue; -+ -+ spin_lock(&iter->cfs_runtime_lock); -+ if (want > 0) { -+ diff = min_t(s64, iter->cfs_runtime, want); -+ iter->cfs_runtime -= diff; -+ want -= diff; -+ } else { -+ iter->cfs_runtime -= want; -+ want -= want; -+ } -+ -+ spin_unlock(&iter->cfs_runtime_lock); -+ if (!want) -+ break; -+ } -+ -+ spin_lock(&cfs_rq->cfs_runtime_lock); -+ /* -+ * We cannot be left wanting - that would mean some -+ * runtime leaked out of the system. -+ */ -+ BUG_ON(want); -+balanced: -+ /* -+ * Disable all the borrow logic by pretending we have infinite -+ * runtime - in which case borrowing doesn't make sense. -+ */ -+ cfs_rq->cfs_runtime = RUNTIME_INF; -+ spin_unlock(&cfs_rq->cfs_runtime_lock); -+ spin_unlock(&cfs_b->cfs_runtime_lock); -+ } -+} -+ -+static void enable_runtime_cfs(struct rq *rq) -+{ -+ struct cfs_rq *cfs_rq; -+ -+ if (unlikely(!scheduler_running)) -+ return; -+ -+ /* -+ * Reset each runqueue's bandwidth settings -+ */ -+ for_each_leaf_cfs_rq(rq, cfs_rq) { -+ struct cfs_bandwidth *cfs_b = &cfs_rq->tg->cfs_bandwidth; -+ -+ spin_lock(&cfs_b->cfs_runtime_lock); -+ spin_lock(&cfs_rq->cfs_runtime_lock); -+ cfs_rq->cfs_runtime = cfs_b->cfs_runtime; -+ cfs_rq->cfs_time = 0; -+ cfs_rq->cfs_throttled = 0; -+ spin_unlock(&cfs_rq->cfs_runtime_lock); -+ spin_unlock(&cfs_b->cfs_runtime_lock); -+ } -+} -+ -+/* -+ * Ran out of runtime, check if we can borrow some from others -+ * instead of getting throttled right away. -+ */ -+static void do_cfs_balance_runtime(struct cfs_rq *cfs_rq) -+{ -+ struct cfs_bandwidth *cfs_b = &cfs_rq->tg->cfs_bandwidth; -+ const struct cpumask *span = sched_bw_period_mask(); -+ int i, weight; -+ u64 cfs_period; -+ -+ weight = cpumask_weight(span); -+ spin_lock(&cfs_b->cfs_runtime_lock); -+ cfs_period = ktime_to_ns(cfs_b->cfs_period); -+ -+ for_each_cpu(i, span) { -+ struct cfs_rq *borrow_cfs_rq = -+ sched_cfs_period_cfs_rq(cfs_b, i); -+ s64 diff; -+ -+ if (borrow_cfs_rq == cfs_rq) -+ continue; -+ -+ cfs_rq_runtime_lock(borrow_cfs_rq); -+ if (borrow_cfs_rq->cfs_runtime == RUNTIME_INF) { -+ cfs_rq_runtime_unlock(borrow_cfs_rq); -+ continue; -+ } -+ -+ diff = borrow_cfs_rq->cfs_runtime - borrow_cfs_rq->cfs_time; -+ if (diff > 0) { -+ diff = div_u64((u64)diff, weight); -+ if (cfs_rq->cfs_runtime + diff > cfs_period) -+ diff = cfs_period - cfs_rq->cfs_runtime; -+ borrow_cfs_rq->cfs_runtime -= diff; -+ cfs_rq->cfs_runtime += diff; -+ if (cfs_rq->cfs_runtime == cfs_period) { -+ cfs_rq_runtime_unlock(borrow_cfs_rq); -+ break; -+ } -+ } -+ cfs_rq_runtime_unlock(borrow_cfs_rq); -+ } -+ spin_unlock(&cfs_b->cfs_runtime_lock); -+} -+ -+/* -+ * Called with rq->runtime_lock held. -+ */ -+static void cfs_balance_runtime(struct cfs_rq *cfs_rq) -+{ -+ cfs_rq_runtime_unlock(cfs_rq); -+ do_cfs_balance_runtime(cfs_rq); -+ cfs_rq_runtime_lock(cfs_rq); -+} -+ -+#else /* !CONFIG_SMP */ -+ -+static void cfs_balance_runtime(struct cfs_rq *cfs_rq) -+{ -+ return; -+} -+#endif /* CONFIG_SMP */ -+ -+/* -+ * Check if group entity exceeded its runtime. If so, mark the cfs_rq as -+ * throttled mark the current task for reschedling. -+ */ -+static void sched_cfs_runtime_exceeded(struct sched_entity *se, -+ struct task_struct *tsk_curr, unsigned long delta_exec) -+{ -+ struct cfs_rq *cfs_rq; -+ -+ cfs_rq = group_cfs_rq(se); -+ -+ if (cfs_rq->cfs_runtime == RUNTIME_INF) -+ return; -+ -+ cfs_rq->cfs_time += delta_exec; -+ -+ if (cfs_rq_throttled(cfs_rq)) -+ return; -+ -+ if (cfs_rq->cfs_time > cfs_rq->cfs_runtime) -+ cfs_balance_runtime(cfs_rq); -+ -+ if (cfs_rq->cfs_time > cfs_rq->cfs_runtime) { -+ cfs_rq->cfs_throttled = 1; -+ update_stats_throttle_start(cfs_rq, se); -+ resched_task(tsk_curr); -+ } -+} -+ -+static inline void update_curr_group(struct sched_entity *curr, -+ unsigned long delta_exec, struct task_struct *tsk_curr) -+{ -+ sched_cfs_runtime_exceeded(curr, tsk_curr, delta_exec); -+} -+ -+static void enqueue_entity_locked(struct cfs_rq *cfs_rq, -+ struct sched_entity *se, int wakeup); -+ -+static void enqueue_throttled_entity(struct rq *rq, struct sched_entity *se) -+{ -+ for_each_sched_entity(se) { -+ struct cfs_rq *gcfs_rq = group_cfs_rq(se); -+ -+ if (se->on_rq || cfs_rq_throttled(gcfs_rq) || -+ !gcfs_rq->nr_running) -+ break; -+ enqueue_entity_locked(cfs_rq_of(se), se, 0); -+ } -+} -+ -+/* -+ * Refresh runtimes of all cfs_rqs in this group, i,e., -+ * refresh runtimes of the representative cfs_rq of this -+ * tg on all cpus. Enqueue any throttled entity back. -+ */ -+void do_sched_cfs_period_timer(struct cfs_bandwidth *cfs_b) -+{ -+ int i; -+ const struct cpumask *span = sched_bw_period_mask(); -+ unsigned long flags; -+ -+ for_each_cpu(i, span) { -+ struct rq *rq = cpu_rq(i); -+ struct cfs_rq *cfs_rq = sched_cfs_period_cfs_rq(cfs_b, i); -+ struct sched_entity *se = cfs_rq->tg->se[i]; -+ -+ spin_lock_irqsave(&rq->lock, flags); -+ cfs_rq_runtime_lock(cfs_rq); -+ cfs_rq->cfs_time = 0; -+ if (cfs_rq_throttled(cfs_rq)) { -+ update_rq_clock(rq); -+ update_stats_throttle_end(cfs_rq, se); -+ cfs_rq->cfs_throttled = 0; -+ enqueue_throttled_entity(rq, se); -+ } -+ cfs_rq_runtime_unlock(cfs_rq); -+ spin_unlock_irqrestore(&rq->lock, flags); -+ } -+} -+ -+#else -+ -+static inline void update_curr_group(struct sched_entity *curr, -+ unsigned long delta_exec, struct task_struct *tsk_curr) -+{ -+ return; -+} -+ -+static inline int cfs_rq_throttled(struct cfs_rq *cfs_rq) -+{ -+ return 0; -+} -+ -+#endif /* CONFIG_CFS_HARD_LIMITS */ -+ -+#else /* CONFIG_FAIR_GROUP_SCHED */ -+ -+static inline void update_curr_group(struct sched_entity *curr, -+ unsigned long delta_exec, struct task_struct *tsk_curr) -+{ -+ return; -+} - - static inline struct task_struct *task_of(struct sched_entity *se) - { -@@ -251,7 +552,6 @@ find_matching_se(struct sched_entity **s - - #endif /* CONFIG_FAIR_GROUP_SCHED */ - -- - /************************************************************** - * Scheduling class tree data structure manipulation methods: - */ -@@ -489,14 +789,25 @@ __update_curr(struct cfs_rq *cfs_rq, str - update_min_vruntime(cfs_rq); - } - --static void update_curr(struct cfs_rq *cfs_rq) -+static void update_curr_task(struct sched_entity *curr, -+ unsigned long delta_exec) -+{ -+ struct task_struct *curtask = task_of(curr); -+ -+ trace_sched_stat_runtime(curtask, delta_exec, curr->vruntime); -+ cpuacct_charge(curtask, delta_exec); -+ account_group_exec_runtime(curtask, delta_exec); -+} -+ -+static int update_curr_common(struct cfs_rq *cfs_rq, unsigned long *delta) - { - struct sched_entity *curr = cfs_rq->curr; -- u64 now = rq_of(cfs_rq)->clock; -+ struct rq *rq = rq_of(cfs_rq); -+ u64 now = rq->clock; - unsigned long delta_exec; - - if (unlikely(!curr)) -- return; -+ return 1; - - /* - * Get the amount of time the current task was running -@@ -505,20 +816,47 @@ static void update_curr(struct cfs_rq *c - */ - delta_exec = (unsigned long)(now - curr->exec_start); - if (!delta_exec) -- return; -+ return 1; - - __update_curr(cfs_rq, curr, delta_exec); - curr->exec_start = now; -+ *delta = delta_exec; -+ return 0; -+} - -- if (entity_is_task(curr)) { -- struct task_struct *curtask = task_of(curr); -+static void update_curr(struct cfs_rq *cfs_rq) -+{ -+ struct sched_entity *curr = cfs_rq->curr; -+ struct rq *rq = rq_of(cfs_rq); -+ unsigned long delta_exec; - -- trace_sched_stat_runtime(curtask, delta_exec, curr->vruntime); -- cpuacct_charge(curtask, delta_exec); -- account_group_exec_runtime(curtask, delta_exec); -+ if (update_curr_common(cfs_rq, &delta_exec)) -+ return ; -+ -+ if (entity_is_task(curr)) -+ update_curr_task(curr, delta_exec); -+ else { -+ cfs_rq_runtime_lock(group_cfs_rq(curr)); -+ update_curr_group(curr, delta_exec, rq->curr); -+ cfs_rq_runtime_unlock(group_cfs_rq(curr)); - } - } - -+static void update_curr_locked(struct cfs_rq *cfs_rq) -+{ -+ struct sched_entity *curr = cfs_rq->curr; -+ struct rq *rq = rq_of(cfs_rq); -+ unsigned long delta_exec; -+ -+ if (update_curr_common(cfs_rq, &delta_exec)) -+ return ; -+ -+ if (entity_is_task(curr)) -+ update_curr_task(curr, delta_exec); -+ else -+ update_curr_group(curr, delta_exec, rq->curr); -+} -+ - static inline void - update_stats_wait_start(struct cfs_rq *cfs_rq, struct sched_entity *se) - { -@@ -740,13 +1078,9 @@ place_entity(struct cfs_rq *cfs_rq, stru - se->vruntime = vruntime; - } - --static void --enqueue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int wakeup) -+static void enqueue_entity_common(struct cfs_rq *cfs_rq, -+ struct sched_entity *se, int wakeup) - { -- /* -- * Update run-time statistics of the 'current'. -- */ -- update_curr(cfs_rq); - account_entity_enqueue(cfs_rq, se); - - if (wakeup) { -@@ -758,6 +1092,29 @@ enqueue_entity(struct cfs_rq *cfs_rq, st - check_spread(cfs_rq, se); - if (se != cfs_rq->curr) - __enqueue_entity(cfs_rq, se); -+ -+ if (entity_is_task(se)) -+ vx_activate_task(task_of(se)); -+} -+ -+static void enqueue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, -+ int wakeup) -+{ -+ /* -+ * Update run-time statistics of the 'current'. -+ */ -+ update_curr(cfs_rq); -+ enqueue_entity_common(cfs_rq, se, wakeup); -+} -+ -+static void enqueue_entity_locked(struct cfs_rq *cfs_rq, -+ struct sched_entity *se, int wakeup) -+{ -+ /* -+ * Update run-time statistics of the 'current'. -+ */ -+ update_curr_locked(cfs_rq); -+ enqueue_entity_common(cfs_rq, se, wakeup); - } - - static void __clear_buddies(struct cfs_rq *cfs_rq, struct sched_entity *se) -@@ -801,6 +1158,8 @@ dequeue_entity(struct cfs_rq *cfs_rq, st - - if (se != cfs_rq->curr) - __dequeue_entity(cfs_rq, se); -+ if (entity_is_task(se)) -+ vx_deactivate_task(task_of(se)); - account_entity_dequeue(cfs_rq, se); - update_min_vruntime(cfs_rq); - } -@@ -897,6 +1256,32 @@ static struct sched_entity *pick_next_en - return se; - } - -+/* -+ * Called from put_prev_entity() -+ * If a group entity (@se) is found to be throttled, it will not be put back -+ * on @cfs_rq, which is equivalent to dequeing it. -+ */ -+static int dequeue_throttled_entity(struct cfs_rq *cfs_rq, -+ struct sched_entity *se) -+{ -+ struct cfs_rq *gcfs_rq = group_cfs_rq(se); -+ -+ if (entity_is_task(se)) -+ return 0; -+ -+ cfs_rq_runtime_lock(gcfs_rq); -+ if (!cfs_rq_throttled(gcfs_rq) && gcfs_rq->nr_running) { -+ cfs_rq_runtime_unlock(gcfs_rq); -+ return 0; -+ } -+ -+ __clear_buddies(cfs_rq, se); -+ account_entity_dequeue(cfs_rq, se); -+ cfs_rq->curr = NULL; -+ cfs_rq_runtime_unlock(gcfs_rq); -+ return 1; -+} -+ - static void put_prev_entity(struct cfs_rq *cfs_rq, struct sched_entity *prev) - { - /* -@@ -908,6 +1293,8 @@ static void put_prev_entity(struct cfs_r - - check_spread(cfs_rq, prev); - if (prev->on_rq) { -+ if (dequeue_throttled_entity(cfs_rq, prev)) -+ return; - update_stats_wait_start(cfs_rq, prev); - /* Put 'current' back into the tree. */ - __enqueue_entity(cfs_rq, prev); -@@ -1004,10 +1391,28 @@ static inline void hrtick_update(struct - } - #endif - -+static int enqueue_group_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, -+ int wakeup) -+{ -+ struct cfs_rq *gcfs_rq = group_cfs_rq(se); -+ int ret = 0; -+ -+ cfs_rq_runtime_lock(gcfs_rq); -+ if (cfs_rq_throttled(gcfs_rq)) { -+ ret = 1; -+ goto out; -+ } -+ enqueue_entity_locked(cfs_rq, se, wakeup); -+out: -+ cfs_rq_runtime_unlock(gcfs_rq); -+ return ret; -+} -+ - /* - * The enqueue_task method is called before nr_running is - * increased. Here we update the fair scheduling stats and - * then put the task into the rbtree: -+ * Don't enqueue a throttled entity further into the hierarchy. - */ - static void enqueue_task_fair(struct rq *rq, struct task_struct *p, int wakeup) - { -@@ -1017,11 +1422,15 @@ static void enqueue_task_fair(struct rq - for_each_sched_entity(se) { - if (se->on_rq) - break; -+ - cfs_rq = cfs_rq_of(se); -- enqueue_entity(cfs_rq, se, wakeup); -+ if (entity_is_task(se)) -+ enqueue_entity(cfs_rq, se, wakeup); -+ else -+ if (enqueue_group_entity(cfs_rq, se, wakeup)) -+ break; - wakeup = 1; - } -- - hrtick_update(rq); - } - -@@ -1041,6 +1450,17 @@ static void dequeue_task_fair(struct rq - /* Don't dequeue parent if it has other entities besides us */ - if (cfs_rq->load.weight) - break; -+ -+ /* -+ * If this cfs_rq is throttled, then it is already -+ * dequeued. -+ */ -+ cfs_rq_runtime_lock(cfs_rq); -+ if (cfs_rq_throttled(cfs_rq)) { -+ cfs_rq_runtime_unlock(cfs_rq); -+ break; -+ } -+ cfs_rq_runtime_unlock(cfs_rq); - sleep = 1; - } - -@@ -1788,9 +2208,10 @@ load_balance_fair(struct rq *this_rq, in - u64 rem_load, moved_load; - - /* -- * empty group -+ * empty group or throttled group - */ -- if (!busiest_cfs_rq->task_weight) -+ if (!busiest_cfs_rq->task_weight || -+ cfs_rq_throttled(busiest_cfs_rq)) - continue; - - rem_load = (u64)rem_load_move * busiest_weight; -@@ -1839,6 +2260,12 @@ move_one_task_fair(struct rq *this_rq, i - - for_each_leaf_cfs_rq(busiest, busy_cfs_rq) { - /* -+ * Don't move task from a throttled cfs_rq -+ */ -+ if (cfs_rq_throttled(busy_cfs_rq)) -+ continue; -+ -+ /* - * pass busy_cfs_rq argument into - * load_balance_[start|next]_fair iterators - */ -diff -NurpP --minimal linux-2.6.32.1/kernel/sched_rt.c linux-2.6.32.1-vs2.3.0.36.27/kernel/sched_rt.c ---- linux-2.6.32.1/kernel/sched_rt.c 2009-12-03 20:02:58.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/kernel/sched_rt.c 2009-12-03 20:04:56.000000000 +0100 -@@ -235,18 +235,6 @@ static int rt_se_boosted(struct sched_rt - return p->prio != p->normal_prio; - } - --#ifdef CONFIG_SMP --static inline const struct cpumask *sched_rt_period_mask(void) --{ -- return cpu_rq(smp_processor_id())->rd->span; --} --#else --static inline const struct cpumask *sched_rt_period_mask(void) --{ -- return cpu_online_mask; --} --#endif -- - static inline - struct rt_rq *sched_rt_period_rt_rq(struct rt_bandwidth *rt_b, int cpu) - { -@@ -296,11 +284,6 @@ static inline int rt_rq_throttled(struct - return rt_rq->rt_throttled; - } - --static inline const struct cpumask *sched_rt_period_mask(void) --{ -- return cpu_online_mask; --} -- - static inline - struct rt_rq *sched_rt_period_rt_rq(struct rt_bandwidth *rt_b, int cpu) - { -@@ -373,7 +356,7 @@ next: - /* - * Ensure this RQ takes back all the runtime it lend to its neighbours. - */ --static void __disable_runtime(struct rq *rq) -+static void disable_runtime_rt(struct rq *rq) - { - struct root_domain *rd = rq->rd; - struct rt_rq *rt_rq; -@@ -450,16 +433,7 @@ balanced: - } - } - --static void disable_runtime(struct rq *rq) --{ -- unsigned long flags; -- -- spin_lock_irqsave(&rq->lock, flags); -- __disable_runtime(rq); -- spin_unlock_irqrestore(&rq->lock, flags); --} -- --static void __enable_runtime(struct rq *rq) -+static void enable_runtime_rt(struct rq *rq) - { - struct rt_rq *rt_rq; - -@@ -482,15 +456,6 @@ static void __enable_runtime(struct rq * - } - } - --static void enable_runtime(struct rq *rq) --{ -- unsigned long flags; -- -- spin_lock_irqsave(&rq->lock, flags); -- __enable_runtime(rq); -- spin_unlock_irqrestore(&rq->lock, flags); --} -- - static int balance_runtime(struct rt_rq *rt_rq) - { - int more = 0; -@@ -518,7 +483,7 @@ static int do_sched_rt_period_timer(stru - if (!rt_bandwidth_enabled() || rt_b->rt_runtime == RUNTIME_INF) - return 1; - -- span = sched_rt_period_mask(); -+ span = sched_bw_period_mask(); - for_each_cpu(i, span) { - int enqueue = 0; - struct rt_rq *rt_rq = sched_rt_period_rt_rq(rt_b, i); -@@ -1564,7 +1529,7 @@ static void rq_online_rt(struct rq *rq) - if (rq->rt.overloaded) - rt_set_overload(rq); - -- __enable_runtime(rq); -+ enable_runtime_rt(rq); - - cpupri_set(&rq->rd->cpupri, rq->cpu, rq->rt.highest_prio.curr); - } -@@ -1575,7 +1540,7 @@ static void rq_offline_rt(struct rq *rq) - if (rq->rt.overloaded) - rt_clear_overload(rq); - -- __disable_runtime(rq); -+ disable_runtime_rt(rq); - - cpupri_set(&rq->rd->cpupri, rq->cpu, CPUPRI_INVALID); - } -diff -NurpP --minimal linux-2.6.32.1/kernel/signal.c linux-2.6.32.1-vs2.3.0.36.27/kernel/signal.c ---- linux-2.6.32.1/kernel/signal.c 2009-12-03 20:02:58.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/kernel/signal.c 2009-12-03 20:04:56.000000000 +0100 -@@ -27,6 +27,8 @@ - #include - #include - #include -+#include -+#include - #include - - #include -@@ -598,6 +600,14 @@ static int check_kill_permission(int sig - if (!valid_signal(sig)) - return -EINVAL; - -+ if ((info != SEND_SIG_NOINFO) && -+ (is_si_special(info) || !SI_FROMUSER(info))) -+ goto skip; -+ -+ vxdprintk(VXD_CBIT(misc, 7), -+ "check_kill_permission(%d,%p,%p[#%u,%u])", -+ sig, info, t, vx_task_xid(t), t->pid); -+ - if (info != SEND_SIG_NOINFO && (is_si_special(info) || SI_FROMKERNEL(info))) - return 0; - -@@ -625,6 +635,20 @@ static int check_kill_permission(int sig - } - } - -+ error = -EPERM; -+ if (t->pid == 1 && current->xid) -+ return error; -+ -+ error = -ESRCH; -+ /* FIXME: we shouldn't return ESRCH ever, to avoid -+ loops, maybe ENOENT or EACCES? */ -+ if (!vx_check(vx_task_xid(t), VS_WATCH_P | VS_IDENT)) { -+ vxdprintk(current->xid || VXD_CBIT(misc, 7), -+ "signal %d[%p] xid mismatch %p[#%u,%u] xid=#%u", -+ sig, info, t, vx_task_xid(t), t->pid, current->xid); -+ return error; -+ } -+skip: - return security_task_kill(t, info, sig, 0); - } - -@@ -1112,7 +1136,7 @@ int kill_pid_info(int sig, struct siginf - rcu_read_lock(); - retry: - p = pid_task(pid, PIDTYPE_PID); -- if (p) { -+ if (p && vx_check(vx_task_xid(p), VS_IDENT)) { - error = group_send_sig_info(sig, info, p); - if (unlikely(error == -ESRCH)) - /* -@@ -1151,7 +1175,7 @@ int kill_pid_info_as_uid(int sig, struct - - read_lock(&tasklist_lock); - p = pid_task(pid, PIDTYPE_PID); -- if (!p) { -+ if (!p || !vx_check(vx_task_xid(p), VS_IDENT)) { - ret = -ESRCH; - goto out_unlock; - } -@@ -1205,8 +1229,10 @@ static int kill_something_info(int sig, - struct task_struct * p; - - for_each_process(p) { -- if (task_pid_vnr(p) > 1 && -- !same_thread_group(p, current)) { -+ if (vx_check(vx_task_xid(p), VS_ADMIN|VS_IDENT) && -+ task_pid_vnr(p) > 1 && -+ !same_thread_group(p, current) && -+ !vx_current_initpid(p->pid)) { - int err = group_send_sig_info(sig, info, p); - ++count; - if (err != -EPERM) -@@ -1871,6 +1897,11 @@ relock: - !sig_kernel_only(signr)) - continue; - -+ /* virtual init is protected against user signals */ -+ if ((info->si_code == SI_USER) && -+ vx_current_initpid(current->pid)) -+ continue; -+ - if (sig_kernel_stop(signr)) { - /* - * The default action is to stop all threads in -diff -NurpP --minimal linux-2.6.32.1/kernel/softirq.c linux-2.6.32.1-vs2.3.0.36.27/kernel/softirq.c ---- linux-2.6.32.1/kernel/softirq.c 2009-12-03 20:02:58.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/kernel/softirq.c 2009-12-03 20:04:56.000000000 +0100 -@@ -24,6 +24,7 @@ - #include - #include - #include -+#include - - #define CREATE_TRACE_POINTS - #include -diff -NurpP --minimal linux-2.6.32.1/kernel/sys.c linux-2.6.32.1-vs2.3.0.36.27/kernel/sys.c ---- linux-2.6.32.1/kernel/sys.c 2009-12-03 20:02:58.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/kernel/sys.c 2009-12-03 20:04:56.000000000 +0100 -@@ -41,6 +41,7 @@ - #include - #include - #include -+#include - - #include - #include -@@ -130,7 +131,10 @@ static int set_one_prio(struct task_stru - goto out; - } - if (niceval < task_nice(p) && !can_nice(p, niceval)) { -- error = -EACCES; -+ if (vx_flags(VXF_IGNEG_NICE, 0)) -+ error = 0; -+ else -+ error = -EACCES; - goto out; - } - no_nice = security_task_setnice(p, niceval); -@@ -179,6 +183,8 @@ SYSCALL_DEFINE3(setpriority, int, which, - else - pgrp = task_pgrp(current); - do_each_pid_thread(pgrp, PIDTYPE_PGID, p) { -+ if (!vx_check(p->xid, VS_ADMIN_P | VS_IDENT)) -+ continue; - error = set_one_prio(p, niceval, error); - } while_each_pid_thread(pgrp, PIDTYPE_PGID, p); - break; -@@ -240,6 +246,8 @@ SYSCALL_DEFINE2(getpriority, int, which, - else - pgrp = task_pgrp(current); - do_each_pid_thread(pgrp, PIDTYPE_PGID, p) { -+ if (!vx_check(p->xid, VS_ADMIN_P | VS_IDENT)) -+ continue; - niceval = 20 - task_nice(p); - if (niceval > retval) - retval = niceval; -@@ -349,6 +357,9 @@ void kernel_power_off(void) - machine_power_off(); - } - EXPORT_SYMBOL_GPL(kernel_power_off); -+ -+long vs_reboot(unsigned int, void __user *); -+ - /* - * Reboot system call: for obvious reasons only root may call it, - * and even root needs to set up some magic numbers in the registers -@@ -381,6 +392,9 @@ SYSCALL_DEFINE4(reboot, int, magic1, int - if ((cmd == LINUX_REBOOT_CMD_POWER_OFF) && !pm_power_off) - cmd = LINUX_REBOOT_CMD_HALT; - -+ if (!vx_check(0, VS_ADMIN|VS_WATCH)) -+ return vs_reboot(cmd, arg); -+ - lock_kernel(); - switch (cmd) { - case LINUX_REBOOT_CMD_RESTART: -@@ -1133,7 +1147,7 @@ SYSCALL_DEFINE2(sethostname, char __user - int errno; - char tmp[__NEW_UTS_LEN]; - -- if (!capable(CAP_SYS_ADMIN)) -+ if (!vx_capable(CAP_SYS_ADMIN, VXC_SET_UTSNAME)) - return -EPERM; - if (len < 0 || len > __NEW_UTS_LEN) - return -EINVAL; -@@ -1182,7 +1196,7 @@ SYSCALL_DEFINE2(setdomainname, char __us - int errno; - char tmp[__NEW_UTS_LEN]; - -- if (!capable(CAP_SYS_ADMIN)) -+ if (!vx_capable(CAP_SYS_ADMIN, VXC_SET_UTSNAME)) - return -EPERM; - if (len < 0 || len > __NEW_UTS_LEN) - return -EINVAL; -@@ -1251,7 +1265,7 @@ SYSCALL_DEFINE2(setrlimit, unsigned int, - return -EINVAL; - old_rlim = current->signal->rlim + resource; - if ((new_rlim.rlim_max > old_rlim->rlim_max) && -- !capable(CAP_SYS_RESOURCE)) -+ !vx_capable(CAP_SYS_RESOURCE, VXC_SET_RLIMIT)) - return -EPERM; - if (resource == RLIMIT_NOFILE && new_rlim.rlim_max > sysctl_nr_open) - return -EPERM; -diff -NurpP --minimal linux-2.6.32.1/kernel/sysctl.c linux-2.6.32.1-vs2.3.0.36.27/kernel/sysctl.c ---- linux-2.6.32.1/kernel/sysctl.c 2009-12-03 20:02:58.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/kernel/sysctl.c 2009-12-03 20:04:56.000000000 +0100 -@@ -124,6 +124,7 @@ static int ngroups_max = NGROUPS_MAX; - extern char modprobe_path[]; - extern int modules_disabled; - #endif -+extern char vshelper_path[]; - #ifdef CONFIG_CHR_DEV_SG - extern int sg_big_buff; - #endif -@@ -593,6 +594,15 @@ static struct ctl_table kern_table[] = { - .strategy = &sysctl_string, - }, - #endif -+ { -+ .ctl_name = KERN_VSHELPER, -+ .procname = "vshelper", -+ .data = &vshelper_path, -+ .maxlen = 256, -+ .mode = 0644, -+ .proc_handler = &proc_dostring, -+ .strategy = &sysctl_string, -+ }, - #ifdef CONFIG_CHR_DEV_SG - { - .ctl_name = KERN_SG_BIG_BUFF, -diff -NurpP --minimal linux-2.6.32.1/kernel/sysctl_check.c linux-2.6.32.1-vs2.3.0.36.27/kernel/sysctl_check.c ---- linux-2.6.32.1/kernel/sysctl_check.c 2009-12-03 20:02:58.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/kernel/sysctl_check.c 2009-12-03 20:04:56.000000000 +0100 -@@ -39,6 +39,7 @@ static const struct trans_ctl_table tran - - { KERN_PANIC, "panic" }, - { KERN_REALROOTDEV, "real-root-dev" }, -+ { KERN_VSHELPER, "vshelper", }, - - { KERN_SPARC_REBOOT, "reboot-cmd" }, - { KERN_CTLALTDEL, "ctrl-alt-del" }, -@@ -1217,6 +1218,22 @@ static const struct trans_ctl_table tran - {} - }; - -+static struct trans_ctl_table trans_vserver_table[] = { -+ { 1, "debug_switch" }, -+ { 2, "debug_xid" }, -+ { 3, "debug_nid" }, -+ { 4, "debug_tag" }, -+ { 5, "debug_net" }, -+ { 6, "debug_limit" }, -+ { 7, "debug_cres" }, -+ { 8, "debug_dlim" }, -+ { 9, "debug_quota" }, -+ { 10, "debug_cvirt" }, -+ { 11, "debug_space" }, -+ { 12, "debug_misc" }, -+ {} -+}; -+ - static const struct trans_ctl_table trans_root_table[] = { - { CTL_KERN, "kernel", trans_kern_table }, - { CTL_VM, "vm", trans_vm_table }, -@@ -1233,6 +1250,7 @@ static const struct trans_ctl_table tran - { CTL_SUNRPC, "sunrpc", trans_sunrpc_table }, - { CTL_PM, "pm", trans_pm_table }, - { CTL_FRV, "frv", trans_frv_table }, -+ { CTL_VSERVER, "vserver", trans_vserver_table }, - {} - }; - -diff -NurpP --minimal linux-2.6.32.1/kernel/time.c linux-2.6.32.1-vs2.3.0.36.27/kernel/time.c ---- linux-2.6.32.1/kernel/time.c 2009-12-03 20:02:58.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/kernel/time.c 2009-12-03 20:04:56.000000000 +0100 -@@ -63,6 +63,7 @@ EXPORT_SYMBOL(sys_tz); - SYSCALL_DEFINE1(time, time_t __user *, tloc) - { - time_t i = get_seconds(); -+/* FIXME: do_gettimeofday(&tv) -> vx_gettimeofday(&tv) */ - - if (tloc) { - if (put_user(i,tloc)) -@@ -93,7 +94,7 @@ SYSCALL_DEFINE1(stime, time_t __user *, - if (err) - return err; - -- do_settimeofday(&tv); -+ vx_settimeofday(&tv); - return 0; - } - -@@ -104,7 +105,7 @@ SYSCALL_DEFINE2(gettimeofday, struct tim - { - if (likely(tv != NULL)) { - struct timeval ktv; -- do_gettimeofday(&ktv); -+ vx_gettimeofday(&ktv); - if (copy_to_user(tv, &ktv, sizeof(ktv))) - return -EFAULT; - } -@@ -179,7 +180,7 @@ int do_sys_settimeofday(struct timespec - /* SMP safe, again the code in arch/foo/time.c should - * globally block out interrupts when it runs. - */ -- return do_settimeofday(tv); -+ return vx_settimeofday(tv); - } - return 0; - } -@@ -311,7 +312,7 @@ void getnstimeofday(struct timespec *tv) - { - struct timeval x; - -- do_gettimeofday(&x); -+ vx_gettimeofday(&x); - tv->tv_sec = x.tv_sec; - tv->tv_nsec = x.tv_usec * NSEC_PER_USEC; - } -diff -NurpP --minimal linux-2.6.32.1/kernel/timer.c linux-2.6.32.1-vs2.3.0.36.27/kernel/timer.c ---- linux-2.6.32.1/kernel/timer.c 2009-12-03 20:02:58.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/kernel/timer.c 2009-12-03 20:04:56.000000000 +0100 -@@ -39,6 +39,10 @@ - #include - #include - #include -+#include -+#include -+#include -+#include - - #include - #include -@@ -1255,12 +1259,6 @@ SYSCALL_DEFINE1(alarm, unsigned int, sec - - #endif - --#ifndef __alpha__ -- --/* -- * The Alpha uses getxpid, getxuid, and getxgid instead. Maybe this -- * should be moved into arch/i386 instead? -- */ - - /** - * sys_getpid - return the thread group id of the current process -@@ -1289,10 +1287,23 @@ SYSCALL_DEFINE0(getppid) - rcu_read_lock(); - pid = task_tgid_vnr(current->real_parent); - rcu_read_unlock(); -+ return vx_map_pid(pid); -+} - -- return pid; -+#ifdef __alpha__ -+ -+/* -+ * The Alpha uses getxpid, getxuid, and getxgid instead. -+ */ -+ -+asmlinkage long do_getxpid(long *ppid) -+{ -+ *ppid = sys_getppid(); -+ return sys_getpid(); - } - -+#else /* _alpha_ */ -+ - SYSCALL_DEFINE0(getuid) - { - /* Only we change this so SMP safe */ -diff -NurpP --minimal linux-2.6.32.1/kernel/user.c linux-2.6.32.1-vs2.3.0.36.27/kernel/user.c ---- linux-2.6.32.1/kernel/user.c 2009-12-03 20:02:58.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/kernel/user.c 2009-12-03 20:04:56.000000000 +0100 -@@ -251,10 +251,10 @@ static struct kobj_type uids_ktype = { - * - * See Documentation/scheduler/sched-design-CFS.txt for ramifications. - */ --static int uids_user_create(struct user_struct *up) -+static int uids_user_create(struct user_namespace *ns, struct user_struct *up) - { - struct kobject *kobj = &up->kobj; -- int error; -+ int error = 0; - - memset(kobj, 0, sizeof(struct kobject)); - if (up->user_ns != &init_user_ns) -@@ -282,7 +282,7 @@ int __init uids_sysfs_init(void) - if (!uids_kset) - return -ENOMEM; - -- return uids_user_create(&root_user); -+ return uids_user_create(NULL, &root_user); - } - - /* delayed work function to remove sysfs directory for a user and free up -@@ -353,7 +353,8 @@ static struct user_struct *uid_hash_find - } - - int uids_sysfs_init(void) { return 0; } --static inline int uids_user_create(struct user_struct *up) { return 0; } -+static inline int uids_user_create(struct user_namespace *ns, -+ struct user_struct *up) { return 0; } - static inline void uids_mutex_lock(void) { } - static inline void uids_mutex_unlock(void) { } - -@@ -450,7 +451,7 @@ struct user_struct *alloc_uid(struct use - - new->user_ns = get_user_ns(ns); - -- if (uids_user_create(new)) -+ if (uids_user_create(ns, new)) - goto out_destoy_sched; - - /* -diff -NurpP --minimal linux-2.6.32.1/kernel/user_namespace.c linux-2.6.32.1-vs2.3.0.36.27/kernel/user_namespace.c ---- linux-2.6.32.1/kernel/user_namespace.c 2009-03-24 14:22:45.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/kernel/user_namespace.c 2009-12-03 20:04:56.000000000 +0100 -@@ -10,6 +10,7 @@ - #include - #include - #include -+#include - - /* - * Create a new user namespace, deriving the creator from the user in the -@@ -30,6 +31,7 @@ int create_user_ns(struct cred *new) - return -ENOMEM; - - kref_init(&ns->kref); -+ atomic_inc(&vs_global_user_ns); - - for (n = 0; n < UIDHASH_SZ; ++n) - INIT_HLIST_HEAD(ns->uidhash_table + n); -@@ -78,6 +80,8 @@ void free_user_ns(struct kref *kref) - struct user_namespace *ns = - container_of(kref, struct user_namespace, kref); - -+ /* FIXME: maybe move into destroyer? */ -+ atomic_dec(&vs_global_user_ns); - INIT_WORK(&ns->destroyer, free_user_ns_work); - schedule_work(&ns->destroyer); - } -diff -NurpP --minimal linux-2.6.32.1/kernel/utsname.c linux-2.6.32.1-vs2.3.0.36.27/kernel/utsname.c ---- linux-2.6.32.1/kernel/utsname.c 2009-09-10 15:26:28.000000000 +0200 -+++ linux-2.6.32.1-vs2.3.0.36.27/kernel/utsname.c 2009-12-03 20:04:56.000000000 +0100 -@@ -14,14 +14,17 @@ - #include - #include - #include -+#include - - static struct uts_namespace *create_uts_ns(void) - { - struct uts_namespace *uts_ns; - - uts_ns = kmalloc(sizeof(struct uts_namespace), GFP_KERNEL); -- if (uts_ns) -+ if (uts_ns) { - kref_init(&uts_ns->kref); -+ atomic_inc(&vs_global_uts_ns); -+ } - return uts_ns; - } - -@@ -71,5 +74,6 @@ void free_uts_ns(struct kref *kref) - struct uts_namespace *ns; - - ns = container_of(kref, struct uts_namespace, kref); -+ atomic_dec(&vs_global_uts_ns); - kfree(ns); - } -diff -NurpP --minimal linux-2.6.32.1/kernel/vserver/cacct.c linux-2.6.32.1-vs2.3.0.36.27/kernel/vserver/cacct.c ---- linux-2.6.32.1/kernel/vserver/cacct.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/kernel/vserver/cacct.c 2009-12-03 20:04:56.000000000 +0100 -@@ -0,0 +1,42 @@ -+/* -+ * linux/kernel/vserver/cacct.c -+ * -+ * Virtual Server: Context Accounting -+ * -+ * Copyright (C) 2006-2007 Herbert Pötzl -+ * -+ * V0.01 added accounting stats -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+ -+int vc_sock_stat(struct vx_info *vxi, void __user *data) -+{ -+ struct vcmd_sock_stat_v0 vc_data; -+ int j, field; -+ -+ if (copy_from_user(&vc_data, data, sizeof(vc_data))) -+ return -EFAULT; -+ -+ field = vc_data.field; -+ if ((field < 0) || (field >= VXA_SOCK_SIZE)) -+ return -EINVAL; -+ -+ for (j = 0; j < 3; j++) { -+ vc_data.count[j] = vx_sock_count(&vxi->cacct, field, j); -+ vc_data.total[j] = vx_sock_total(&vxi->cacct, field, j); -+ } -+ -+ if (copy_to_user(data, &vc_data, sizeof(vc_data))) -+ return -EFAULT; -+ return 0; -+} -+ -diff -NurpP --minimal linux-2.6.32.1/kernel/vserver/cacct_init.h linux-2.6.32.1-vs2.3.0.36.27/kernel/vserver/cacct_init.h ---- linux-2.6.32.1/kernel/vserver/cacct_init.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/kernel/vserver/cacct_init.h 2009-12-03 20:04:56.000000000 +0100 -@@ -0,0 +1,25 @@ -+ -+ -+static inline void vx_info_init_cacct(struct _vx_cacct *cacct) -+{ -+ int i, j; -+ -+ -+ for (i = 0; i < VXA_SOCK_SIZE; i++) { -+ for (j = 0; j < 3; j++) { -+ atomic_long_set(&cacct->sock[i][j].count, 0); -+ atomic_long_set(&cacct->sock[i][j].total, 0); -+ } -+ } -+ for (i = 0; i < 8; i++) -+ atomic_set(&cacct->slab[i], 0); -+ for (i = 0; i < 5; i++) -+ for (j = 0; j < 4; j++) -+ atomic_set(&cacct->page[i][j], 0); -+} -+ -+static inline void vx_info_exit_cacct(struct _vx_cacct *cacct) -+{ -+ return; -+} -+ -diff -NurpP --minimal linux-2.6.32.1/kernel/vserver/cacct_proc.h linux-2.6.32.1-vs2.3.0.36.27/kernel/vserver/cacct_proc.h ---- linux-2.6.32.1/kernel/vserver/cacct_proc.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/kernel/vserver/cacct_proc.h 2009-12-03 20:04:56.000000000 +0100 -@@ -0,0 +1,53 @@ -+#ifndef _VX_CACCT_PROC_H -+#define _VX_CACCT_PROC_H -+ -+#include -+ -+ -+#define VX_SOCKA_TOP \ -+ "Type\t recv #/bytes\t\t send #/bytes\t\t fail #/bytes\n" -+ -+static inline int vx_info_proc_cacct(struct _vx_cacct *cacct, char *buffer) -+{ -+ int i, j, length = 0; -+ static char *type[VXA_SOCK_SIZE] = { -+ "UNSPEC", "UNIX", "INET", "INET6", "PACKET", "OTHER" -+ }; -+ -+ length += sprintf(buffer + length, VX_SOCKA_TOP); -+ for (i = 0; i < VXA_SOCK_SIZE; i++) { -+ length += sprintf(buffer + length, "%s:", type[i]); -+ for (j = 0; j < 3; j++) { -+ length += sprintf(buffer + length, -+ "\t%10lu/%-10lu", -+ vx_sock_count(cacct, i, j), -+ vx_sock_total(cacct, i, j)); -+ } -+ buffer[length++] = '\n'; -+ } -+ -+ length += sprintf(buffer + length, "\n"); -+ length += sprintf(buffer + length, -+ "slab:\t %8u %8u %8u %8u\n", -+ atomic_read(&cacct->slab[1]), -+ atomic_read(&cacct->slab[4]), -+ atomic_read(&cacct->slab[0]), -+ atomic_read(&cacct->slab[2])); -+ -+ length += sprintf(buffer + length, "\n"); -+ for (i = 0; i < 5; i++) { -+ length += sprintf(buffer + length, -+ "page[%d]: %8u %8u %8u %8u\t %8u %8u %8u %8u\n", i, -+ atomic_read(&cacct->page[i][0]), -+ atomic_read(&cacct->page[i][1]), -+ atomic_read(&cacct->page[i][2]), -+ atomic_read(&cacct->page[i][3]), -+ atomic_read(&cacct->page[i][4]), -+ atomic_read(&cacct->page[i][5]), -+ atomic_read(&cacct->page[i][6]), -+ atomic_read(&cacct->page[i][7])); -+ } -+ return length; -+} -+ -+#endif /* _VX_CACCT_PROC_H */ -diff -NurpP --minimal linux-2.6.32.1/kernel/vserver/context.c linux-2.6.32.1-vs2.3.0.36.27/kernel/vserver/context.c ---- linux-2.6.32.1/kernel/vserver/context.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/kernel/vserver/context.c 2009-12-03 20:04:56.000000000 +0100 -@@ -0,0 +1,1057 @@ -+/* -+ * linux/kernel/vserver/context.c -+ * -+ * Virtual Server: Context Support -+ * -+ * Copyright (C) 2003-2007 Herbert Pötzl -+ * -+ * V0.01 context helper -+ * V0.02 vx_ctx_kill syscall command -+ * V0.03 replaced context_info calls -+ * V0.04 redesign of struct (de)alloc -+ * V0.05 rlimit basic implementation -+ * V0.06 task_xid and info commands -+ * V0.07 context flags and caps -+ * V0.08 switch to RCU based hash -+ * V0.09 revert to non RCU for now -+ * V0.10 and back to working RCU hash -+ * V0.11 and back to locking again -+ * V0.12 referenced context store -+ * V0.13 separate per cpu data -+ * V0.14 changed vcmds to vxi arg -+ * V0.15 added context stat -+ * V0.16 have __create claim() the vxi -+ * V0.17 removed older and legacy stuff -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+ -+#include "cvirt_init.h" -+#include "cacct_init.h" -+#include "limit_init.h" -+#include "sched_init.h" -+ -+ -+atomic_t vx_global_ctotal = ATOMIC_INIT(0); -+atomic_t vx_global_cactive = ATOMIC_INIT(0); -+ -+ -+/* now inactive context structures */ -+ -+static struct hlist_head vx_info_inactive = HLIST_HEAD_INIT; -+ -+static spinlock_t vx_info_inactive_lock = SPIN_LOCK_UNLOCKED; -+ -+ -+/* __alloc_vx_info() -+ -+ * allocate an initialized vx_info struct -+ * doesn't make it visible (hash) */ -+ -+static struct vx_info *__alloc_vx_info(xid_t xid) -+{ -+ struct vx_info *new = NULL; -+ int cpu, index; -+ -+ vxdprintk(VXD_CBIT(xid, 0), "alloc_vx_info(%d)*", xid); -+ -+ /* would this benefit from a slab cache? */ -+ new = kmalloc(sizeof(struct vx_info), GFP_KERNEL); -+ if (!new) -+ return 0; -+ -+ memset(new, 0, sizeof(struct vx_info)); -+#ifdef CONFIG_SMP -+ new->ptr_pc = alloc_percpu(struct _vx_info_pc); -+ if (!new->ptr_pc) -+ goto error; -+#endif -+ new->vx_id = xid; -+ INIT_HLIST_NODE(&new->vx_hlist); -+ atomic_set(&new->vx_usecnt, 0); -+ atomic_set(&new->vx_tasks, 0); -+ new->vx_parent = NULL; -+ new->vx_state = 0; -+ init_waitqueue_head(&new->vx_wait); -+ -+ /* prepare reaper */ -+ get_task_struct(init_pid_ns.child_reaper); -+ new->vx_reaper = init_pid_ns.child_reaper; -+ new->vx_badness_bias = 0; -+ -+ /* rest of init goes here */ -+ vx_info_init_limit(&new->limit); -+ vx_info_init_sched(&new->sched); -+ vx_info_init_cvirt(&new->cvirt); -+ vx_info_init_cacct(&new->cacct); -+ -+ /* per cpu data structures */ -+ for_each_possible_cpu(cpu) { -+ vx_info_init_sched_pc( -+ &vx_per_cpu(new, sched_pc, cpu), cpu); -+ vx_info_init_cvirt_pc( -+ &vx_per_cpu(new, cvirt_pc, cpu), cpu); -+ } -+ -+ new->vx_flags = VXF_INIT_SET; -+ cap_set_init_eff(new->vx_bcaps); -+ new->vx_ccaps = 0; -+ new->vx_umask = 0; -+ -+ new->reboot_cmd = 0; -+ new->exit_code = 0; -+ -+ // preconfig fs entries -+ for (index = 0; index < VX_SPACES; index++) { -+ write_lock(&init_fs.lock); -+ init_fs.users++; -+ write_unlock(&init_fs.lock); -+ new->vx_fs[index] = &init_fs; -+ } -+ -+ vxdprintk(VXD_CBIT(xid, 0), -+ "alloc_vx_info(%d) = %p", xid, new); -+ vxh_alloc_vx_info(new); -+ atomic_inc(&vx_global_ctotal); -+ return new; -+#ifdef CONFIG_SMP -+error: -+ kfree(new); -+ return 0; -+#endif -+} -+ -+/* __dealloc_vx_info() -+ -+ * final disposal of vx_info */ -+ -+static void __dealloc_vx_info(struct vx_info *vxi) -+{ -+ struct vx_info_save vxis; -+ int cpu; -+ -+ vxdprintk(VXD_CBIT(xid, 0), -+ "dealloc_vx_info(%p)", vxi); -+ vxh_dealloc_vx_info(vxi); -+ -+#ifdef CONFIG_VSERVER_WARN -+ enter_vx_info(vxi, &vxis); -+ vx_info_exit_limit(&vxi->limit); -+ vx_info_exit_sched(&vxi->sched); -+ vx_info_exit_cvirt(&vxi->cvirt); -+ vx_info_exit_cacct(&vxi->cacct); -+ -+ for_each_possible_cpu(cpu) { -+ vx_info_exit_sched_pc( -+ &vx_per_cpu(vxi, sched_pc, cpu), cpu); -+ vx_info_exit_cvirt_pc( -+ &vx_per_cpu(vxi, cvirt_pc, cpu), cpu); -+ } -+ leave_vx_info(&vxis); -+#endif -+ -+ vxi->vx_id = -1; -+ vxi->vx_state |= VXS_RELEASED; -+ -+#ifdef CONFIG_SMP -+ free_percpu(vxi->ptr_pc); -+#endif -+ kfree(vxi); -+ atomic_dec(&vx_global_ctotal); -+} -+ -+static void __shutdown_vx_info(struct vx_info *vxi) -+{ -+ struct nsproxy *nsproxy; -+ struct fs_struct *fs; -+ int index, kill; -+ -+ might_sleep(); -+ -+ vxi->vx_state |= VXS_SHUTDOWN; -+ vs_state_change(vxi, VSC_SHUTDOWN); -+ -+ for (index = 0; index < VX_SPACES; index++) { -+ nsproxy = xchg(&vxi->vx_nsproxy[index], NULL); -+ if (nsproxy) -+ put_nsproxy(nsproxy); -+ -+ fs = xchg(&vxi->vx_fs[index], NULL); -+ write_lock(&fs->lock); -+ kill = !--fs->users; -+ write_unlock(&fs->lock); -+ if (kill) -+ free_fs_struct(fs); -+ } -+} -+ -+/* exported stuff */ -+ -+void free_vx_info(struct vx_info *vxi) -+{ -+ unsigned long flags; -+ unsigned index; -+ -+ /* check for reference counts first */ -+ BUG_ON(atomic_read(&vxi->vx_usecnt)); -+ BUG_ON(atomic_read(&vxi->vx_tasks)); -+ -+ /* context must not be hashed */ -+ BUG_ON(vx_info_state(vxi, VXS_HASHED)); -+ -+ /* context shutdown is mandatory */ -+ BUG_ON(!vx_info_state(vxi, VXS_SHUTDOWN)); -+ -+ /* nsproxy and fs check */ -+ for (index = 0; index < VX_SPACES; index++) { -+ BUG_ON(vxi->vx_nsproxy[index]); -+ BUG_ON(vxi->vx_fs[index]); -+ } -+ -+ spin_lock_irqsave(&vx_info_inactive_lock, flags); -+ hlist_del(&vxi->vx_hlist); -+ spin_unlock_irqrestore(&vx_info_inactive_lock, flags); -+ -+ __dealloc_vx_info(vxi); -+} -+ -+ -+/* hash table for vx_info hash */ -+ -+#define VX_HASH_SIZE 13 -+ -+static struct hlist_head vx_info_hash[VX_HASH_SIZE] = -+ { [0 ... VX_HASH_SIZE-1] = HLIST_HEAD_INIT }; -+ -+static spinlock_t vx_info_hash_lock = SPIN_LOCK_UNLOCKED; -+ -+ -+static inline unsigned int __hashval(xid_t xid) -+{ -+ return (xid % VX_HASH_SIZE); -+} -+ -+ -+ -+/* __hash_vx_info() -+ -+ * add the vxi to the global hash table -+ * requires the hash_lock to be held */ -+ -+static inline void __hash_vx_info(struct vx_info *vxi) -+{ -+ struct hlist_head *head; -+ -+ vxd_assert_lock(&vx_info_hash_lock); -+ vxdprintk(VXD_CBIT(xid, 4), -+ "__hash_vx_info: %p[#%d]", vxi, vxi->vx_id); -+ vxh_hash_vx_info(vxi); -+ -+ /* context must not be hashed */ -+ BUG_ON(vx_info_state(vxi, VXS_HASHED)); -+ -+ vxi->vx_state |= VXS_HASHED; -+ head = &vx_info_hash[__hashval(vxi->vx_id)]; -+ hlist_add_head(&vxi->vx_hlist, head); -+ atomic_inc(&vx_global_cactive); -+} -+ -+/* __unhash_vx_info() -+ -+ * remove the vxi from the global hash table -+ * requires the hash_lock to be held */ -+ -+static inline void __unhash_vx_info(struct vx_info *vxi) -+{ -+ unsigned long flags; -+ -+ vxd_assert_lock(&vx_info_hash_lock); -+ vxdprintk(VXD_CBIT(xid, 4), -+ "__unhash_vx_info: %p[#%d.%d.%d]", vxi, vxi->vx_id, -+ atomic_read(&vxi->vx_usecnt), atomic_read(&vxi->vx_tasks)); -+ vxh_unhash_vx_info(vxi); -+ -+ /* context must be hashed */ -+ BUG_ON(!vx_info_state(vxi, VXS_HASHED)); -+ /* but without tasks */ -+ BUG_ON(atomic_read(&vxi->vx_tasks)); -+ -+ vxi->vx_state &= ~VXS_HASHED; -+ hlist_del_init(&vxi->vx_hlist); -+ spin_lock_irqsave(&vx_info_inactive_lock, flags); -+ hlist_add_head(&vxi->vx_hlist, &vx_info_inactive); -+ spin_unlock_irqrestore(&vx_info_inactive_lock, flags); -+ atomic_dec(&vx_global_cactive); -+} -+ -+ -+/* __lookup_vx_info() -+ -+ * requires the hash_lock to be held -+ * doesn't increment the vx_refcnt */ -+ -+static inline struct vx_info *__lookup_vx_info(xid_t xid) -+{ -+ struct hlist_head *head = &vx_info_hash[__hashval(xid)]; -+ struct hlist_node *pos; -+ struct vx_info *vxi; -+ -+ vxd_assert_lock(&vx_info_hash_lock); -+ hlist_for_each(pos, head) { -+ vxi = hlist_entry(pos, struct vx_info, vx_hlist); -+ -+ if (vxi->vx_id == xid) -+ goto found; -+ } -+ vxi = NULL; -+found: -+ vxdprintk(VXD_CBIT(xid, 0), -+ "__lookup_vx_info(#%u): %p[#%u]", -+ xid, vxi, vxi ? vxi->vx_id : 0); -+ vxh_lookup_vx_info(vxi, xid); -+ return vxi; -+} -+ -+ -+/* __create_vx_info() -+ -+ * create the requested context -+ * get(), claim() and hash it */ -+ -+static struct vx_info *__create_vx_info(int id) -+{ -+ struct vx_info *new, *vxi = NULL; -+ -+ vxdprintk(VXD_CBIT(xid, 1), "create_vx_info(%d)*", id); -+ -+ if (!(new = __alloc_vx_info(id))) -+ return ERR_PTR(-ENOMEM); -+ -+ /* required to make dynamic xids unique */ -+ spin_lock(&vx_info_hash_lock); -+ -+ /* static context requested */ -+ if ((vxi = __lookup_vx_info(id))) { -+ vxdprintk(VXD_CBIT(xid, 0), -+ "create_vx_info(%d) = %p (already there)", id, vxi); -+ if (vx_info_flags(vxi, VXF_STATE_SETUP, 0)) -+ vxi = ERR_PTR(-EBUSY); -+ else -+ vxi = ERR_PTR(-EEXIST); -+ goto out_unlock; -+ } -+ /* new context */ -+ vxdprintk(VXD_CBIT(xid, 0), -+ "create_vx_info(%d) = %p (new)", id, new); -+ claim_vx_info(new, NULL); -+ __hash_vx_info(get_vx_info(new)); -+ vxi = new, new = NULL; -+ -+out_unlock: -+ spin_unlock(&vx_info_hash_lock); -+ vxh_create_vx_info(IS_ERR(vxi) ? NULL : vxi, id); -+ if (new) -+ __dealloc_vx_info(new); -+ return vxi; -+} -+ -+ -+/* exported stuff */ -+ -+ -+void unhash_vx_info(struct vx_info *vxi) -+{ -+ __shutdown_vx_info(vxi); -+ spin_lock(&vx_info_hash_lock); -+ __unhash_vx_info(vxi); -+ spin_unlock(&vx_info_hash_lock); -+ __wakeup_vx_info(vxi); -+} -+ -+ -+/* lookup_vx_info() -+ -+ * search for a vx_info and get() it -+ * negative id means current */ -+ -+struct vx_info *lookup_vx_info(int id) -+{ -+ struct vx_info *vxi = NULL; -+ -+ if (id < 0) { -+ vxi = get_vx_info(current_vx_info()); -+ } else if (id > 1) { -+ spin_lock(&vx_info_hash_lock); -+ vxi = get_vx_info(__lookup_vx_info(id)); -+ spin_unlock(&vx_info_hash_lock); -+ } -+ return vxi; -+} -+ -+/* xid_is_hashed() -+ -+ * verify that xid is still hashed */ -+ -+int xid_is_hashed(xid_t xid) -+{ -+ int hashed; -+ -+ spin_lock(&vx_info_hash_lock); -+ hashed = (__lookup_vx_info(xid) != NULL); -+ spin_unlock(&vx_info_hash_lock); -+ return hashed; -+} -+ -+#ifdef CONFIG_PROC_FS -+ -+/* get_xid_list() -+ -+ * get a subset of hashed xids for proc -+ * assumes size is at least one */ -+ -+int get_xid_list(int index, unsigned int *xids, int size) -+{ -+ int hindex, nr_xids = 0; -+ -+ /* only show current and children */ -+ if (!vx_check(0, VS_ADMIN | VS_WATCH)) { -+ if (index > 0) -+ return 0; -+ xids[nr_xids] = vx_current_xid(); -+ return 1; -+ } -+ -+ for (hindex = 0; hindex < VX_HASH_SIZE; hindex++) { -+ struct hlist_head *head = &vx_info_hash[hindex]; -+ struct hlist_node *pos; -+ -+ spin_lock(&vx_info_hash_lock); -+ hlist_for_each(pos, head) { -+ struct vx_info *vxi; -+ -+ if (--index > 0) -+ continue; -+ -+ vxi = hlist_entry(pos, struct vx_info, vx_hlist); -+ xids[nr_xids] = vxi->vx_id; -+ if (++nr_xids >= size) { -+ spin_unlock(&vx_info_hash_lock); -+ goto out; -+ } -+ } -+ /* keep the lock time short */ -+ spin_unlock(&vx_info_hash_lock); -+ } -+out: -+ return nr_xids; -+} -+#endif -+ -+#ifdef CONFIG_VSERVER_DEBUG -+ -+void dump_vx_info_inactive(int level) -+{ -+ struct hlist_node *entry, *next; -+ -+ hlist_for_each_safe(entry, next, &vx_info_inactive) { -+ struct vx_info *vxi = -+ list_entry(entry, struct vx_info, vx_hlist); -+ -+ dump_vx_info(vxi, level); -+ } -+} -+ -+#endif -+ -+#if 0 -+int vx_migrate_user(struct task_struct *p, struct vx_info *vxi) -+{ -+ struct user_struct *new_user, *old_user; -+ -+ if (!p || !vxi) -+ BUG(); -+ -+ if (vx_info_flags(vxi, VXF_INFO_PRIVATE, 0)) -+ return -EACCES; -+ -+ new_user = alloc_uid(vxi->vx_id, p->uid); -+ if (!new_user) -+ return -ENOMEM; -+ -+ old_user = p->user; -+ if (new_user != old_user) { -+ atomic_inc(&new_user->processes); -+ atomic_dec(&old_user->processes); -+ p->user = new_user; -+ } -+ free_uid(old_user); -+ return 0; -+} -+#endif -+ -+#if 0 -+void vx_mask_cap_bset(struct vx_info *vxi, struct task_struct *p) -+{ -+ // p->cap_effective &= vxi->vx_cap_bset; -+ p->cap_effective = -+ cap_intersect(p->cap_effective, vxi->cap_bset); -+ // p->cap_inheritable &= vxi->vx_cap_bset; -+ p->cap_inheritable = -+ cap_intersect(p->cap_inheritable, vxi->cap_bset); -+ // p->cap_permitted &= vxi->vx_cap_bset; -+ p->cap_permitted = -+ cap_intersect(p->cap_permitted, vxi->cap_bset); -+} -+#endif -+ -+ -+#include -+#include -+ -+static int vx_openfd_task(struct task_struct *tsk) -+{ -+ struct files_struct *files = tsk->files; -+ struct fdtable *fdt; -+ const unsigned long *bptr; -+ int count, total; -+ -+ /* no rcu_read_lock() because of spin_lock() */ -+ spin_lock(&files->file_lock); -+ fdt = files_fdtable(files); -+ bptr = fdt->open_fds->fds_bits; -+ count = fdt->max_fds / (sizeof(unsigned long) * 8); -+ for (total = 0; count > 0; count--) { -+ if (*bptr) -+ total += hweight_long(*bptr); -+ bptr++; -+ } -+ spin_unlock(&files->file_lock); -+ return total; -+} -+ -+ -+/* for *space compatibility */ -+ -+asmlinkage long sys_unshare(unsigned long); -+ -+/* -+ * migrate task to new context -+ * gets vxi, puts old_vxi on change -+ * optionally unshares namespaces (hack) -+ */ -+ -+int vx_migrate_task(struct task_struct *p, struct vx_info *vxi, int unshare) -+{ -+ struct vx_info *old_vxi; -+ int ret = 0; -+ -+ if (!p || !vxi) -+ BUG(); -+ -+ vxdprintk(VXD_CBIT(xid, 5), -+ "vx_migrate_task(%p,%p[#%d.%d])", p, vxi, -+ vxi->vx_id, atomic_read(&vxi->vx_usecnt)); -+ -+ if (vx_info_flags(vxi, VXF_INFO_PRIVATE, 0) && -+ !vx_info_flags(vxi, VXF_STATE_SETUP, 0)) -+ return -EACCES; -+ -+ if (vx_info_state(vxi, VXS_SHUTDOWN)) -+ return -EFAULT; -+ -+ old_vxi = task_get_vx_info(p); -+ if (old_vxi == vxi) -+ goto out; -+ -+// if (!(ret = vx_migrate_user(p, vxi))) { -+ { -+ int openfd; -+ -+ task_lock(p); -+ openfd = vx_openfd_task(p); -+ -+ if (old_vxi) { -+ atomic_dec(&old_vxi->cvirt.nr_threads); -+ atomic_dec(&old_vxi->cvirt.nr_running); -+ __rlim_dec(&old_vxi->limit, RLIMIT_NPROC); -+ /* FIXME: what about the struct files here? */ -+ __rlim_sub(&old_vxi->limit, VLIMIT_OPENFD, openfd); -+ /* account for the executable */ -+ __rlim_dec(&old_vxi->limit, VLIMIT_DENTRY); -+ } -+ atomic_inc(&vxi->cvirt.nr_threads); -+ atomic_inc(&vxi->cvirt.nr_running); -+ __rlim_inc(&vxi->limit, RLIMIT_NPROC); -+ /* FIXME: what about the struct files here? */ -+ __rlim_add(&vxi->limit, VLIMIT_OPENFD, openfd); -+ /* account for the executable */ -+ __rlim_inc(&vxi->limit, VLIMIT_DENTRY); -+ -+ if (old_vxi) { -+ release_vx_info(old_vxi, p); -+ clr_vx_info(&p->vx_info); -+ } -+ claim_vx_info(vxi, p); -+ set_vx_info(&p->vx_info, vxi); -+ p->xid = vxi->vx_id; -+ -+ vxdprintk(VXD_CBIT(xid, 5), -+ "moved task %p into vxi:%p[#%d]", -+ p, vxi, vxi->vx_id); -+ -+ // vx_mask_cap_bset(vxi, p); -+ task_unlock(p); -+ -+ /* hack for *spaces to provide compatibility */ -+ if (unshare) { -+ struct nsproxy *old_nsp, *new_nsp; -+ -+ ret = unshare_nsproxy_namespaces( -+ CLONE_NEWUTS | CLONE_NEWIPC | CLONE_NEWUSER, -+ &new_nsp, NULL); -+ if (ret) -+ goto out; -+ -+ old_nsp = xchg(&p->nsproxy, new_nsp); -+ vx_set_space(vxi, -+ CLONE_NEWUTS | CLONE_NEWIPC | CLONE_NEWUSER, 0); -+ put_nsproxy(old_nsp); -+ } -+ } -+out: -+ put_vx_info(old_vxi); -+ return ret; -+} -+ -+int vx_set_reaper(struct vx_info *vxi, struct task_struct *p) -+{ -+ struct task_struct *old_reaper; -+ -+ if (!vxi) -+ return -EINVAL; -+ -+ vxdprintk(VXD_CBIT(xid, 6), -+ "vx_set_reaper(%p[#%d],%p[#%d,%d])", -+ vxi, vxi->vx_id, p, p->xid, p->pid); -+ -+ old_reaper = vxi->vx_reaper; -+ if (old_reaper == p) -+ return 0; -+ -+ /* set new child reaper */ -+ get_task_struct(p); -+ vxi->vx_reaper = p; -+ put_task_struct(old_reaper); -+ return 0; -+} -+ -+int vx_set_init(struct vx_info *vxi, struct task_struct *p) -+{ -+ if (!vxi) -+ return -EINVAL; -+ -+ vxdprintk(VXD_CBIT(xid, 6), -+ "vx_set_init(%p[#%d],%p[#%d,%d,%d])", -+ vxi, vxi->vx_id, p, p->xid, p->pid, p->tgid); -+ -+ vxi->vx_flags &= ~VXF_STATE_INIT; -+ // vxi->vx_initpid = p->tgid; -+ vxi->vx_initpid = p->pid; -+ return 0; -+} -+ -+void vx_exit_init(struct vx_info *vxi, struct task_struct *p, int code) -+{ -+ vxdprintk(VXD_CBIT(xid, 6), -+ "vx_exit_init(%p[#%d],%p[#%d,%d,%d])", -+ vxi, vxi->vx_id, p, p->xid, p->pid, p->tgid); -+ -+ vxi->exit_code = code; -+ vxi->vx_initpid = 0; -+} -+ -+ -+void vx_set_persistent(struct vx_info *vxi) -+{ -+ vxdprintk(VXD_CBIT(xid, 6), -+ "vx_set_persistent(%p[#%d])", vxi, vxi->vx_id); -+ -+ get_vx_info(vxi); -+ claim_vx_info(vxi, NULL); -+} -+ -+void vx_clear_persistent(struct vx_info *vxi) -+{ -+ vxdprintk(VXD_CBIT(xid, 6), -+ "vx_clear_persistent(%p[#%d])", vxi, vxi->vx_id); -+ -+ release_vx_info(vxi, NULL); -+ put_vx_info(vxi); -+} -+ -+void vx_update_persistent(struct vx_info *vxi) -+{ -+ if (vx_info_flags(vxi, VXF_PERSISTENT, 0)) -+ vx_set_persistent(vxi); -+ else -+ vx_clear_persistent(vxi); -+} -+ -+ -+/* task must be current or locked */ -+ -+void exit_vx_info(struct task_struct *p, int code) -+{ -+ struct vx_info *vxi = p->vx_info; -+ -+ if (vxi) { -+ atomic_dec(&vxi->cvirt.nr_threads); -+ vx_nproc_dec(p); -+ -+ vxi->exit_code = code; -+ release_vx_info(vxi, p); -+ } -+} -+ -+void exit_vx_info_early(struct task_struct *p, int code) -+{ -+ struct vx_info *vxi = p->vx_info; -+ -+ if (vxi) { -+ if (vxi->vx_initpid == p->pid) -+ vx_exit_init(vxi, p, code); -+ if (vxi->vx_reaper == p) -+ vx_set_reaper(vxi, init_pid_ns.child_reaper); -+ } -+} -+ -+ -+/* vserver syscall commands below here */ -+ -+/* taks xid and vx_info functions */ -+ -+#include -+ -+ -+int vc_task_xid(uint32_t id) -+{ -+ xid_t xid; -+ -+ if (id) { -+ struct task_struct *tsk; -+ -+ read_lock(&tasklist_lock); -+ tsk = find_task_by_real_pid(id); -+ xid = (tsk) ? tsk->xid : -ESRCH; -+ read_unlock(&tasklist_lock); -+ } else -+ xid = vx_current_xid(); -+ return xid; -+} -+ -+ -+int vc_vx_info(struct vx_info *vxi, void __user *data) -+{ -+ struct vcmd_vx_info_v0 vc_data; -+ -+ vc_data.xid = vxi->vx_id; -+ vc_data.initpid = vxi->vx_initpid; -+ -+ if (copy_to_user(data, &vc_data, sizeof(vc_data))) -+ return -EFAULT; -+ return 0; -+} -+ -+ -+int vc_ctx_stat(struct vx_info *vxi, void __user *data) -+{ -+ struct vcmd_ctx_stat_v0 vc_data; -+ -+ vc_data.usecnt = atomic_read(&vxi->vx_usecnt); -+ vc_data.tasks = atomic_read(&vxi->vx_tasks); -+ -+ if (copy_to_user(data, &vc_data, sizeof(vc_data))) -+ return -EFAULT; -+ return 0; -+} -+ -+ -+/* context functions */ -+ -+int vc_ctx_create(uint32_t xid, void __user *data) -+{ -+ struct vcmd_ctx_create vc_data = { .flagword = VXF_INIT_SET }; -+ struct vx_info *new_vxi; -+ int ret; -+ -+ if (data && copy_from_user(&vc_data, data, sizeof(vc_data))) -+ return -EFAULT; -+ -+ if ((xid > MAX_S_CONTEXT) || (xid < 2)) -+ return -EINVAL; -+ -+ new_vxi = __create_vx_info(xid); -+ if (IS_ERR(new_vxi)) -+ return PTR_ERR(new_vxi); -+ -+ /* initial flags */ -+ new_vxi->vx_flags = vc_data.flagword; -+ -+ ret = -ENOEXEC; -+ if (vs_state_change(new_vxi, VSC_STARTUP)) -+ goto out; -+ -+ ret = vx_migrate_task(current, new_vxi, (!data)); -+ if (ret) -+ goto out; -+ -+ /* return context id on success */ -+ ret = new_vxi->vx_id; -+ -+ /* get a reference for persistent contexts */ -+ if ((vc_data.flagword & VXF_PERSISTENT)) -+ vx_set_persistent(new_vxi); -+out: -+ release_vx_info(new_vxi, NULL); -+ put_vx_info(new_vxi); -+ return ret; -+} -+ -+ -+int vc_ctx_migrate(struct vx_info *vxi, void __user *data) -+{ -+ struct vcmd_ctx_migrate vc_data = { .flagword = 0 }; -+ int ret; -+ -+ if (data && copy_from_user(&vc_data, data, sizeof(vc_data))) -+ return -EFAULT; -+ -+ ret = vx_migrate_task(current, vxi, 0); -+ if (ret) -+ return ret; -+ if (vc_data.flagword & VXM_SET_INIT) -+ ret = vx_set_init(vxi, current); -+ if (ret) -+ return ret; -+ if (vc_data.flagword & VXM_SET_REAPER) -+ ret = vx_set_reaper(vxi, current); -+ return ret; -+} -+ -+ -+int vc_get_cflags(struct vx_info *vxi, void __user *data) -+{ -+ struct vcmd_ctx_flags_v0 vc_data; -+ -+ vc_data.flagword = vxi->vx_flags; -+ -+ /* special STATE flag handling */ -+ vc_data.mask = vs_mask_flags(~0ULL, vxi->vx_flags, VXF_ONE_TIME); -+ -+ if (copy_to_user(data, &vc_data, sizeof(vc_data))) -+ return -EFAULT; -+ return 0; -+} -+ -+int vc_set_cflags(struct vx_info *vxi, void __user *data) -+{ -+ struct vcmd_ctx_flags_v0 vc_data; -+ uint64_t mask, trigger; -+ -+ if (copy_from_user(&vc_data, data, sizeof(vc_data))) -+ return -EFAULT; -+ -+ /* special STATE flag handling */ -+ mask = vs_mask_mask(vc_data.mask, vxi->vx_flags, VXF_ONE_TIME); -+ trigger = (mask & vxi->vx_flags) ^ (mask & vc_data.flagword); -+ -+ if (vxi == current_vx_info()) { -+ /* if (trigger & VXF_STATE_SETUP) -+ vx_mask_cap_bset(vxi, current); */ -+ if (trigger & VXF_STATE_INIT) { -+ int ret; -+ -+ ret = vx_set_init(vxi, current); -+ if (ret) -+ return ret; -+ ret = vx_set_reaper(vxi, current); -+ if (ret) -+ return ret; -+ } -+ } -+ -+ vxi->vx_flags = vs_mask_flags(vxi->vx_flags, -+ vc_data.flagword, mask); -+ if (trigger & VXF_PERSISTENT) -+ vx_update_persistent(vxi); -+ -+ return 0; -+} -+ -+ -+static inline uint64_t caps_from_cap_t(kernel_cap_t c) -+{ -+ uint64_t v = c.cap[0] | ((uint64_t)c.cap[1] << 32); -+ -+ // printk("caps_from_cap_t(%08x:%08x) = %016llx\n", c.cap[1], c.cap[0], v); -+ return v; -+} -+ -+static inline kernel_cap_t cap_t_from_caps(uint64_t v) -+{ -+ kernel_cap_t c = __cap_empty_set; -+ -+ c.cap[0] = v & 0xFFFFFFFF; -+ c.cap[1] = (v >> 32) & 0xFFFFFFFF; -+ -+ // printk("cap_t_from_caps(%016llx) = %08x:%08x\n", v, c.cap[1], c.cap[0]); -+ return c; -+} -+ -+ -+static int do_get_caps(struct vx_info *vxi, uint64_t *bcaps, uint64_t *ccaps) -+{ -+ if (bcaps) -+ *bcaps = caps_from_cap_t(vxi->vx_bcaps); -+ if (ccaps) -+ *ccaps = vxi->vx_ccaps; -+ -+ return 0; -+} -+ -+int vc_get_ccaps(struct vx_info *vxi, void __user *data) -+{ -+ struct vcmd_ctx_caps_v1 vc_data; -+ int ret; -+ -+ ret = do_get_caps(vxi, NULL, &vc_data.ccaps); -+ if (ret) -+ return ret; -+ vc_data.cmask = ~0ULL; -+ -+ if (copy_to_user(data, &vc_data, sizeof(vc_data))) -+ return -EFAULT; -+ return 0; -+} -+ -+static int do_set_caps(struct vx_info *vxi, -+ uint64_t bcaps, uint64_t bmask, uint64_t ccaps, uint64_t cmask) -+{ -+ uint64_t bcold = caps_from_cap_t(vxi->vx_bcaps); -+ -+#if 0 -+ printk("do_set_caps(%16llx, %16llx, %16llx, %16llx)\n", -+ bcaps, bmask, ccaps, cmask); -+#endif -+ vxi->vx_bcaps = cap_t_from_caps( -+ vs_mask_flags(bcold, bcaps, bmask)); -+ vxi->vx_ccaps = vs_mask_flags(vxi->vx_ccaps, ccaps, cmask); -+ -+ return 0; -+} -+ -+int vc_set_ccaps(struct vx_info *vxi, void __user *data) -+{ -+ struct vcmd_ctx_caps_v1 vc_data; -+ -+ if (copy_from_user(&vc_data, data, sizeof(vc_data))) -+ return -EFAULT; -+ -+ return do_set_caps(vxi, 0, 0, vc_data.ccaps, vc_data.cmask); -+} -+ -+int vc_get_bcaps(struct vx_info *vxi, void __user *data) -+{ -+ struct vcmd_bcaps vc_data; -+ int ret; -+ -+ ret = do_get_caps(vxi, &vc_data.bcaps, NULL); -+ if (ret) -+ return ret; -+ vc_data.bmask = ~0ULL; -+ -+ if (copy_to_user(data, &vc_data, sizeof(vc_data))) -+ return -EFAULT; -+ return 0; -+} -+ -+int vc_set_bcaps(struct vx_info *vxi, void __user *data) -+{ -+ struct vcmd_bcaps vc_data; -+ -+ if (copy_from_user(&vc_data, data, sizeof(vc_data))) -+ return -EFAULT; -+ -+ return do_set_caps(vxi, vc_data.bcaps, vc_data.bmask, 0, 0); -+} -+ -+ -+int vc_get_umask(struct vx_info *vxi, void __user *data) -+{ -+ struct vcmd_umask vc_data; -+ -+ vc_data.umask = vxi->vx_umask; -+ vc_data.mask = ~0ULL; -+ -+ if (copy_to_user(data, &vc_data, sizeof(vc_data))) -+ return -EFAULT; -+ return 0; -+} -+ -+int vc_set_umask(struct vx_info *vxi, void __user *data) -+{ -+ struct vcmd_umask vc_data; -+ -+ if (copy_from_user(&vc_data, data, sizeof(vc_data))) -+ return -EFAULT; -+ -+ vxi->vx_umask = vs_mask_flags(vxi->vx_umask, -+ vc_data.umask, vc_data.mask); -+ return 0; -+} -+ -+ -+int vc_get_badness(struct vx_info *vxi, void __user *data) -+{ -+ struct vcmd_badness_v0 vc_data; -+ -+ vc_data.bias = vxi->vx_badness_bias; -+ -+ if (copy_to_user(data, &vc_data, sizeof(vc_data))) -+ return -EFAULT; -+ return 0; -+} -+ -+int vc_set_badness(struct vx_info *vxi, void __user *data) -+{ -+ struct vcmd_badness_v0 vc_data; -+ -+ if (copy_from_user(&vc_data, data, sizeof(vc_data))) -+ return -EFAULT; -+ -+ vxi->vx_badness_bias = vc_data.bias; -+ return 0; -+} -+ -+#include -+ -+EXPORT_SYMBOL_GPL(free_vx_info); -+ -diff -NurpP --minimal linux-2.6.32.1/kernel/vserver/cvirt.c linux-2.6.32.1-vs2.3.0.36.27/kernel/vserver/cvirt.c ---- linux-2.6.32.1/kernel/vserver/cvirt.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/kernel/vserver/cvirt.c 2009-12-03 20:04:56.000000000 +0100 -@@ -0,0 +1,304 @@ -+/* -+ * linux/kernel/vserver/cvirt.c -+ * -+ * Virtual Server: Context Virtualization -+ * -+ * Copyright (C) 2004-2007 Herbert Pötzl -+ * -+ * V0.01 broken out from limit.c -+ * V0.02 added utsname stuff -+ * V0.03 changed vcmds to vxi arg -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+ -+void vx_vsi_uptime(struct timespec *uptime, struct timespec *idle) -+{ -+ struct vx_info *vxi = current_vx_info(); -+ -+ set_normalized_timespec(uptime, -+ uptime->tv_sec - vxi->cvirt.bias_uptime.tv_sec, -+ uptime->tv_nsec - vxi->cvirt.bias_uptime.tv_nsec); -+ if (!idle) -+ return; -+ set_normalized_timespec(idle, -+ idle->tv_sec - vxi->cvirt.bias_idle.tv_sec, -+ idle->tv_nsec - vxi->cvirt.bias_idle.tv_nsec); -+ return; -+} -+ -+uint64_t vx_idle_jiffies(void) -+{ -+ return init_task.utime + init_task.stime; -+} -+ -+ -+ -+static inline uint32_t __update_loadavg(uint32_t load, -+ int wsize, int delta, int n) -+{ -+ unsigned long long calc, prev; -+ -+ /* just set it to n */ -+ if (unlikely(delta >= wsize)) -+ return (n << FSHIFT); -+ -+ calc = delta * n; -+ calc <<= FSHIFT; -+ prev = (wsize - delta); -+ prev *= load; -+ calc += prev; -+ do_div(calc, wsize); -+ return calc; -+} -+ -+ -+void vx_update_load(struct vx_info *vxi) -+{ -+ uint32_t now, last, delta; -+ unsigned int nr_running, nr_uninterruptible; -+ unsigned int total; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&vxi->cvirt.load_lock, flags); -+ -+ now = jiffies; -+ last = vxi->cvirt.load_last; -+ delta = now - last; -+ -+ if (delta < 5*HZ) -+ goto out; -+ -+ nr_running = atomic_read(&vxi->cvirt.nr_running); -+ nr_uninterruptible = atomic_read(&vxi->cvirt.nr_uninterruptible); -+ total = nr_running + nr_uninterruptible; -+ -+ vxi->cvirt.load[0] = __update_loadavg(vxi->cvirt.load[0], -+ 60*HZ, delta, total); -+ vxi->cvirt.load[1] = __update_loadavg(vxi->cvirt.load[1], -+ 5*60*HZ, delta, total); -+ vxi->cvirt.load[2] = __update_loadavg(vxi->cvirt.load[2], -+ 15*60*HZ, delta, total); -+ -+ vxi->cvirt.load_last = now; -+out: -+ atomic_inc(&vxi->cvirt.load_updates); -+ spin_unlock_irqrestore(&vxi->cvirt.load_lock, flags); -+} -+ -+ -+/* -+ * Commands to do_syslog: -+ * -+ * 0 -- Close the log. Currently a NOP. -+ * 1 -- Open the log. Currently a NOP. -+ * 2 -- Read from the log. -+ * 3 -- Read all messages remaining in the ring buffer. -+ * 4 -- Read and clear all messages remaining in the ring buffer -+ * 5 -- Clear ring buffer. -+ * 6 -- Disable printk's to console -+ * 7 -- Enable printk's to console -+ * 8 -- Set level of messages printed to console -+ * 9 -- Return number of unread characters in the log buffer -+ * 10 -- Return size of the log buffer -+ */ -+int vx_do_syslog(int type, char __user *buf, int len) -+{ -+ int error = 0; -+ int do_clear = 0; -+ struct vx_info *vxi = current_vx_info(); -+ struct _vx_syslog *log; -+ -+ if (!vxi) -+ return -EINVAL; -+ log = &vxi->cvirt.syslog; -+ -+ switch (type) { -+ case 0: /* Close log */ -+ case 1: /* Open log */ -+ break; -+ case 2: /* Read from log */ -+ error = wait_event_interruptible(log->log_wait, -+ (log->log_start - log->log_end)); -+ if (error) -+ break; -+ spin_lock_irq(&log->logbuf_lock); -+ spin_unlock_irq(&log->logbuf_lock); -+ break; -+ case 4: /* Read/clear last kernel messages */ -+ do_clear = 1; -+ /* fall through */ -+ case 3: /* Read last kernel messages */ -+ return 0; -+ -+ case 5: /* Clear ring buffer */ -+ return 0; -+ -+ case 6: /* Disable logging to console */ -+ case 7: /* Enable logging to console */ -+ case 8: /* Set level of messages printed to console */ -+ break; -+ -+ case 9: /* Number of chars in the log buffer */ -+ return 0; -+ case 10: /* Size of the log buffer */ -+ return 0; -+ default: -+ error = -EINVAL; -+ break; -+ } -+ return error; -+} -+ -+ -+/* virtual host info names */ -+ -+static char *vx_vhi_name(struct vx_info *vxi, int id) -+{ -+ struct nsproxy *nsproxy; -+ struct uts_namespace *uts; -+ -+ if (id == VHIN_CONTEXT) -+ return vxi->vx_name; -+ -+ nsproxy = vxi->vx_nsproxy[0]; -+ if (!nsproxy) -+ return NULL; -+ -+ uts = nsproxy->uts_ns; -+ if (!uts) -+ return NULL; -+ -+ switch (id) { -+ case VHIN_SYSNAME: -+ return uts->name.sysname; -+ case VHIN_NODENAME: -+ return uts->name.nodename; -+ case VHIN_RELEASE: -+ return uts->name.release; -+ case VHIN_VERSION: -+ return uts->name.version; -+ case VHIN_MACHINE: -+ return uts->name.machine; -+ case VHIN_DOMAINNAME: -+ return uts->name.domainname; -+ default: -+ return NULL; -+ } -+ return NULL; -+} -+ -+int vc_set_vhi_name(struct vx_info *vxi, void __user *data) -+{ -+ struct vcmd_vhi_name_v0 vc_data; -+ char *name; -+ -+ if (copy_from_user(&vc_data, data, sizeof(vc_data))) -+ return -EFAULT; -+ -+ name = vx_vhi_name(vxi, vc_data.field); -+ if (!name) -+ return -EINVAL; -+ -+ memcpy(name, vc_data.name, 65); -+ return 0; -+} -+ -+int vc_get_vhi_name(struct vx_info *vxi, void __user *data) -+{ -+ struct vcmd_vhi_name_v0 vc_data; -+ char *name; -+ -+ if (copy_from_user(&vc_data, data, sizeof(vc_data))) -+ return -EFAULT; -+ -+ name = vx_vhi_name(vxi, vc_data.field); -+ if (!name) -+ return -EINVAL; -+ -+ memcpy(vc_data.name, name, 65); -+ if (copy_to_user(data, &vc_data, sizeof(vc_data))) -+ return -EFAULT; -+ return 0; -+} -+ -+ -+int vc_virt_stat(struct vx_info *vxi, void __user *data) -+{ -+ struct vcmd_virt_stat_v0 vc_data; -+ struct _vx_cvirt *cvirt = &vxi->cvirt; -+ struct timespec uptime; -+ -+ do_posix_clock_monotonic_gettime(&uptime); -+ set_normalized_timespec(&uptime, -+ uptime.tv_sec - cvirt->bias_uptime.tv_sec, -+ uptime.tv_nsec - cvirt->bias_uptime.tv_nsec); -+ -+ vc_data.offset = timeval_to_ns(&cvirt->bias_tv); -+ vc_data.uptime = timespec_to_ns(&uptime); -+ vc_data.nr_threads = atomic_read(&cvirt->nr_threads); -+ vc_data.nr_running = atomic_read(&cvirt->nr_running); -+ vc_data.nr_uninterruptible = atomic_read(&cvirt->nr_uninterruptible); -+ vc_data.nr_onhold = atomic_read(&cvirt->nr_onhold); -+ vc_data.nr_forks = atomic_read(&cvirt->total_forks); -+ vc_data.load[0] = cvirt->load[0]; -+ vc_data.load[1] = cvirt->load[1]; -+ vc_data.load[2] = cvirt->load[2]; -+ -+ if (copy_to_user(data, &vc_data, sizeof(vc_data))) -+ return -EFAULT; -+ return 0; -+} -+ -+ -+#ifdef CONFIG_VSERVER_VTIME -+ -+/* virtualized time base */ -+ -+void vx_gettimeofday(struct timeval *tv) -+{ -+ struct vx_info *vxi; -+ -+ do_gettimeofday(tv); -+ if (!vx_flags(VXF_VIRT_TIME, 0)) -+ return; -+ -+ vxi = current_vx_info(); -+ tv->tv_sec += vxi->cvirt.bias_tv.tv_sec; -+ tv->tv_usec += vxi->cvirt.bias_tv.tv_usec; -+ -+ if (tv->tv_usec >= USEC_PER_SEC) { -+ tv->tv_sec++; -+ tv->tv_usec -= USEC_PER_SEC; -+ } else if (tv->tv_usec < 0) { -+ tv->tv_sec--; -+ tv->tv_usec += USEC_PER_SEC; -+ } -+} -+ -+int vx_settimeofday(struct timespec *ts) -+{ -+ struct timeval tv; -+ struct vx_info *vxi; -+ -+ if (!vx_flags(VXF_VIRT_TIME, 0)) -+ return do_settimeofday(ts); -+ -+ do_gettimeofday(&tv); -+ vxi = current_vx_info(); -+ vxi->cvirt.bias_tv.tv_sec = ts->tv_sec - tv.tv_sec; -+ vxi->cvirt.bias_tv.tv_usec = -+ (ts->tv_nsec/NSEC_PER_USEC) - tv.tv_usec; -+ return 0; -+} -+ -+#endif -+ -diff -NurpP --minimal linux-2.6.32.1/kernel/vserver/cvirt_init.h linux-2.6.32.1-vs2.3.0.36.27/kernel/vserver/cvirt_init.h ---- linux-2.6.32.1/kernel/vserver/cvirt_init.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/kernel/vserver/cvirt_init.h 2009-12-03 20:04:56.000000000 +0100 -@@ -0,0 +1,69 @@ -+ -+ -+extern uint64_t vx_idle_jiffies(void); -+ -+static inline void vx_info_init_cvirt(struct _vx_cvirt *cvirt) -+{ -+ uint64_t idle_jiffies = vx_idle_jiffies(); -+ uint64_t nsuptime; -+ -+ do_posix_clock_monotonic_gettime(&cvirt->bias_uptime); -+ nsuptime = (unsigned long long)cvirt->bias_uptime.tv_sec -+ * NSEC_PER_SEC + cvirt->bias_uptime.tv_nsec; -+ cvirt->bias_clock = nsec_to_clock_t(nsuptime); -+ cvirt->bias_tv.tv_sec = 0; -+ cvirt->bias_tv.tv_usec = 0; -+ -+ jiffies_to_timespec(idle_jiffies, &cvirt->bias_idle); -+ atomic_set(&cvirt->nr_threads, 0); -+ atomic_set(&cvirt->nr_running, 0); -+ atomic_set(&cvirt->nr_uninterruptible, 0); -+ atomic_set(&cvirt->nr_onhold, 0); -+ -+ spin_lock_init(&cvirt->load_lock); -+ cvirt->load_last = jiffies; -+ atomic_set(&cvirt->load_updates, 0); -+ cvirt->load[0] = 0; -+ cvirt->load[1] = 0; -+ cvirt->load[2] = 0; -+ atomic_set(&cvirt->total_forks, 0); -+ -+ spin_lock_init(&cvirt->syslog.logbuf_lock); -+ init_waitqueue_head(&cvirt->syslog.log_wait); -+ cvirt->syslog.log_start = 0; -+ cvirt->syslog.log_end = 0; -+ cvirt->syslog.con_start = 0; -+ cvirt->syslog.logged_chars = 0; -+} -+ -+static inline -+void vx_info_init_cvirt_pc(struct _vx_cvirt_pc *cvirt_pc, int cpu) -+{ -+ // cvirt_pc->cpustat = { 0 }; -+} -+ -+static inline void vx_info_exit_cvirt(struct _vx_cvirt *cvirt) -+{ -+ int value; -+ -+ vxwprintk_xid((value = atomic_read(&cvirt->nr_threads)), -+ "!!! cvirt: %p[nr_threads] = %d on exit.", -+ cvirt, value); -+ vxwprintk_xid((value = atomic_read(&cvirt->nr_running)), -+ "!!! cvirt: %p[nr_running] = %d on exit.", -+ cvirt, value); -+ vxwprintk_xid((value = atomic_read(&cvirt->nr_uninterruptible)), -+ "!!! cvirt: %p[nr_uninterruptible] = %d on exit.", -+ cvirt, value); -+ vxwprintk_xid((value = atomic_read(&cvirt->nr_onhold)), -+ "!!! cvirt: %p[nr_onhold] = %d on exit.", -+ cvirt, value); -+ return; -+} -+ -+static inline -+void vx_info_exit_cvirt_pc(struct _vx_cvirt_pc *cvirt_pc, int cpu) -+{ -+ return; -+} -+ -diff -NurpP --minimal linux-2.6.32.1/kernel/vserver/cvirt_proc.h linux-2.6.32.1-vs2.3.0.36.27/kernel/vserver/cvirt_proc.h ---- linux-2.6.32.1/kernel/vserver/cvirt_proc.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/kernel/vserver/cvirt_proc.h 2009-12-03 20:04:56.000000000 +0100 -@@ -0,0 +1,135 @@ -+#ifndef _VX_CVIRT_PROC_H -+#define _VX_CVIRT_PROC_H -+ -+#include -+#include -+#include -+#include -+#include -+ -+ -+static inline -+int vx_info_proc_nsproxy(struct nsproxy *nsproxy, char *buffer) -+{ -+ struct mnt_namespace *ns; -+ struct uts_namespace *uts; -+ struct ipc_namespace *ipc; -+ struct path path; -+ char *pstr, *root; -+ int length = 0; -+ -+ if (!nsproxy) -+ goto out; -+ -+ length += sprintf(buffer + length, -+ "NSProxy:\t%p [%p,%p,%p]\n", -+ nsproxy, nsproxy->mnt_ns, -+ nsproxy->uts_ns, nsproxy->ipc_ns); -+ -+ ns = nsproxy->mnt_ns; -+ if (!ns) -+ goto skip_ns; -+ -+ pstr = kmalloc(PATH_MAX, GFP_KERNEL); -+ if (!pstr) -+ goto skip_ns; -+ -+ path.mnt = ns->root; -+ path.dentry = ns->root->mnt_root; -+ root = d_path(&path, pstr, PATH_MAX - 2); -+ length += sprintf(buffer + length, -+ "Namespace:\t%p [#%u]\n" -+ "RootPath:\t%s\n", -+ ns, atomic_read(&ns->count), -+ root); -+ kfree(pstr); -+skip_ns: -+ -+ uts = nsproxy->uts_ns; -+ if (!uts) -+ goto skip_uts; -+ -+ length += sprintf(buffer + length, -+ "SysName:\t%.*s\n" -+ "NodeName:\t%.*s\n" -+ "Release:\t%.*s\n" -+ "Version:\t%.*s\n" -+ "Machine:\t%.*s\n" -+ "DomainName:\t%.*s\n", -+ __NEW_UTS_LEN, uts->name.sysname, -+ __NEW_UTS_LEN, uts->name.nodename, -+ __NEW_UTS_LEN, uts->name.release, -+ __NEW_UTS_LEN, uts->name.version, -+ __NEW_UTS_LEN, uts->name.machine, -+ __NEW_UTS_LEN, uts->name.domainname); -+skip_uts: -+ -+ ipc = nsproxy->ipc_ns; -+ if (!ipc) -+ goto skip_ipc; -+ -+ length += sprintf(buffer + length, -+ "SEMS:\t\t%d %d %d %d %d\n" -+ "MSG:\t\t%d %d %d\n" -+ "SHM:\t\t%lu %lu %d %d\n", -+ ipc->sem_ctls[0], ipc->sem_ctls[1], -+ ipc->sem_ctls[2], ipc->sem_ctls[3], -+ ipc->used_sems, -+ ipc->msg_ctlmax, ipc->msg_ctlmnb, ipc->msg_ctlmni, -+ (unsigned long)ipc->shm_ctlmax, -+ (unsigned long)ipc->shm_ctlall, -+ ipc->shm_ctlmni, ipc->shm_tot); -+skip_ipc: -+out: -+ return length; -+} -+ -+ -+#include -+ -+#define LOAD_INT(x) ((x) >> FSHIFT) -+#define LOAD_FRAC(x) LOAD_INT(((x) & (FIXED_1 - 1)) * 100) -+ -+static inline -+int vx_info_proc_cvirt(struct _vx_cvirt *cvirt, char *buffer) -+{ -+ int length = 0; -+ int a, b, c; -+ -+ length += sprintf(buffer + length, -+ "BiasUptime:\t%lu.%02lu\n", -+ (unsigned long)cvirt->bias_uptime.tv_sec, -+ (cvirt->bias_uptime.tv_nsec / (NSEC_PER_SEC / 100))); -+ -+ a = cvirt->load[0] + (FIXED_1 / 200); -+ b = cvirt->load[1] + (FIXED_1 / 200); -+ c = cvirt->load[2] + (FIXED_1 / 200); -+ length += sprintf(buffer + length, -+ "nr_threads:\t%d\n" -+ "nr_running:\t%d\n" -+ "nr_unintr:\t%d\n" -+ "nr_onhold:\t%d\n" -+ "load_updates:\t%d\n" -+ "loadavg:\t%d.%02d %d.%02d %d.%02d\n" -+ "total_forks:\t%d\n", -+ atomic_read(&cvirt->nr_threads), -+ atomic_read(&cvirt->nr_running), -+ atomic_read(&cvirt->nr_uninterruptible), -+ atomic_read(&cvirt->nr_onhold), -+ atomic_read(&cvirt->load_updates), -+ LOAD_INT(a), LOAD_FRAC(a), -+ LOAD_INT(b), LOAD_FRAC(b), -+ LOAD_INT(c), LOAD_FRAC(c), -+ atomic_read(&cvirt->total_forks)); -+ return length; -+} -+ -+static inline -+int vx_info_proc_cvirt_pc(struct _vx_cvirt_pc *cvirt_pc, -+ char *buffer, int cpu) -+{ -+ int length = 0; -+ return length; -+} -+ -+#endif /* _VX_CVIRT_PROC_H */ -diff -NurpP --minimal linux-2.6.32.1/kernel/vserver/debug.c linux-2.6.32.1-vs2.3.0.36.27/kernel/vserver/debug.c ---- linux-2.6.32.1/kernel/vserver/debug.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/kernel/vserver/debug.c 2009-12-03 20:04:56.000000000 +0100 -@@ -0,0 +1,32 @@ -+/* -+ * kernel/vserver/debug.c -+ * -+ * Copyright (C) 2005-2007 Herbert Pötzl -+ * -+ * V0.01 vx_info dump support -+ * -+ */ -+ -+#include -+ -+#include -+ -+ -+void dump_vx_info(struct vx_info *vxi, int level) -+{ -+ printk("vx_info %p[#%d, %d.%d, %4x]\n", vxi, vxi->vx_id, -+ atomic_read(&vxi->vx_usecnt), -+ atomic_read(&vxi->vx_tasks), -+ vxi->vx_state); -+ if (level > 0) { -+ __dump_vx_limit(&vxi->limit); -+ __dump_vx_sched(&vxi->sched); -+ __dump_vx_cvirt(&vxi->cvirt); -+ __dump_vx_cacct(&vxi->cacct); -+ } -+ printk("---\n"); -+} -+ -+ -+EXPORT_SYMBOL_GPL(dump_vx_info); -+ -diff -NurpP --minimal linux-2.6.32.1/kernel/vserver/device.c linux-2.6.32.1-vs2.3.0.36.27/kernel/vserver/device.c ---- linux-2.6.32.1/kernel/vserver/device.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/kernel/vserver/device.c 2009-12-03 20:04:56.000000000 +0100 -@@ -0,0 +1,443 @@ -+/* -+ * linux/kernel/vserver/device.c -+ * -+ * Linux-VServer: Device Support -+ * -+ * Copyright (C) 2006 Herbert Pötzl -+ * Copyright (C) 2007 Daniel Hokka Zakrisson -+ * -+ * V0.01 device mapping basics -+ * V0.02 added defaults -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+ -+#define DMAP_HASH_BITS 4 -+ -+ -+struct vs_mapping { -+ union { -+ struct hlist_node hlist; -+ struct list_head list; -+ } u; -+#define dm_hlist u.hlist -+#define dm_list u.list -+ xid_t xid; -+ dev_t device; -+ struct vx_dmap_target target; -+}; -+ -+ -+static struct hlist_head dmap_main_hash[1 << DMAP_HASH_BITS]; -+ -+static spinlock_t dmap_main_hash_lock = SPIN_LOCK_UNLOCKED; -+ -+static struct vx_dmap_target dmap_defaults[2] = { -+ { .flags = DATTR_OPEN }, -+ { .flags = DATTR_OPEN }, -+}; -+ -+ -+struct kmem_cache *dmap_cachep __read_mostly; -+ -+int __init dmap_cache_init(void) -+{ -+ dmap_cachep = kmem_cache_create("dmap_cache", -+ sizeof(struct vs_mapping), 0, -+ SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL); -+ return 0; -+} -+ -+__initcall(dmap_cache_init); -+ -+ -+static inline unsigned int __hashval(dev_t dev, int bits) -+{ -+ return hash_long((unsigned long)dev, bits); -+} -+ -+ -+/* __hash_mapping() -+ * add the mapping to the hash table -+ */ -+static inline void __hash_mapping(struct vx_info *vxi, struct vs_mapping *vdm) -+{ -+ spinlock_t *hash_lock = &dmap_main_hash_lock; -+ struct hlist_head *head, *hash = dmap_main_hash; -+ int device = vdm->device; -+ -+ spin_lock(hash_lock); -+ vxdprintk(VXD_CBIT(misc, 8), "__hash_mapping: %p[#%d] %08x:%08x", -+ vxi, vxi ? vxi->vx_id : 0, device, vdm->target.target); -+ -+ head = &hash[__hashval(device, DMAP_HASH_BITS)]; -+ hlist_add_head(&vdm->dm_hlist, head); -+ spin_unlock(hash_lock); -+} -+ -+ -+static inline int __mode_to_default(umode_t mode) -+{ -+ switch (mode) { -+ case S_IFBLK: -+ return 0; -+ case S_IFCHR: -+ return 1; -+ default: -+ BUG(); -+ } -+} -+ -+ -+/* __set_default() -+ * set a default -+ */ -+static inline void __set_default(struct vx_info *vxi, umode_t mode, -+ struct vx_dmap_target *vdmt) -+{ -+ spinlock_t *hash_lock = &dmap_main_hash_lock; -+ spin_lock(hash_lock); -+ -+ if (vxi) -+ vxi->dmap.targets[__mode_to_default(mode)] = *vdmt; -+ else -+ dmap_defaults[__mode_to_default(mode)] = *vdmt; -+ -+ -+ spin_unlock(hash_lock); -+ -+ vxdprintk(VXD_CBIT(misc, 8), "__set_default: %p[#%u] %08x %04x", -+ vxi, vxi ? vxi->vx_id : 0, vdmt->target, vdmt->flags); -+} -+ -+ -+/* __remove_default() -+ * remove a default -+ */ -+static inline int __remove_default(struct vx_info *vxi, umode_t mode) -+{ -+ spinlock_t *hash_lock = &dmap_main_hash_lock; -+ spin_lock(hash_lock); -+ -+ if (vxi) -+ vxi->dmap.targets[__mode_to_default(mode)].flags = 0; -+ else /* remove == reset */ -+ dmap_defaults[__mode_to_default(mode)].flags = DATTR_OPEN | mode; -+ -+ spin_unlock(hash_lock); -+ return 0; -+} -+ -+ -+/* __find_mapping() -+ * find a mapping in the hash table -+ * -+ * caller must hold hash_lock -+ */ -+static inline int __find_mapping(xid_t xid, dev_t device, umode_t mode, -+ struct vs_mapping **local, struct vs_mapping **global) -+{ -+ struct hlist_head *hash = dmap_main_hash; -+ struct hlist_head *head = &hash[__hashval(device, DMAP_HASH_BITS)]; -+ struct hlist_node *pos; -+ struct vs_mapping *vdm; -+ -+ *local = NULL; -+ if (global) -+ *global = NULL; -+ -+ hlist_for_each(pos, head) { -+ vdm = hlist_entry(pos, struct vs_mapping, dm_hlist); -+ -+ if ((vdm->device == device) && -+ !((vdm->target.flags ^ mode) & S_IFMT)) { -+ if (vdm->xid == xid) { -+ *local = vdm; -+ return 1; -+ } else if (global && vdm->xid == 0) -+ *global = vdm; -+ } -+ } -+ -+ if (global && *global) -+ return 0; -+ else -+ return -ENOENT; -+} -+ -+ -+/* __lookup_mapping() -+ * find a mapping and store the result in target and flags -+ */ -+static inline int __lookup_mapping(struct vx_info *vxi, -+ dev_t device, dev_t *target, int *flags, umode_t mode) -+{ -+ spinlock_t *hash_lock = &dmap_main_hash_lock; -+ struct vs_mapping *vdm, *global; -+ struct vx_dmap_target *vdmt; -+ int ret = 0; -+ xid_t xid = vxi->vx_id; -+ int index; -+ -+ spin_lock(hash_lock); -+ if (__find_mapping(xid, device, mode, &vdm, &global) > 0) { -+ ret = 1; -+ vdmt = &vdm->target; -+ goto found; -+ } -+ -+ index = __mode_to_default(mode); -+ if (vxi && vxi->dmap.targets[index].flags) { -+ ret = 2; -+ vdmt = &vxi->dmap.targets[index]; -+ } else if (global) { -+ ret = 3; -+ vdmt = &global->target; -+ goto found; -+ } else { -+ ret = 4; -+ vdmt = &dmap_defaults[index]; -+ } -+ -+found: -+ if (target && (vdmt->flags & DATTR_REMAP)) -+ *target = vdmt->target; -+ else if (target) -+ *target = device; -+ if (flags) -+ *flags = vdmt->flags; -+ -+ spin_unlock(hash_lock); -+ -+ return ret; -+} -+ -+ -+/* __remove_mapping() -+ * remove a mapping from the hash table -+ */ -+static inline int __remove_mapping(struct vx_info *vxi, dev_t device, -+ umode_t mode) -+{ -+ spinlock_t *hash_lock = &dmap_main_hash_lock; -+ struct vs_mapping *vdm = NULL; -+ int ret = 0; -+ -+ spin_lock(hash_lock); -+ -+ ret = __find_mapping((vxi ? vxi->vx_id : 0), device, mode, &vdm, -+ NULL); -+ vxdprintk(VXD_CBIT(misc, 8), "__remove_mapping: %p[#%d] %08x %04x", -+ vxi, vxi ? vxi->vx_id : 0, device, mode); -+ if (ret < 0) -+ goto out; -+ hlist_del(&vdm->dm_hlist); -+ -+out: -+ spin_unlock(hash_lock); -+ if (vdm) -+ kmem_cache_free(dmap_cachep, vdm); -+ return ret; -+} -+ -+ -+ -+int vs_map_device(struct vx_info *vxi, -+ dev_t device, dev_t *target, umode_t mode) -+{ -+ int ret, flags = DATTR_MASK; -+ -+ if (!vxi) { -+ if (target) -+ *target = device; -+ goto out; -+ } -+ ret = __lookup_mapping(vxi, device, target, &flags, mode); -+ vxdprintk(VXD_CBIT(misc, 8), "vs_map_device: %08x target: %08x flags: %04x mode: %04x mapped=%d", -+ device, target ? *target : 0, flags, mode, ret); -+out: -+ return (flags & DATTR_MASK); -+} -+ -+ -+ -+static int do_set_mapping(struct vx_info *vxi, -+ dev_t device, dev_t target, int flags, umode_t mode) -+{ -+ if (device) { -+ struct vs_mapping *new; -+ -+ new = kmem_cache_alloc(dmap_cachep, GFP_KERNEL); -+ if (!new) -+ return -ENOMEM; -+ -+ INIT_HLIST_NODE(&new->dm_hlist); -+ new->device = device; -+ new->target.target = target; -+ new->target.flags = flags | mode; -+ new->xid = (vxi ? vxi->vx_id : 0); -+ -+ vxdprintk(VXD_CBIT(misc, 8), "do_set_mapping: %08x target: %08x flags: %04x", device, target, flags); -+ __hash_mapping(vxi, new); -+ } else { -+ struct vx_dmap_target new = { -+ .target = target, -+ .flags = flags | mode, -+ }; -+ __set_default(vxi, mode, &new); -+ } -+ return 0; -+} -+ -+ -+static int do_unset_mapping(struct vx_info *vxi, -+ dev_t device, dev_t target, int flags, umode_t mode) -+{ -+ int ret = -EINVAL; -+ -+ if (device) { -+ ret = __remove_mapping(vxi, device, mode); -+ if (ret < 0) -+ goto out; -+ } else { -+ ret = __remove_default(vxi, mode); -+ if (ret < 0) -+ goto out; -+ } -+ -+out: -+ return ret; -+} -+ -+ -+static inline int __user_device(const char __user *name, dev_t *dev, -+ umode_t *mode) -+{ -+ struct nameidata nd; -+ int ret; -+ -+ if (!name) { -+ *dev = 0; -+ return 0; -+ } -+ ret = user_lpath(name, &nd.path); -+ if (ret) -+ return ret; -+ if (nd.path.dentry->d_inode) { -+ *dev = nd.path.dentry->d_inode->i_rdev; -+ *mode = nd.path.dentry->d_inode->i_mode; -+ } -+ path_put(&nd.path); -+ return 0; -+} -+ -+static inline int __mapping_mode(dev_t device, dev_t target, -+ umode_t device_mode, umode_t target_mode, umode_t *mode) -+{ -+ if (device) -+ *mode = device_mode & S_IFMT; -+ else if (target) -+ *mode = target_mode & S_IFMT; -+ else -+ return -EINVAL; -+ -+ /* if both given, device and target mode have to match */ -+ if (device && target && -+ ((device_mode ^ target_mode) & S_IFMT)) -+ return -EINVAL; -+ return 0; -+} -+ -+ -+static inline int do_mapping(struct vx_info *vxi, const char __user *device_path, -+ const char __user *target_path, int flags, int set) -+{ -+ dev_t device = ~0, target = ~0; -+ umode_t device_mode = 0, target_mode = 0, mode; -+ int ret; -+ -+ ret = __user_device(device_path, &device, &device_mode); -+ if (ret) -+ return ret; -+ ret = __user_device(target_path, &target, &target_mode); -+ if (ret) -+ return ret; -+ -+ ret = __mapping_mode(device, target, -+ device_mode, target_mode, &mode); -+ if (ret) -+ return ret; -+ -+ if (set) -+ return do_set_mapping(vxi, device, target, -+ flags, mode); -+ else -+ return do_unset_mapping(vxi, device, target, -+ flags, mode); -+} -+ -+ -+int vc_set_mapping(struct vx_info *vxi, void __user *data) -+{ -+ struct vcmd_set_mapping_v0 vc_data; -+ -+ if (copy_from_user(&vc_data, data, sizeof(vc_data))) -+ return -EFAULT; -+ -+ return do_mapping(vxi, vc_data.device, vc_data.target, -+ vc_data.flags, 1); -+} -+ -+int vc_unset_mapping(struct vx_info *vxi, void __user *data) -+{ -+ struct vcmd_set_mapping_v0 vc_data; -+ -+ if (copy_from_user(&vc_data, data, sizeof(vc_data))) -+ return -EFAULT; -+ -+ return do_mapping(vxi, vc_data.device, vc_data.target, -+ vc_data.flags, 0); -+} -+ -+ -+#ifdef CONFIG_COMPAT -+ -+int vc_set_mapping_x32(struct vx_info *vxi, void __user *data) -+{ -+ struct vcmd_set_mapping_v0_x32 vc_data; -+ -+ if (copy_from_user(&vc_data, data, sizeof(vc_data))) -+ return -EFAULT; -+ -+ return do_mapping(vxi, compat_ptr(vc_data.device_ptr), -+ compat_ptr(vc_data.target_ptr), vc_data.flags, 1); -+} -+ -+int vc_unset_mapping_x32(struct vx_info *vxi, void __user *data) -+{ -+ struct vcmd_set_mapping_v0_x32 vc_data; -+ -+ if (copy_from_user(&vc_data, data, sizeof(vc_data))) -+ return -EFAULT; -+ -+ return do_mapping(vxi, compat_ptr(vc_data.device_ptr), -+ compat_ptr(vc_data.target_ptr), vc_data.flags, 0); -+} -+ -+#endif /* CONFIG_COMPAT */ -+ -+ -diff -NurpP --minimal linux-2.6.32.1/kernel/vserver/dlimit.c linux-2.6.32.1-vs2.3.0.36.27/kernel/vserver/dlimit.c ---- linux-2.6.32.1/kernel/vserver/dlimit.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/kernel/vserver/dlimit.c 2009-12-03 20:04:56.000000000 +0100 -@@ -0,0 +1,529 @@ -+/* -+ * linux/kernel/vserver/dlimit.c -+ * -+ * Virtual Server: Context Disk Limits -+ * -+ * Copyright (C) 2004-2009 Herbert Pötzl -+ * -+ * V0.01 initial version -+ * V0.02 compat32 splitup -+ * V0.03 extended interface -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+/* __alloc_dl_info() -+ -+ * allocate an initialized dl_info struct -+ * doesn't make it visible (hash) */ -+ -+static struct dl_info *__alloc_dl_info(struct super_block *sb, tag_t tag) -+{ -+ struct dl_info *new = NULL; -+ -+ vxdprintk(VXD_CBIT(dlim, 5), -+ "alloc_dl_info(%p,%d)*", sb, tag); -+ -+ /* would this benefit from a slab cache? */ -+ new = kmalloc(sizeof(struct dl_info), GFP_KERNEL); -+ if (!new) -+ return 0; -+ -+ memset(new, 0, sizeof(struct dl_info)); -+ new->dl_tag = tag; -+ new->dl_sb = sb; -+ INIT_RCU_HEAD(&new->dl_rcu); -+ INIT_HLIST_NODE(&new->dl_hlist); -+ spin_lock_init(&new->dl_lock); -+ atomic_set(&new->dl_refcnt, 0); -+ atomic_set(&new->dl_usecnt, 0); -+ -+ /* rest of init goes here */ -+ -+ vxdprintk(VXD_CBIT(dlim, 4), -+ "alloc_dl_info(%p,%d) = %p", sb, tag, new); -+ return new; -+} -+ -+/* __dealloc_dl_info() -+ -+ * final disposal of dl_info */ -+ -+static void __dealloc_dl_info(struct dl_info *dli) -+{ -+ vxdprintk(VXD_CBIT(dlim, 4), -+ "dealloc_dl_info(%p)", dli); -+ -+ dli->dl_hlist.next = LIST_POISON1; -+ dli->dl_tag = -1; -+ dli->dl_sb = 0; -+ -+ BUG_ON(atomic_read(&dli->dl_usecnt)); -+ BUG_ON(atomic_read(&dli->dl_refcnt)); -+ -+ kfree(dli); -+} -+ -+ -+/* hash table for dl_info hash */ -+ -+#define DL_HASH_SIZE 13 -+ -+struct hlist_head dl_info_hash[DL_HASH_SIZE]; -+ -+static spinlock_t dl_info_hash_lock = SPIN_LOCK_UNLOCKED; -+ -+ -+static inline unsigned int __hashval(struct super_block *sb, tag_t tag) -+{ -+ return ((tag ^ (unsigned long)sb) % DL_HASH_SIZE); -+} -+ -+ -+ -+/* __hash_dl_info() -+ -+ * add the dli to the global hash table -+ * requires the hash_lock to be held */ -+ -+static inline void __hash_dl_info(struct dl_info *dli) -+{ -+ struct hlist_head *head; -+ -+ vxdprintk(VXD_CBIT(dlim, 6), -+ "__hash_dl_info: %p[#%d]", dli, dli->dl_tag); -+ get_dl_info(dli); -+ head = &dl_info_hash[__hashval(dli->dl_sb, dli->dl_tag)]; -+ hlist_add_head_rcu(&dli->dl_hlist, head); -+} -+ -+/* __unhash_dl_info() -+ -+ * remove the dli from the global hash table -+ * requires the hash_lock to be held */ -+ -+static inline void __unhash_dl_info(struct dl_info *dli) -+{ -+ vxdprintk(VXD_CBIT(dlim, 6), -+ "__unhash_dl_info: %p[#%d]", dli, dli->dl_tag); -+ hlist_del_rcu(&dli->dl_hlist); -+ put_dl_info(dli); -+} -+ -+ -+/* __lookup_dl_info() -+ -+ * requires the rcu_read_lock() -+ * doesn't increment the dl_refcnt */ -+ -+static inline struct dl_info *__lookup_dl_info(struct super_block *sb, tag_t tag) -+{ -+ struct hlist_head *head = &dl_info_hash[__hashval(sb, tag)]; -+ struct hlist_node *pos; -+ struct dl_info *dli; -+ -+ hlist_for_each_entry_rcu(dli, pos, head, dl_hlist) { -+ -+ if (dli->dl_tag == tag && dli->dl_sb == sb) { -+ return dli; -+ } -+ } -+ return NULL; -+} -+ -+ -+struct dl_info *locate_dl_info(struct super_block *sb, tag_t tag) -+{ -+ struct dl_info *dli; -+ -+ rcu_read_lock(); -+ dli = get_dl_info(__lookup_dl_info(sb, tag)); -+ vxdprintk(VXD_CBIT(dlim, 7), -+ "locate_dl_info(%p,#%d) = %p", sb, tag, dli); -+ rcu_read_unlock(); -+ return dli; -+} -+ -+void rcu_free_dl_info(struct rcu_head *head) -+{ -+ struct dl_info *dli = container_of(head, struct dl_info, dl_rcu); -+ int usecnt, refcnt; -+ -+ BUG_ON(!dli || !head); -+ -+ usecnt = atomic_read(&dli->dl_usecnt); -+ BUG_ON(usecnt < 0); -+ -+ refcnt = atomic_read(&dli->dl_refcnt); -+ BUG_ON(refcnt < 0); -+ -+ vxdprintk(VXD_CBIT(dlim, 3), -+ "rcu_free_dl_info(%p)", dli); -+ if (!usecnt) -+ __dealloc_dl_info(dli); -+ else -+ printk("!!! rcu didn't free\n"); -+} -+ -+ -+ -+ -+static int do_addrem_dlimit(uint32_t id, const char __user *name, -+ uint32_t flags, int add) -+{ -+ struct path path; -+ int ret; -+ -+ ret = user_lpath(name, &path); -+ if (!ret) { -+ struct super_block *sb; -+ struct dl_info *dli; -+ -+ ret = -EINVAL; -+ if (!path.dentry->d_inode) -+ goto out_release; -+ if (!(sb = path.dentry->d_inode->i_sb)) -+ goto out_release; -+ -+ if (add) { -+ dli = __alloc_dl_info(sb, id); -+ spin_lock(&dl_info_hash_lock); -+ -+ ret = -EEXIST; -+ if (__lookup_dl_info(sb, id)) -+ goto out_unlock; -+ __hash_dl_info(dli); -+ dli = NULL; -+ } else { -+ spin_lock(&dl_info_hash_lock); -+ dli = __lookup_dl_info(sb, id); -+ -+ ret = -ESRCH; -+ if (!dli) -+ goto out_unlock; -+ __unhash_dl_info(dli); -+ } -+ ret = 0; -+ out_unlock: -+ spin_unlock(&dl_info_hash_lock); -+ if (add && dli) -+ __dealloc_dl_info(dli); -+ out_release: -+ path_put(&path); -+ } -+ return ret; -+} -+ -+int vc_add_dlimit(uint32_t id, void __user *data) -+{ -+ struct vcmd_ctx_dlimit_base_v0 vc_data; -+ -+ if (copy_from_user(&vc_data, data, sizeof(vc_data))) -+ return -EFAULT; -+ -+ return do_addrem_dlimit(id, vc_data.name, vc_data.flags, 1); -+} -+ -+int vc_rem_dlimit(uint32_t id, void __user *data) -+{ -+ struct vcmd_ctx_dlimit_base_v0 vc_data; -+ -+ if (copy_from_user(&vc_data, data, sizeof(vc_data))) -+ return -EFAULT; -+ -+ return do_addrem_dlimit(id, vc_data.name, vc_data.flags, 0); -+} -+ -+#ifdef CONFIG_COMPAT -+ -+int vc_add_dlimit_x32(uint32_t id, void __user *data) -+{ -+ struct vcmd_ctx_dlimit_base_v0_x32 vc_data; -+ -+ if (copy_from_user(&vc_data, data, sizeof(vc_data))) -+ return -EFAULT; -+ -+ return do_addrem_dlimit(id, -+ compat_ptr(vc_data.name_ptr), vc_data.flags, 1); -+} -+ -+int vc_rem_dlimit_x32(uint32_t id, void __user *data) -+{ -+ struct vcmd_ctx_dlimit_base_v0_x32 vc_data; -+ -+ if (copy_from_user(&vc_data, data, sizeof(vc_data))) -+ return -EFAULT; -+ -+ return do_addrem_dlimit(id, -+ compat_ptr(vc_data.name_ptr), vc_data.flags, 0); -+} -+ -+#endif /* CONFIG_COMPAT */ -+ -+ -+static inline -+int do_set_dlimit(uint32_t id, const char __user *name, -+ uint32_t space_used, uint32_t space_total, -+ uint32_t inodes_used, uint32_t inodes_total, -+ uint32_t reserved, uint32_t flags) -+{ -+ struct path path; -+ int ret; -+ -+ ret = user_lpath(name, &path); -+ if (!ret) { -+ struct super_block *sb; -+ struct dl_info *dli; -+ -+ ret = -EINVAL; -+ if (!path.dentry->d_inode) -+ goto out_release; -+ if (!(sb = path.dentry->d_inode->i_sb)) -+ goto out_release; -+ -+ /* sanity checks */ -+ if ((reserved != CDLIM_KEEP && -+ reserved > 100) || -+ (inodes_used != CDLIM_KEEP && -+ inodes_used > inodes_total) || -+ (space_used != CDLIM_KEEP && -+ space_used > space_total)) -+ goto out_release; -+ -+ ret = -ESRCH; -+ dli = locate_dl_info(sb, id); -+ if (!dli) -+ goto out_release; -+ -+ spin_lock(&dli->dl_lock); -+ -+ if (inodes_used != CDLIM_KEEP) -+ dli->dl_inodes_used = inodes_used; -+ if (inodes_total != CDLIM_KEEP) -+ dli->dl_inodes_total = inodes_total; -+ if (space_used != CDLIM_KEEP) -+ dli->dl_space_used = dlimit_space_32to64( -+ space_used, flags, DLIMS_USED); -+ -+ if (space_total == CDLIM_INFINITY) -+ dli->dl_space_total = DLIM_INFINITY; -+ else if (space_total != CDLIM_KEEP) -+ dli->dl_space_total = dlimit_space_32to64( -+ space_total, flags, DLIMS_TOTAL); -+ -+ if (reserved != CDLIM_KEEP) -+ dli->dl_nrlmult = (1 << 10) * (100 - reserved) / 100; -+ -+ spin_unlock(&dli->dl_lock); -+ -+ put_dl_info(dli); -+ ret = 0; -+ -+ out_release: -+ path_put(&path); -+ } -+ return ret; -+} -+ -+int vc_set_dlimit(uint32_t id, void __user *data) -+{ -+ struct vcmd_ctx_dlimit_v0 vc_data; -+ -+ if (copy_from_user(&vc_data, data, sizeof(vc_data))) -+ return -EFAULT; -+ -+ return do_set_dlimit(id, vc_data.name, -+ vc_data.space_used, vc_data.space_total, -+ vc_data.inodes_used, vc_data.inodes_total, -+ vc_data.reserved, vc_data.flags); -+} -+ -+#ifdef CONFIG_COMPAT -+ -+int vc_set_dlimit_x32(uint32_t id, void __user *data) -+{ -+ struct vcmd_ctx_dlimit_v0_x32 vc_data; -+ -+ if (copy_from_user(&vc_data, data, sizeof(vc_data))) -+ return -EFAULT; -+ -+ return do_set_dlimit(id, compat_ptr(vc_data.name_ptr), -+ vc_data.space_used, vc_data.space_total, -+ vc_data.inodes_used, vc_data.inodes_total, -+ vc_data.reserved, vc_data.flags); -+} -+ -+#endif /* CONFIG_COMPAT */ -+ -+ -+static inline -+int do_get_dlimit(uint32_t id, const char __user *name, -+ uint32_t *space_used, uint32_t *space_total, -+ uint32_t *inodes_used, uint32_t *inodes_total, -+ uint32_t *reserved, uint32_t *flags) -+{ -+ struct path path; -+ int ret; -+ -+ ret = user_lpath(name, &path); -+ if (!ret) { -+ struct super_block *sb; -+ struct dl_info *dli; -+ -+ ret = -EINVAL; -+ if (!path.dentry->d_inode) -+ goto out_release; -+ if (!(sb = path.dentry->d_inode->i_sb)) -+ goto out_release; -+ -+ ret = -ESRCH; -+ dli = locate_dl_info(sb, id); -+ if (!dli) -+ goto out_release; -+ -+ spin_lock(&dli->dl_lock); -+ *inodes_used = dli->dl_inodes_used; -+ *inodes_total = dli->dl_inodes_total; -+ -+ *space_used = dlimit_space_64to32( -+ dli->dl_space_used, flags, DLIMS_USED); -+ -+ if (dli->dl_space_total == DLIM_INFINITY) -+ *space_total = CDLIM_INFINITY; -+ else -+ *space_total = dlimit_space_64to32( -+ dli->dl_space_total, flags, DLIMS_TOTAL); -+ -+ *reserved = 100 - ((dli->dl_nrlmult * 100 + 512) >> 10); -+ spin_unlock(&dli->dl_lock); -+ -+ put_dl_info(dli); -+ ret = -EFAULT; -+ -+ ret = 0; -+ out_release: -+ path_put(&path); -+ } -+ return ret; -+} -+ -+ -+int vc_get_dlimit(uint32_t id, void __user *data) -+{ -+ struct vcmd_ctx_dlimit_v0 vc_data; -+ int ret; -+ -+ if (copy_from_user(&vc_data, data, sizeof(vc_data))) -+ return -EFAULT; -+ -+ ret = do_get_dlimit(id, vc_data.name, -+ &vc_data.space_used, &vc_data.space_total, -+ &vc_data.inodes_used, &vc_data.inodes_total, -+ &vc_data.reserved, &vc_data.flags); -+ if (ret) -+ return ret; -+ -+ if (copy_to_user(data, &vc_data, sizeof(vc_data))) -+ return -EFAULT; -+ return 0; -+} -+ -+#ifdef CONFIG_COMPAT -+ -+int vc_get_dlimit_x32(uint32_t id, void __user *data) -+{ -+ struct vcmd_ctx_dlimit_v0_x32 vc_data; -+ int ret; -+ -+ if (copy_from_user(&vc_data, data, sizeof(vc_data))) -+ return -EFAULT; -+ -+ ret = do_get_dlimit(id, compat_ptr(vc_data.name_ptr), -+ &vc_data.space_used, &vc_data.space_total, -+ &vc_data.inodes_used, &vc_data.inodes_total, -+ &vc_data.reserved, &vc_data.flags); -+ if (ret) -+ return ret; -+ -+ if (copy_to_user(data, &vc_data, sizeof(vc_data))) -+ return -EFAULT; -+ return 0; -+} -+ -+#endif /* CONFIG_COMPAT */ -+ -+ -+void vx_vsi_statfs(struct super_block *sb, struct kstatfs *buf) -+{ -+ struct dl_info *dli; -+ __u64 blimit, bfree, bavail; -+ __u32 ifree; -+ -+ dli = locate_dl_info(sb, dx_current_tag()); -+ if (!dli) -+ return; -+ -+ spin_lock(&dli->dl_lock); -+ if (dli->dl_inodes_total == (unsigned long)DLIM_INFINITY) -+ goto no_ilim; -+ -+ /* reduce max inodes available to limit */ -+ if (buf->f_files > dli->dl_inodes_total) -+ buf->f_files = dli->dl_inodes_total; -+ -+ ifree = dli->dl_inodes_total - dli->dl_inodes_used; -+ /* reduce free inodes to min */ -+ if (ifree < buf->f_ffree) -+ buf->f_ffree = ifree; -+ -+no_ilim: -+ if (dli->dl_space_total == DLIM_INFINITY) -+ goto no_blim; -+ -+ blimit = dli->dl_space_total >> sb->s_blocksize_bits; -+ -+ if (dli->dl_space_total < dli->dl_space_used) -+ bfree = 0; -+ else -+ bfree = (dli->dl_space_total - dli->dl_space_used) -+ >> sb->s_blocksize_bits; -+ -+ bavail = ((dli->dl_space_total >> 10) * dli->dl_nrlmult); -+ if (bavail < dli->dl_space_used) -+ bavail = 0; -+ else -+ bavail = (bavail - dli->dl_space_used) -+ >> sb->s_blocksize_bits; -+ -+ /* reduce max space available to limit */ -+ if (buf->f_blocks > blimit) -+ buf->f_blocks = blimit; -+ -+ /* reduce free space to min */ -+ if (bfree < buf->f_bfree) -+ buf->f_bfree = bfree; -+ -+ /* reduce avail space to min */ -+ if (bavail < buf->f_bavail) -+ buf->f_bavail = bavail; -+ -+no_blim: -+ spin_unlock(&dli->dl_lock); -+ put_dl_info(dli); -+ -+ return; -+} -+ -+#include -+ -+EXPORT_SYMBOL_GPL(locate_dl_info); -+EXPORT_SYMBOL_GPL(rcu_free_dl_info); -+ -diff -NurpP --minimal linux-2.6.32.1/kernel/vserver/helper.c linux-2.6.32.1-vs2.3.0.36.27/kernel/vserver/helper.c ---- linux-2.6.32.1/kernel/vserver/helper.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/kernel/vserver/helper.c 2009-12-03 22:20:22.000000000 +0100 -@@ -0,0 +1,223 @@ -+/* -+ * linux/kernel/vserver/helper.c -+ * -+ * Virtual Context Support -+ * -+ * Copyright (C) 2004-2007 Herbert Pötzl -+ * -+ * V0.01 basic helper -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+ -+ -+char vshelper_path[255] = "/sbin/vshelper"; -+ -+ -+static int do_vshelper(char *name, char *argv[], char *envp[], int sync) -+{ -+ int ret; -+ -+ if ((ret = call_usermodehelper(name, argv, envp, sync))) { -+ printk( KERN_WARNING -+ "%s: (%s %s) returned %s with %d\n", -+ name, argv[1], argv[2], -+ sync ? "sync" : "async", ret); -+ } -+ vxdprintk(VXD_CBIT(switch, 4), -+ "%s: (%s %s) returned %s with %d", -+ name, argv[1], argv[2], sync ? "sync" : "async", ret); -+ return ret; -+} -+ -+/* -+ * vshelper path is set via /proc/sys -+ * invoked by vserver sys_reboot(), with -+ * the following arguments -+ * -+ * argv [0] = vshelper_path; -+ * argv [1] = action: "restart", "halt", "poweroff", ... -+ * argv [2] = context identifier -+ * -+ * envp [*] = type-specific parameters -+ */ -+ -+long vs_reboot_helper(struct vx_info *vxi, int cmd, void __user *arg) -+{ -+ char id_buf[8], cmd_buf[16]; -+ char uid_buf[16], pid_buf[16]; -+ int ret; -+ -+ char *argv[] = {vshelper_path, NULL, id_buf, 0}; -+ char *envp[] = {"HOME=/", "TERM=linux", -+ "PATH=/sbin:/usr/sbin:/bin:/usr/bin", -+ uid_buf, pid_buf, cmd_buf, 0}; -+ -+ if (vx_info_state(vxi, VXS_HELPER)) -+ return -EAGAIN; -+ vxi->vx_state |= VXS_HELPER; -+ -+ snprintf(id_buf, sizeof(id_buf)-1, "%d", vxi->vx_id); -+ -+ snprintf(cmd_buf, sizeof(cmd_buf)-1, "VS_CMD=%08x", cmd); -+ snprintf(uid_buf, sizeof(uid_buf)-1, "VS_UID=%d", current_uid()); -+ snprintf(pid_buf, sizeof(pid_buf)-1, "VS_PID=%d", current->pid); -+ -+ switch (cmd) { -+ case LINUX_REBOOT_CMD_RESTART: -+ argv[1] = "restart"; -+ break; -+ -+ case LINUX_REBOOT_CMD_HALT: -+ argv[1] = "halt"; -+ break; -+ -+ case LINUX_REBOOT_CMD_POWER_OFF: -+ argv[1] = "poweroff"; -+ break; -+ -+ case LINUX_REBOOT_CMD_SW_SUSPEND: -+ argv[1] = "swsusp"; -+ break; -+ -+ case LINUX_REBOOT_CMD_OOM: -+ argv[1] = "oom"; -+ break; -+ -+ default: -+ vxi->vx_state &= ~VXS_HELPER; -+ return 0; -+ } -+ -+ ret = do_vshelper(vshelper_path, argv, envp, 0); -+ vxi->vx_state &= ~VXS_HELPER; -+ __wakeup_vx_info(vxi); -+ return (ret) ? -EPERM : 0; -+} -+ -+ -+long vs_reboot(unsigned int cmd, void __user *arg) -+{ -+ struct vx_info *vxi = current_vx_info(); -+ long ret = 0; -+ -+ vxdprintk(VXD_CBIT(misc, 5), -+ "vs_reboot(%p[#%d],%u)", -+ vxi, vxi ? vxi->vx_id : 0, cmd); -+ -+ ret = vs_reboot_helper(vxi, cmd, arg); -+ if (ret) -+ return ret; -+ -+ vxi->reboot_cmd = cmd; -+ if (vx_info_flags(vxi, VXF_REBOOT_KILL, 0)) { -+ switch (cmd) { -+ case LINUX_REBOOT_CMD_RESTART: -+ case LINUX_REBOOT_CMD_HALT: -+ case LINUX_REBOOT_CMD_POWER_OFF: -+ vx_info_kill(vxi, 0, SIGKILL); -+ vx_info_kill(vxi, 1, SIGKILL); -+ default: -+ break; -+ } -+ } -+ return 0; -+} -+ -+long vs_oom_action(unsigned int cmd) -+{ -+ struct vx_info *vxi = current_vx_info(); -+ long ret = 0; -+ -+ vxdprintk(VXD_CBIT(misc, 5), -+ "vs_oom_action(%p[#%d],%u)", -+ vxi, vxi ? vxi->vx_id : 0, cmd); -+ -+ ret = vs_reboot_helper(vxi, cmd, NULL); -+ if (ret) -+ return ret; -+ -+ vxi->reboot_cmd = cmd; -+ if (vx_info_flags(vxi, VXF_REBOOT_KILL, 0)) { -+ vx_info_kill(vxi, 0, SIGKILL); -+ vx_info_kill(vxi, 1, SIGKILL); -+ } -+ return 0; -+} -+ -+/* -+ * argv [0] = vshelper_path; -+ * argv [1] = action: "startup", "shutdown" -+ * argv [2] = context identifier -+ * -+ * envp [*] = type-specific parameters -+ */ -+ -+long vs_state_change(struct vx_info *vxi, unsigned int cmd) -+{ -+ char id_buf[8], cmd_buf[16]; -+ char *argv[] = {vshelper_path, NULL, id_buf, 0}; -+ char *envp[] = {"HOME=/", "TERM=linux", -+ "PATH=/sbin:/usr/sbin:/bin:/usr/bin", cmd_buf, 0}; -+ -+ if (!vx_info_flags(vxi, VXF_SC_HELPER, 0)) -+ return 0; -+ -+ snprintf(id_buf, sizeof(id_buf)-1, "%d", vxi->vx_id); -+ snprintf(cmd_buf, sizeof(cmd_buf)-1, "VS_CMD=%08x", cmd); -+ -+ switch (cmd) { -+ case VSC_STARTUP: -+ argv[1] = "startup"; -+ break; -+ case VSC_SHUTDOWN: -+ argv[1] = "shutdown"; -+ break; -+ default: -+ return 0; -+ } -+ -+ return do_vshelper(vshelper_path, argv, envp, 1); -+} -+ -+ -+/* -+ * argv [0] = vshelper_path; -+ * argv [1] = action: "netup", "netdown" -+ * argv [2] = context identifier -+ * -+ * envp [*] = type-specific parameters -+ */ -+ -+long vs_net_change(struct nx_info *nxi, unsigned int cmd) -+{ -+ char id_buf[8], cmd_buf[16]; -+ char *argv[] = {vshelper_path, NULL, id_buf, 0}; -+ char *envp[] = {"HOME=/", "TERM=linux", -+ "PATH=/sbin:/usr/sbin:/bin:/usr/bin", cmd_buf, 0}; -+ -+ if (!nx_info_flags(nxi, NXF_SC_HELPER, 0)) -+ return 0; -+ -+ snprintf(id_buf, sizeof(id_buf)-1, "%d", nxi->nx_id); -+ snprintf(cmd_buf, sizeof(cmd_buf)-1, "VS_CMD=%08x", cmd); -+ -+ switch (cmd) { -+ case VSC_NETUP: -+ argv[1] = "netup"; -+ break; -+ case VSC_NETDOWN: -+ argv[1] = "netdown"; -+ break; -+ default: -+ return 0; -+ } -+ -+ return do_vshelper(vshelper_path, argv, envp, 1); -+} -+ -diff -NurpP --minimal linux-2.6.32.1/kernel/vserver/history.c linux-2.6.32.1-vs2.3.0.36.27/kernel/vserver/history.c ---- linux-2.6.32.1/kernel/vserver/history.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/kernel/vserver/history.c 2009-12-03 20:04:56.000000000 +0100 -@@ -0,0 +1,258 @@ -+/* -+ * kernel/vserver/history.c -+ * -+ * Virtual Context History Backtrace -+ * -+ * Copyright (C) 2004-2007 Herbert Pötzl -+ * -+ * V0.01 basic structure -+ * V0.02 hash/unhash and trace -+ * V0.03 preemption fixes -+ * -+ */ -+ -+#include -+#include -+ -+#include -+#include -+#include -+#include -+ -+ -+#ifdef CONFIG_VSERVER_HISTORY -+#define VXH_SIZE CONFIG_VSERVER_HISTORY_SIZE -+#else -+#define VXH_SIZE 64 -+#endif -+ -+struct _vx_history { -+ unsigned int counter; -+ -+ struct _vx_hist_entry entry[VXH_SIZE + 1]; -+}; -+ -+ -+DEFINE_PER_CPU(struct _vx_history, vx_history_buffer); -+ -+unsigned volatile int vxh_active = 1; -+ -+static atomic_t sequence = ATOMIC_INIT(0); -+ -+ -+/* vxh_advance() -+ -+ * requires disabled preemption */ -+ -+struct _vx_hist_entry *vxh_advance(void *loc) -+{ -+ unsigned int cpu = smp_processor_id(); -+ struct _vx_history *hist = &per_cpu(vx_history_buffer, cpu); -+ struct _vx_hist_entry *entry; -+ unsigned int index; -+ -+ index = vxh_active ? (hist->counter++ % VXH_SIZE) : VXH_SIZE; -+ entry = &hist->entry[index]; -+ -+ entry->seq = atomic_inc_return(&sequence); -+ entry->loc = loc; -+ return entry; -+} -+ -+EXPORT_SYMBOL_GPL(vxh_advance); -+ -+ -+#define VXH_LOC_FMTS "(#%04x,*%d):%p" -+ -+#define VXH_LOC_ARGS(e) (e)->seq, cpu, (e)->loc -+ -+ -+#define VXH_VXI_FMTS "%p[#%d,%d.%d]" -+ -+#define VXH_VXI_ARGS(e) (e)->vxi.ptr, \ -+ (e)->vxi.ptr ? (e)->vxi.xid : 0, \ -+ (e)->vxi.ptr ? (e)->vxi.usecnt : 0, \ -+ (e)->vxi.ptr ? (e)->vxi.tasks : 0 -+ -+void vxh_dump_entry(struct _vx_hist_entry *e, unsigned cpu) -+{ -+ switch (e->type) { -+ case VXH_THROW_OOPS: -+ printk( VXH_LOC_FMTS " oops \n", VXH_LOC_ARGS(e)); -+ break; -+ -+ case VXH_GET_VX_INFO: -+ case VXH_PUT_VX_INFO: -+ printk( VXH_LOC_FMTS " %s_vx_info " VXH_VXI_FMTS "\n", -+ VXH_LOC_ARGS(e), -+ (e->type == VXH_GET_VX_INFO) ? "get" : "put", -+ VXH_VXI_ARGS(e)); -+ break; -+ -+ case VXH_INIT_VX_INFO: -+ case VXH_SET_VX_INFO: -+ case VXH_CLR_VX_INFO: -+ printk( VXH_LOC_FMTS " %s_vx_info " VXH_VXI_FMTS " @%p\n", -+ VXH_LOC_ARGS(e), -+ (e->type == VXH_INIT_VX_INFO) ? "init" : -+ ((e->type == VXH_SET_VX_INFO) ? "set" : "clr"), -+ VXH_VXI_ARGS(e), e->sc.data); -+ break; -+ -+ case VXH_CLAIM_VX_INFO: -+ case VXH_RELEASE_VX_INFO: -+ printk( VXH_LOC_FMTS " %s_vx_info " VXH_VXI_FMTS " @%p\n", -+ VXH_LOC_ARGS(e), -+ (e->type == VXH_CLAIM_VX_INFO) ? "claim" : "release", -+ VXH_VXI_ARGS(e), e->sc.data); -+ break; -+ -+ case VXH_ALLOC_VX_INFO: -+ case VXH_DEALLOC_VX_INFO: -+ printk( VXH_LOC_FMTS " %s_vx_info " VXH_VXI_FMTS "\n", -+ VXH_LOC_ARGS(e), -+ (e->type == VXH_ALLOC_VX_INFO) ? "alloc" : "dealloc", -+ VXH_VXI_ARGS(e)); -+ break; -+ -+ case VXH_HASH_VX_INFO: -+ case VXH_UNHASH_VX_INFO: -+ printk( VXH_LOC_FMTS " __%s_vx_info " VXH_VXI_FMTS "\n", -+ VXH_LOC_ARGS(e), -+ (e->type == VXH_HASH_VX_INFO) ? "hash" : "unhash", -+ VXH_VXI_ARGS(e)); -+ break; -+ -+ case VXH_LOC_VX_INFO: -+ case VXH_LOOKUP_VX_INFO: -+ case VXH_CREATE_VX_INFO: -+ printk( VXH_LOC_FMTS " __%s_vx_info [#%d] -> " VXH_VXI_FMTS "\n", -+ VXH_LOC_ARGS(e), -+ (e->type == VXH_CREATE_VX_INFO) ? "create" : -+ ((e->type == VXH_LOC_VX_INFO) ? "loc" : "lookup"), -+ e->ll.arg, VXH_VXI_ARGS(e)); -+ break; -+ } -+} -+ -+static void __vxh_dump_history(void) -+{ -+ unsigned int i, cpu; -+ -+ printk("History:\tSEQ: %8x\tNR_CPUS: %d\n", -+ atomic_read(&sequence), NR_CPUS); -+ -+ for (i = 0; i < VXH_SIZE; i++) { -+ for_each_online_cpu(cpu) { -+ struct _vx_history *hist = -+ &per_cpu(vx_history_buffer, cpu); -+ unsigned int index = (hist->counter - i) % VXH_SIZE; -+ struct _vx_hist_entry *entry = &hist->entry[index]; -+ -+ vxh_dump_entry(entry, cpu); -+ } -+ } -+} -+ -+void vxh_dump_history(void) -+{ -+ vxh_active = 0; -+#ifdef CONFIG_SMP -+ local_irq_enable(); -+ smp_send_stop(); -+ local_irq_disable(); -+#endif -+ __vxh_dump_history(); -+} -+ -+ -+/* vserver syscall commands below here */ -+ -+ -+int vc_dump_history(uint32_t id) -+{ -+ vxh_active = 0; -+ __vxh_dump_history(); -+ vxh_active = 1; -+ -+ return 0; -+} -+ -+ -+int do_read_history(struct __user _vx_hist_entry *data, -+ int cpu, uint32_t *index, uint32_t *count) -+{ -+ int pos, ret = 0; -+ struct _vx_history *hist = &per_cpu(vx_history_buffer, cpu); -+ int end = hist->counter; -+ int start = end - VXH_SIZE + 2; -+ int idx = *index; -+ -+ /* special case: get current pos */ -+ if (!*count) { -+ *index = end; -+ return 0; -+ } -+ -+ /* have we lost some data? */ -+ if (idx < start) -+ idx = start; -+ -+ for (pos = 0; (pos < *count) && (idx < end); pos++, idx++) { -+ struct _vx_hist_entry *entry = -+ &hist->entry[idx % VXH_SIZE]; -+ -+ /* send entry to userspace */ -+ ret = copy_to_user(&data[pos], entry, sizeof(*entry)); -+ if (ret) -+ break; -+ } -+ /* save new index and count */ -+ *index = idx; -+ *count = pos; -+ return ret ? ret : (*index < end); -+} -+ -+int vc_read_history(uint32_t id, void __user *data) -+{ -+ struct vcmd_read_history_v0 vc_data; -+ int ret; -+ -+ if (id >= NR_CPUS) -+ return -EINVAL; -+ -+ if (copy_from_user(&vc_data, data, sizeof(vc_data))) -+ return -EFAULT; -+ -+ ret = do_read_history((struct __user _vx_hist_entry *)vc_data.data, -+ id, &vc_data.index, &vc_data.count); -+ -+ if (copy_to_user(data, &vc_data, sizeof(vc_data))) -+ return -EFAULT; -+ return ret; -+} -+ -+#ifdef CONFIG_COMPAT -+ -+int vc_read_history_x32(uint32_t id, void __user *data) -+{ -+ struct vcmd_read_history_v0_x32 vc_data; -+ int ret; -+ -+ if (id >= NR_CPUS) -+ return -EINVAL; -+ -+ if (copy_from_user(&vc_data, data, sizeof(vc_data))) -+ return -EFAULT; -+ -+ ret = do_read_history((struct __user _vx_hist_entry *) -+ compat_ptr(vc_data.data_ptr), -+ id, &vc_data.index, &vc_data.count); -+ -+ if (copy_to_user(data, &vc_data, sizeof(vc_data))) -+ return -EFAULT; -+ return ret; -+} -+ -+#endif /* CONFIG_COMPAT */ -+ -diff -NurpP --minimal linux-2.6.32.1/kernel/vserver/inet.c linux-2.6.32.1-vs2.3.0.36.27/kernel/vserver/inet.c ---- linux-2.6.32.1/kernel/vserver/inet.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/kernel/vserver/inet.c 2009-12-03 20:04:56.000000000 +0100 -@@ -0,0 +1,225 @@ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+ -+int nx_v4_addr_conflict(struct nx_info *nxi1, struct nx_info *nxi2) -+{ -+ int ret = 0; -+ -+ if (!nxi1 || !nxi2 || nxi1 == nxi2) -+ ret = 1; -+ else { -+ struct nx_addr_v4 *ptr; -+ -+ for (ptr = &nxi1->v4; ptr; ptr = ptr->next) { -+ if (v4_nx_addr_in_nx_info(nxi2, ptr, -1)) { -+ ret = 1; -+ break; -+ } -+ } -+ } -+ -+ vxdprintk(VXD_CBIT(net, 2), -+ "nx_v4_addr_conflict(%p,%p): %d", -+ nxi1, nxi2, ret); -+ -+ return ret; -+} -+ -+ -+#ifdef CONFIG_IPV6 -+ -+int nx_v6_addr_conflict(struct nx_info *nxi1, struct nx_info *nxi2) -+{ -+ int ret = 0; -+ -+ if (!nxi1 || !nxi2 || nxi1 == nxi2) -+ ret = 1; -+ else { -+ struct nx_addr_v6 *ptr; -+ -+ for (ptr = &nxi1->v6; ptr; ptr = ptr->next) { -+ if (v6_nx_addr_in_nx_info(nxi2, ptr, -1)) { -+ ret = 1; -+ break; -+ } -+ } -+ } -+ -+ vxdprintk(VXD_CBIT(net, 2), -+ "nx_v6_addr_conflict(%p,%p): %d", -+ nxi1, nxi2, ret); -+ -+ return ret; -+} -+ -+#endif -+ -+int v4_dev_in_nx_info(struct net_device *dev, struct nx_info *nxi) -+{ -+ struct in_device *in_dev; -+ struct in_ifaddr **ifap; -+ struct in_ifaddr *ifa; -+ int ret = 0; -+ -+ if (!dev) -+ goto out; -+ in_dev = in_dev_get(dev); -+ if (!in_dev) -+ goto out; -+ -+ for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL; -+ ifap = &ifa->ifa_next) { -+ if (v4_addr_in_nx_info(nxi, ifa->ifa_local, NXA_MASK_SHOW)) { -+ ret = 1; -+ break; -+ } -+ } -+ in_dev_put(in_dev); -+out: -+ return ret; -+} -+ -+ -+#ifdef CONFIG_IPV6 -+ -+int v6_dev_in_nx_info(struct net_device *dev, struct nx_info *nxi) -+{ -+ struct inet6_dev *in_dev; -+ struct inet6_ifaddr **ifap; -+ struct inet6_ifaddr *ifa; -+ int ret = 0; -+ -+ if (!dev) -+ goto out; -+ in_dev = in6_dev_get(dev); -+ if (!in_dev) -+ goto out; -+ -+ for (ifap = &in_dev->addr_list; (ifa = *ifap) != NULL; -+ ifap = &ifa->if_next) { -+ if (v6_addr_in_nx_info(nxi, &ifa->addr, -1)) { -+ ret = 1; -+ break; -+ } -+ } -+ in6_dev_put(in_dev); -+out: -+ return ret; -+} -+ -+#endif -+ -+int dev_in_nx_info(struct net_device *dev, struct nx_info *nxi) -+{ -+ int ret = 1; -+ -+ if (!nxi) -+ goto out; -+ if (nxi->v4.type && v4_dev_in_nx_info(dev, nxi)) -+ goto out; -+#ifdef CONFIG_IPV6 -+ ret = 2; -+ if (nxi->v6.type && v6_dev_in_nx_info(dev, nxi)) -+ goto out; -+#endif -+ ret = 0; -+out: -+ vxdprintk(VXD_CBIT(net, 3), -+ "dev_in_nx_info(%p,%p[#%d]) = %d", -+ dev, nxi, nxi ? nxi->nx_id : 0, ret); -+ return ret; -+} -+ -+int ip_v4_find_src(struct net *net, struct nx_info *nxi, -+ struct rtable **rp, struct flowi *fl) -+{ -+ if (!nxi) -+ return 0; -+ -+ /* FIXME: handle lback only case */ -+ if (!NX_IPV4(nxi)) -+ return -EPERM; -+ -+ vxdprintk(VXD_CBIT(net, 4), -+ "ip_v4_find_src(%p[#%u]) " NIPQUAD_FMT " -> " NIPQUAD_FMT, -+ nxi, nxi ? nxi->nx_id : 0, -+ NIPQUAD(fl->fl4_src), NIPQUAD(fl->fl4_dst)); -+ -+ /* single IP is unconditional */ -+ if (nx_info_flags(nxi, NXF_SINGLE_IP, 0) && -+ (fl->fl4_src == INADDR_ANY)) -+ fl->fl4_src = nxi->v4.ip[0].s_addr; -+ -+ if (fl->fl4_src == INADDR_ANY) { -+ struct nx_addr_v4 *ptr; -+ __be32 found = 0; -+ int err; -+ -+ err = __ip_route_output_key(net, rp, fl); -+ if (!err) { -+ found = (*rp)->rt_src; -+ ip_rt_put(*rp); -+ vxdprintk(VXD_CBIT(net, 4), -+ "ip_v4_find_src(%p[#%u]) rok[%u]: " NIPQUAD_FMT, -+ nxi, nxi ? nxi->nx_id : 0, fl->oif, NIPQUAD(found)); -+ if (v4_addr_in_nx_info(nxi, found, NXA_MASK_BIND)) -+ goto found; -+ } -+ -+ for (ptr = &nxi->v4; ptr; ptr = ptr->next) { -+ __be32 primary = ptr->ip[0].s_addr; -+ __be32 mask = ptr->mask.s_addr; -+ __be32 neta = primary & mask; -+ -+ vxdprintk(VXD_CBIT(net, 4), "ip_v4_find_src(%p[#%u]) chk: " -+ NIPQUAD_FMT "/" NIPQUAD_FMT "/" NIPQUAD_FMT, -+ nxi, nxi ? nxi->nx_id : 0, NIPQUAD(primary), -+ NIPQUAD(mask), NIPQUAD(neta)); -+ if ((found & mask) != neta) -+ continue; -+ -+ fl->fl4_src = primary; -+ err = __ip_route_output_key(net, rp, fl); -+ vxdprintk(VXD_CBIT(net, 4), -+ "ip_v4_find_src(%p[#%u]) rok[%u]: " NIPQUAD_FMT, -+ nxi, nxi ? nxi->nx_id : 0, fl->oif, NIPQUAD(primary)); -+ if (!err) { -+ found = (*rp)->rt_src; -+ ip_rt_put(*rp); -+ if (found == primary) -+ goto found; -+ } -+ } -+ /* still no source ip? */ -+ found = ipv4_is_loopback(fl->fl4_dst) -+ ? IPI_LOOPBACK : nxi->v4.ip[0].s_addr; -+ found: -+ /* assign src ip to flow */ -+ fl->fl4_src = found; -+ -+ } else { -+ if (!v4_addr_in_nx_info(nxi, fl->fl4_src, NXA_MASK_BIND)) -+ return -EPERM; -+ } -+ -+ if (nx_info_flags(nxi, NXF_LBACK_REMAP, 0)) { -+ if (ipv4_is_loopback(fl->fl4_dst)) -+ fl->fl4_dst = nxi->v4_lback.s_addr; -+ if (ipv4_is_loopback(fl->fl4_src)) -+ fl->fl4_src = nxi->v4_lback.s_addr; -+ } else if (ipv4_is_loopback(fl->fl4_dst) && -+ !nx_info_flags(nxi, NXF_LBACK_ALLOW, 0)) -+ return -EPERM; -+ -+ return 0; -+} -+ -+EXPORT_SYMBOL_GPL(ip_v4_find_src); -+ -diff -NurpP --minimal linux-2.6.32.1/kernel/vserver/init.c linux-2.6.32.1-vs2.3.0.36.27/kernel/vserver/init.c ---- linux-2.6.32.1/kernel/vserver/init.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/kernel/vserver/init.c 2009-12-03 20:04:56.000000000 +0100 -@@ -0,0 +1,45 @@ -+/* -+ * linux/kernel/init.c -+ * -+ * Virtual Server Init -+ * -+ * Copyright (C) 2004-2007 Herbert Pötzl -+ * -+ * V0.01 basic structure -+ * -+ */ -+ -+#include -+ -+int vserver_register_sysctl(void); -+void vserver_unregister_sysctl(void); -+ -+ -+static int __init init_vserver(void) -+{ -+ int ret = 0; -+ -+#ifdef CONFIG_VSERVER_DEBUG -+ vserver_register_sysctl(); -+#endif -+ return ret; -+} -+ -+ -+static void __exit exit_vserver(void) -+{ -+ -+#ifdef CONFIG_VSERVER_DEBUG -+ vserver_unregister_sysctl(); -+#endif -+ return; -+} -+ -+/* FIXME: GFP_ZONETYPES gone -+long vx_slab[GFP_ZONETYPES]; */ -+long vx_area; -+ -+ -+module_init(init_vserver); -+module_exit(exit_vserver); -+ -diff -NurpP --minimal linux-2.6.32.1/kernel/vserver/inode.c linux-2.6.32.1-vs2.3.0.36.27/kernel/vserver/inode.c ---- linux-2.6.32.1/kernel/vserver/inode.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/kernel/vserver/inode.c 2009-12-03 20:04:56.000000000 +0100 -@@ -0,0 +1,433 @@ -+/* -+ * linux/kernel/vserver/inode.c -+ * -+ * Virtual Server: File System Support -+ * -+ * Copyright (C) 2004-2007 Herbert Pötzl -+ * -+ * V0.01 separated from vcontext V0.05 -+ * V0.02 moved to tag (instead of xid) -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+ -+static int __vc_get_iattr(struct inode *in, uint32_t *tag, uint32_t *flags, uint32_t *mask) -+{ -+ struct proc_dir_entry *entry; -+ -+ if (!in || !in->i_sb) -+ return -ESRCH; -+ -+ *flags = IATTR_TAG -+ | (IS_IMMUTABLE(in) ? IATTR_IMMUTABLE : 0) -+ | (IS_IXUNLINK(in) ? IATTR_IXUNLINK : 0) -+ | (IS_BARRIER(in) ? IATTR_BARRIER : 0) -+ | (IS_COW(in) ? IATTR_COW : 0); -+ *mask = IATTR_IXUNLINK | IATTR_IMMUTABLE | IATTR_COW; -+ -+ if (S_ISDIR(in->i_mode)) -+ *mask |= IATTR_BARRIER; -+ -+ if (IS_TAGGED(in)) { -+ *tag = in->i_tag; -+ *mask |= IATTR_TAG; -+ } -+ -+ switch (in->i_sb->s_magic) { -+ case PROC_SUPER_MAGIC: -+ entry = PROC_I(in)->pde; -+ -+ /* check for specific inodes? */ -+ if (entry) -+ *mask |= IATTR_FLAGS; -+ if (entry) -+ *flags |= (entry->vx_flags & IATTR_FLAGS); -+ else -+ *flags |= (PROC_I(in)->vx_flags & IATTR_FLAGS); -+ break; -+ -+ case DEVPTS_SUPER_MAGIC: -+ *tag = in->i_tag; -+ *mask |= IATTR_TAG; -+ break; -+ -+ default: -+ break; -+ } -+ return 0; -+} -+ -+int vc_get_iattr(void __user *data) -+{ -+ struct path path; -+ struct vcmd_ctx_iattr_v1 vc_data = { .tag = -1 }; -+ int ret; -+ -+ if (copy_from_user(&vc_data, data, sizeof(vc_data))) -+ return -EFAULT; -+ -+ ret = user_lpath(vc_data.name, &path); -+ if (!ret) { -+ ret = __vc_get_iattr(path.dentry->d_inode, -+ &vc_data.tag, &vc_data.flags, &vc_data.mask); -+ path_put(&path); -+ } -+ if (ret) -+ return ret; -+ -+ if (copy_to_user(data, &vc_data, sizeof(vc_data))) -+ ret = -EFAULT; -+ return ret; -+} -+ -+#ifdef CONFIG_COMPAT -+ -+int vc_get_iattr_x32(void __user *data) -+{ -+ struct path path; -+ struct vcmd_ctx_iattr_v1_x32 vc_data = { .tag = -1 }; -+ int ret; -+ -+ if (copy_from_user(&vc_data, data, sizeof(vc_data))) -+ return -EFAULT; -+ -+ ret = user_lpath(compat_ptr(vc_data.name_ptr), &path); -+ if (!ret) { -+ ret = __vc_get_iattr(path.dentry->d_inode, -+ &vc_data.tag, &vc_data.flags, &vc_data.mask); -+ path_put(&path); -+ } -+ if (ret) -+ return ret; -+ -+ if (copy_to_user(data, &vc_data, sizeof(vc_data))) -+ ret = -EFAULT; -+ return ret; -+} -+ -+#endif /* CONFIG_COMPAT */ -+ -+ -+int vc_fget_iattr(uint32_t fd, void __user *data) -+{ -+ struct file *filp; -+ struct vcmd_ctx_fiattr_v0 vc_data = { .tag = -1 }; -+ int ret; -+ -+ if (copy_from_user(&vc_data, data, sizeof(vc_data))) -+ return -EFAULT; -+ -+ filp = fget(fd); -+ if (!filp || !filp->f_dentry || !filp->f_dentry->d_inode) -+ return -EBADF; -+ -+ ret = __vc_get_iattr(filp->f_dentry->d_inode, -+ &vc_data.tag, &vc_data.flags, &vc_data.mask); -+ -+ fput(filp); -+ -+ if (copy_to_user(data, &vc_data, sizeof(vc_data))) -+ ret = -EFAULT; -+ return ret; -+} -+ -+ -+static int __vc_set_iattr(struct dentry *de, uint32_t *tag, uint32_t *flags, uint32_t *mask) -+{ -+ struct inode *in = de->d_inode; -+ int error = 0, is_proc = 0, has_tag = 0; -+ struct iattr attr = { 0 }; -+ -+ if (!in || !in->i_sb) -+ return -ESRCH; -+ -+ is_proc = (in->i_sb->s_magic == PROC_SUPER_MAGIC); -+ if ((*mask & IATTR_FLAGS) && !is_proc) -+ return -EINVAL; -+ -+ has_tag = IS_TAGGED(in) || -+ (in->i_sb->s_magic == DEVPTS_SUPER_MAGIC); -+ if ((*mask & IATTR_TAG) && !has_tag) -+ return -EINVAL; -+ -+ mutex_lock(&in->i_mutex); -+ if (*mask & IATTR_TAG) { -+ attr.ia_tag = *tag; -+ attr.ia_valid |= ATTR_TAG; -+ } -+ -+ if (*mask & IATTR_FLAGS) { -+ struct proc_dir_entry *entry = PROC_I(in)->pde; -+ unsigned int iflags = PROC_I(in)->vx_flags; -+ -+ iflags = (iflags & ~(*mask & IATTR_FLAGS)) -+ | (*flags & IATTR_FLAGS); -+ PROC_I(in)->vx_flags = iflags; -+ if (entry) -+ entry->vx_flags = iflags; -+ } -+ -+ if (*mask & (IATTR_IMMUTABLE | IATTR_IXUNLINK | -+ IATTR_BARRIER | IATTR_COW)) { -+ int iflags = in->i_flags; -+ int vflags = in->i_vflags; -+ -+ if (*mask & IATTR_IMMUTABLE) { -+ if (*flags & IATTR_IMMUTABLE) -+ iflags |= S_IMMUTABLE; -+ else -+ iflags &= ~S_IMMUTABLE; -+ } -+ if (*mask & IATTR_IXUNLINK) { -+ if (*flags & IATTR_IXUNLINK) -+ iflags |= S_IXUNLINK; -+ else -+ iflags &= ~S_IXUNLINK; -+ } -+ if (S_ISDIR(in->i_mode) && (*mask & IATTR_BARRIER)) { -+ if (*flags & IATTR_BARRIER) -+ vflags |= V_BARRIER; -+ else -+ vflags &= ~V_BARRIER; -+ } -+ if (S_ISREG(in->i_mode) && (*mask & IATTR_COW)) { -+ if (*flags & IATTR_COW) -+ vflags |= V_COW; -+ else -+ vflags &= ~V_COW; -+ } -+ if (in->i_op && in->i_op->sync_flags) { -+ error = in->i_op->sync_flags(in, iflags, vflags); -+ if (error) -+ goto out; -+ } -+ } -+ -+ if (attr.ia_valid) { -+ if (in->i_op && in->i_op->setattr) -+ error = in->i_op->setattr(de, &attr); -+ else { -+ error = inode_change_ok(in, &attr); -+ if (!error) -+ error = inode_setattr(in, &attr); -+ } -+ } -+ -+out: -+ mutex_unlock(&in->i_mutex); -+ return error; -+} -+ -+int vc_set_iattr(void __user *data) -+{ -+ struct path path; -+ struct vcmd_ctx_iattr_v1 vc_data; -+ int ret; -+ -+ if (!capable(CAP_LINUX_IMMUTABLE)) -+ return -EPERM; -+ if (copy_from_user(&vc_data, data, sizeof(vc_data))) -+ return -EFAULT; -+ -+ ret = user_lpath(vc_data.name, &path); -+ if (!ret) { -+ ret = __vc_set_iattr(path.dentry, -+ &vc_data.tag, &vc_data.flags, &vc_data.mask); -+ path_put(&path); -+ } -+ -+ if (copy_to_user(data, &vc_data, sizeof(vc_data))) -+ ret = -EFAULT; -+ return ret; -+} -+ -+#ifdef CONFIG_COMPAT -+ -+int vc_set_iattr_x32(void __user *data) -+{ -+ struct path path; -+ struct vcmd_ctx_iattr_v1_x32 vc_data; -+ int ret; -+ -+ if (!capable(CAP_LINUX_IMMUTABLE)) -+ return -EPERM; -+ if (copy_from_user(&vc_data, data, sizeof(vc_data))) -+ return -EFAULT; -+ -+ ret = user_lpath(compat_ptr(vc_data.name_ptr), &path); -+ if (!ret) { -+ ret = __vc_set_iattr(path.dentry, -+ &vc_data.tag, &vc_data.flags, &vc_data.mask); -+ path_put(&path); -+ } -+ -+ if (copy_to_user(data, &vc_data, sizeof(vc_data))) -+ ret = -EFAULT; -+ return ret; -+} -+ -+#endif /* CONFIG_COMPAT */ -+ -+int vc_fset_iattr(uint32_t fd, void __user *data) -+{ -+ struct file *filp; -+ struct vcmd_ctx_fiattr_v0 vc_data; -+ int ret; -+ -+ if (!capable(CAP_LINUX_IMMUTABLE)) -+ return -EPERM; -+ if (copy_from_user(&vc_data, data, sizeof(vc_data))) -+ return -EFAULT; -+ -+ filp = fget(fd); -+ if (!filp || !filp->f_dentry || !filp->f_dentry->d_inode) -+ return -EBADF; -+ -+ ret = __vc_set_iattr(filp->f_dentry, &vc_data.tag, -+ &vc_data.flags, &vc_data.mask); -+ -+ fput(filp); -+ -+ if (copy_to_user(data, &vc_data, sizeof(vc_data))) -+ return -EFAULT; -+ return ret; -+} -+ -+ -+enum { Opt_notagcheck, Opt_tag, Opt_notag, Opt_tagid, Opt_err }; -+ -+static match_table_t tokens = { -+ {Opt_notagcheck, "notagcheck"}, -+#ifdef CONFIG_PROPAGATE -+ {Opt_notag, "notag"}, -+ {Opt_tag, "tag"}, -+ {Opt_tagid, "tagid=%u"}, -+#endif -+ {Opt_err, NULL} -+}; -+ -+ -+static void __dx_parse_remove(char *string, char *opt) -+{ -+ char *p = strstr(string, opt); -+ char *q = p; -+ -+ if (p) { -+ while (*q != '\0' && *q != ',') -+ q++; -+ while (*q) -+ *p++ = *q++; -+ while (*p) -+ *p++ = '\0'; -+ } -+} -+ -+int dx_parse_tag(char *string, tag_t *tag, int remove, int *mnt_flags, -+ unsigned long *flags) -+{ -+ int set = 0; -+ substring_t args[MAX_OPT_ARGS]; -+ int token, option = 0; -+ char *s, *p, *opts; -+ -+ if (!string) -+ return 0; -+ s = kstrdup(string, GFP_KERNEL | GFP_ATOMIC); -+ if (!s) -+ return 0; -+ -+ opts = s; -+ while ((p = strsep(&opts, ",")) != NULL) { -+ token = match_token(p, tokens, args); -+ -+ vxdprintk(VXD_CBIT(tag, 7), -+ "dx_parse_tag(»%s«): %d:#%d", -+ p, token, option); -+ -+ switch (token) { -+#ifdef CONFIG_PROPAGATE -+ case Opt_tag: -+ if (tag) -+ *tag = 0; -+ if (remove) -+ __dx_parse_remove(s, "tag"); -+ *mnt_flags |= MNT_TAGID; -+ set |= MNT_TAGID; -+ break; -+ case Opt_notag: -+ if (remove) -+ __dx_parse_remove(s, "notag"); -+ *mnt_flags |= MNT_NOTAG; -+ set |= MNT_NOTAG; -+ break; -+ case Opt_tagid: -+ if (tag && !match_int(args, &option)) -+ *tag = option; -+ if (remove) -+ __dx_parse_remove(s, "tagid"); -+ *mnt_flags |= MNT_TAGID; -+ set |= MNT_TAGID; -+ break; -+#endif -+ case Opt_notagcheck: -+ if (remove) -+ __dx_parse_remove(s, "notagcheck"); -+ *flags |= MS_NOTAGCHECK; -+ set |= MS_NOTAGCHECK; -+ break; -+ } -+ } -+ if (set) -+ strcpy(string, s); -+ kfree(s); -+ return set; -+} -+ -+#ifdef CONFIG_PROPAGATE -+ -+void __dx_propagate_tag(struct nameidata *nd, struct inode *inode) -+{ -+ tag_t new_tag = 0; -+ struct vfsmount *mnt; -+ int propagate; -+ -+ if (!nd) -+ return; -+ mnt = nd->path.mnt; -+ if (!mnt) -+ return; -+ -+ propagate = (mnt->mnt_flags & MNT_TAGID); -+ if (propagate) -+ new_tag = mnt->mnt_tag; -+ -+ vxdprintk(VXD_CBIT(tag, 7), -+ "dx_propagate_tag(%p[#%lu.%d]): %d,%d", -+ inode, inode->i_ino, inode->i_tag, -+ new_tag, (propagate) ? 1 : 0); -+ -+ if (propagate) -+ inode->i_tag = new_tag; -+} -+ -+#include -+ -+EXPORT_SYMBOL_GPL(__dx_propagate_tag); -+ -+#endif /* CONFIG_PROPAGATE */ -+ -diff -NurpP --minimal linux-2.6.32.1/kernel/vserver/Kconfig linux-2.6.32.1-vs2.3.0.36.27/kernel/vserver/Kconfig ---- linux-2.6.32.1/kernel/vserver/Kconfig 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/kernel/vserver/Kconfig 2009-12-03 20:04:56.000000000 +0100 -@@ -0,0 +1,251 @@ -+# -+# Linux VServer configuration -+# -+ -+menu "Linux VServer" -+ -+config VSERVER_AUTO_LBACK -+ bool "Automatically Assign Loopback IP" -+ default y -+ help -+ Automatically assign a guest specific loopback -+ IP and add it to the kernel network stack on -+ startup. -+ -+config VSERVER_AUTO_SINGLE -+ bool "Automatic Single IP Special Casing" -+ depends on EXPERIMENTAL -+ default y -+ help -+ This allows network contexts with a single IP to -+ automatically remap 0.0.0.0 bindings to that IP, -+ avoiding further network checks and improving -+ performance. -+ -+ (note: such guests do not allow to change the ip -+ on the fly and do not show loopback addresses) -+ -+config VSERVER_COWBL -+ bool "Enable COW Immutable Link Breaking" -+ default y -+ help -+ This enables the COW (Copy-On-Write) link break code. -+ It allows you to treat unified files like normal files -+ when writing to them (which will implicitely break the -+ link and create a copy of the unified file) -+ -+config VSERVER_VTIME -+ bool "Enable Virtualized Guest Time" -+ depends on EXPERIMENTAL -+ default n -+ help -+ This enables per guest time offsets to allow for -+ adjusting the system clock individually per guest. -+ this adds some overhead to the time functions and -+ therefore should not be enabled without good reason. -+ -+config VSERVER_DEVICE -+ bool "Enable Guest Device Mapping" -+ depends on EXPERIMENTAL -+ default n -+ help -+ This enables generic device remapping. -+ -+config VSERVER_PROC_SECURE -+ bool "Enable Proc Security" -+ depends on PROC_FS -+ default y -+ help -+ This configures ProcFS security to initially hide -+ non-process entries for all contexts except the main and -+ spectator context (i.e. for all guests), which is a secure -+ default. -+ -+ (note: on 1.2x the entries were visible by default) -+ -+config VSERVER_HARDCPU -+ bool "Enable Hard CPU Limits" -+ default y -+ help -+ Activate the Hard CPU Limits -+ -+ This will compile in code that allows the Token Bucket -+ Scheduler to put processes on hold when a context's -+ tokens are depleted (provided that its per-context -+ sched_hard flag is set). -+ -+ Processes belonging to that context will not be able -+ to consume CPU resources again until a per-context -+ configured minimum of tokens has been reached. -+ -+config VSERVER_IDLETIME -+ bool "Avoid idle CPUs by skipping Time" -+ depends on VSERVER_HARDCPU -+ default y -+ help -+ This option allows the scheduler to artificially -+ advance time (per cpu) when otherwise the idle -+ task would be scheduled, thus keeping the cpu -+ busy and sharing the available resources among -+ certain contexts. -+ -+config VSERVER_IDLELIMIT -+ bool "Limit the IDLE task" -+ depends on VSERVER_HARDCPU -+ default n -+ help -+ Limit the idle slices, so the the next context -+ will be scheduled as soon as possible. -+ -+ This might improve interactivity and latency, but -+ will also marginally increase scheduling overhead. -+ -+choice -+ prompt "Persistent Inode Tagging" -+ default TAGGING_ID24 -+ help -+ This adds persistent context information to filesystems -+ mounted with the tagxid option. Tagging is a requirement -+ for per-context disk limits and per-context quota. -+ -+ -+config TAGGING_NONE -+ bool "Disabled" -+ help -+ do not store per-context information in inodes. -+ -+config TAGGING_UID16 -+ bool "UID16/GID32" -+ help -+ reduces UID to 16 bit, but leaves GID at 32 bit. -+ -+config TAGGING_GID16 -+ bool "UID32/GID16" -+ help -+ reduces GID to 16 bit, but leaves UID at 32 bit. -+ -+config TAGGING_ID24 -+ bool "UID24/GID24" -+ help -+ uses the upper 8bit from UID and GID for XID tagging -+ which leaves 24bit for UID/GID each, which should be -+ more than sufficient for normal use. -+ -+config TAGGING_INTERN -+ bool "UID32/GID32" -+ help -+ this uses otherwise reserved inode fields in the on -+ disk representation, which limits the use to a few -+ filesystems (currently ext2 and ext3) -+ -+endchoice -+ -+config TAG_NFSD -+ bool "Tag NFSD User Auth and Files" -+ default n -+ help -+ Enable this if you do want the in-kernel NFS -+ Server to use the tagging specified above. -+ (will require patched clients too) -+ -+config VSERVER_PRIVACY -+ bool "Honor Privacy Aspects of Guests" -+ default n -+ help -+ When enabled, most context checks will disallow -+ access to structures assigned to a specific context, -+ like ptys or loop devices. -+ -+config VSERVER_CONTEXTS -+ int "Maximum number of Contexts (1-65533)" if EMBEDDED -+ range 1 65533 -+ default "768" if 64BIT -+ default "256" -+ help -+ This setting will optimize certain data structures -+ and memory allocations according to the expected -+ maximum. -+ -+ note: this is not a strict upper limit. -+ -+config VSERVER_WARN -+ bool "VServer Warnings" -+ default y -+ help -+ This enables various runtime warnings, which will -+ notify about potential manipulation attempts or -+ resource shortage. It is generally considered to -+ be a good idea to have that enabled. -+ -+config VSERVER_DEBUG -+ bool "VServer Debugging Code" -+ default n -+ help -+ Set this to yes if you want to be able to activate -+ debugging output at runtime. It adds a very small -+ overhead to all vserver related functions and -+ increases the kernel size by about 20k. -+ -+config VSERVER_HISTORY -+ bool "VServer History Tracing" -+ depends on VSERVER_DEBUG -+ default n -+ help -+ Set this to yes if you want to record the history of -+ linux-vserver activities, so they can be replayed in -+ the event of a kernel panic or oops. -+ -+config VSERVER_HISTORY_SIZE -+ int "Per-CPU History Size (32-65536)" -+ depends on VSERVER_HISTORY -+ range 32 65536 -+ default 64 -+ help -+ This allows you to specify the number of entries in -+ the per-CPU history buffer. -+ -+config VSERVER_MONITOR -+ bool "VServer Scheduling Monitor" -+ depends on VSERVER_DISABLED -+ default n -+ help -+ Set this to yes if you want to record the scheduling -+ decisions, so that they can be relayed to userspace -+ for detailed analysis. -+ -+config VSERVER_MONITOR_SIZE -+ int "Per-CPU Monitor Queue Size (32-65536)" -+ depends on VSERVER_MONITOR -+ range 32 65536 -+ default 1024 -+ help -+ This allows you to specify the number of entries in -+ the per-CPU scheduling monitor buffer. -+ -+config VSERVER_MONITOR_SYNC -+ int "Per-CPU Monitor Sync Interval (0-65536)" -+ depends on VSERVER_MONITOR -+ range 0 65536 -+ default 256 -+ help -+ This allows you to specify the interval in ticks -+ when a time sync entry is inserted. -+ -+endmenu -+ -+ -+config VSERVER -+ bool -+ default y -+ select NAMESPACES -+ select UTS_NS -+ select IPC_NS -+ select USER_NS -+ select SYSVIPC -+ -+config VSERVER_SECURITY -+ bool -+ depends on SECURITY -+ default y -+ select SECURITY_CAPABILITIES -+ -diff -NurpP --minimal linux-2.6.32.1/kernel/vserver/limit.c linux-2.6.32.1-vs2.3.0.36.27/kernel/vserver/limit.c ---- linux-2.6.32.1/kernel/vserver/limit.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/kernel/vserver/limit.c 2009-12-03 20:04:56.000000000 +0100 -@@ -0,0 +1,333 @@ -+/* -+ * linux/kernel/vserver/limit.c -+ * -+ * Virtual Server: Context Limits -+ * -+ * Copyright (C) 2004-2007 Herbert Pötzl -+ * -+ * V0.01 broken out from vcontext V0.05 -+ * V0.02 changed vcmds to vxi arg -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+ -+const char *vlimit_name[NUM_LIMITS] = { -+ [RLIMIT_CPU] = "CPU", -+ [RLIMIT_RSS] = "RSS", -+ [RLIMIT_NPROC] = "NPROC", -+ [RLIMIT_NOFILE] = "NOFILE", -+ [RLIMIT_MEMLOCK] = "VML", -+ [RLIMIT_AS] = "VM", -+ [RLIMIT_LOCKS] = "LOCKS", -+ [RLIMIT_SIGPENDING] = "SIGP", -+ [RLIMIT_MSGQUEUE] = "MSGQ", -+ -+ [VLIMIT_NSOCK] = "NSOCK", -+ [VLIMIT_OPENFD] = "OPENFD", -+ [VLIMIT_ANON] = "ANON", -+ [VLIMIT_SHMEM] = "SHMEM", -+ [VLIMIT_DENTRY] = "DENTRY", -+}; -+ -+EXPORT_SYMBOL_GPL(vlimit_name); -+ -+#define MASK_ENTRY(x) (1 << (x)) -+ -+const struct vcmd_ctx_rlimit_mask_v0 vlimit_mask = { -+ /* minimum */ -+ 0 -+ , /* softlimit */ -+ MASK_ENTRY( RLIMIT_RSS ) | -+ MASK_ENTRY( VLIMIT_ANON ) | -+ 0 -+ , /* maximum */ -+ MASK_ENTRY( RLIMIT_RSS ) | -+ MASK_ENTRY( RLIMIT_NPROC ) | -+ MASK_ENTRY( RLIMIT_NOFILE ) | -+ MASK_ENTRY( RLIMIT_MEMLOCK ) | -+ MASK_ENTRY( RLIMIT_AS ) | -+ MASK_ENTRY( RLIMIT_LOCKS ) | -+ MASK_ENTRY( RLIMIT_MSGQUEUE ) | -+ -+ MASK_ENTRY( VLIMIT_NSOCK ) | -+ MASK_ENTRY( VLIMIT_OPENFD ) | -+ MASK_ENTRY( VLIMIT_ANON ) | -+ MASK_ENTRY( VLIMIT_SHMEM ) | -+ MASK_ENTRY( VLIMIT_DENTRY ) | -+ 0 -+}; -+ /* accounting only */ -+uint32_t account_mask = -+ MASK_ENTRY( VLIMIT_SEMARY ) | -+ MASK_ENTRY( VLIMIT_NSEMS ) | -+ MASK_ENTRY( VLIMIT_MAPPED ) | -+ 0; -+ -+ -+static int is_valid_vlimit(int id) -+{ -+ uint32_t mask = vlimit_mask.minimum | -+ vlimit_mask.softlimit | vlimit_mask.maximum; -+ return mask & (1 << id); -+} -+ -+static int is_accounted_vlimit(int id) -+{ -+ if (is_valid_vlimit(id)) -+ return 1; -+ return account_mask & (1 << id); -+} -+ -+ -+static inline uint64_t vc_get_soft(struct vx_info *vxi, int id) -+{ -+ rlim_t limit = __rlim_soft(&vxi->limit, id); -+ return VX_VLIM(limit); -+} -+ -+static inline uint64_t vc_get_hard(struct vx_info *vxi, int id) -+{ -+ rlim_t limit = __rlim_hard(&vxi->limit, id); -+ return VX_VLIM(limit); -+} -+ -+static int do_get_rlimit(struct vx_info *vxi, uint32_t id, -+ uint64_t *minimum, uint64_t *softlimit, uint64_t *maximum) -+{ -+ if (!is_valid_vlimit(id)) -+ return -EINVAL; -+ -+ if (minimum) -+ *minimum = CRLIM_UNSET; -+ if (softlimit) -+ *softlimit = vc_get_soft(vxi, id); -+ if (maximum) -+ *maximum = vc_get_hard(vxi, id); -+ return 0; -+} -+ -+int vc_get_rlimit(struct vx_info *vxi, void __user *data) -+{ -+ struct vcmd_ctx_rlimit_v0 vc_data; -+ int ret; -+ -+ if (copy_from_user(&vc_data, data, sizeof(vc_data))) -+ return -EFAULT; -+ -+ ret = do_get_rlimit(vxi, vc_data.id, -+ &vc_data.minimum, &vc_data.softlimit, &vc_data.maximum); -+ if (ret) -+ return ret; -+ -+ if (copy_to_user(data, &vc_data, sizeof(vc_data))) -+ return -EFAULT; -+ return 0; -+} -+ -+static int do_set_rlimit(struct vx_info *vxi, uint32_t id, -+ uint64_t minimum, uint64_t softlimit, uint64_t maximum) -+{ -+ if (!is_valid_vlimit(id)) -+ return -EINVAL; -+ -+ if (maximum != CRLIM_KEEP) -+ __rlim_hard(&vxi->limit, id) = VX_RLIM(maximum); -+ if (softlimit != CRLIM_KEEP) -+ __rlim_soft(&vxi->limit, id) = VX_RLIM(softlimit); -+ -+ /* clamp soft limit */ -+ if (__rlim_soft(&vxi->limit, id) > __rlim_hard(&vxi->limit, id)) -+ __rlim_soft(&vxi->limit, id) = __rlim_hard(&vxi->limit, id); -+ -+ return 0; -+} -+ -+int vc_set_rlimit(struct vx_info *vxi, void __user *data) -+{ -+ struct vcmd_ctx_rlimit_v0 vc_data; -+ -+ if (copy_from_user(&vc_data, data, sizeof(vc_data))) -+ return -EFAULT; -+ -+ return do_set_rlimit(vxi, vc_data.id, -+ vc_data.minimum, vc_data.softlimit, vc_data.maximum); -+} -+ -+#ifdef CONFIG_IA32_EMULATION -+ -+int vc_set_rlimit_x32(struct vx_info *vxi, void __user *data) -+{ -+ struct vcmd_ctx_rlimit_v0_x32 vc_data; -+ -+ if (copy_from_user(&vc_data, data, sizeof(vc_data))) -+ return -EFAULT; -+ -+ return do_set_rlimit(vxi, vc_data.id, -+ vc_data.minimum, vc_data.softlimit, vc_data.maximum); -+} -+ -+int vc_get_rlimit_x32(struct vx_info *vxi, void __user *data) -+{ -+ struct vcmd_ctx_rlimit_v0_x32 vc_data; -+ int ret; -+ -+ if (copy_from_user(&vc_data, data, sizeof(vc_data))) -+ return -EFAULT; -+ -+ ret = do_get_rlimit(vxi, vc_data.id, -+ &vc_data.minimum, &vc_data.softlimit, &vc_data.maximum); -+ if (ret) -+ return ret; -+ -+ if (copy_to_user(data, &vc_data, sizeof(vc_data))) -+ return -EFAULT; -+ return 0; -+} -+ -+#endif /* CONFIG_IA32_EMULATION */ -+ -+ -+int vc_get_rlimit_mask(uint32_t id, void __user *data) -+{ -+ if (copy_to_user(data, &vlimit_mask, sizeof(vlimit_mask))) -+ return -EFAULT; -+ return 0; -+} -+ -+ -+static inline void vx_reset_hits(struct _vx_limit *limit) -+{ -+ int lim; -+ -+ for (lim = 0; lim < NUM_LIMITS; lim++) { -+ atomic_set(&__rlim_lhit(limit, lim), 0); -+ } -+} -+ -+int vc_reset_hits(struct vx_info *vxi, void __user *data) -+{ -+ vx_reset_hits(&vxi->limit); -+ return 0; -+} -+ -+static inline void vx_reset_minmax(struct _vx_limit *limit) -+{ -+ rlim_t value; -+ int lim; -+ -+ for (lim = 0; lim < NUM_LIMITS; lim++) { -+ value = __rlim_get(limit, lim); -+ __rlim_rmax(limit, lim) = value; -+ __rlim_rmin(limit, lim) = value; -+ } -+} -+ -+int vc_reset_minmax(struct vx_info *vxi, void __user *data) -+{ -+ vx_reset_minmax(&vxi->limit); -+ return 0; -+} -+ -+ -+int vc_rlimit_stat(struct vx_info *vxi, void __user *data) -+{ -+ struct vcmd_rlimit_stat_v0 vc_data; -+ struct _vx_limit *limit = &vxi->limit; -+ int id; -+ -+ if (copy_from_user(&vc_data, data, sizeof(vc_data))) -+ return -EFAULT; -+ -+ id = vc_data.id; -+ if (!is_accounted_vlimit(id)) -+ return -EINVAL; -+ -+ vx_limit_fixup(limit, id); -+ vc_data.hits = atomic_read(&__rlim_lhit(limit, id)); -+ vc_data.value = __rlim_get(limit, id); -+ vc_data.minimum = __rlim_rmin(limit, id); -+ vc_data.maximum = __rlim_rmax(limit, id); -+ -+ if (copy_to_user(data, &vc_data, sizeof(vc_data))) -+ return -EFAULT; -+ return 0; -+} -+ -+ -+void vx_vsi_meminfo(struct sysinfo *val) -+{ -+ struct vx_info *vxi = current_vx_info(); -+ unsigned long totalram, freeram; -+ rlim_t v; -+ -+ /* we blindly accept the max */ -+ v = __rlim_soft(&vxi->limit, RLIMIT_RSS); -+ totalram = (v != RLIM_INFINITY) ? v : val->totalram; -+ -+ /* total minus used equals free */ -+ v = __vx_cres_array_fixup(&vxi->limit, VLA_RSS); -+ freeram = (v < totalram) ? totalram - v : 0; -+ -+ val->totalram = totalram; -+ val->freeram = freeram; -+ val->bufferram = 0; -+ val->totalhigh = 0; -+ val->freehigh = 0; -+ return; -+} -+ -+void vx_vsi_swapinfo(struct sysinfo *val) -+{ -+ struct vx_info *vxi = current_vx_info(); -+ unsigned long totalswap, freeswap; -+ rlim_t v, w; -+ -+ v = __rlim_soft(&vxi->limit, RLIMIT_RSS); -+ if (v == RLIM_INFINITY) { -+ val->freeswap = val->totalswap; -+ return; -+ } -+ -+ /* we blindly accept the max */ -+ w = __rlim_hard(&vxi->limit, RLIMIT_RSS); -+ totalswap = (w != RLIM_INFINITY) ? (w - v) : val->totalswap; -+ -+ /* currently 'used' swap */ -+ w = __vx_cres_array_fixup(&vxi->limit, VLA_RSS); -+ w -= (w > v) ? v : w; -+ -+ /* total minus used equals free */ -+ freeswap = (w < totalswap) ? totalswap - w : 0; -+ -+ val->totalswap = totalswap; -+ val->freeswap = freeswap; -+ return; -+} -+ -+ -+unsigned long vx_badness(struct task_struct *task, struct mm_struct *mm) -+{ -+ struct vx_info *vxi = mm->mm_vx_info; -+ unsigned long points; -+ rlim_t v, w; -+ -+ if (!vxi) -+ return 0; -+ -+ points = vxi->vx_badness_bias; -+ -+ v = __vx_cres_array_fixup(&vxi->limit, VLA_RSS); -+ w = __rlim_soft(&vxi->limit, RLIMIT_RSS); -+ points += (v > w) ? (v - w) : 0; -+ -+ return points; -+} -+ -diff -NurpP --minimal linux-2.6.32.1/kernel/vserver/limit_init.h linux-2.6.32.1-vs2.3.0.36.27/kernel/vserver/limit_init.h ---- linux-2.6.32.1/kernel/vserver/limit_init.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/kernel/vserver/limit_init.h 2009-12-03 20:04:56.000000000 +0100 -@@ -0,0 +1,31 @@ -+ -+ -+static inline void vx_info_init_limit(struct _vx_limit *limit) -+{ -+ int lim; -+ -+ for (lim = 0; lim < NUM_LIMITS; lim++) { -+ __rlim_soft(limit, lim) = RLIM_INFINITY; -+ __rlim_hard(limit, lim) = RLIM_INFINITY; -+ __rlim_set(limit, lim, 0); -+ atomic_set(&__rlim_lhit(limit, lim), 0); -+ __rlim_rmin(limit, lim) = 0; -+ __rlim_rmax(limit, lim) = 0; -+ } -+} -+ -+static inline void vx_info_exit_limit(struct _vx_limit *limit) -+{ -+ rlim_t value; -+ int lim; -+ -+ for (lim = 0; lim < NUM_LIMITS; lim++) { -+ if ((1 << lim) & VLIM_NOCHECK) -+ continue; -+ value = __rlim_get(limit, lim); -+ vxwprintk_xid(value, -+ "!!! limit: %p[%s,%d] = %ld on exit.", -+ limit, vlimit_name[lim], lim, (long)value); -+ } -+} -+ -diff -NurpP --minimal linux-2.6.32.1/kernel/vserver/limit_proc.h linux-2.6.32.1-vs2.3.0.36.27/kernel/vserver/limit_proc.h ---- linux-2.6.32.1/kernel/vserver/limit_proc.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/kernel/vserver/limit_proc.h 2009-12-03 20:04:56.000000000 +0100 -@@ -0,0 +1,57 @@ -+#ifndef _VX_LIMIT_PROC_H -+#define _VX_LIMIT_PROC_H -+ -+#include -+ -+ -+#define VX_LIMIT_FMT ":\t%8ld\t%8ld/%8ld\t%8lld/%8lld\t%6d\n" -+#define VX_LIMIT_TOP \ -+ "Limit\t current\t min/max\t\t soft/hard\t\thits\n" -+ -+#define VX_LIMIT_ARG(r) \ -+ (unsigned long)__rlim_get(limit, r), \ -+ (unsigned long)__rlim_rmin(limit, r), \ -+ (unsigned long)__rlim_rmax(limit, r), \ -+ VX_VLIM(__rlim_soft(limit, r)), \ -+ VX_VLIM(__rlim_hard(limit, r)), \ -+ atomic_read(&__rlim_lhit(limit, r)) -+ -+static inline int vx_info_proc_limit(struct _vx_limit *limit, char *buffer) -+{ -+ vx_limit_fixup(limit, -1); -+ return sprintf(buffer, VX_LIMIT_TOP -+ "PROC" VX_LIMIT_FMT -+ "VM" VX_LIMIT_FMT -+ "VML" VX_LIMIT_FMT -+ "RSS" VX_LIMIT_FMT -+ "ANON" VX_LIMIT_FMT -+ "RMAP" VX_LIMIT_FMT -+ "FILES" VX_LIMIT_FMT -+ "OFD" VX_LIMIT_FMT -+ "LOCKS" VX_LIMIT_FMT -+ "SOCK" VX_LIMIT_FMT -+ "MSGQ" VX_LIMIT_FMT -+ "SHM" VX_LIMIT_FMT -+ "SEMA" VX_LIMIT_FMT -+ "SEMS" VX_LIMIT_FMT -+ "DENT" VX_LIMIT_FMT, -+ VX_LIMIT_ARG(RLIMIT_NPROC), -+ VX_LIMIT_ARG(RLIMIT_AS), -+ VX_LIMIT_ARG(RLIMIT_MEMLOCK), -+ VX_LIMIT_ARG(RLIMIT_RSS), -+ VX_LIMIT_ARG(VLIMIT_ANON), -+ VX_LIMIT_ARG(VLIMIT_MAPPED), -+ VX_LIMIT_ARG(RLIMIT_NOFILE), -+ VX_LIMIT_ARG(VLIMIT_OPENFD), -+ VX_LIMIT_ARG(RLIMIT_LOCKS), -+ VX_LIMIT_ARG(VLIMIT_NSOCK), -+ VX_LIMIT_ARG(RLIMIT_MSGQUEUE), -+ VX_LIMIT_ARG(VLIMIT_SHMEM), -+ VX_LIMIT_ARG(VLIMIT_SEMARY), -+ VX_LIMIT_ARG(VLIMIT_NSEMS), -+ VX_LIMIT_ARG(VLIMIT_DENTRY)); -+} -+ -+#endif /* _VX_LIMIT_PROC_H */ -+ -+ -diff -NurpP --minimal linux-2.6.32.1/kernel/vserver/Makefile linux-2.6.32.1-vs2.3.0.36.27/kernel/vserver/Makefile ---- linux-2.6.32.1/kernel/vserver/Makefile 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/kernel/vserver/Makefile 2009-12-03 20:04:56.000000000 +0100 -@@ -0,0 +1,18 @@ -+# -+# Makefile for the Linux vserver routines. -+# -+ -+ -+obj-y += vserver.o -+ -+vserver-y := switch.o context.o space.o sched.o network.o inode.o \ -+ limit.o cvirt.o cacct.o signal.o helper.o init.o \ -+ dlimit.o tag.o -+ -+vserver-$(CONFIG_INET) += inet.o -+vserver-$(CONFIG_PROC_FS) += proc.o -+vserver-$(CONFIG_VSERVER_DEBUG) += sysctl.o debug.o -+vserver-$(CONFIG_VSERVER_HISTORY) += history.o -+vserver-$(CONFIG_VSERVER_MONITOR) += monitor.o -+vserver-$(CONFIG_VSERVER_DEVICE) += device.o -+ -diff -NurpP --minimal linux-2.6.32.1/kernel/vserver/monitor.c linux-2.6.32.1-vs2.3.0.36.27/kernel/vserver/monitor.c ---- linux-2.6.32.1/kernel/vserver/monitor.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/kernel/vserver/monitor.c 2009-12-03 20:04:56.000000000 +0100 -@@ -0,0 +1,138 @@ -+/* -+ * kernel/vserver/monitor.c -+ * -+ * Virtual Context Scheduler Monitor -+ * -+ * Copyright (C) 2006-2007 Herbert Pötzl -+ * -+ * V0.01 basic design -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+ -+#ifdef CONFIG_VSERVER_MONITOR -+#define VXM_SIZE CONFIG_VSERVER_MONITOR_SIZE -+#else -+#define VXM_SIZE 64 -+#endif -+ -+struct _vx_monitor { -+ unsigned int counter; -+ -+ struct _vx_mon_entry entry[VXM_SIZE+1]; -+}; -+ -+ -+DEFINE_PER_CPU(struct _vx_monitor, vx_monitor_buffer); -+ -+unsigned volatile int vxm_active = 1; -+ -+static atomic_t sequence = ATOMIC_INIT(0); -+ -+ -+/* vxm_advance() -+ -+ * requires disabled preemption */ -+ -+struct _vx_mon_entry *vxm_advance(int cpu) -+{ -+ struct _vx_monitor *mon = &per_cpu(vx_monitor_buffer, cpu); -+ struct _vx_mon_entry *entry; -+ unsigned int index; -+ -+ index = vxm_active ? (mon->counter++ % VXM_SIZE) : VXM_SIZE; -+ entry = &mon->entry[index]; -+ -+ entry->ev.seq = atomic_inc_return(&sequence); -+ entry->ev.jif = jiffies; -+ return entry; -+} -+ -+EXPORT_SYMBOL_GPL(vxm_advance); -+ -+ -+int do_read_monitor(struct __user _vx_mon_entry *data, -+ int cpu, uint32_t *index, uint32_t *count) -+{ -+ int pos, ret = 0; -+ struct _vx_monitor *mon = &per_cpu(vx_monitor_buffer, cpu); -+ int end = mon->counter; -+ int start = end - VXM_SIZE + 2; -+ int idx = *index; -+ -+ /* special case: get current pos */ -+ if (!*count) { -+ *index = end; -+ return 0; -+ } -+ -+ /* have we lost some data? */ -+ if (idx < start) -+ idx = start; -+ -+ for (pos = 0; (pos < *count) && (idx < end); pos++, idx++) { -+ struct _vx_mon_entry *entry = -+ &mon->entry[idx % VXM_SIZE]; -+ -+ /* send entry to userspace */ -+ ret = copy_to_user(&data[pos], entry, sizeof(*entry)); -+ if (ret) -+ break; -+ } -+ /* save new index and count */ -+ *index = idx; -+ *count = pos; -+ return ret ? ret : (*index < end); -+} -+ -+int vc_read_monitor(uint32_t id, void __user *data) -+{ -+ struct vcmd_read_monitor_v0 vc_data; -+ int ret; -+ -+ if (id >= NR_CPUS) -+ return -EINVAL; -+ -+ if (copy_from_user(&vc_data, data, sizeof(vc_data))) -+ return -EFAULT; -+ -+ ret = do_read_monitor((struct __user _vx_mon_entry *)vc_data.data, -+ id, &vc_data.index, &vc_data.count); -+ -+ if (copy_to_user(data, &vc_data, sizeof(vc_data))) -+ return -EFAULT; -+ return ret; -+} -+ -+#ifdef CONFIG_COMPAT -+ -+int vc_read_monitor_x32(uint32_t id, void __user *data) -+{ -+ struct vcmd_read_monitor_v0_x32 vc_data; -+ int ret; -+ -+ if (id >= NR_CPUS) -+ return -EINVAL; -+ -+ if (copy_from_user(&vc_data, data, sizeof(vc_data))) -+ return -EFAULT; -+ -+ ret = do_read_monitor((struct __user _vx_mon_entry *) -+ compat_ptr(vc_data.data_ptr), -+ id, &vc_data.index, &vc_data.count); -+ -+ if (copy_to_user(data, &vc_data, sizeof(vc_data))) -+ return -EFAULT; -+ return ret; -+} -+ -+#endif /* CONFIG_COMPAT */ -+ -diff -NurpP --minimal linux-2.6.32.1/kernel/vserver/network.c linux-2.6.32.1-vs2.3.0.36.27/kernel/vserver/network.c ---- linux-2.6.32.1/kernel/vserver/network.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/kernel/vserver/network.c 2009-12-03 20:04:56.000000000 +0100 -@@ -0,0 +1,864 @@ -+/* -+ * linux/kernel/vserver/network.c -+ * -+ * Virtual Server: Network Support -+ * -+ * Copyright (C) 2003-2007 Herbert Pötzl -+ * -+ * V0.01 broken out from vcontext V0.05 -+ * V0.02 cleaned up implementation -+ * V0.03 added equiv nx commands -+ * V0.04 switch to RCU based hash -+ * V0.05 and back to locking again -+ * V0.06 changed vcmds to nxi arg -+ * V0.07 have __create claim() the nxi -+ * -+ */ -+ -+#include -+#include -+#include -+ -+#include -+#include -+#include -+ -+ -+atomic_t nx_global_ctotal = ATOMIC_INIT(0); -+atomic_t nx_global_cactive = ATOMIC_INIT(0); -+ -+static struct kmem_cache *nx_addr_v4_cachep = NULL; -+static struct kmem_cache *nx_addr_v6_cachep = NULL; -+ -+ -+static int __init init_network(void) -+{ -+ nx_addr_v4_cachep = kmem_cache_create("nx_v4_addr_cache", -+ sizeof(struct nx_addr_v4), 0, -+ SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL); -+ nx_addr_v6_cachep = kmem_cache_create("nx_v6_addr_cache", -+ sizeof(struct nx_addr_v6), 0, -+ SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL); -+ return 0; -+} -+ -+ -+/* __alloc_nx_addr_v4() */ -+ -+static inline struct nx_addr_v4 *__alloc_nx_addr_v4(void) -+{ -+ struct nx_addr_v4 *nxa = kmem_cache_alloc( -+ nx_addr_v4_cachep, GFP_KERNEL); -+ -+ if (!IS_ERR(nxa)) -+ memset(nxa, 0, sizeof(*nxa)); -+ return nxa; -+} -+ -+/* __dealloc_nx_addr_v4() */ -+ -+static inline void __dealloc_nx_addr_v4(struct nx_addr_v4 *nxa) -+{ -+ kmem_cache_free(nx_addr_v4_cachep, nxa); -+} -+ -+/* __dealloc_nx_addr_v4_all() */ -+ -+static inline void __dealloc_nx_addr_v4_all(struct nx_addr_v4 *nxa) -+{ -+ while (nxa) { -+ struct nx_addr_v4 *next = nxa->next; -+ -+ __dealloc_nx_addr_v4(nxa); -+ nxa = next; -+ } -+} -+ -+ -+#ifdef CONFIG_IPV6 -+ -+/* __alloc_nx_addr_v6() */ -+ -+static inline struct nx_addr_v6 *__alloc_nx_addr_v6(void) -+{ -+ struct nx_addr_v6 *nxa = kmem_cache_alloc( -+ nx_addr_v6_cachep, GFP_KERNEL); -+ -+ if (!IS_ERR(nxa)) -+ memset(nxa, 0, sizeof(*nxa)); -+ return nxa; -+} -+ -+/* __dealloc_nx_addr_v6() */ -+ -+static inline void __dealloc_nx_addr_v6(struct nx_addr_v6 *nxa) -+{ -+ kmem_cache_free(nx_addr_v6_cachep, nxa); -+} -+ -+/* __dealloc_nx_addr_v6_all() */ -+ -+static inline void __dealloc_nx_addr_v6_all(struct nx_addr_v6 *nxa) -+{ -+ while (nxa) { -+ struct nx_addr_v6 *next = nxa->next; -+ -+ __dealloc_nx_addr_v6(nxa); -+ nxa = next; -+ } -+} -+ -+#endif /* CONFIG_IPV6 */ -+ -+/* __alloc_nx_info() -+ -+ * allocate an initialized nx_info struct -+ * doesn't make it visible (hash) */ -+ -+static struct nx_info *__alloc_nx_info(nid_t nid) -+{ -+ struct nx_info *new = NULL; -+ -+ vxdprintk(VXD_CBIT(nid, 1), "alloc_nx_info(%d)*", nid); -+ -+ /* would this benefit from a slab cache? */ -+ new = kmalloc(sizeof(struct nx_info), GFP_KERNEL); -+ if (!new) -+ return 0; -+ -+ memset(new, 0, sizeof(struct nx_info)); -+ new->nx_id = nid; -+ INIT_HLIST_NODE(&new->nx_hlist); -+ atomic_set(&new->nx_usecnt, 0); -+ atomic_set(&new->nx_tasks, 0); -+ new->nx_state = 0; -+ -+ new->nx_flags = NXF_INIT_SET; -+ -+ /* rest of init goes here */ -+ -+ new->v4_lback.s_addr = htonl(INADDR_LOOPBACK); -+ new->v4_bcast.s_addr = htonl(INADDR_BROADCAST); -+ -+ vxdprintk(VXD_CBIT(nid, 0), -+ "alloc_nx_info(%d) = %p", nid, new); -+ atomic_inc(&nx_global_ctotal); -+ return new; -+} -+ -+/* __dealloc_nx_info() -+ -+ * final disposal of nx_info */ -+ -+static void __dealloc_nx_info(struct nx_info *nxi) -+{ -+ vxdprintk(VXD_CBIT(nid, 0), -+ "dealloc_nx_info(%p)", nxi); -+ -+ nxi->nx_hlist.next = LIST_POISON1; -+ nxi->nx_id = -1; -+ -+ BUG_ON(atomic_read(&nxi->nx_usecnt)); -+ BUG_ON(atomic_read(&nxi->nx_tasks)); -+ -+ __dealloc_nx_addr_v4_all(nxi->v4.next); -+ -+ nxi->nx_state |= NXS_RELEASED; -+ kfree(nxi); -+ atomic_dec(&nx_global_ctotal); -+} -+ -+static void __shutdown_nx_info(struct nx_info *nxi) -+{ -+ nxi->nx_state |= NXS_SHUTDOWN; -+ vs_net_change(nxi, VSC_NETDOWN); -+} -+ -+/* exported stuff */ -+ -+void free_nx_info(struct nx_info *nxi) -+{ -+ /* context shutdown is mandatory */ -+ BUG_ON(nxi->nx_state != NXS_SHUTDOWN); -+ -+ /* context must not be hashed */ -+ BUG_ON(nxi->nx_state & NXS_HASHED); -+ -+ BUG_ON(atomic_read(&nxi->nx_usecnt)); -+ BUG_ON(atomic_read(&nxi->nx_tasks)); -+ -+ __dealloc_nx_info(nxi); -+} -+ -+ -+void __nx_set_lback(struct nx_info *nxi) -+{ -+ int nid = nxi->nx_id; -+ __be32 lback = htonl(INADDR_LOOPBACK ^ ((nid & 0xFFFF) << 8)); -+ -+ nxi->v4_lback.s_addr = lback; -+} -+ -+extern int __nx_inet_add_lback(__be32 addr); -+extern int __nx_inet_del_lback(__be32 addr); -+ -+ -+/* hash table for nx_info hash */ -+ -+#define NX_HASH_SIZE 13 -+ -+struct hlist_head nx_info_hash[NX_HASH_SIZE]; -+ -+static spinlock_t nx_info_hash_lock = SPIN_LOCK_UNLOCKED; -+ -+ -+static inline unsigned int __hashval(nid_t nid) -+{ -+ return (nid % NX_HASH_SIZE); -+} -+ -+ -+ -+/* __hash_nx_info() -+ -+ * add the nxi to the global hash table -+ * requires the hash_lock to be held */ -+ -+static inline void __hash_nx_info(struct nx_info *nxi) -+{ -+ struct hlist_head *head; -+ -+ vxd_assert_lock(&nx_info_hash_lock); -+ vxdprintk(VXD_CBIT(nid, 4), -+ "__hash_nx_info: %p[#%d]", nxi, nxi->nx_id); -+ -+ /* context must not be hashed */ -+ BUG_ON(nx_info_state(nxi, NXS_HASHED)); -+ -+ nxi->nx_state |= NXS_HASHED; -+ head = &nx_info_hash[__hashval(nxi->nx_id)]; -+ hlist_add_head(&nxi->nx_hlist, head); -+ atomic_inc(&nx_global_cactive); -+} -+ -+/* __unhash_nx_info() -+ -+ * remove the nxi from the global hash table -+ * requires the hash_lock to be held */ -+ -+static inline void __unhash_nx_info(struct nx_info *nxi) -+{ -+ vxd_assert_lock(&nx_info_hash_lock); -+ vxdprintk(VXD_CBIT(nid, 4), -+ "__unhash_nx_info: %p[#%d.%d.%d]", nxi, nxi->nx_id, -+ atomic_read(&nxi->nx_usecnt), atomic_read(&nxi->nx_tasks)); -+ -+ /* context must be hashed */ -+ BUG_ON(!nx_info_state(nxi, NXS_HASHED)); -+ /* but without tasks */ -+ BUG_ON(atomic_read(&nxi->nx_tasks)); -+ -+ nxi->nx_state &= ~NXS_HASHED; -+ hlist_del(&nxi->nx_hlist); -+ atomic_dec(&nx_global_cactive); -+} -+ -+ -+/* __lookup_nx_info() -+ -+ * requires the hash_lock to be held -+ * doesn't increment the nx_refcnt */ -+ -+static inline struct nx_info *__lookup_nx_info(nid_t nid) -+{ -+ struct hlist_head *head = &nx_info_hash[__hashval(nid)]; -+ struct hlist_node *pos; -+ struct nx_info *nxi; -+ -+ vxd_assert_lock(&nx_info_hash_lock); -+ hlist_for_each(pos, head) { -+ nxi = hlist_entry(pos, struct nx_info, nx_hlist); -+ -+ if (nxi->nx_id == nid) -+ goto found; -+ } -+ nxi = NULL; -+found: -+ vxdprintk(VXD_CBIT(nid, 0), -+ "__lookup_nx_info(#%u): %p[#%u]", -+ nid, nxi, nxi ? nxi->nx_id : 0); -+ return nxi; -+} -+ -+ -+/* __create_nx_info() -+ -+ * create the requested context -+ * get(), claim() and hash it */ -+ -+static struct nx_info *__create_nx_info(int id) -+{ -+ struct nx_info *new, *nxi = NULL; -+ -+ vxdprintk(VXD_CBIT(nid, 1), "create_nx_info(%d)*", id); -+ -+ if (!(new = __alloc_nx_info(id))) -+ return ERR_PTR(-ENOMEM); -+ -+ /* required to make dynamic xids unique */ -+ spin_lock(&nx_info_hash_lock); -+ -+ /* static context requested */ -+ if ((nxi = __lookup_nx_info(id))) { -+ vxdprintk(VXD_CBIT(nid, 0), -+ "create_nx_info(%d) = %p (already there)", id, nxi); -+ if (nx_info_flags(nxi, NXF_STATE_SETUP, 0)) -+ nxi = ERR_PTR(-EBUSY); -+ else -+ nxi = ERR_PTR(-EEXIST); -+ goto out_unlock; -+ } -+ /* new context */ -+ vxdprintk(VXD_CBIT(nid, 0), -+ "create_nx_info(%d) = %p (new)", id, new); -+ claim_nx_info(new, NULL); -+ __nx_set_lback(new); -+ __hash_nx_info(get_nx_info(new)); -+ nxi = new, new = NULL; -+ -+out_unlock: -+ spin_unlock(&nx_info_hash_lock); -+ if (new) -+ __dealloc_nx_info(new); -+ return nxi; -+} -+ -+ -+ -+/* exported stuff */ -+ -+ -+void unhash_nx_info(struct nx_info *nxi) -+{ -+ __shutdown_nx_info(nxi); -+ spin_lock(&nx_info_hash_lock); -+ __unhash_nx_info(nxi); -+ spin_unlock(&nx_info_hash_lock); -+} -+ -+/* lookup_nx_info() -+ -+ * search for a nx_info and get() it -+ * negative id means current */ -+ -+struct nx_info *lookup_nx_info(int id) -+{ -+ struct nx_info *nxi = NULL; -+ -+ if (id < 0) { -+ nxi = get_nx_info(current_nx_info()); -+ } else if (id > 1) { -+ spin_lock(&nx_info_hash_lock); -+ nxi = get_nx_info(__lookup_nx_info(id)); -+ spin_unlock(&nx_info_hash_lock); -+ } -+ return nxi; -+} -+ -+/* nid_is_hashed() -+ -+ * verify that nid is still hashed */ -+ -+int nid_is_hashed(nid_t nid) -+{ -+ int hashed; -+ -+ spin_lock(&nx_info_hash_lock); -+ hashed = (__lookup_nx_info(nid) != NULL); -+ spin_unlock(&nx_info_hash_lock); -+ return hashed; -+} -+ -+ -+#ifdef CONFIG_PROC_FS -+ -+/* get_nid_list() -+ -+ * get a subset of hashed nids for proc -+ * assumes size is at least one */ -+ -+int get_nid_list(int index, unsigned int *nids, int size) -+{ -+ int hindex, nr_nids = 0; -+ -+ /* only show current and children */ -+ if (!nx_check(0, VS_ADMIN | VS_WATCH)) { -+ if (index > 0) -+ return 0; -+ nids[nr_nids] = nx_current_nid(); -+ return 1; -+ } -+ -+ for (hindex = 0; hindex < NX_HASH_SIZE; hindex++) { -+ struct hlist_head *head = &nx_info_hash[hindex]; -+ struct hlist_node *pos; -+ -+ spin_lock(&nx_info_hash_lock); -+ hlist_for_each(pos, head) { -+ struct nx_info *nxi; -+ -+ if (--index > 0) -+ continue; -+ -+ nxi = hlist_entry(pos, struct nx_info, nx_hlist); -+ nids[nr_nids] = nxi->nx_id; -+ if (++nr_nids >= size) { -+ spin_unlock(&nx_info_hash_lock); -+ goto out; -+ } -+ } -+ /* keep the lock time short */ -+ spin_unlock(&nx_info_hash_lock); -+ } -+out: -+ return nr_nids; -+} -+#endif -+ -+ -+/* -+ * migrate task to new network -+ * gets nxi, puts old_nxi on change -+ */ -+ -+int nx_migrate_task(struct task_struct *p, struct nx_info *nxi) -+{ -+ struct nx_info *old_nxi; -+ int ret = 0; -+ -+ if (!p || !nxi) -+ BUG(); -+ -+ vxdprintk(VXD_CBIT(nid, 5), -+ "nx_migrate_task(%p,%p[#%d.%d.%d])", -+ p, nxi, nxi->nx_id, -+ atomic_read(&nxi->nx_usecnt), -+ atomic_read(&nxi->nx_tasks)); -+ -+ if (nx_info_flags(nxi, NXF_INFO_PRIVATE, 0) && -+ !nx_info_flags(nxi, NXF_STATE_SETUP, 0)) -+ return -EACCES; -+ -+ if (nx_info_state(nxi, NXS_SHUTDOWN)) -+ return -EFAULT; -+ -+ /* maybe disallow this completely? */ -+ old_nxi = task_get_nx_info(p); -+ if (old_nxi == nxi) -+ goto out; -+ -+ task_lock(p); -+ if (old_nxi) -+ clr_nx_info(&p->nx_info); -+ claim_nx_info(nxi, p); -+ set_nx_info(&p->nx_info, nxi); -+ p->nid = nxi->nx_id; -+ task_unlock(p); -+ -+ vxdprintk(VXD_CBIT(nid, 5), -+ "moved task %p into nxi:%p[#%d]", -+ p, nxi, nxi->nx_id); -+ -+ if (old_nxi) -+ release_nx_info(old_nxi, p); -+ ret = 0; -+out: -+ put_nx_info(old_nxi); -+ return ret; -+} -+ -+ -+void nx_set_persistent(struct nx_info *nxi) -+{ -+ vxdprintk(VXD_CBIT(nid, 6), -+ "nx_set_persistent(%p[#%d])", nxi, nxi->nx_id); -+ -+ get_nx_info(nxi); -+ claim_nx_info(nxi, NULL); -+} -+ -+void nx_clear_persistent(struct nx_info *nxi) -+{ -+ vxdprintk(VXD_CBIT(nid, 6), -+ "nx_clear_persistent(%p[#%d])", nxi, nxi->nx_id); -+ -+ release_nx_info(nxi, NULL); -+ put_nx_info(nxi); -+} -+ -+void nx_update_persistent(struct nx_info *nxi) -+{ -+ if (nx_info_flags(nxi, NXF_PERSISTENT, 0)) -+ nx_set_persistent(nxi); -+ else -+ nx_clear_persistent(nxi); -+} -+ -+/* vserver syscall commands below here */ -+ -+/* taks nid and nx_info functions */ -+ -+#include -+ -+ -+int vc_task_nid(uint32_t id) -+{ -+ nid_t nid; -+ -+ if (id) { -+ struct task_struct *tsk; -+ -+ read_lock(&tasklist_lock); -+ tsk = find_task_by_real_pid(id); -+ nid = (tsk) ? tsk->nid : -ESRCH; -+ read_unlock(&tasklist_lock); -+ } else -+ nid = nx_current_nid(); -+ return nid; -+} -+ -+ -+int vc_nx_info(struct nx_info *nxi, void __user *data) -+{ -+ struct vcmd_nx_info_v0 vc_data; -+ -+ vc_data.nid = nxi->nx_id; -+ -+ if (copy_to_user(data, &vc_data, sizeof(vc_data))) -+ return -EFAULT; -+ return 0; -+} -+ -+ -+/* network functions */ -+ -+int vc_net_create(uint32_t nid, void __user *data) -+{ -+ struct vcmd_net_create vc_data = { .flagword = NXF_INIT_SET }; -+ struct nx_info *new_nxi; -+ int ret; -+ -+ if (data && copy_from_user(&vc_data, data, sizeof(vc_data))) -+ return -EFAULT; -+ -+ if ((nid > MAX_S_CONTEXT) || (nid < 2)) -+ return -EINVAL; -+ -+ new_nxi = __create_nx_info(nid); -+ if (IS_ERR(new_nxi)) -+ return PTR_ERR(new_nxi); -+ -+ /* initial flags */ -+ new_nxi->nx_flags = vc_data.flagword; -+ -+ ret = -ENOEXEC; -+ if (vs_net_change(new_nxi, VSC_NETUP)) -+ goto out; -+ -+ ret = nx_migrate_task(current, new_nxi); -+ if (ret) -+ goto out; -+ -+ /* return context id on success */ -+ ret = new_nxi->nx_id; -+ -+ /* get a reference for persistent contexts */ -+ if ((vc_data.flagword & NXF_PERSISTENT)) -+ nx_set_persistent(new_nxi); -+out: -+ release_nx_info(new_nxi, NULL); -+ put_nx_info(new_nxi); -+ return ret; -+} -+ -+ -+int vc_net_migrate(struct nx_info *nxi, void __user *data) -+{ -+ return nx_migrate_task(current, nxi); -+} -+ -+ -+ -+int do_add_v4_addr(struct nx_info *nxi, __be32 ip, __be32 ip2, __be32 mask, -+ uint16_t type, uint16_t flags) -+{ -+ struct nx_addr_v4 *nxa = &nxi->v4; -+ -+ if (NX_IPV4(nxi)) { -+ /* locate last entry */ -+ for (; nxa->next; nxa = nxa->next); -+ nxa->next = __alloc_nx_addr_v4(); -+ nxa = nxa->next; -+ -+ if (IS_ERR(nxa)) -+ return PTR_ERR(nxa); -+ } -+ -+ if (nxi->v4.next) -+ /* remove single ip for ip list */ -+ nxi->nx_flags &= ~NXF_SINGLE_IP; -+ -+ nxa->ip[0].s_addr = ip; -+ nxa->ip[1].s_addr = ip2; -+ nxa->mask.s_addr = mask; -+ nxa->type = type; -+ nxa->flags = flags; -+ return 0; -+} -+ -+ -+int vc_net_add(struct nx_info *nxi, void __user *data) -+{ -+ struct vcmd_net_addr_v0 vc_data; -+ int index, ret = 0; -+ -+ if (data && copy_from_user(&vc_data, data, sizeof(vc_data))) -+ return -EFAULT; -+ -+ switch (vc_data.type) { -+ case NXA_TYPE_IPV4: -+ if ((vc_data.count < 1) || (vc_data.count > 4)) -+ return -EINVAL; -+ -+ index = 0; -+ while (index < vc_data.count) { -+ ret = do_add_v4_addr(nxi, vc_data.ip[index].s_addr, 0, -+ vc_data.mask[index].s_addr, NXA_TYPE_ADDR, 0); -+ if (ret) -+ return ret; -+ index++; -+ } -+ ret = index; -+ break; -+ -+ case NXA_TYPE_IPV4|NXA_MOD_BCAST: -+ nxi->v4_bcast = vc_data.ip[0]; -+ ret = 1; -+ break; -+ -+ case NXA_TYPE_IPV4|NXA_MOD_LBACK: -+ nxi->v4_lback = vc_data.ip[0]; -+ ret = 1; -+ break; -+ -+ default: -+ ret = -EINVAL; -+ break; -+ } -+ return ret; -+} -+ -+int vc_net_remove(struct nx_info *nxi, void __user *data) -+{ -+ struct vcmd_net_addr_v0 vc_data; -+ -+ if (data && copy_from_user(&vc_data, data, sizeof(vc_data))) -+ return -EFAULT; -+ -+ switch (vc_data.type) { -+ case NXA_TYPE_ANY: -+ __dealloc_nx_addr_v4_all(xchg(&nxi->v4.next, NULL)); -+ memset(&nxi->v4, 0, sizeof(nxi->v4)); -+ break; -+ -+ default: -+ return -EINVAL; -+ } -+ return 0; -+} -+ -+ -+int vc_net_add_ipv4(struct nx_info *nxi, void __user *data) -+{ -+ struct vcmd_net_addr_ipv4_v1 vc_data; -+ -+ if (data && copy_from_user(&vc_data, data, sizeof(vc_data))) -+ return -EFAULT; -+ -+ switch (vc_data.type) { -+ case NXA_TYPE_ADDR: -+ case NXA_TYPE_RANGE: -+ case NXA_TYPE_MASK: -+ return do_add_v4_addr(nxi, vc_data.ip.s_addr, 0, -+ vc_data.mask.s_addr, vc_data.type, vc_data.flags); -+ -+ case NXA_TYPE_ADDR | NXA_MOD_BCAST: -+ nxi->v4_bcast = vc_data.ip; -+ break; -+ -+ case NXA_TYPE_ADDR | NXA_MOD_LBACK: -+ nxi->v4_lback = vc_data.ip; -+ break; -+ -+ default: -+ return -EINVAL; -+ } -+ return 0; -+} -+ -+int vc_net_remove_ipv4(struct nx_info *nxi, void __user *data) -+{ -+ struct vcmd_net_addr_ipv4_v1 vc_data; -+ -+ if (data && copy_from_user(&vc_data, data, sizeof(vc_data))) -+ return -EFAULT; -+ -+ switch (vc_data.type) { -+/* case NXA_TYPE_ADDR: -+ break; */ -+ -+ case NXA_TYPE_ANY: -+ __dealloc_nx_addr_v4_all(xchg(&nxi->v4.next, NULL)); -+ memset(&nxi->v4, 0, sizeof(nxi->v4)); -+ break; -+ -+ default: -+ return -EINVAL; -+ } -+ return 0; -+} -+ -+ -+#ifdef CONFIG_IPV6 -+ -+int do_add_v6_addr(struct nx_info *nxi, -+ struct in6_addr *ip, struct in6_addr *mask, -+ uint32_t prefix, uint16_t type, uint16_t flags) -+{ -+ struct nx_addr_v6 *nxa = &nxi->v6; -+ -+ if (NX_IPV6(nxi)) { -+ /* locate last entry */ -+ for (; nxa->next; nxa = nxa->next); -+ nxa->next = __alloc_nx_addr_v6(); -+ nxa = nxa->next; -+ -+ if (IS_ERR(nxa)) -+ return PTR_ERR(nxa); -+ } -+ -+ nxa->ip = *ip; -+ nxa->mask = *mask; -+ nxa->prefix = prefix; -+ nxa->type = type; -+ nxa->flags = flags; -+ return 0; -+} -+ -+ -+int vc_net_add_ipv6(struct nx_info *nxi, void __user *data) -+{ -+ struct vcmd_net_addr_ipv6_v1 vc_data; -+ -+ if (data && copy_from_user(&vc_data, data, sizeof(vc_data))) -+ return -EFAULT; -+ -+ switch (vc_data.type) { -+ case NXA_TYPE_ADDR: -+ case NXA_TYPE_MASK: -+ return do_add_v6_addr(nxi, &vc_data.ip, &vc_data.mask, -+ vc_data.prefix, vc_data.type, vc_data.flags); -+ default: -+ return -EINVAL; -+ } -+ return 0; -+} -+ -+int vc_net_remove_ipv6(struct nx_info *nxi, void __user *data) -+{ -+ struct vcmd_net_addr_ipv6_v1 vc_data; -+ -+ if (data && copy_from_user(&vc_data, data, sizeof(vc_data))) -+ return -EFAULT; -+ -+ switch (vc_data.type) { -+ case NXA_TYPE_ANY: -+ __dealloc_nx_addr_v6_all(xchg(&nxi->v6.next, NULL)); -+ memset(&nxi->v6, 0, sizeof(nxi->v6)); -+ break; -+ -+ default: -+ return -EINVAL; -+ } -+ return 0; -+} -+ -+#endif /* CONFIG_IPV6 */ -+ -+ -+int vc_get_nflags(struct nx_info *nxi, void __user *data) -+{ -+ struct vcmd_net_flags_v0 vc_data; -+ -+ vc_data.flagword = nxi->nx_flags; -+ -+ /* special STATE flag handling */ -+ vc_data.mask = vs_mask_flags(~0ULL, nxi->nx_flags, NXF_ONE_TIME); -+ -+ if (copy_to_user(data, &vc_data, sizeof(vc_data))) -+ return -EFAULT; -+ return 0; -+} -+ -+int vc_set_nflags(struct nx_info *nxi, void __user *data) -+{ -+ struct vcmd_net_flags_v0 vc_data; -+ uint64_t mask, trigger; -+ -+ if (copy_from_user(&vc_data, data, sizeof(vc_data))) -+ return -EFAULT; -+ -+ /* special STATE flag handling */ -+ mask = vs_mask_mask(vc_data.mask, nxi->nx_flags, NXF_ONE_TIME); -+ trigger = (mask & nxi->nx_flags) ^ (mask & vc_data.flagword); -+ -+ nxi->nx_flags = vs_mask_flags(nxi->nx_flags, -+ vc_data.flagword, mask); -+ if (trigger & NXF_PERSISTENT) -+ nx_update_persistent(nxi); -+ -+ return 0; -+} -+ -+int vc_get_ncaps(struct nx_info *nxi, void __user *data) -+{ -+ struct vcmd_net_caps_v0 vc_data; -+ -+ vc_data.ncaps = nxi->nx_ncaps; -+ vc_data.cmask = ~0ULL; -+ -+ if (copy_to_user(data, &vc_data, sizeof(vc_data))) -+ return -EFAULT; -+ return 0; -+} -+ -+int vc_set_ncaps(struct nx_info *nxi, void __user *data) -+{ -+ struct vcmd_net_caps_v0 vc_data; -+ -+ if (copy_from_user(&vc_data, data, sizeof(vc_data))) -+ return -EFAULT; -+ -+ nxi->nx_ncaps = vs_mask_flags(nxi->nx_ncaps, -+ vc_data.ncaps, vc_data.cmask); -+ return 0; -+} -+ -+ -+#include -+ -+module_init(init_network); -+ -+EXPORT_SYMBOL_GPL(free_nx_info); -+EXPORT_SYMBOL_GPL(unhash_nx_info); -+ -diff -NurpP --minimal linux-2.6.32.1/kernel/vserver/proc.c linux-2.6.32.1-vs2.3.0.36.27/kernel/vserver/proc.c ---- linux-2.6.32.1/kernel/vserver/proc.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/kernel/vserver/proc.c 2009-12-03 20:04:56.000000000 +0100 -@@ -0,0 +1,1098 @@ -+/* -+ * linux/kernel/vserver/proc.c -+ * -+ * Virtual Context Support -+ * -+ * Copyright (C) 2003-2007 Herbert Pötzl -+ * -+ * V0.01 basic structure -+ * V0.02 adaptation vs1.3.0 -+ * V0.03 proc permissions -+ * V0.04 locking/generic -+ * V0.05 next generation procfs -+ * V0.06 inode validation -+ * V0.07 generic rewrite vid -+ * V0.08 remove inode type -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+ -+#include -+ -+#include "cvirt_proc.h" -+#include "cacct_proc.h" -+#include "limit_proc.h" -+#include "sched_proc.h" -+#include "vci_config.h" -+ -+ -+static inline char *print_cap_t(char *buffer, kernel_cap_t *c) -+{ -+ unsigned __capi; -+ -+ CAP_FOR_EACH_U32(__capi) { -+ buffer += sprintf(buffer, "%08x", -+ c->cap[(_KERNEL_CAPABILITY_U32S-1) - __capi]); -+ } -+ return buffer; -+} -+ -+ -+static struct proc_dir_entry *proc_virtual; -+ -+static struct proc_dir_entry *proc_virtnet; -+ -+ -+/* first the actual feeds */ -+ -+ -+static int proc_vci(char *buffer) -+{ -+ return sprintf(buffer, -+ "VCIVersion:\t%04x:%04x\n" -+ "VCISyscall:\t%d\n" -+ "VCIKernel:\t%08x\n", -+ VCI_VERSION >> 16, -+ VCI_VERSION & 0xFFFF, -+ __NR_vserver, -+ vci_kernel_config()); -+} -+ -+static int proc_virtual_info(char *buffer) -+{ -+ return proc_vci(buffer); -+} -+ -+static int proc_virtual_status(char *buffer) -+{ -+ return sprintf(buffer, -+ "#CTotal:\t%d\n" -+ "#CActive:\t%d\n" -+ "#NSProxy:\t%d\t%d %d %d %d %d %d\n" -+ "#InitTask:\t%d\t%d %d\n", -+ atomic_read(&vx_global_ctotal), -+ atomic_read(&vx_global_cactive), -+ atomic_read(&vs_global_nsproxy), -+ atomic_read(&vs_global_fs), -+ atomic_read(&vs_global_mnt_ns), -+ atomic_read(&vs_global_uts_ns), -+ atomic_read(&nr_ipc_ns), -+ atomic_read(&vs_global_user_ns), -+ atomic_read(&vs_global_pid_ns), -+ atomic_read(&init_task.usage), -+ atomic_read(&init_task.nsproxy->count), -+ init_task.fs->users); -+} -+ -+ -+int proc_vxi_info(struct vx_info *vxi, char *buffer) -+{ -+ int length; -+ -+ length = sprintf(buffer, -+ "ID:\t%d\n" -+ "Info:\t%p\n" -+ "Init:\t%d\n" -+ "OOM:\t%lld\n", -+ vxi->vx_id, -+ vxi, -+ vxi->vx_initpid, -+ vxi->vx_badness_bias); -+ return length; -+} -+ -+int proc_vxi_status(struct vx_info *vxi, char *buffer) -+{ -+ char *orig = buffer; -+ -+ buffer += sprintf(buffer, -+ "UseCnt:\t%d\n" -+ "Tasks:\t%d\n" -+ "Flags:\t%016llx\n", -+ atomic_read(&vxi->vx_usecnt), -+ atomic_read(&vxi->vx_tasks), -+ (unsigned long long)vxi->vx_flags); -+ -+ buffer += sprintf(buffer, "BCaps:\t"); -+ buffer = print_cap_t(buffer, &vxi->vx_bcaps); -+ buffer += sprintf(buffer, "\n"); -+ -+ buffer += sprintf(buffer, -+ "CCaps:\t%016llx\n" -+ "Spaces:\t%08lx %08lx\n", -+ (unsigned long long)vxi->vx_ccaps, -+ vxi->vx_nsmask[0], vxi->vx_nsmask[1]); -+ return buffer - orig; -+} -+ -+int proc_vxi_limit(struct vx_info *vxi, char *buffer) -+{ -+ return vx_info_proc_limit(&vxi->limit, buffer); -+} -+ -+int proc_vxi_sched(struct vx_info *vxi, char *buffer) -+{ -+ int cpu, length; -+ -+ length = vx_info_proc_sched(&vxi->sched, buffer); -+ for_each_online_cpu(cpu) { -+ length += vx_info_proc_sched_pc( -+ &vx_per_cpu(vxi, sched_pc, cpu), -+ buffer + length, cpu); -+ } -+ return length; -+} -+ -+int proc_vxi_nsproxy0(struct vx_info *vxi, char *buffer) -+{ -+ return vx_info_proc_nsproxy(vxi->vx_nsproxy[0], buffer); -+} -+ -+int proc_vxi_nsproxy1(struct vx_info *vxi, char *buffer) -+{ -+ return vx_info_proc_nsproxy(vxi->vx_nsproxy[1], buffer); -+} -+ -+int proc_vxi_cvirt(struct vx_info *vxi, char *buffer) -+{ -+ int cpu, length; -+ -+ vx_update_load(vxi); -+ length = vx_info_proc_cvirt(&vxi->cvirt, buffer); -+ for_each_online_cpu(cpu) { -+ length += vx_info_proc_cvirt_pc( -+ &vx_per_cpu(vxi, cvirt_pc, cpu), -+ buffer + length, cpu); -+ } -+ return length; -+} -+ -+int proc_vxi_cacct(struct vx_info *vxi, char *buffer) -+{ -+ return vx_info_proc_cacct(&vxi->cacct, buffer); -+} -+ -+ -+static int proc_virtnet_info(char *buffer) -+{ -+ return proc_vci(buffer); -+} -+ -+static int proc_virtnet_status(char *buffer) -+{ -+ return sprintf(buffer, -+ "#CTotal:\t%d\n" -+ "#CActive:\t%d\n", -+ atomic_read(&nx_global_ctotal), -+ atomic_read(&nx_global_cactive)); -+} -+ -+int proc_nxi_info(struct nx_info *nxi, char *buffer) -+{ -+ struct nx_addr_v4 *v4a; -+#ifdef CONFIG_IPV6 -+ struct nx_addr_v6 *v6a; -+#endif -+ int length, i; -+ -+ length = sprintf(buffer, -+ "ID:\t%d\n" -+ "Info:\t%p\n" -+ "Bcast:\t" NIPQUAD_FMT "\n" -+ "Lback:\t" NIPQUAD_FMT "\n", -+ nxi->nx_id, -+ nxi, -+ NIPQUAD(nxi->v4_bcast.s_addr), -+ NIPQUAD(nxi->v4_lback.s_addr)); -+ -+ if (!NX_IPV4(nxi)) -+ goto skip_v4; -+ for (i = 0, v4a = &nxi->v4; v4a; i++, v4a = v4a->next) -+ length += sprintf(buffer + length, "%d:\t" NXAV4_FMT "\n", -+ i, NXAV4(v4a)); -+skip_v4: -+#ifdef CONFIG_IPV6 -+ if (!NX_IPV6(nxi)) -+ goto skip_v6; -+ for (i = 0, v6a = &nxi->v6; v6a; i++, v6a = v6a->next) -+ length += sprintf(buffer + length, "%d:\t" NXAV6_FMT "\n", -+ i, NXAV6(v6a)); -+skip_v6: -+#endif -+ return length; -+} -+ -+int proc_nxi_status(struct nx_info *nxi, char *buffer) -+{ -+ int length; -+ -+ length = sprintf(buffer, -+ "UseCnt:\t%d\n" -+ "Tasks:\t%d\n" -+ "Flags:\t%016llx\n" -+ "NCaps:\t%016llx\n", -+ atomic_read(&nxi->nx_usecnt), -+ atomic_read(&nxi->nx_tasks), -+ (unsigned long long)nxi->nx_flags, -+ (unsigned long long)nxi->nx_ncaps); -+ return length; -+} -+ -+ -+ -+/* here the inode helpers */ -+ -+struct vs_entry { -+ int len; -+ char *name; -+ mode_t mode; -+ struct inode_operations *iop; -+ struct file_operations *fop; -+ union proc_op op; -+}; -+ -+static struct inode *vs_proc_make_inode(struct super_block *sb, struct vs_entry *p) -+{ -+ struct inode *inode = new_inode(sb); -+ -+ if (!inode) -+ goto out; -+ -+ inode->i_mode = p->mode; -+ if (p->iop) -+ inode->i_op = p->iop; -+ if (p->fop) -+ inode->i_fop = p->fop; -+ -+ inode->i_nlink = (p->mode & S_IFDIR) ? 2 : 1; -+ inode->i_flags |= S_IMMUTABLE; -+ -+ inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; -+ -+ inode->i_uid = 0; -+ inode->i_gid = 0; -+ inode->i_tag = 0; -+out: -+ return inode; -+} -+ -+static struct dentry *vs_proc_instantiate(struct inode *dir, -+ struct dentry *dentry, int id, void *ptr) -+{ -+ struct vs_entry *p = ptr; -+ struct inode *inode = vs_proc_make_inode(dir->i_sb, p); -+ struct dentry *error = ERR_PTR(-EINVAL); -+ -+ if (!inode) -+ goto out; -+ -+ PROC_I(inode)->op = p->op; -+ PROC_I(inode)->fd = id; -+ d_add(dentry, inode); -+ error = NULL; -+out: -+ return error; -+} -+ -+/* Lookups */ -+ -+typedef struct dentry *instantiate_t(struct inode *, struct dentry *, int, void *); -+ -+/* -+ * Fill a directory entry. -+ * -+ * If possible create the dcache entry and derive our inode number and -+ * file type from dcache entry. -+ * -+ * Since all of the proc inode numbers are dynamically generated, the inode -+ * numbers do not exist until the inode is cache. This means creating the -+ * the dcache entry in readdir is necessary to keep the inode numbers -+ * reported by readdir in sync with the inode numbers reported -+ * by stat. -+ */ -+static int proc_fill_cache(struct file *filp, void *dirent, filldir_t filldir, -+ char *name, int len, instantiate_t instantiate, int id, void *ptr) -+{ -+ struct dentry *child, *dir = filp->f_dentry; -+ struct inode *inode; -+ struct qstr qname; -+ ino_t ino = 0; -+ unsigned type = DT_UNKNOWN; -+ -+ qname.name = name; -+ qname.len = len; -+ qname.hash = full_name_hash(name, len); -+ -+ child = d_lookup(dir, &qname); -+ if (!child) { -+ struct dentry *new; -+ new = d_alloc(dir, &qname); -+ if (new) { -+ child = instantiate(dir->d_inode, new, id, ptr); -+ if (child) -+ dput(new); -+ else -+ child = new; -+ } -+ } -+ if (!child || IS_ERR(child) || !child->d_inode) -+ goto end_instantiate; -+ inode = child->d_inode; -+ if (inode) { -+ ino = inode->i_ino; -+ type = inode->i_mode >> 12; -+ } -+ dput(child); -+end_instantiate: -+ if (!ino) -+ ino = find_inode_number(dir, &qname); -+ if (!ino) -+ ino = 1; -+ return filldir(dirent, name, len, filp->f_pos, ino, type); -+} -+ -+ -+ -+/* get and revalidate vx_info/xid */ -+ -+static inline -+struct vx_info *get_proc_vx_info(struct inode *inode) -+{ -+ return lookup_vx_info(PROC_I(inode)->fd); -+} -+ -+static int proc_xid_revalidate(struct dentry *dentry, struct nameidata *nd) -+{ -+ struct inode *inode = dentry->d_inode; -+ xid_t xid = PROC_I(inode)->fd; -+ -+ if (!xid || xid_is_hashed(xid)) -+ return 1; -+ d_drop(dentry); -+ return 0; -+} -+ -+ -+/* get and revalidate nx_info/nid */ -+ -+static int proc_nid_revalidate(struct dentry *dentry, struct nameidata *nd) -+{ -+ struct inode *inode = dentry->d_inode; -+ nid_t nid = PROC_I(inode)->fd; -+ -+ if (!nid || nid_is_hashed(nid)) -+ return 1; -+ d_drop(dentry); -+ return 0; -+} -+ -+ -+ -+#define PROC_BLOCK_SIZE (PAGE_SIZE - 1024) -+ -+static ssize_t proc_vs_info_read(struct file *file, char __user *buf, -+ size_t count, loff_t *ppos) -+{ -+ struct inode *inode = file->f_dentry->d_inode; -+ unsigned long page; -+ ssize_t length = 0; -+ -+ if (count > PROC_BLOCK_SIZE) -+ count = PROC_BLOCK_SIZE; -+ -+ /* fade that out as soon as stable */ -+ WARN_ON(PROC_I(inode)->fd); -+ -+ if (!(page = __get_free_page(GFP_KERNEL))) -+ return -ENOMEM; -+ -+ BUG_ON(!PROC_I(inode)->op.proc_vs_read); -+ length = PROC_I(inode)->op.proc_vs_read((char *)page); -+ -+ if (length >= 0) -+ length = simple_read_from_buffer(buf, count, ppos, -+ (char *)page, length); -+ -+ free_page(page); -+ return length; -+} -+ -+static ssize_t proc_vx_info_read(struct file *file, char __user *buf, -+ size_t count, loff_t *ppos) -+{ -+ struct inode *inode = file->f_dentry->d_inode; -+ struct vx_info *vxi = NULL; -+ xid_t xid = PROC_I(inode)->fd; -+ unsigned long page; -+ ssize_t length = 0; -+ -+ if (count > PROC_BLOCK_SIZE) -+ count = PROC_BLOCK_SIZE; -+ -+ /* fade that out as soon as stable */ -+ WARN_ON(!xid); -+ vxi = lookup_vx_info(xid); -+ if (!vxi) -+ goto out; -+ -+ length = -ENOMEM; -+ if (!(page = __get_free_page(GFP_KERNEL))) -+ goto out_put; -+ -+ BUG_ON(!PROC_I(inode)->op.proc_vxi_read); -+ length = PROC_I(inode)->op.proc_vxi_read(vxi, (char *)page); -+ -+ if (length >= 0) -+ length = simple_read_from_buffer(buf, count, ppos, -+ (char *)page, length); -+ -+ free_page(page); -+out_put: -+ put_vx_info(vxi); -+out: -+ return length; -+} -+ -+static ssize_t proc_nx_info_read(struct file *file, char __user *buf, -+ size_t count, loff_t *ppos) -+{ -+ struct inode *inode = file->f_dentry->d_inode; -+ struct nx_info *nxi = NULL; -+ nid_t nid = PROC_I(inode)->fd; -+ unsigned long page; -+ ssize_t length = 0; -+ -+ if (count > PROC_BLOCK_SIZE) -+ count = PROC_BLOCK_SIZE; -+ -+ /* fade that out as soon as stable */ -+ WARN_ON(!nid); -+ nxi = lookup_nx_info(nid); -+ if (!nxi) -+ goto out; -+ -+ length = -ENOMEM; -+ if (!(page = __get_free_page(GFP_KERNEL))) -+ goto out_put; -+ -+ BUG_ON(!PROC_I(inode)->op.proc_nxi_read); -+ length = PROC_I(inode)->op.proc_nxi_read(nxi, (char *)page); -+ -+ if (length >= 0) -+ length = simple_read_from_buffer(buf, count, ppos, -+ (char *)page, length); -+ -+ free_page(page); -+out_put: -+ put_nx_info(nxi); -+out: -+ return length; -+} -+ -+ -+ -+/* here comes the lower level */ -+ -+ -+#define NOD(NAME, MODE, IOP, FOP, OP) { \ -+ .len = sizeof(NAME) - 1, \ -+ .name = (NAME), \ -+ .mode = MODE, \ -+ .iop = IOP, \ -+ .fop = FOP, \ -+ .op = OP, \ -+} -+ -+ -+#define DIR(NAME, MODE, OTYPE) \ -+ NOD(NAME, (S_IFDIR | (MODE)), \ -+ &proc_ ## OTYPE ## _inode_operations, \ -+ &proc_ ## OTYPE ## _file_operations, { } ) -+ -+#define INF(NAME, MODE, OTYPE) \ -+ NOD(NAME, (S_IFREG | (MODE)), NULL, \ -+ &proc_vs_info_file_operations, \ -+ { .proc_vs_read = &proc_##OTYPE } ) -+ -+#define VINF(NAME, MODE, OTYPE) \ -+ NOD(NAME, (S_IFREG | (MODE)), NULL, \ -+ &proc_vx_info_file_operations, \ -+ { .proc_vxi_read = &proc_##OTYPE } ) -+ -+#define NINF(NAME, MODE, OTYPE) \ -+ NOD(NAME, (S_IFREG | (MODE)), NULL, \ -+ &proc_nx_info_file_operations, \ -+ { .proc_nxi_read = &proc_##OTYPE } ) -+ -+ -+static struct file_operations proc_vs_info_file_operations = { -+ .read = proc_vs_info_read, -+}; -+ -+static struct file_operations proc_vx_info_file_operations = { -+ .read = proc_vx_info_read, -+}; -+ -+static struct dentry_operations proc_xid_dentry_operations = { -+ .d_revalidate = proc_xid_revalidate, -+}; -+ -+static struct vs_entry vx_base_stuff[] = { -+ VINF("info", S_IRUGO, vxi_info), -+ VINF("status", S_IRUGO, vxi_status), -+ VINF("limit", S_IRUGO, vxi_limit), -+ VINF("sched", S_IRUGO, vxi_sched), -+ VINF("nsproxy", S_IRUGO, vxi_nsproxy0), -+ VINF("nsproxy1",S_IRUGO, vxi_nsproxy1), -+ VINF("cvirt", S_IRUGO, vxi_cvirt), -+ VINF("cacct", S_IRUGO, vxi_cacct), -+ {} -+}; -+ -+ -+ -+ -+static struct dentry *proc_xid_instantiate(struct inode *dir, -+ struct dentry *dentry, int id, void *ptr) -+{ -+ dentry->d_op = &proc_xid_dentry_operations; -+ return vs_proc_instantiate(dir, dentry, id, ptr); -+} -+ -+static struct dentry *proc_xid_lookup(struct inode *dir, -+ struct dentry *dentry, struct nameidata *nd) -+{ -+ struct vs_entry *p = vx_base_stuff; -+ struct dentry *error = ERR_PTR(-ENOENT); -+ -+ for (; p->name; p++) { -+ if (p->len != dentry->d_name.len) -+ continue; -+ if (!memcmp(dentry->d_name.name, p->name, p->len)) -+ break; -+ } -+ if (!p->name) -+ goto out; -+ -+ error = proc_xid_instantiate(dir, dentry, PROC_I(dir)->fd, p); -+out: -+ return error; -+} -+ -+static int proc_xid_readdir(struct file *filp, -+ void *dirent, filldir_t filldir) -+{ -+ struct dentry *dentry = filp->f_dentry; -+ struct inode *inode = dentry->d_inode; -+ struct vs_entry *p = vx_base_stuff; -+ int size = sizeof(vx_base_stuff) / sizeof(struct vs_entry); -+ int pos, index; -+ u64 ino; -+ -+ pos = filp->f_pos; -+ switch (pos) { -+ case 0: -+ ino = inode->i_ino; -+ if (filldir(dirent, ".", 1, pos, ino, DT_DIR) < 0) -+ goto out; -+ pos++; -+ /* fall through */ -+ case 1: -+ ino = parent_ino(dentry); -+ if (filldir(dirent, "..", 2, pos, ino, DT_DIR) < 0) -+ goto out; -+ pos++; -+ /* fall through */ -+ default: -+ index = pos - 2; -+ if (index >= size) -+ goto out; -+ for (p += index; p->name; p++) { -+ if (proc_fill_cache(filp, dirent, filldir, p->name, p->len, -+ vs_proc_instantiate, PROC_I(inode)->fd, p)) -+ goto out; -+ pos++; -+ } -+ } -+out: -+ filp->f_pos = pos; -+ return 1; -+} -+ -+ -+ -+static struct file_operations proc_nx_info_file_operations = { -+ .read = proc_nx_info_read, -+}; -+ -+static struct dentry_operations proc_nid_dentry_operations = { -+ .d_revalidate = proc_nid_revalidate, -+}; -+ -+static struct vs_entry nx_base_stuff[] = { -+ NINF("info", S_IRUGO, nxi_info), -+ NINF("status", S_IRUGO, nxi_status), -+ {} -+}; -+ -+ -+static struct dentry *proc_nid_instantiate(struct inode *dir, -+ struct dentry *dentry, int id, void *ptr) -+{ -+ dentry->d_op = &proc_nid_dentry_operations; -+ return vs_proc_instantiate(dir, dentry, id, ptr); -+} -+ -+static struct dentry *proc_nid_lookup(struct inode *dir, -+ struct dentry *dentry, struct nameidata *nd) -+{ -+ struct vs_entry *p = nx_base_stuff; -+ struct dentry *error = ERR_PTR(-ENOENT); -+ -+ for (; p->name; p++) { -+ if (p->len != dentry->d_name.len) -+ continue; -+ if (!memcmp(dentry->d_name.name, p->name, p->len)) -+ break; -+ } -+ if (!p->name) -+ goto out; -+ -+ error = proc_nid_instantiate(dir, dentry, PROC_I(dir)->fd, p); -+out: -+ return error; -+} -+ -+static int proc_nid_readdir(struct file *filp, -+ void *dirent, filldir_t filldir) -+{ -+ struct dentry *dentry = filp->f_dentry; -+ struct inode *inode = dentry->d_inode; -+ struct vs_entry *p = nx_base_stuff; -+ int size = sizeof(nx_base_stuff) / sizeof(struct vs_entry); -+ int pos, index; -+ u64 ino; -+ -+ pos = filp->f_pos; -+ switch (pos) { -+ case 0: -+ ino = inode->i_ino; -+ if (filldir(dirent, ".", 1, pos, ino, DT_DIR) < 0) -+ goto out; -+ pos++; -+ /* fall through */ -+ case 1: -+ ino = parent_ino(dentry); -+ if (filldir(dirent, "..", 2, pos, ino, DT_DIR) < 0) -+ goto out; -+ pos++; -+ /* fall through */ -+ default: -+ index = pos - 2; -+ if (index >= size) -+ goto out; -+ for (p += index; p->name; p++) { -+ if (proc_fill_cache(filp, dirent, filldir, p->name, p->len, -+ vs_proc_instantiate, PROC_I(inode)->fd, p)) -+ goto out; -+ pos++; -+ } -+ } -+out: -+ filp->f_pos = pos; -+ return 1; -+} -+ -+ -+#define MAX_MULBY10 ((~0U - 9) / 10) -+ -+static inline int atovid(const char *str, int len) -+{ -+ int vid, c; -+ -+ vid = 0; -+ while (len-- > 0) { -+ c = *str - '0'; -+ str++; -+ if (c > 9) -+ return -1; -+ if (vid >= MAX_MULBY10) -+ return -1; -+ vid *= 10; -+ vid += c; -+ if (!vid) -+ return -1; -+ } -+ return vid; -+} -+ -+/* now the upper level (virtual) */ -+ -+ -+static struct file_operations proc_xid_file_operations = { -+ .read = generic_read_dir, -+ .readdir = proc_xid_readdir, -+}; -+ -+static struct inode_operations proc_xid_inode_operations = { -+ .lookup = proc_xid_lookup, -+}; -+ -+static struct vs_entry vx_virtual_stuff[] = { -+ INF("info", S_IRUGO, virtual_info), -+ INF("status", S_IRUGO, virtual_status), -+ DIR(NULL, S_IRUGO | S_IXUGO, xid), -+}; -+ -+ -+static struct dentry *proc_virtual_lookup(struct inode *dir, -+ struct dentry *dentry, struct nameidata *nd) -+{ -+ struct vs_entry *p = vx_virtual_stuff; -+ struct dentry *error = ERR_PTR(-ENOENT); -+ int id = 0; -+ -+ for (; p->name; p++) { -+ if (p->len != dentry->d_name.len) -+ continue; -+ if (!memcmp(dentry->d_name.name, p->name, p->len)) -+ break; -+ } -+ if (p->name) -+ goto instantiate; -+ -+ id = atovid(dentry->d_name.name, dentry->d_name.len); -+ if ((id < 0) || !xid_is_hashed(id)) -+ goto out; -+ -+instantiate: -+ error = proc_xid_instantiate(dir, dentry, id, p); -+out: -+ return error; -+} -+ -+static struct file_operations proc_nid_file_operations = { -+ .read = generic_read_dir, -+ .readdir = proc_nid_readdir, -+}; -+ -+static struct inode_operations proc_nid_inode_operations = { -+ .lookup = proc_nid_lookup, -+}; -+ -+static struct vs_entry nx_virtnet_stuff[] = { -+ INF("info", S_IRUGO, virtnet_info), -+ INF("status", S_IRUGO, virtnet_status), -+ DIR(NULL, S_IRUGO | S_IXUGO, nid), -+}; -+ -+ -+static struct dentry *proc_virtnet_lookup(struct inode *dir, -+ struct dentry *dentry, struct nameidata *nd) -+{ -+ struct vs_entry *p = nx_virtnet_stuff; -+ struct dentry *error = ERR_PTR(-ENOENT); -+ int id = 0; -+ -+ for (; p->name; p++) { -+ if (p->len != dentry->d_name.len) -+ continue; -+ if (!memcmp(dentry->d_name.name, p->name, p->len)) -+ break; -+ } -+ if (p->name) -+ goto instantiate; -+ -+ id = atovid(dentry->d_name.name, dentry->d_name.len); -+ if ((id < 0) || !nid_is_hashed(id)) -+ goto out; -+ -+instantiate: -+ error = proc_nid_instantiate(dir, dentry, id, p); -+out: -+ return error; -+} -+ -+ -+#define PROC_MAXVIDS 32 -+ -+int proc_virtual_readdir(struct file *filp, -+ void *dirent, filldir_t filldir) -+{ -+ struct dentry *dentry = filp->f_dentry; -+ struct inode *inode = dentry->d_inode; -+ struct vs_entry *p = vx_virtual_stuff; -+ int size = sizeof(vx_virtual_stuff) / sizeof(struct vs_entry); -+ int pos, index; -+ unsigned int xid_array[PROC_MAXVIDS]; -+ char buf[PROC_NUMBUF]; -+ unsigned int nr_xids, i; -+ u64 ino; -+ -+ pos = filp->f_pos; -+ switch (pos) { -+ case 0: -+ ino = inode->i_ino; -+ if (filldir(dirent, ".", 1, pos, ino, DT_DIR) < 0) -+ goto out; -+ pos++; -+ /* fall through */ -+ case 1: -+ ino = parent_ino(dentry); -+ if (filldir(dirent, "..", 2, pos, ino, DT_DIR) < 0) -+ goto out; -+ pos++; -+ /* fall through */ -+ default: -+ index = pos - 2; -+ if (index >= size) -+ goto entries; -+ for (p += index; p->name; p++) { -+ if (proc_fill_cache(filp, dirent, filldir, p->name, p->len, -+ vs_proc_instantiate, 0, p)) -+ goto out; -+ pos++; -+ } -+ entries: -+ index = pos - size; -+ p = &vx_virtual_stuff[size - 1]; -+ nr_xids = get_xid_list(index, xid_array, PROC_MAXVIDS); -+ for (i = 0; i < nr_xids; i++) { -+ int n, xid = xid_array[i]; -+ unsigned int j = PROC_NUMBUF; -+ -+ n = xid; -+ do -+ buf[--j] = '0' + (n % 10); -+ while (n /= 10); -+ -+ if (proc_fill_cache(filp, dirent, filldir, -+ buf + j, PROC_NUMBUF - j, -+ vs_proc_instantiate, xid, p)) -+ goto out; -+ pos++; -+ } -+ } -+out: -+ filp->f_pos = pos; -+ return 0; -+} -+ -+static int proc_virtual_getattr(struct vfsmount *mnt, -+ struct dentry *dentry, struct kstat *stat) -+{ -+ struct inode *inode = dentry->d_inode; -+ -+ generic_fillattr(inode, stat); -+ stat->nlink = 2 + atomic_read(&vx_global_cactive); -+ return 0; -+} -+ -+static struct file_operations proc_virtual_dir_operations = { -+ .read = generic_read_dir, -+ .readdir = proc_virtual_readdir, -+}; -+ -+static struct inode_operations proc_virtual_dir_inode_operations = { -+ .getattr = proc_virtual_getattr, -+ .lookup = proc_virtual_lookup, -+}; -+ -+ -+ -+ -+ -+int proc_virtnet_readdir(struct file *filp, -+ void *dirent, filldir_t filldir) -+{ -+ struct dentry *dentry = filp->f_dentry; -+ struct inode *inode = dentry->d_inode; -+ struct vs_entry *p = nx_virtnet_stuff; -+ int size = sizeof(nx_virtnet_stuff) / sizeof(struct vs_entry); -+ int pos, index; -+ unsigned int nid_array[PROC_MAXVIDS]; -+ char buf[PROC_NUMBUF]; -+ unsigned int nr_nids, i; -+ u64 ino; -+ -+ pos = filp->f_pos; -+ switch (pos) { -+ case 0: -+ ino = inode->i_ino; -+ if (filldir(dirent, ".", 1, pos, ino, DT_DIR) < 0) -+ goto out; -+ pos++; -+ /* fall through */ -+ case 1: -+ ino = parent_ino(dentry); -+ if (filldir(dirent, "..", 2, pos, ino, DT_DIR) < 0) -+ goto out; -+ pos++; -+ /* fall through */ -+ default: -+ index = pos - 2; -+ if (index >= size) -+ goto entries; -+ for (p += index; p->name; p++) { -+ if (proc_fill_cache(filp, dirent, filldir, p->name, p->len, -+ vs_proc_instantiate, 0, p)) -+ goto out; -+ pos++; -+ } -+ entries: -+ index = pos - size; -+ p = &nx_virtnet_stuff[size - 1]; -+ nr_nids = get_nid_list(index, nid_array, PROC_MAXVIDS); -+ for (i = 0; i < nr_nids; i++) { -+ int n, nid = nid_array[i]; -+ unsigned int j = PROC_NUMBUF; -+ -+ n = nid; -+ do -+ buf[--j] = '0' + (n % 10); -+ while (n /= 10); -+ -+ if (proc_fill_cache(filp, dirent, filldir, -+ buf + j, PROC_NUMBUF - j, -+ vs_proc_instantiate, nid, p)) -+ goto out; -+ pos++; -+ } -+ } -+out: -+ filp->f_pos = pos; -+ return 0; -+} -+ -+static int proc_virtnet_getattr(struct vfsmount *mnt, -+ struct dentry *dentry, struct kstat *stat) -+{ -+ struct inode *inode = dentry->d_inode; -+ -+ generic_fillattr(inode, stat); -+ stat->nlink = 2 + atomic_read(&nx_global_cactive); -+ return 0; -+} -+ -+static struct file_operations proc_virtnet_dir_operations = { -+ .read = generic_read_dir, -+ .readdir = proc_virtnet_readdir, -+}; -+ -+static struct inode_operations proc_virtnet_dir_inode_operations = { -+ .getattr = proc_virtnet_getattr, -+ .lookup = proc_virtnet_lookup, -+}; -+ -+ -+ -+void proc_vx_init(void) -+{ -+ struct proc_dir_entry *ent; -+ -+ ent = proc_mkdir("virtual", 0); -+ if (ent) { -+ ent->proc_fops = &proc_virtual_dir_operations; -+ ent->proc_iops = &proc_virtual_dir_inode_operations; -+ } -+ proc_virtual = ent; -+ -+ ent = proc_mkdir("virtnet", 0); -+ if (ent) { -+ ent->proc_fops = &proc_virtnet_dir_operations; -+ ent->proc_iops = &proc_virtnet_dir_inode_operations; -+ } -+ proc_virtnet = ent; -+} -+ -+ -+ -+ -+/* per pid info */ -+ -+ -+int proc_pid_vx_info(struct task_struct *p, char *buffer) -+{ -+ struct vx_info *vxi; -+ char *orig = buffer; -+ -+ buffer += sprintf(buffer, "XID:\t%d\n", vx_task_xid(p)); -+ -+ vxi = task_get_vx_info(p); -+ if (!vxi) -+ goto out; -+ -+ buffer += sprintf(buffer, "BCaps:\t"); -+ buffer = print_cap_t(buffer, &vxi->vx_bcaps); -+ buffer += sprintf(buffer, "\n"); -+ buffer += sprintf(buffer, "CCaps:\t%016llx\n", -+ (unsigned long long)vxi->vx_ccaps); -+ buffer += sprintf(buffer, "CFlags:\t%016llx\n", -+ (unsigned long long)vxi->vx_flags); -+ buffer += sprintf(buffer, "CIPid:\t%d\n", vxi->vx_initpid); -+ -+ put_vx_info(vxi); -+out: -+ return buffer - orig; -+} -+ -+ -+int proc_pid_nx_info(struct task_struct *p, char *buffer) -+{ -+ struct nx_info *nxi; -+ struct nx_addr_v4 *v4a; -+#ifdef CONFIG_IPV6 -+ struct nx_addr_v6 *v6a; -+#endif -+ char *orig = buffer; -+ int i; -+ -+ buffer += sprintf(buffer, "NID:\t%d\n", nx_task_nid(p)); -+ -+ nxi = task_get_nx_info(p); -+ if (!nxi) -+ goto out; -+ -+ buffer += sprintf(buffer, "NCaps:\t%016llx\n", -+ (unsigned long long)nxi->nx_ncaps); -+ buffer += sprintf(buffer, "NFlags:\t%016llx\n", -+ (unsigned long long)nxi->nx_flags); -+ -+ buffer += sprintf(buffer, -+ "V4Root[bcast]:\t" NIPQUAD_FMT "\n", -+ NIPQUAD(nxi->v4_bcast.s_addr)); -+ buffer += sprintf (buffer, -+ "V4Root[lback]:\t" NIPQUAD_FMT "\n", -+ NIPQUAD(nxi->v4_lback.s_addr)); -+ if (!NX_IPV4(nxi)) -+ goto skip_v4; -+ for (i = 0, v4a = &nxi->v4; v4a; i++, v4a = v4a->next) -+ buffer += sprintf(buffer, "V4Root[%d]:\t" NXAV4_FMT "\n", -+ i, NXAV4(v4a)); -+skip_v4: -+#ifdef CONFIG_IPV6 -+ if (!NX_IPV6(nxi)) -+ goto skip_v6; -+ for (i = 0, v6a = &nxi->v6; v6a; i++, v6a = v6a->next) -+ buffer += sprintf(buffer, "V6Root[%d]:\t" NXAV6_FMT "\n", -+ i, NXAV6(v6a)); -+skip_v6: -+#endif -+ put_nx_info(nxi); -+out: -+ return buffer - orig; -+} -+ -diff -NurpP --minimal linux-2.6.32.1/kernel/vserver/sched.c linux-2.6.32.1-vs2.3.0.36.27/kernel/vserver/sched.c ---- linux-2.6.32.1/kernel/vserver/sched.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/kernel/vserver/sched.c 2009-12-03 20:04:56.000000000 +0100 -@@ -0,0 +1,414 @@ -+/* -+ * linux/kernel/vserver/sched.c -+ * -+ * Virtual Server: Scheduler Support -+ * -+ * Copyright (C) 2004-2007 Herbert Pötzl -+ * -+ * V0.01 adapted Sam Vilains version to 2.6.3 -+ * V0.02 removed legacy interface -+ * V0.03 changed vcmds to vxi arg -+ * V0.04 removed older and legacy interfaces -+ * -+ */ -+ -+#include -+#include -+#include -+ -+#include -+ -+ -+#define vxd_check_range(val, min, max) do { \ -+ vxlprintk((val < min) || (val > max), \ -+ "check_range(%ld,%ld,%ld)", \ -+ (long)val, (long)min, (long)max, \ -+ __FILE__, __LINE__); \ -+ } while (0) -+ -+ -+void vx_update_sched_param(struct _vx_sched *sched, -+ struct _vx_sched_pc *sched_pc) -+{ -+ unsigned int set_mask = sched->update_mask; -+ -+ if (set_mask & VXSM_FILL_RATE) -+ sched_pc->fill_rate[0] = sched->fill_rate[0]; -+ if (set_mask & VXSM_INTERVAL) -+ sched_pc->interval[0] = sched->interval[0]; -+ if (set_mask & VXSM_FILL_RATE2) -+ sched_pc->fill_rate[1] = sched->fill_rate[1]; -+ if (set_mask & VXSM_INTERVAL2) -+ sched_pc->interval[1] = sched->interval[1]; -+ if (set_mask & VXSM_TOKENS) -+ sched_pc->tokens = sched->tokens; -+ if (set_mask & VXSM_TOKENS_MIN) -+ sched_pc->tokens_min = sched->tokens_min; -+ if (set_mask & VXSM_TOKENS_MAX) -+ sched_pc->tokens_max = sched->tokens_max; -+ if (set_mask & VXSM_PRIO_BIAS) -+ sched_pc->prio_bias = sched->prio_bias; -+ -+ if (set_mask & VXSM_IDLE_TIME) -+ sched_pc->flags |= VXSF_IDLE_TIME; -+ else -+ sched_pc->flags &= ~VXSF_IDLE_TIME; -+ -+ /* reset time */ -+ sched_pc->norm_time = jiffies; -+} -+ -+ -+/* -+ * recalculate the context's scheduling tokens -+ * -+ * ret > 0 : number of tokens available -+ * ret < 0 : on hold, check delta_min[] -+ * -1 only jiffies -+ * -2 also idle time -+ * -+ */ -+int vx_tokens_recalc(struct _vx_sched_pc *sched_pc, -+ unsigned long *norm_time, unsigned long *idle_time, int delta_min[2]) -+{ -+ long delta; -+ long tokens = 0; -+ int flags = sched_pc->flags; -+ -+ /* how much time did pass? */ -+ delta = *norm_time - sched_pc->norm_time; -+ // printk("@ %ld, %ld, %ld\n", *norm_time, sched_pc->norm_time, jiffies); -+ vxd_check_range(delta, 0, INT_MAX); -+ -+ if (delta >= sched_pc->interval[0]) { -+ long tokens, integral; -+ -+ /* calc integral token part */ -+ tokens = delta / sched_pc->interval[0]; -+ integral = tokens * sched_pc->interval[0]; -+ tokens *= sched_pc->fill_rate[0]; -+#ifdef CONFIG_VSERVER_HARDCPU -+ delta_min[0] = delta - integral; -+ vxd_check_range(delta_min[0], 0, sched_pc->interval[0]); -+#endif -+ /* advance time */ -+ sched_pc->norm_time += delta; -+ -+ /* add tokens */ -+ sched_pc->tokens += tokens; -+ sched_pc->token_time += tokens; -+ } else -+ delta_min[0] = delta; -+ -+#ifdef CONFIG_VSERVER_IDLETIME -+ if (!(flags & VXSF_IDLE_TIME)) -+ goto skip_idle; -+ -+ /* how much was the idle skip? */ -+ delta = *idle_time - sched_pc->idle_time; -+ vxd_check_range(delta, 0, INT_MAX); -+ -+ if (delta >= sched_pc->interval[1]) { -+ long tokens, integral; -+ -+ /* calc fair share token part */ -+ tokens = delta / sched_pc->interval[1]; -+ integral = tokens * sched_pc->interval[1]; -+ tokens *= sched_pc->fill_rate[1]; -+ delta_min[1] = delta - integral; -+ vxd_check_range(delta_min[1], 0, sched_pc->interval[1]); -+ -+ /* advance idle time */ -+ sched_pc->idle_time += integral; -+ -+ /* add tokens */ -+ sched_pc->tokens += tokens; -+ sched_pc->token_time += tokens; -+ } else -+ delta_min[1] = delta; -+skip_idle: -+#endif -+ -+ /* clip at maximum */ -+ if (sched_pc->tokens > sched_pc->tokens_max) -+ sched_pc->tokens = sched_pc->tokens_max; -+ tokens = sched_pc->tokens; -+ -+ if ((flags & VXSF_ONHOLD)) { -+ /* can we unhold? */ -+ if (tokens >= sched_pc->tokens_min) { -+ flags &= ~VXSF_ONHOLD; -+ sched_pc->hold_ticks += -+ *norm_time - sched_pc->onhold; -+ } else -+ goto on_hold; -+ } else { -+ /* put on hold? */ -+ if (tokens <= 0) { -+ flags |= VXSF_ONHOLD; -+ sched_pc->onhold = *norm_time; -+ goto on_hold; -+ } -+ } -+ sched_pc->flags = flags; -+ return tokens; -+ -+on_hold: -+ tokens = sched_pc->tokens_min - tokens; -+ sched_pc->flags = flags; -+ // BUG_ON(tokens < 0); probably doesn't hold anymore -+ -+#ifdef CONFIG_VSERVER_HARDCPU -+ /* next interval? */ -+ if (!sched_pc->fill_rate[0]) -+ delta_min[0] = HZ; -+ else if (tokens > sched_pc->fill_rate[0]) -+ delta_min[0] += sched_pc->interval[0] * -+ tokens / sched_pc->fill_rate[0]; -+ else -+ delta_min[0] = sched_pc->interval[0] - delta_min[0]; -+ vxd_check_range(delta_min[0], 0, INT_MAX); -+ -+#ifdef CONFIG_VSERVER_IDLETIME -+ if (!(flags & VXSF_IDLE_TIME)) -+ return -1; -+ -+ /* next interval? */ -+ if (!sched_pc->fill_rate[1]) -+ delta_min[1] = HZ; -+ else if (tokens > sched_pc->fill_rate[1]) -+ delta_min[1] += sched_pc->interval[1] * -+ tokens / sched_pc->fill_rate[1]; -+ else -+ delta_min[1] = sched_pc->interval[1] - delta_min[1]; -+ vxd_check_range(delta_min[1], 0, INT_MAX); -+ -+ return -2; -+#else -+ return -1; -+#endif /* CONFIG_VSERVER_IDLETIME */ -+#else -+ return 0; -+#endif /* CONFIG_VSERVER_HARDCPU */ -+} -+ -+static inline unsigned long msec_to_ticks(unsigned long msec) -+{ -+ return msecs_to_jiffies(msec); -+} -+ -+static inline unsigned long ticks_to_msec(unsigned long ticks) -+{ -+ return jiffies_to_msecs(ticks); -+} -+ -+static inline unsigned long ticks_to_usec(unsigned long ticks) -+{ -+ return jiffies_to_usecs(ticks); -+} -+ -+ -+static int do_set_sched(struct vx_info *vxi, struct vcmd_sched_v5 *data) -+{ -+ unsigned int set_mask = data->mask; -+ unsigned int update_mask; -+ int i, cpu; -+ -+ /* Sanity check data values */ -+ if (data->tokens_max <= 0) -+ data->tokens_max = HZ; -+ if (data->tokens_min < 0) -+ data->tokens_min = HZ / 3; -+ if (data->tokens_min >= data->tokens_max) -+ data->tokens_min = data->tokens_max; -+ -+ if (data->prio_bias > MAX_PRIO_BIAS) -+ data->prio_bias = MAX_PRIO_BIAS; -+ if (data->prio_bias < MIN_PRIO_BIAS) -+ data->prio_bias = MIN_PRIO_BIAS; -+ -+ spin_lock(&vxi->sched.tokens_lock); -+ -+ /* sync up on delayed updates */ -+ for_each_cpu_mask(cpu, vxi->sched.update) -+ vx_update_sched_param(&vxi->sched, -+ &vx_per_cpu(vxi, sched_pc, cpu)); -+ -+ if (set_mask & VXSM_FILL_RATE) -+ vxi->sched.fill_rate[0] = data->fill_rate[0]; -+ if (set_mask & VXSM_FILL_RATE2) -+ vxi->sched.fill_rate[1] = data->fill_rate[1]; -+ if (set_mask & VXSM_INTERVAL) -+ vxi->sched.interval[0] = (set_mask & VXSM_MSEC) ? -+ msec_to_ticks(data->interval[0]) : data->interval[0]; -+ if (set_mask & VXSM_INTERVAL2) -+ vxi->sched.interval[1] = (set_mask & VXSM_MSEC) ? -+ msec_to_ticks(data->interval[1]) : data->interval[1]; -+ if (set_mask & VXSM_TOKENS) -+ vxi->sched.tokens = data->tokens; -+ if (set_mask & VXSM_TOKENS_MIN) -+ vxi->sched.tokens_min = data->tokens_min; -+ if (set_mask & VXSM_TOKENS_MAX) -+ vxi->sched.tokens_max = data->tokens_max; -+ if (set_mask & VXSM_PRIO_BIAS) -+ vxi->sched.prio_bias = data->prio_bias; -+ -+ /* Sanity check rate/interval */ -+ for (i = 0; i < 2; i++) { -+ if (data->fill_rate[i] < 0) -+ data->fill_rate[i] = 0; -+ if (data->interval[i] <= 0) -+ data->interval[i] = HZ; -+ } -+ -+ update_mask = vxi->sched.update_mask & VXSM_SET_MASK; -+ update_mask |= (set_mask & (VXSM_SET_MASK | VXSM_IDLE_TIME)); -+ vxi->sched.update_mask = update_mask; -+ -+#ifdef CONFIG_SMP -+ rmb(); -+ if (set_mask & VXSM_CPU_ID) { -+ vxi->sched.update = cpumask_of_cpu(data->cpu_id); -+ cpus_and(vxi->sched.update, cpu_online_map, -+ vxi->sched.update); -+ } else -+ vxi->sched.update = cpu_online_map; -+ -+ /* forced reload? */ -+ if (set_mask & VXSM_FORCE) { -+ for_each_cpu_mask(cpu, vxi->sched.update) -+ vx_update_sched_param(&vxi->sched, -+ &vx_per_cpu(vxi, sched_pc, cpu)); -+ vxi->sched.update = CPU_MASK_NONE; -+ } -+#else -+ /* on UP we update immediately */ -+ vx_update_sched_param(&vxi->sched, -+ &vx_per_cpu(vxi, sched_pc, 0)); -+#endif -+ -+ spin_unlock(&vxi->sched.tokens_lock); -+ return 0; -+} -+ -+ -+#define COPY_IDS(C) C(cpu_id); C(bucket_id) -+#define COPY_PRI(C) C(prio_bias) -+#define COPY_TOK(C) C(tokens); C(tokens_min); C(tokens_max) -+#define COPY_FRI(C) C(fill_rate[0]); C(interval[0]); \ -+ C(fill_rate[1]); C(interval[1]); -+ -+#define COPY_VALUE(name) vc_data.name = data->name -+ -+static int do_set_sched_v4(struct vx_info *vxi, struct vcmd_set_sched_v4 *data) -+{ -+ struct vcmd_sched_v5 vc_data; -+ -+ vc_data.mask = data->set_mask; -+ COPY_IDS(COPY_VALUE); -+ COPY_PRI(COPY_VALUE); -+ COPY_TOK(COPY_VALUE); -+ vc_data.fill_rate[0] = vc_data.fill_rate[1] = data->fill_rate; -+ vc_data.interval[0] = vc_data.interval[1] = data->interval; -+ return do_set_sched(vxi, &vc_data); -+} -+ -+int vc_set_sched_v4(struct vx_info *vxi, void __user *data) -+{ -+ struct vcmd_set_sched_v4 vc_data; -+ -+ if (copy_from_user(&vc_data, data, sizeof(vc_data))) -+ return -EFAULT; -+ -+ return do_set_sched_v4(vxi, &vc_data); -+} -+ -+ /* latest interface is v5 */ -+ -+int vc_set_sched(struct vx_info *vxi, void __user *data) -+{ -+ struct vcmd_sched_v5 vc_data; -+ -+ if (copy_from_user(&vc_data, data, sizeof(vc_data))) -+ return -EFAULT; -+ -+ return do_set_sched(vxi, &vc_data); -+} -+ -+ -+#define COPY_PRI(C) C(prio_bias) -+#define COPY_TOK(C) C(tokens); C(tokens_min); C(tokens_max) -+#define COPY_FRI(C) C(fill_rate[0]); C(interval[0]); \ -+ C(fill_rate[1]); C(interval[1]); -+ -+#define COPY_VALUE(name) vc_data.name = data->name -+ -+ -+int vc_get_sched(struct vx_info *vxi, void __user *data) -+{ -+ struct vcmd_sched_v5 vc_data; -+ -+ if (copy_from_user(&vc_data, data, sizeof(vc_data))) -+ return -EFAULT; -+ -+ if (vc_data.mask & VXSM_CPU_ID) { -+ int cpu = vc_data.cpu_id; -+ struct _vx_sched_pc *data; -+ -+ if (!cpu_possible(cpu)) -+ return -EINVAL; -+ -+ data = &vx_per_cpu(vxi, sched_pc, cpu); -+ COPY_TOK(COPY_VALUE); -+ COPY_PRI(COPY_VALUE); -+ COPY_FRI(COPY_VALUE); -+ -+ if (data->flags & VXSF_IDLE_TIME) -+ vc_data.mask |= VXSM_IDLE_TIME; -+ } else { -+ struct _vx_sched *data = &vxi->sched; -+ -+ COPY_TOK(COPY_VALUE); -+ COPY_PRI(COPY_VALUE); -+ COPY_FRI(COPY_VALUE); -+ } -+ -+ if (vc_data.mask & VXSM_MSEC) { -+ vc_data.interval[0] = ticks_to_msec(vc_data.interval[0]); -+ vc_data.interval[1] = ticks_to_msec(vc_data.interval[1]); -+ } -+ -+ if (copy_to_user(data, &vc_data, sizeof(vc_data))) -+ return -EFAULT; -+ return 0; -+} -+ -+ -+int vc_sched_info(struct vx_info *vxi, void __user *data) -+{ -+ struct vcmd_sched_info vc_data; -+ int cpu; -+ -+ if (copy_from_user(&vc_data, data, sizeof(vc_data))) -+ return -EFAULT; -+ -+ cpu = vc_data.cpu_id; -+ if (!cpu_possible(cpu)) -+ return -EINVAL; -+ -+ if (vxi) { -+ struct _vx_sched_pc *sched_pc = -+ &vx_per_cpu(vxi, sched_pc, cpu); -+ -+ vc_data.user_msec = ticks_to_msec(sched_pc->user_ticks); -+ vc_data.sys_msec = ticks_to_msec(sched_pc->sys_ticks); -+ vc_data.hold_msec = ticks_to_msec(sched_pc->hold_ticks); -+ vc_data.vavavoom = sched_pc->vavavoom; -+ } -+ vc_data.token_usec = ticks_to_usec(1); -+ -+ if (copy_to_user(data, &vc_data, sizeof(vc_data))) -+ return -EFAULT; -+ return 0; -+} -+ -diff -NurpP --minimal linux-2.6.32.1/kernel/vserver/sched_init.h linux-2.6.32.1-vs2.3.0.36.27/kernel/vserver/sched_init.h ---- linux-2.6.32.1/kernel/vserver/sched_init.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/kernel/vserver/sched_init.h 2009-12-03 20:04:56.000000000 +0100 -@@ -0,0 +1,50 @@ -+ -+static inline void vx_info_init_sched(struct _vx_sched *sched) -+{ -+ static struct lock_class_key tokens_lock_key; -+ -+ /* scheduling; hard code starting values as constants */ -+ sched->fill_rate[0] = 1; -+ sched->interval[0] = 4; -+ sched->fill_rate[1] = 1; -+ sched->interval[1] = 8; -+ sched->tokens = HZ >> 2; -+ sched->tokens_min = HZ >> 4; -+ sched->tokens_max = HZ >> 1; -+ sched->tokens_lock = SPIN_LOCK_UNLOCKED; -+ sched->prio_bias = 0; -+ -+ lockdep_set_class(&sched->tokens_lock, &tokens_lock_key); -+} -+ -+static inline -+void vx_info_init_sched_pc(struct _vx_sched_pc *sched_pc, int cpu) -+{ -+ sched_pc->fill_rate[0] = 1; -+ sched_pc->interval[0] = 4; -+ sched_pc->fill_rate[1] = 1; -+ sched_pc->interval[1] = 8; -+ sched_pc->tokens = HZ >> 2; -+ sched_pc->tokens_min = HZ >> 4; -+ sched_pc->tokens_max = HZ >> 1; -+ sched_pc->prio_bias = 0; -+ sched_pc->vavavoom = 0; -+ sched_pc->token_time = 0; -+ sched_pc->idle_time = 0; -+ sched_pc->norm_time = jiffies; -+ -+ sched_pc->user_ticks = 0; -+ sched_pc->sys_ticks = 0; -+ sched_pc->hold_ticks = 0; -+} -+ -+static inline void vx_info_exit_sched(struct _vx_sched *sched) -+{ -+ return; -+} -+ -+static inline -+void vx_info_exit_sched_pc(struct _vx_sched_pc *sched_pc, int cpu) -+{ -+ return; -+} -diff -NurpP --minimal linux-2.6.32.1/kernel/vserver/sched_proc.h linux-2.6.32.1-vs2.3.0.36.27/kernel/vserver/sched_proc.h ---- linux-2.6.32.1/kernel/vserver/sched_proc.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/kernel/vserver/sched_proc.h 2009-12-03 20:04:56.000000000 +0100 -@@ -0,0 +1,57 @@ -+#ifndef _VX_SCHED_PROC_H -+#define _VX_SCHED_PROC_H -+ -+ -+static inline -+int vx_info_proc_sched(struct _vx_sched *sched, char *buffer) -+{ -+ int length = 0; -+ -+ length += sprintf(buffer, -+ "FillRate:\t%8d,%d\n" -+ "Interval:\t%8d,%d\n" -+ "TokensMin:\t%8d\n" -+ "TokensMax:\t%8d\n" -+ "PrioBias:\t%8d\n", -+ sched->fill_rate[0], -+ sched->fill_rate[1], -+ sched->interval[0], -+ sched->interval[1], -+ sched->tokens_min, -+ sched->tokens_max, -+ sched->prio_bias); -+ return length; -+} -+ -+static inline -+int vx_info_proc_sched_pc(struct _vx_sched_pc *sched_pc, -+ char *buffer, int cpu) -+{ -+ int length = 0; -+ -+ length += sprintf(buffer + length, -+ "cpu %d: %lld %lld %lld %ld %ld", cpu, -+ (unsigned long long)sched_pc->user_ticks, -+ (unsigned long long)sched_pc->sys_ticks, -+ (unsigned long long)sched_pc->hold_ticks, -+ sched_pc->token_time, -+ sched_pc->idle_time); -+ length += sprintf(buffer + length, -+ " %c%c %d %d %d %d/%d %d/%d", -+ (sched_pc->flags & VXSF_ONHOLD) ? 'H' : 'R', -+ (sched_pc->flags & VXSF_IDLE_TIME) ? 'I' : '-', -+ sched_pc->tokens, -+ sched_pc->tokens_min, -+ sched_pc->tokens_max, -+ sched_pc->fill_rate[0], -+ sched_pc->interval[0], -+ sched_pc->fill_rate[1], -+ sched_pc->interval[1]); -+ length += sprintf(buffer + length, -+ " %d %d\n", -+ sched_pc->prio_bias, -+ sched_pc->vavavoom); -+ return length; -+} -+ -+#endif /* _VX_SCHED_PROC_H */ -diff -NurpP --minimal linux-2.6.32.1/kernel/vserver/signal.c linux-2.6.32.1-vs2.3.0.36.27/kernel/vserver/signal.c ---- linux-2.6.32.1/kernel/vserver/signal.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/kernel/vserver/signal.c 2009-12-03 20:04:56.000000000 +0100 -@@ -0,0 +1,132 @@ -+/* -+ * linux/kernel/vserver/signal.c -+ * -+ * Virtual Server: Signal Support -+ * -+ * Copyright (C) 2003-2007 Herbert Pötzl -+ * -+ * V0.01 broken out from vcontext V0.05 -+ * V0.02 changed vcmds to vxi arg -+ * V0.03 adjusted siginfo for kill -+ * -+ */ -+ -+#include -+ -+#include -+#include -+#include -+ -+ -+int vx_info_kill(struct vx_info *vxi, int pid, int sig) -+{ -+ int retval, count = 0; -+ struct task_struct *p; -+ struct siginfo *sip = SEND_SIG_PRIV; -+ -+ retval = -ESRCH; -+ vxdprintk(VXD_CBIT(misc, 4), -+ "vx_info_kill(%p[#%d],%d,%d)*", -+ vxi, vxi->vx_id, pid, sig); -+ read_lock(&tasklist_lock); -+ switch (pid) { -+ case 0: -+ case -1: -+ for_each_process(p) { -+ int err = 0; -+ -+ if (vx_task_xid(p) != vxi->vx_id || p->pid <= 1 || -+ (pid && vxi->vx_initpid == p->pid)) -+ continue; -+ -+ err = group_send_sig_info(sig, sip, p); -+ ++count; -+ if (err != -EPERM) -+ retval = err; -+ } -+ break; -+ -+ case 1: -+ if (vxi->vx_initpid) { -+ pid = vxi->vx_initpid; -+ /* for now, only SIGINT to private init ... */ -+ if (!vx_info_flags(vxi, VXF_STATE_ADMIN, 0) && -+ /* ... as long as there are tasks left */ -+ (atomic_read(&vxi->vx_tasks) > 1)) -+ sig = SIGINT; -+ } -+ /* fallthrough */ -+ default: -+ p = find_task_by_real_pid(pid); -+ if (p) { -+ if (vx_task_xid(p) == vxi->vx_id) -+ retval = group_send_sig_info(sig, sip, p); -+ } -+ break; -+ } -+ read_unlock(&tasklist_lock); -+ vxdprintk(VXD_CBIT(misc, 4), -+ "vx_info_kill(%p[#%d],%d,%d,%ld) = %d", -+ vxi, vxi->vx_id, pid, sig, (long)sip, retval); -+ return retval; -+} -+ -+int vc_ctx_kill(struct vx_info *vxi, void __user *data) -+{ -+ struct vcmd_ctx_kill_v0 vc_data; -+ -+ if (copy_from_user(&vc_data, data, sizeof(vc_data))) -+ return -EFAULT; -+ -+ /* special check to allow guest shutdown */ -+ if (!vx_info_flags(vxi, VXF_STATE_ADMIN, 0) && -+ /* forbid killall pid=0 when init is present */ -+ (((vc_data.pid < 1) && vxi->vx_initpid) || -+ (vc_data.pid > 1))) -+ return -EACCES; -+ -+ return vx_info_kill(vxi, vc_data.pid, vc_data.sig); -+} -+ -+ -+static int __wait_exit(struct vx_info *vxi) -+{ -+ DECLARE_WAITQUEUE(wait, current); -+ int ret = 0; -+ -+ add_wait_queue(&vxi->vx_wait, &wait); -+ set_current_state(TASK_INTERRUPTIBLE); -+ -+wait: -+ if (vx_info_state(vxi, -+ VXS_SHUTDOWN | VXS_HASHED | VXS_HELPER) == VXS_SHUTDOWN) -+ goto out; -+ if (signal_pending(current)) { -+ ret = -ERESTARTSYS; -+ goto out; -+ } -+ schedule(); -+ goto wait; -+ -+out: -+ set_current_state(TASK_RUNNING); -+ remove_wait_queue(&vxi->vx_wait, &wait); -+ return ret; -+} -+ -+ -+ -+int vc_wait_exit(struct vx_info *vxi, void __user *data) -+{ -+ struct vcmd_wait_exit_v0 vc_data; -+ int ret; -+ -+ ret = __wait_exit(vxi); -+ vc_data.reboot_cmd = vxi->reboot_cmd; -+ vc_data.exit_code = vxi->exit_code; -+ -+ if (copy_to_user(data, &vc_data, sizeof(vc_data))) -+ ret = -EFAULT; -+ return ret; -+} -+ -diff -NurpP --minimal linux-2.6.32.1/kernel/vserver/space.c linux-2.6.32.1-vs2.3.0.36.27/kernel/vserver/space.c ---- linux-2.6.32.1/kernel/vserver/space.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/kernel/vserver/space.c 2009-12-03 20:04:56.000000000 +0100 -@@ -0,0 +1,375 @@ -+/* -+ * linux/kernel/vserver/space.c -+ * -+ * Virtual Server: Context Space Support -+ * -+ * Copyright (C) 2003-2007 Herbert Pötzl -+ * -+ * V0.01 broken out from context.c 0.07 -+ * V0.02 added task locking for namespace -+ * V0.03 broken out vx_enter_namespace -+ * V0.04 added *space support and commands -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+ -+atomic_t vs_global_nsproxy = ATOMIC_INIT(0); -+atomic_t vs_global_fs = ATOMIC_INIT(0); -+atomic_t vs_global_mnt_ns = ATOMIC_INIT(0); -+atomic_t vs_global_uts_ns = ATOMIC_INIT(0); -+atomic_t vs_global_user_ns = ATOMIC_INIT(0); -+atomic_t vs_global_pid_ns = ATOMIC_INIT(0); -+ -+ -+/* namespace functions */ -+ -+#include -+#include -+#include -+#include -+#include -+ -+ -+static const struct vcmd_space_mask_v1 space_mask_v0 = { -+ .mask = CLONE_FS | -+ CLONE_NEWNS | -+ CLONE_NEWUTS | -+ CLONE_NEWIPC | -+ CLONE_NEWUSER | -+ 0 -+}; -+ -+static const struct vcmd_space_mask_v1 space_mask = { -+ .mask = CLONE_FS | -+ CLONE_NEWNS | -+ CLONE_NEWUTS | -+ CLONE_NEWIPC | -+ CLONE_NEWUSER | -+#ifdef CONFIG_PID_NS -+ CLONE_NEWPID | -+#endif -+#ifdef CONFIG_NET_NS -+ CLONE_NEWNET | -+#endif -+ 0 -+}; -+ -+static const struct vcmd_space_mask_v1 default_space_mask = { -+ .mask = CLONE_FS | -+ CLONE_NEWNS | -+ CLONE_NEWUTS | -+ CLONE_NEWIPC | -+ CLONE_NEWUSER | -+#ifdef CONFIG_PID_NS -+// CLONE_NEWPID | -+#endif -+ 0 -+}; -+ -+/* -+ * build a new nsproxy mix -+ * assumes that both proxies are 'const' -+ * does not touch nsproxy refcounts -+ * will hold a reference on the result. -+ */ -+ -+struct nsproxy *vs_mix_nsproxy(struct nsproxy *old_nsproxy, -+ struct nsproxy *new_nsproxy, unsigned long mask) -+{ -+ struct mnt_namespace *old_ns; -+ struct uts_namespace *old_uts; -+ struct ipc_namespace *old_ipc; -+#ifdef CONFIG_PID_NS -+ struct pid_namespace *old_pid; -+#endif -+#ifdef CONFIG_NET_NS -+ struct net *old_net; -+#endif -+ struct nsproxy *nsproxy; -+ -+ nsproxy = copy_nsproxy(old_nsproxy); -+ if (!nsproxy) -+ goto out; -+ -+ if (mask & CLONE_NEWNS) { -+ old_ns = nsproxy->mnt_ns; -+ nsproxy->mnt_ns = new_nsproxy->mnt_ns; -+ if (nsproxy->mnt_ns) -+ get_mnt_ns(nsproxy->mnt_ns); -+ } else -+ old_ns = NULL; -+ -+ if (mask & CLONE_NEWUTS) { -+ old_uts = nsproxy->uts_ns; -+ nsproxy->uts_ns = new_nsproxy->uts_ns; -+ if (nsproxy->uts_ns) -+ get_uts_ns(nsproxy->uts_ns); -+ } else -+ old_uts = NULL; -+ -+ if (mask & CLONE_NEWIPC) { -+ old_ipc = nsproxy->ipc_ns; -+ nsproxy->ipc_ns = new_nsproxy->ipc_ns; -+ if (nsproxy->ipc_ns) -+ get_ipc_ns(nsproxy->ipc_ns); -+ } else -+ old_ipc = NULL; -+ -+#ifdef CONFIG_PID_NS -+ if (mask & CLONE_NEWPID) { -+ old_pid = nsproxy->pid_ns; -+ nsproxy->pid_ns = new_nsproxy->pid_ns; -+ if (nsproxy->pid_ns) -+ get_pid_ns(nsproxy->pid_ns); -+ } else -+ old_pid = NULL; -+#endif -+#ifdef CONFIG_NET_NS -+ if (mask & CLONE_NEWNET) { -+ old_net = nsproxy->net_ns; -+ nsproxy->net_ns = new_nsproxy->net_ns; -+ if (nsproxy->net_ns) -+ get_net(nsproxy->net_ns); -+ } else -+ old_net = NULL; -+#endif -+ if (old_ns) -+ put_mnt_ns(old_ns); -+ if (old_uts) -+ put_uts_ns(old_uts); -+ if (old_ipc) -+ put_ipc_ns(old_ipc); -+#ifdef CONFIG_PID_NS -+ if (old_pid) -+ put_pid_ns(old_pid); -+#endif -+#ifdef CONFIG_NET_NS -+ if (old_net) -+ put_net(old_net); -+#endif -+out: -+ return nsproxy; -+} -+ -+ -+/* -+ * merge two nsproxy structs into a new one. -+ * will hold a reference on the result. -+ */ -+ -+static inline -+struct nsproxy *__vs_merge_nsproxy(struct nsproxy *old, -+ struct nsproxy *proxy, unsigned long mask) -+{ -+ struct nsproxy null_proxy = { .mnt_ns = NULL }; -+ -+ if (!proxy) -+ return NULL; -+ -+ if (mask) { -+ /* vs_mix_nsproxy returns with reference */ -+ return vs_mix_nsproxy(old ? old : &null_proxy, -+ proxy, mask); -+ } -+ get_nsproxy(proxy); -+ return proxy; -+} -+ -+ -+int vx_enter_space(struct vx_info *vxi, unsigned long mask, unsigned index) -+{ -+ struct nsproxy *proxy, *proxy_cur, *proxy_new; -+ struct fs_struct *fs_cur, *fs = NULL; -+ int ret, kill = 0; -+ -+ vxdprintk(VXD_CBIT(space, 8), "vx_enter_space(%p[#%u],0x%08lx,%d)", -+ vxi, vxi->vx_id, mask, index); -+ -+ if (vx_info_flags(vxi, VXF_INFO_PRIVATE, 0)) -+ return -EACCES; -+ -+ if (!mask) -+ mask = vxi->vx_nsmask[index]; -+ -+ if ((mask & vxi->vx_nsmask[index]) != mask) -+ return -EINVAL; -+ -+ if (mask & CLONE_FS) { -+ fs = copy_fs_struct(vxi->vx_fs[index]); -+ if (!fs) -+ return -ENOMEM; -+ } -+ proxy = vxi->vx_nsproxy[index]; -+ -+ vxdprintk(VXD_CBIT(space, 9), -+ "vx_enter_space(%p[#%u],0x%08lx,%d) -> (%p,%p)", -+ vxi, vxi->vx_id, mask, index, proxy, fs); -+ -+ task_lock(current); -+ fs_cur = current->fs; -+ -+ if (mask & CLONE_FS) { -+ write_lock(&fs_cur->lock); -+ current->fs = fs; -+ kill = !--fs_cur->users; -+ write_unlock(&fs_cur->lock); -+ } -+ -+ proxy_cur = current->nsproxy; -+ get_nsproxy(proxy_cur); -+ task_unlock(current); -+ -+ if (kill) -+ free_fs_struct(fs_cur); -+ -+ proxy_new = __vs_merge_nsproxy(proxy_cur, proxy, mask); -+ if (IS_ERR(proxy_new)) { -+ ret = PTR_ERR(proxy_new); -+ goto out_put; -+ } -+ -+ proxy_new = xchg(¤t->nsproxy, proxy_new); -+ ret = 0; -+ -+ if (proxy_new) -+ put_nsproxy(proxy_new); -+out_put: -+ if (proxy_cur) -+ put_nsproxy(proxy_cur); -+ return ret; -+} -+ -+ -+int vx_set_space(struct vx_info *vxi, unsigned long mask, unsigned index) -+{ -+ struct nsproxy *proxy_vxi, *proxy_cur, *proxy_new; -+ struct fs_struct *fs_vxi, *fs; -+ int ret, kill = 0; -+ -+ vxdprintk(VXD_CBIT(space, 8), "vx_set_space(%p[#%u],0x%08lx,%d)", -+ vxi, vxi->vx_id, mask, index); -+#if 0 -+ if (!mask) -+ mask = default_space_mask.mask; -+#endif -+ if ((mask & space_mask.mask) != mask) -+ return -EINVAL; -+ -+ proxy_vxi = vxi->vx_nsproxy[index]; -+ fs_vxi = vxi->vx_fs[index]; -+ -+ if (mask & CLONE_FS) { -+ fs = copy_fs_struct(current->fs); -+ if (!fs) -+ return -ENOMEM; -+ } -+ -+ task_lock(current); -+ -+ if (mask & CLONE_FS) { -+ write_lock(&fs_vxi->lock); -+ vxi->vx_fs[index] = fs; -+ kill = !--fs_vxi->users; -+ write_unlock(&fs_vxi->lock); -+ } -+ -+ proxy_cur = current->nsproxy; -+ get_nsproxy(proxy_cur); -+ task_unlock(current); -+ -+ if (kill) -+ free_fs_struct(fs_vxi); -+ -+ proxy_new = __vs_merge_nsproxy(proxy_vxi, proxy_cur, mask); -+ if (IS_ERR(proxy_new)) { -+ ret = PTR_ERR(proxy_new); -+ goto out_put; -+ } -+ -+ proxy_new = xchg(&vxi->vx_nsproxy[index], proxy_new); -+ vxi->vx_nsmask[index] |= mask; -+ ret = 0; -+ -+ if (proxy_new) -+ put_nsproxy(proxy_new); -+out_put: -+ if (proxy_cur) -+ put_nsproxy(proxy_cur); -+ return ret; -+} -+ -+ -+int vc_enter_space_v1(struct vx_info *vxi, void __user *data) -+{ -+ struct vcmd_space_mask_v1 vc_data = { .mask = 0 }; -+ -+ if (data && copy_from_user(&vc_data, data, sizeof(vc_data))) -+ return -EFAULT; -+ -+ return vx_enter_space(vxi, vc_data.mask, 0); -+} -+ -+int vc_enter_space(struct vx_info *vxi, void __user *data) -+{ -+ struct vcmd_space_mask_v2 vc_data = { .mask = 0 }; -+ -+ if (data && copy_from_user(&vc_data, data, sizeof(vc_data))) -+ return -EFAULT; -+ -+ if (vc_data.index >= VX_SPACES) -+ return -EINVAL; -+ -+ return vx_enter_space(vxi, vc_data.mask, vc_data.index); -+} -+ -+int vc_set_space_v1(struct vx_info *vxi, void __user *data) -+{ -+ struct vcmd_space_mask_v1 vc_data = { .mask = 0 }; -+ -+ if (data && copy_from_user(&vc_data, data, sizeof(vc_data))) -+ return -EFAULT; -+ -+ return vx_set_space(vxi, vc_data.mask, 0); -+} -+ -+int vc_set_space(struct vx_info *vxi, void __user *data) -+{ -+ struct vcmd_space_mask_v2 vc_data = { .mask = 0 }; -+ -+ if (data && copy_from_user(&vc_data, data, sizeof(vc_data))) -+ return -EFAULT; -+ -+ if (vc_data.index >= VX_SPACES) -+ return -EINVAL; -+ -+ return vx_set_space(vxi, vc_data.mask, vc_data.index); -+} -+ -+int vc_get_space_mask(void __user *data, int type) -+{ -+ const struct vcmd_space_mask_v1 *mask; -+ -+ if (type == 0) -+ mask = &space_mask_v0; -+ else if (type == 1) -+ mask = &space_mask; -+ else -+ mask = &default_space_mask; -+ -+ vxdprintk(VXD_CBIT(space, 10), -+ "vc_get_space_mask(%d) = %08llx", type, mask->mask); -+ -+ if (copy_to_user(data, mask, sizeof(*mask))) -+ return -EFAULT; -+ return 0; -+} -+ -diff -NurpP --minimal linux-2.6.32.1/kernel/vserver/switch.c linux-2.6.32.1-vs2.3.0.36.27/kernel/vserver/switch.c ---- linux-2.6.32.1/kernel/vserver/switch.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/kernel/vserver/switch.c 2009-12-03 20:04:56.000000000 +0100 -@@ -0,0 +1,546 @@ -+/* -+ * linux/kernel/vserver/switch.c -+ * -+ * Virtual Server: Syscall Switch -+ * -+ * Copyright (C) 2003-2007 Herbert Pötzl -+ * -+ * V0.01 syscall switch -+ * V0.02 added signal to context -+ * V0.03 added rlimit functions -+ * V0.04 added iattr, task/xid functions -+ * V0.05 added debug/history stuff -+ * V0.06 added compat32 layer -+ * V0.07 vcmd args and perms -+ * V0.08 added status commands -+ * V0.09 added tag commands -+ * V0.10 added oom bias -+ * V0.11 added device commands -+ * -+ */ -+ -+#include -+#include -+#include -+ -+#include "vci_config.h" -+ -+ -+static inline -+int vc_get_version(uint32_t id) -+{ -+ return VCI_VERSION; -+} -+ -+static inline -+int vc_get_vci(uint32_t id) -+{ -+ return vci_kernel_config(); -+} -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+ -+#ifdef CONFIG_COMPAT -+#define __COMPAT(name, id, data, compat) \ -+ (compat) ? name ## _x32(id, data) : name(id, data) -+#define __COMPAT_NO_ID(name, data, compat) \ -+ (compat) ? name ## _x32(data) : name(data) -+#else -+#define __COMPAT(name, id, data, compat) \ -+ name(id, data) -+#define __COMPAT_NO_ID(name, data, compat) \ -+ name(data) -+#endif -+ -+ -+static inline -+long do_vcmd(uint32_t cmd, uint32_t id, -+ struct vx_info *vxi, struct nx_info *nxi, -+ void __user *data, int compat) -+{ -+ switch (cmd) { -+ -+ case VCMD_get_version: -+ return vc_get_version(id); -+ case VCMD_get_vci: -+ return vc_get_vci(id); -+ -+ case VCMD_task_xid: -+ return vc_task_xid(id); -+ case VCMD_vx_info: -+ return vc_vx_info(vxi, data); -+ -+ case VCMD_task_nid: -+ return vc_task_nid(id); -+ case VCMD_nx_info: -+ return vc_nx_info(nxi, data); -+ -+ case VCMD_task_tag: -+ return vc_task_tag(id); -+ -+ case VCMD_set_space_v1: -+ return vc_set_space_v1(vxi, data); -+ /* this is version 2 */ -+ case VCMD_set_space: -+ return vc_set_space(vxi, data); -+ -+ case VCMD_get_space_mask_v0: -+ return vc_get_space_mask(data, 0); -+ /* this is version 1 */ -+ case VCMD_get_space_mask: -+ return vc_get_space_mask(data, 1); -+ -+ case VCMD_get_space_default: -+ return vc_get_space_mask(data, -1); -+ -+#ifdef CONFIG_IA32_EMULATION -+ case VCMD_get_rlimit: -+ return __COMPAT(vc_get_rlimit, vxi, data, compat); -+ case VCMD_set_rlimit: -+ return __COMPAT(vc_set_rlimit, vxi, data, compat); -+#else -+ case VCMD_get_rlimit: -+ return vc_get_rlimit(vxi, data); -+ case VCMD_set_rlimit: -+ return vc_set_rlimit(vxi, data); -+#endif -+ case VCMD_get_rlimit_mask: -+ return vc_get_rlimit_mask(id, data); -+ case VCMD_reset_hits: -+ return vc_reset_hits(vxi, data); -+ case VCMD_reset_minmax: -+ return vc_reset_minmax(vxi, data); -+ -+ case VCMD_get_vhi_name: -+ return vc_get_vhi_name(vxi, data); -+ case VCMD_set_vhi_name: -+ return vc_set_vhi_name(vxi, data); -+ -+ case VCMD_ctx_stat: -+ return vc_ctx_stat(vxi, data); -+ case VCMD_virt_stat: -+ return vc_virt_stat(vxi, data); -+ case VCMD_sock_stat: -+ return vc_sock_stat(vxi, data); -+ case VCMD_rlimit_stat: -+ return vc_rlimit_stat(vxi, data); -+ -+ case VCMD_set_cflags: -+ return vc_set_cflags(vxi, data); -+ case VCMD_get_cflags: -+ return vc_get_cflags(vxi, data); -+ -+ /* this is version 1 */ -+ case VCMD_set_ccaps: -+ return vc_set_ccaps(vxi, data); -+ /* this is version 1 */ -+ case VCMD_get_ccaps: -+ return vc_get_ccaps(vxi, data); -+ case VCMD_set_bcaps: -+ return vc_set_bcaps(vxi, data); -+ case VCMD_get_bcaps: -+ return vc_get_bcaps(vxi, data); -+ -+ case VCMD_set_badness: -+ return vc_set_badness(vxi, data); -+ case VCMD_get_badness: -+ return vc_get_badness(vxi, data); -+ -+ case VCMD_set_nflags: -+ return vc_set_nflags(nxi, data); -+ case VCMD_get_nflags: -+ return vc_get_nflags(nxi, data); -+ -+ case VCMD_set_ncaps: -+ return vc_set_ncaps(nxi, data); -+ case VCMD_get_ncaps: -+ return vc_get_ncaps(nxi, data); -+ -+ case VCMD_set_sched_v4: -+ return vc_set_sched_v4(vxi, data); -+ /* this is version 5 */ -+ case VCMD_set_sched: -+ return vc_set_sched(vxi, data); -+ case VCMD_get_sched: -+ return vc_get_sched(vxi, data); -+ case VCMD_sched_info: -+ return vc_sched_info(vxi, data); -+ -+ case VCMD_add_dlimit: -+ return __COMPAT(vc_add_dlimit, id, data, compat); -+ case VCMD_rem_dlimit: -+ return __COMPAT(vc_rem_dlimit, id, data, compat); -+ case VCMD_set_dlimit: -+ return __COMPAT(vc_set_dlimit, id, data, compat); -+ case VCMD_get_dlimit: -+ return __COMPAT(vc_get_dlimit, id, data, compat); -+ -+ case VCMD_ctx_kill: -+ return vc_ctx_kill(vxi, data); -+ -+ case VCMD_wait_exit: -+ return vc_wait_exit(vxi, data); -+ -+ case VCMD_get_iattr: -+ return __COMPAT_NO_ID(vc_get_iattr, data, compat); -+ case VCMD_set_iattr: -+ return __COMPAT_NO_ID(vc_set_iattr, data, compat); -+ -+ case VCMD_fget_iattr: -+ return vc_fget_iattr(id, data); -+ case VCMD_fset_iattr: -+ return vc_fset_iattr(id, data); -+ -+ case VCMD_enter_space_v0: -+ return vc_enter_space_v1(vxi, NULL); -+ case VCMD_enter_space_v1: -+ return vc_enter_space_v1(vxi, data); -+ /* this is version 2 */ -+ case VCMD_enter_space: -+ return vc_enter_space(vxi, data); -+ -+ case VCMD_ctx_create_v0: -+ return vc_ctx_create(id, NULL); -+ case VCMD_ctx_create: -+ return vc_ctx_create(id, data); -+ case VCMD_ctx_migrate_v0: -+ return vc_ctx_migrate(vxi, NULL); -+ case VCMD_ctx_migrate: -+ return vc_ctx_migrate(vxi, data); -+ -+ case VCMD_net_create_v0: -+ return vc_net_create(id, NULL); -+ case VCMD_net_create: -+ return vc_net_create(id, data); -+ case VCMD_net_migrate: -+ return vc_net_migrate(nxi, data); -+ -+ case VCMD_tag_migrate: -+ return vc_tag_migrate(id); -+ -+ case VCMD_net_add: -+ return vc_net_add(nxi, data); -+ case VCMD_net_remove: -+ return vc_net_remove(nxi, data); -+ -+ case VCMD_net_add_ipv4: -+ return vc_net_add_ipv4(nxi, data); -+ case VCMD_net_remove_ipv4: -+ return vc_net_remove_ipv4(nxi, data); -+#ifdef CONFIG_IPV6 -+ case VCMD_net_add_ipv6: -+ return vc_net_add_ipv6(nxi, data); -+ case VCMD_net_remove_ipv6: -+ return vc_net_remove_ipv6(nxi, data); -+#endif -+/* case VCMD_add_match_ipv4: -+ return vc_add_match_ipv4(nxi, data); -+ case VCMD_get_match_ipv4: -+ return vc_get_match_ipv4(nxi, data); -+#ifdef CONFIG_IPV6 -+ case VCMD_add_match_ipv6: -+ return vc_add_match_ipv6(nxi, data); -+ case VCMD_get_match_ipv6: -+ return vc_get_match_ipv6(nxi, data); -+#endif */ -+ -+#ifdef CONFIG_VSERVER_DEVICE -+ case VCMD_set_mapping: -+ return __COMPAT(vc_set_mapping, vxi, data, compat); -+ case VCMD_unset_mapping: -+ return __COMPAT(vc_unset_mapping, vxi, data, compat); -+#endif -+#ifdef CONFIG_VSERVER_HISTORY -+ case VCMD_dump_history: -+ return vc_dump_history(id); -+ case VCMD_read_history: -+ return __COMPAT(vc_read_history, id, data, compat); -+#endif -+#ifdef CONFIG_VSERVER_MONITOR -+ case VCMD_read_monitor: -+ return __COMPAT(vc_read_monitor, id, data, compat); -+#endif -+ default: -+ vxwprintk_task(1, "unimplemented VCMD_%02d_%d[%d]", -+ VC_CATEGORY(cmd), VC_COMMAND(cmd), VC_VERSION(cmd)); -+ } -+ return -ENOSYS; -+} -+ -+ -+#define __VCMD(vcmd, _perm, _args, _flags) \ -+ case VCMD_ ## vcmd: perm = _perm; \ -+ args = _args; flags = _flags; break -+ -+ -+#define VCA_NONE 0x00 -+#define VCA_VXI 0x01 -+#define VCA_NXI 0x02 -+ -+#define VCF_NONE 0x00 -+#define VCF_INFO 0x01 -+#define VCF_ADMIN 0x02 -+#define VCF_ARES 0x06 /* includes admin */ -+#define VCF_SETUP 0x08 -+ -+#define VCF_ZIDOK 0x10 /* zero id okay */ -+ -+ -+static inline -+long do_vserver(uint32_t cmd, uint32_t id, void __user *data, int compat) -+{ -+ long ret; -+ int permit = -1, state = 0; -+ int perm = -1, args = 0, flags = 0; -+ struct vx_info *vxi = NULL; -+ struct nx_info *nxi = NULL; -+ -+ switch (cmd) { -+ /* unpriviledged commands */ -+ __VCMD(get_version, 0, VCA_NONE, 0); -+ __VCMD(get_vci, 0, VCA_NONE, 0); -+ __VCMD(get_rlimit_mask, 0, VCA_NONE, 0); -+ __VCMD(get_space_mask_v0,0, VCA_NONE, 0); -+ __VCMD(get_space_mask, 0, VCA_NONE, 0); -+ __VCMD(get_space_default,0, VCA_NONE, 0); -+ -+ /* info commands */ -+ __VCMD(task_xid, 2, VCA_NONE, 0); -+ __VCMD(reset_hits, 2, VCA_VXI, 0); -+ __VCMD(reset_minmax, 2, VCA_VXI, 0); -+ __VCMD(vx_info, 3, VCA_VXI, VCF_INFO); -+ __VCMD(get_bcaps, 3, VCA_VXI, VCF_INFO); -+ __VCMD(get_ccaps, 3, VCA_VXI, VCF_INFO); -+ __VCMD(get_cflags, 3, VCA_VXI, VCF_INFO); -+ __VCMD(get_badness, 3, VCA_VXI, VCF_INFO); -+ __VCMD(get_vhi_name, 3, VCA_VXI, VCF_INFO); -+ __VCMD(get_rlimit, 3, VCA_VXI, VCF_INFO); -+ -+ __VCMD(ctx_stat, 3, VCA_VXI, VCF_INFO); -+ __VCMD(virt_stat, 3, VCA_VXI, VCF_INFO); -+ __VCMD(sock_stat, 3, VCA_VXI, VCF_INFO); -+ __VCMD(rlimit_stat, 3, VCA_VXI, VCF_INFO); -+ -+ __VCMD(task_nid, 2, VCA_NONE, 0); -+ __VCMD(nx_info, 3, VCA_NXI, VCF_INFO); -+ __VCMD(get_ncaps, 3, VCA_NXI, VCF_INFO); -+ __VCMD(get_nflags, 3, VCA_NXI, VCF_INFO); -+ -+ __VCMD(task_tag, 2, VCA_NONE, 0); -+ -+ __VCMD(get_iattr, 2, VCA_NONE, 0); -+ __VCMD(fget_iattr, 2, VCA_NONE, 0); -+ __VCMD(get_dlimit, 3, VCA_NONE, VCF_INFO); -+ __VCMD(get_sched, 3, VCA_VXI, VCF_INFO); -+ __VCMD(sched_info, 3, VCA_VXI, VCF_INFO | VCF_ZIDOK); -+ -+ /* lower admin commands */ -+ __VCMD(wait_exit, 4, VCA_VXI, VCF_INFO); -+ __VCMD(ctx_create_v0, 5, VCA_NONE, 0); -+ __VCMD(ctx_create, 5, VCA_NONE, 0); -+ __VCMD(ctx_migrate_v0, 5, VCA_VXI, VCF_ADMIN); -+ __VCMD(ctx_migrate, 5, VCA_VXI, VCF_ADMIN); -+ __VCMD(enter_space_v0, 5, VCA_VXI, VCF_ADMIN); -+ __VCMD(enter_space_v1, 5, VCA_VXI, VCF_ADMIN); -+ __VCMD(enter_space, 5, VCA_VXI, VCF_ADMIN); -+ -+ __VCMD(net_create_v0, 5, VCA_NONE, 0); -+ __VCMD(net_create, 5, VCA_NONE, 0); -+ __VCMD(net_migrate, 5, VCA_NXI, VCF_ADMIN); -+ -+ __VCMD(tag_migrate, 5, VCA_NONE, VCF_ADMIN); -+ -+ /* higher admin commands */ -+ __VCMD(ctx_kill, 6, VCA_VXI, VCF_ARES); -+ __VCMD(set_space_v1, 7, VCA_VXI, VCF_ARES | VCF_SETUP); -+ __VCMD(set_space, 7, VCA_VXI, VCF_ARES | VCF_SETUP); -+ -+ __VCMD(set_ccaps, 7, VCA_VXI, VCF_ARES | VCF_SETUP); -+ __VCMD(set_bcaps, 7, VCA_VXI, VCF_ARES | VCF_SETUP); -+ __VCMD(set_cflags, 7, VCA_VXI, VCF_ARES | VCF_SETUP); -+ __VCMD(set_badness, 7, VCA_VXI, VCF_ARES | VCF_SETUP); -+ -+ __VCMD(set_vhi_name, 7, VCA_VXI, VCF_ARES | VCF_SETUP); -+ __VCMD(set_rlimit, 7, VCA_VXI, VCF_ARES | VCF_SETUP); -+ __VCMD(set_sched, 7, VCA_VXI, VCF_ARES | VCF_SETUP); -+ __VCMD(set_sched_v4, 7, VCA_VXI, VCF_ARES | VCF_SETUP); -+ -+ __VCMD(set_ncaps, 7, VCA_NXI, VCF_ARES | VCF_SETUP); -+ __VCMD(set_nflags, 7, VCA_NXI, VCF_ARES | VCF_SETUP); -+ __VCMD(net_add, 8, VCA_NXI, VCF_ARES | VCF_SETUP); -+ __VCMD(net_remove, 8, VCA_NXI, VCF_ARES | VCF_SETUP); -+ __VCMD(net_add_ipv4, 8, VCA_NXI, VCF_ARES | VCF_SETUP); -+ __VCMD(net_remove_ipv4, 8, VCA_NXI, VCF_ARES | VCF_SETUP); -+#ifdef CONFIG_IPV6 -+ __VCMD(net_add_ipv6, 8, VCA_NXI, VCF_ARES | VCF_SETUP); -+ __VCMD(net_remove_ipv6, 8, VCA_NXI, VCF_ARES | VCF_SETUP); -+#endif -+ __VCMD(set_iattr, 7, VCA_NONE, 0); -+ __VCMD(fset_iattr, 7, VCA_NONE, 0); -+ __VCMD(set_dlimit, 7, VCA_NONE, VCF_ARES); -+ __VCMD(add_dlimit, 8, VCA_NONE, VCF_ARES); -+ __VCMD(rem_dlimit, 8, VCA_NONE, VCF_ARES); -+ -+#ifdef CONFIG_VSERVER_DEVICE -+ __VCMD(set_mapping, 8, VCA_VXI, VCF_ARES|VCF_ZIDOK); -+ __VCMD(unset_mapping, 8, VCA_VXI, VCF_ARES|VCF_ZIDOK); -+#endif -+ /* debug level admin commands */ -+#ifdef CONFIG_VSERVER_HISTORY -+ __VCMD(dump_history, 9, VCA_NONE, 0); -+ __VCMD(read_history, 9, VCA_NONE, 0); -+#endif -+#ifdef CONFIG_VSERVER_MONITOR -+ __VCMD(read_monitor, 9, VCA_NONE, 0); -+#endif -+ -+ default: -+ perm = -1; -+ } -+ -+ vxdprintk(VXD_CBIT(switch, 0), -+ "vc: VCMD_%02d_%d[%d], %d,%p [%d,%d,%x,%x]", -+ VC_CATEGORY(cmd), VC_COMMAND(cmd), -+ VC_VERSION(cmd), id, data, compat, -+ perm, args, flags); -+ -+ ret = -ENOSYS; -+ if (perm < 0) -+ goto out; -+ -+ state = 1; -+ if (!capable(CAP_CONTEXT)) -+ goto out; -+ -+ state = 2; -+ /* moved here from the individual commands */ -+ ret = -EPERM; -+ if ((perm > 1) && !capable(CAP_SYS_ADMIN)) -+ goto out; -+ -+ state = 3; -+ /* vcmd involves resource management */ -+ ret = -EPERM; -+ if ((flags & VCF_ARES) && !capable(CAP_SYS_RESOURCE)) -+ goto out; -+ -+ state = 4; -+ /* various legacy exceptions */ -+ switch (cmd) { -+ /* will go away when spectator is a cap */ -+ case VCMD_ctx_migrate_v0: -+ case VCMD_ctx_migrate: -+ if (id == 1) { -+ current->xid = 1; -+ ret = 1; -+ goto out; -+ } -+ break; -+ -+ /* will go away when spectator is a cap */ -+ case VCMD_net_migrate: -+ if (id == 1) { -+ current->nid = 1; -+ ret = 1; -+ goto out; -+ } -+ break; -+ } -+ -+ /* vcmds are fine by default */ -+ permit = 1; -+ -+ /* admin type vcmds require admin ... */ -+ if (flags & VCF_ADMIN) -+ permit = vx_check(0, VS_ADMIN) ? 1 : 0; -+ -+ /* ... but setup type vcmds override that */ -+ if (!permit && (flags & VCF_SETUP)) -+ permit = vx_flags(VXF_STATE_SETUP, 0) ? 2 : 0; -+ -+ state = 5; -+ ret = -EPERM; -+ if (!permit) -+ goto out; -+ -+ state = 6; -+ if (!id && (flags & VCF_ZIDOK)) -+ goto skip_id; -+ -+ ret = -ESRCH; -+ if (args & VCA_VXI) { -+ vxi = lookup_vx_info(id); -+ if (!vxi) -+ goto out; -+ -+ if ((flags & VCF_ADMIN) && -+ /* special case kill for shutdown */ -+ (cmd != VCMD_ctx_kill) && -+ /* can context be administrated? */ -+ !vx_info_flags(vxi, VXF_STATE_ADMIN, 0)) { -+ ret = -EACCES; -+ goto out_vxi; -+ } -+ } -+ state = 7; -+ if (args & VCA_NXI) { -+ nxi = lookup_nx_info(id); -+ if (!nxi) -+ goto out_vxi; -+ -+ if ((flags & VCF_ADMIN) && -+ /* can context be administrated? */ -+ !nx_info_flags(nxi, NXF_STATE_ADMIN, 0)) { -+ ret = -EACCES; -+ goto out_nxi; -+ } -+ } -+skip_id: -+ state = 8; -+ ret = do_vcmd(cmd, id, vxi, nxi, data, compat); -+ -+out_nxi: -+ if ((args & VCA_NXI) && nxi) -+ put_nx_info(nxi); -+out_vxi: -+ if ((args & VCA_VXI) && vxi) -+ put_vx_info(vxi); -+out: -+ vxdprintk(VXD_CBIT(switch, 1), -+ "vc: VCMD_%02d_%d[%d] = %08lx(%ld) [%d,%d]", -+ VC_CATEGORY(cmd), VC_COMMAND(cmd), -+ VC_VERSION(cmd), ret, ret, state, permit); -+ return ret; -+} -+ -+asmlinkage long -+sys_vserver(uint32_t cmd, uint32_t id, void __user *data) -+{ -+ return do_vserver(cmd, id, data, 0); -+} -+ -+#ifdef CONFIG_COMPAT -+ -+asmlinkage long -+sys32_vserver(uint32_t cmd, uint32_t id, void __user *data) -+{ -+ return do_vserver(cmd, id, data, 1); -+} -+ -+#endif /* CONFIG_COMPAT */ -diff -NurpP --minimal linux-2.6.32.1/kernel/vserver/sysctl.c linux-2.6.32.1-vs2.3.0.36.27/kernel/vserver/sysctl.c ---- linux-2.6.32.1/kernel/vserver/sysctl.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/kernel/vserver/sysctl.c 2009-12-03 20:04:56.000000000 +0100 -@@ -0,0 +1,244 @@ -+/* -+ * kernel/vserver/sysctl.c -+ * -+ * Virtual Context Support -+ * -+ * Copyright (C) 2004-2007 Herbert Pötzl -+ * -+ * V0.01 basic structure -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+ -+ -+enum { -+ CTL_DEBUG_ERROR = 0, -+ CTL_DEBUG_SWITCH = 1, -+ CTL_DEBUG_XID, -+ CTL_DEBUG_NID, -+ CTL_DEBUG_TAG, -+ CTL_DEBUG_NET, -+ CTL_DEBUG_LIMIT, -+ CTL_DEBUG_CRES, -+ CTL_DEBUG_DLIM, -+ CTL_DEBUG_QUOTA, -+ CTL_DEBUG_CVIRT, -+ CTL_DEBUG_SPACE, -+ CTL_DEBUG_MISC, -+}; -+ -+ -+unsigned int vx_debug_switch = 0; -+unsigned int vx_debug_xid = 0; -+unsigned int vx_debug_nid = 0; -+unsigned int vx_debug_tag = 0; -+unsigned int vx_debug_net = 0; -+unsigned int vx_debug_limit = 0; -+unsigned int vx_debug_cres = 0; -+unsigned int vx_debug_dlim = 0; -+unsigned int vx_debug_quota = 0; -+unsigned int vx_debug_cvirt = 0; -+unsigned int vx_debug_space = 0; -+unsigned int vx_debug_misc = 0; -+ -+ -+static struct ctl_table_header *vserver_table_header; -+static ctl_table vserver_root_table[]; -+ -+ -+void vserver_register_sysctl(void) -+{ -+ if (!vserver_table_header) { -+ vserver_table_header = register_sysctl_table(vserver_root_table); -+ } -+ -+} -+ -+void vserver_unregister_sysctl(void) -+{ -+ if (vserver_table_header) { -+ unregister_sysctl_table(vserver_table_header); -+ vserver_table_header = NULL; -+ } -+} -+ -+ -+static int proc_dodebug(ctl_table *table, int write, -+ struct file *filp, void __user *buffer, size_t *lenp, loff_t *ppos) -+{ -+ char tmpbuf[20], *p, c; -+ unsigned int value; -+ size_t left, len; -+ -+ if ((*ppos && !write) || !*lenp) { -+ *lenp = 0; -+ return 0; -+ } -+ -+ left = *lenp; -+ -+ if (write) { -+ if (!access_ok(VERIFY_READ, buffer, left)) -+ return -EFAULT; -+ p = (char *)buffer; -+ while (left && __get_user(c, p) >= 0 && isspace(c)) -+ left--, p++; -+ if (!left) -+ goto done; -+ -+ if (left > sizeof(tmpbuf) - 1) -+ return -EINVAL; -+ if (copy_from_user(tmpbuf, p, left)) -+ return -EFAULT; -+ tmpbuf[left] = '\0'; -+ -+ for (p = tmpbuf, value = 0; '0' <= *p && *p <= '9'; p++, left--) -+ value = 10 * value + (*p - '0'); -+ if (*p && !isspace(*p)) -+ return -EINVAL; -+ while (left && isspace(*p)) -+ left--, p++; -+ *(unsigned int *)table->data = value; -+ } else { -+ if (!access_ok(VERIFY_WRITE, buffer, left)) -+ return -EFAULT; -+ len = sprintf(tmpbuf, "%d", *(unsigned int *)table->data); -+ if (len > left) -+ len = left; -+ if (__copy_to_user(buffer, tmpbuf, len)) -+ return -EFAULT; -+ if ((left -= len) > 0) { -+ if (put_user('\n', (char *)buffer + len)) -+ return -EFAULT; -+ left--; -+ } -+ } -+ -+done: -+ *lenp -= left; -+ *ppos += *lenp; -+ return 0; -+} -+ -+static int zero; -+ -+#define CTL_ENTRY(ctl, name) \ -+ { \ -+ .ctl_name = ctl, \ -+ .procname = #name, \ -+ .data = &vx_ ## name, \ -+ .maxlen = sizeof(int), \ -+ .mode = 0644, \ -+ .proc_handler = &proc_dodebug, \ -+ .strategy = &sysctl_intvec, \ -+ .extra1 = &zero, \ -+ } -+ -+static ctl_table vserver_debug_table[] = { -+ CTL_ENTRY(CTL_DEBUG_SWITCH, debug_switch), -+ CTL_ENTRY(CTL_DEBUG_XID, debug_xid), -+ CTL_ENTRY(CTL_DEBUG_NID, debug_nid), -+ CTL_ENTRY(CTL_DEBUG_TAG, debug_tag), -+ CTL_ENTRY(CTL_DEBUG_NET, debug_net), -+ CTL_ENTRY(CTL_DEBUG_LIMIT, debug_limit), -+ CTL_ENTRY(CTL_DEBUG_CRES, debug_cres), -+ CTL_ENTRY(CTL_DEBUG_DLIM, debug_dlim), -+ CTL_ENTRY(CTL_DEBUG_QUOTA, debug_quota), -+ CTL_ENTRY(CTL_DEBUG_CVIRT, debug_cvirt), -+ CTL_ENTRY(CTL_DEBUG_SPACE, debug_space), -+ CTL_ENTRY(CTL_DEBUG_MISC, debug_misc), -+ { .ctl_name = 0 } -+}; -+ -+static ctl_table vserver_root_table[] = { -+ { -+ .ctl_name = CTL_VSERVER, -+ .procname = "vserver", -+ .mode = 0555, -+ .child = vserver_debug_table -+ }, -+ { .ctl_name = 0 } -+}; -+ -+ -+static match_table_t tokens = { -+ { CTL_DEBUG_SWITCH, "switch=%x" }, -+ { CTL_DEBUG_XID, "xid=%x" }, -+ { CTL_DEBUG_NID, "nid=%x" }, -+ { CTL_DEBUG_TAG, "tag=%x" }, -+ { CTL_DEBUG_NET, "net=%x" }, -+ { CTL_DEBUG_LIMIT, "limit=%x" }, -+ { CTL_DEBUG_CRES, "cres=%x" }, -+ { CTL_DEBUG_DLIM, "dlim=%x" }, -+ { CTL_DEBUG_QUOTA, "quota=%x" }, -+ { CTL_DEBUG_CVIRT, "cvirt=%x" }, -+ { CTL_DEBUG_SPACE, "space=%x" }, -+ { CTL_DEBUG_MISC, "misc=%x" }, -+ { CTL_DEBUG_ERROR, NULL } -+}; -+ -+#define HANDLE_CASE(id, name, val) \ -+ case CTL_DEBUG_ ## id: \ -+ vx_debug_ ## name = val; \ -+ printk("vs_debug_" #name "=0x%x\n", val); \ -+ break -+ -+ -+static int __init vs_debug_setup(char *str) -+{ -+ char *p; -+ int token; -+ -+ printk("vs_debug_setup(%s)\n", str); -+ while ((p = strsep(&str, ",")) != NULL) { -+ substring_t args[MAX_OPT_ARGS]; -+ unsigned int value; -+ -+ if (!*p) -+ continue; -+ -+ token = match_token(p, tokens, args); -+ value = (token > 0) ? simple_strtoul(args[0].from, NULL, 0) : 0; -+ -+ switch (token) { -+ HANDLE_CASE(SWITCH, switch, value); -+ HANDLE_CASE(XID, xid, value); -+ HANDLE_CASE(NID, nid, value); -+ HANDLE_CASE(TAG, tag, value); -+ HANDLE_CASE(NET, net, value); -+ HANDLE_CASE(LIMIT, limit, value); -+ HANDLE_CASE(CRES, cres, value); -+ HANDLE_CASE(DLIM, dlim, value); -+ HANDLE_CASE(QUOTA, quota, value); -+ HANDLE_CASE(CVIRT, cvirt, value); -+ HANDLE_CASE(SPACE, space, value); -+ HANDLE_CASE(MISC, misc, value); -+ default: -+ return -EINVAL; -+ break; -+ } -+ } -+ return 1; -+} -+ -+__setup("vsdebug=", vs_debug_setup); -+ -+ -+ -+EXPORT_SYMBOL_GPL(vx_debug_switch); -+EXPORT_SYMBOL_GPL(vx_debug_xid); -+EXPORT_SYMBOL_GPL(vx_debug_nid); -+EXPORT_SYMBOL_GPL(vx_debug_net); -+EXPORT_SYMBOL_GPL(vx_debug_limit); -+EXPORT_SYMBOL_GPL(vx_debug_cres); -+EXPORT_SYMBOL_GPL(vx_debug_dlim); -+EXPORT_SYMBOL_GPL(vx_debug_quota); -+EXPORT_SYMBOL_GPL(vx_debug_cvirt); -+EXPORT_SYMBOL_GPL(vx_debug_space); -+EXPORT_SYMBOL_GPL(vx_debug_misc); -+ -diff -NurpP --minimal linux-2.6.32.1/kernel/vserver/tag.c linux-2.6.32.1-vs2.3.0.36.27/kernel/vserver/tag.c ---- linux-2.6.32.1/kernel/vserver/tag.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/kernel/vserver/tag.c 2009-12-03 20:04:56.000000000 +0100 -@@ -0,0 +1,63 @@ -+/* -+ * linux/kernel/vserver/tag.c -+ * -+ * Virtual Server: Shallow Tag Space -+ * -+ * Copyright (C) 2007 Herbert Pötzl -+ * -+ * V0.01 basic implementation -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+ -+#include -+ -+ -+int dx_migrate_task(struct task_struct *p, tag_t tag) -+{ -+ if (!p) -+ BUG(); -+ -+ vxdprintk(VXD_CBIT(tag, 5), -+ "dx_migrate_task(%p[#%d],#%d)", p, p->tag, tag); -+ -+ task_lock(p); -+ p->tag = tag; -+ task_unlock(p); -+ -+ vxdprintk(VXD_CBIT(tag, 5), -+ "moved task %p into [#%d]", p, tag); -+ return 0; -+} -+ -+/* vserver syscall commands below here */ -+ -+/* taks xid and vx_info functions */ -+ -+ -+int vc_task_tag(uint32_t id) -+{ -+ tag_t tag; -+ -+ if (id) { -+ struct task_struct *tsk; -+ read_lock(&tasklist_lock); -+ tsk = find_task_by_real_pid(id); -+ tag = (tsk) ? tsk->tag : -ESRCH; -+ read_unlock(&tasklist_lock); -+ } else -+ tag = dx_current_tag(); -+ return tag; -+} -+ -+ -+int vc_tag_migrate(uint32_t tag) -+{ -+ return dx_migrate_task(current, tag & 0xFFFF); -+} -+ -+ -diff -NurpP --minimal linux-2.6.32.1/kernel/vserver/vci_config.h linux-2.6.32.1-vs2.3.0.36.27/kernel/vserver/vci_config.h ---- linux-2.6.32.1/kernel/vserver/vci_config.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/kernel/vserver/vci_config.h 2009-12-03 20:04:56.000000000 +0100 -@@ -0,0 +1,81 @@ -+ -+/* interface version */ -+ -+#define VCI_VERSION 0x00020305 -+ -+ -+enum { -+ VCI_KCBIT_NO_DYNAMIC = 0, -+ -+ VCI_KCBIT_PROC_SECURE = 4, -+ VCI_KCBIT_HARDCPU = 5, -+ VCI_KCBIT_IDLELIMIT = 6, -+ VCI_KCBIT_IDLETIME = 7, -+ -+ VCI_KCBIT_COWBL = 8, -+ VCI_KCBIT_FULLCOWBL = 9, -+ VCI_KCBIT_SPACES = 10, -+ VCI_KCBIT_NETV2 = 11, -+ -+ VCI_KCBIT_DEBUG = 16, -+ VCI_KCBIT_HISTORY = 20, -+ VCI_KCBIT_TAGGED = 24, -+ VCI_KCBIT_PPTAG = 28, -+ -+ VCI_KCBIT_MORE = 31, -+}; -+ -+ -+static inline uint32_t vci_kernel_config(void) -+{ -+ return -+ (1 << VCI_KCBIT_NO_DYNAMIC) | -+ -+ /* configured features */ -+#ifdef CONFIG_VSERVER_PROC_SECURE -+ (1 << VCI_KCBIT_PROC_SECURE) | -+#endif -+#ifdef CONFIG_VSERVER_HARDCPU -+ (1 << VCI_KCBIT_HARDCPU) | -+#endif -+#ifdef CONFIG_VSERVER_IDLELIMIT -+ (1 << VCI_KCBIT_IDLELIMIT) | -+#endif -+#ifdef CONFIG_VSERVER_IDLETIME -+ (1 << VCI_KCBIT_IDLETIME) | -+#endif -+#ifdef CONFIG_VSERVER_COWBL -+ (1 << VCI_KCBIT_COWBL) | -+ (1 << VCI_KCBIT_FULLCOWBL) | -+#endif -+ (1 << VCI_KCBIT_SPACES) | -+ (1 << VCI_KCBIT_NETV2) | -+ -+ /* debug options */ -+#ifdef CONFIG_VSERVER_DEBUG -+ (1 << VCI_KCBIT_DEBUG) | -+#endif -+#ifdef CONFIG_VSERVER_HISTORY -+ (1 << VCI_KCBIT_HISTORY) | -+#endif -+ -+ /* inode context tagging */ -+#if defined(CONFIG_TAGGING_NONE) -+ (0 << VCI_KCBIT_TAGGED) | -+#elif defined(CONFIG_TAGGING_UID16) -+ (1 << VCI_KCBIT_TAGGED) | -+#elif defined(CONFIG_TAGGING_GID16) -+ (2 << VCI_KCBIT_TAGGED) | -+#elif defined(CONFIG_TAGGING_ID24) -+ (3 << VCI_KCBIT_TAGGED) | -+#elif defined(CONFIG_TAGGING_INTERN) -+ (4 << VCI_KCBIT_TAGGED) | -+#elif defined(CONFIG_TAGGING_RUNTIME) -+ (5 << VCI_KCBIT_TAGGED) | -+#else -+ (7 << VCI_KCBIT_TAGGED) | -+#endif -+ (1 << VCI_KCBIT_PPTAG) | -+ 0; -+} -+ -diff -NurpP --minimal linux-2.6.32.1/mm/allocpercpu.c linux-2.6.32.1-vs2.3.0.36.27/mm/allocpercpu.c ---- linux-2.6.32.1/mm/allocpercpu.c 2009-12-03 20:02:58.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/mm/allocpercpu.c 2009-12-03 20:04:56.000000000 +0100 -@@ -160,12 +160,14 @@ EXPORT_SYMBOL(__per_cpu_offset); - - void __init setup_per_cpu_areas(void) - { -- unsigned long size, i; -+ unsigned long size, vspc, i; - char *ptr; - unsigned long nr_possible_cpus = num_possible_cpus(); - -+ vspc = PERCPU_PERCTX * CONFIG_VSERVER_CONTEXTS; -+ - /* Copy section for each CPU (we discard the original) */ -- size = ALIGN(PERCPU_ENOUGH_ROOM, PAGE_SIZE); -+ size = ALIGN(PERCPU_ENOUGH_ROOM + vspc, PAGE_SIZE); - ptr = alloc_bootmem_pages(size * nr_possible_cpus); - - for_each_possible_cpu(i) { -diff -NurpP --minimal linux-2.6.32.1/mm/filemap_xip.c linux-2.6.32.1-vs2.3.0.36.27/mm/filemap_xip.c ---- linux-2.6.32.1/mm/filemap_xip.c 2009-12-03 20:02:58.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/mm/filemap_xip.c 2009-12-03 20:04:56.000000000 +0100 -@@ -17,6 +17,7 @@ - #include - #include - #include -+#include - #include - #include - -diff -NurpP --minimal linux-2.6.32.1/mm/fremap.c linux-2.6.32.1-vs2.3.0.36.27/mm/fremap.c ---- linux-2.6.32.1/mm/fremap.c 2009-03-24 14:22:45.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/mm/fremap.c 2009-12-03 20:04:56.000000000 +0100 -@@ -16,6 +16,7 @@ - #include - #include - #include -+#include - - #include - #include -diff -NurpP --minimal linux-2.6.32.1/mm/hugetlb.c linux-2.6.32.1-vs2.3.0.36.27/mm/hugetlb.c ---- linux-2.6.32.1/mm/hugetlb.c 2009-12-03 20:02:58.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/mm/hugetlb.c 2009-12-03 20:04:56.000000000 +0100 -@@ -24,6 +24,7 @@ - #include - - #include -+#include - #include "internal.h" - - const unsigned long hugetlb_zero = 0, hugetlb_infinity = ~0UL; -diff -NurpP --minimal linux-2.6.32.1/mm/memory.c linux-2.6.32.1-vs2.3.0.36.27/mm/memory.c ---- linux-2.6.32.1/mm/memory.c 2009-12-03 20:02:58.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/mm/memory.c 2009-12-03 20:04:56.000000000 +0100 -@@ -56,6 +56,7 @@ - #include - #include - #include -+// #include - - #include - #include -@@ -647,6 +648,9 @@ static int copy_pte_range(struct mm_stru - int progress = 0; - int rss[2]; - -+ if (!vx_rss_avail(dst_mm, ((end - addr)/PAGE_SIZE + 1))) -+ return -ENOMEM; -+ - again: - rss[1] = rss[0] = 0; - dst_pte = pte_alloc_map_lock(dst_mm, dst_pmd, addr, &dst_ptl); -@@ -2645,6 +2649,8 @@ static int do_anonymous_page(struct mm_s - /* Allocate our own private page. */ - pte_unmap(page_table); - -+ if (!vx_rss_avail(mm, 1)) -+ goto oom; - if (unlikely(anon_vma_prepare(vma))) - goto oom; - page = alloc_zeroed_user_highpage_movable(vma, address); -@@ -2936,6 +2942,7 @@ static inline int handle_pte_fault(struc - { - pte_t entry; - spinlock_t *ptl; -+ int ret = 0, type = VXPT_UNKNOWN; - - entry = *pte; - if (!pte_present(entry)) { -@@ -2960,9 +2967,12 @@ static inline int handle_pte_fault(struc - if (unlikely(!pte_same(*pte, entry))) - goto unlock; - if (flags & FAULT_FLAG_WRITE) { -- if (!pte_write(entry)) -- return do_wp_page(mm, vma, address, -+ if (!pte_write(entry)) { -+ ret = do_wp_page(mm, vma, address, - pte, pmd, ptl, entry); -+ type = VXPT_WRITE; -+ goto out; -+ } - entry = pte_mkdirty(entry); - } - entry = pte_mkyoung(entry); -@@ -2980,7 +2990,10 @@ static inline int handle_pte_fault(struc - } - unlock: - pte_unmap_unlock(pte, ptl); -- return 0; -+ ret = 0; -+out: -+ vx_page_fault(mm, vma, type, ret); -+ return ret; - } - - /* -diff -NurpP --minimal linux-2.6.32.1/mm/mlock.c linux-2.6.32.1-vs2.3.0.36.27/mm/mlock.c ---- linux-2.6.32.1/mm/mlock.c 2009-12-03 20:02:58.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/mm/mlock.c 2009-12-03 20:04:56.000000000 +0100 -@@ -18,6 +18,7 @@ - #include - #include - #include -+#include - - #include "internal.h" - -@@ -401,7 +402,7 @@ success: - nr_pages = (end - start) >> PAGE_SHIFT; - if (!lock) - nr_pages = -nr_pages; -- mm->locked_vm += nr_pages; -+ vx_vmlocked_add(mm, nr_pages); - - /* - * vm_flags is protected by the mmap_sem held in write mode. -@@ -474,7 +475,7 @@ static int do_mlock(unsigned long start, - - SYSCALL_DEFINE2(mlock, unsigned long, start, size_t, len) - { -- unsigned long locked; -+ unsigned long locked, grow; - unsigned long lock_limit; - int error = -ENOMEM; - -@@ -487,8 +488,10 @@ SYSCALL_DEFINE2(mlock, unsigned long, st - len = PAGE_ALIGN(len + (start & ~PAGE_MASK)); - start &= PAGE_MASK; - -- locked = len >> PAGE_SHIFT; -- locked += current->mm->locked_vm; -+ grow = len >> PAGE_SHIFT; -+ if (!vx_vmlocked_avail(current->mm, grow)) -+ goto out; -+ locked = current->mm->locked_vm + grow; - - lock_limit = current->signal->rlim[RLIMIT_MEMLOCK].rlim_cur; - lock_limit >>= PAGE_SHIFT; -@@ -496,6 +499,7 @@ SYSCALL_DEFINE2(mlock, unsigned long, st - /* check against resource limits */ - if ((locked <= lock_limit) || capable(CAP_IPC_LOCK)) - error = do_mlock(start, len, 1); -+out: - up_write(¤t->mm->mmap_sem); - return error; - } -@@ -557,6 +561,8 @@ SYSCALL_DEFINE1(mlockall, int, flags) - lock_limit >>= PAGE_SHIFT; - - ret = -ENOMEM; -+ if (!vx_vmlocked_avail(current->mm, current->mm->total_vm)) -+ goto out; - if (!(flags & MCL_CURRENT) || (current->mm->total_vm <= lock_limit) || - capable(CAP_IPC_LOCK)) - ret = do_mlockall(flags); -@@ -631,8 +637,10 @@ int account_locked_memory(struct mm_stru - if (lim < vm) - goto out; - -- mm->total_vm += pgsz; -- mm->locked_vm += pgsz; -+ // mm->total_vm += pgsz; -+ vx_vmpages_add(mm, pgsz); -+ // mm->locked_vm += pgsz; -+ vx_vmlocked_add(mm, pgsz); - - error = 0; - out: -@@ -646,8 +654,10 @@ void refund_locked_memory(struct mm_stru - - down_write(&mm->mmap_sem); - -- mm->total_vm -= pgsz; -- mm->locked_vm -= pgsz; -+ // mm->total_vm -= pgsz; -+ vx_vmpages_sub(mm, pgsz); -+ // mm->locked_vm -= pgsz; -+ vx_vmlocked_sub(mm, pgsz); - - up_write(&mm->mmap_sem); - } -diff -NurpP --minimal linux-2.6.32.1/mm/mmap.c linux-2.6.32.1-vs2.3.0.36.27/mm/mmap.c ---- linux-2.6.32.1/mm/mmap.c 2009-12-03 20:02:58.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/mm/mmap.c 2009-12-03 20:04:56.000000000 +0100 -@@ -1236,7 +1236,8 @@ munmap_back: - out: - perf_event_mmap(vma); - -- mm->total_vm += len >> PAGE_SHIFT; -+ // mm->total_vm += len >> PAGE_SHIFT; -+ vx_vmpages_add(mm, len >> PAGE_SHIFT); - vm_stat_account(mm, vm_flags, file, len >> PAGE_SHIFT); - if (vm_flags & VM_LOCKED) { - /* -@@ -1245,7 +1246,8 @@ out: - long nr_pages = mlock_vma_pages_range(vma, addr, addr + len); - if (nr_pages < 0) - return nr_pages; /* vma gone! */ -- mm->locked_vm += (len >> PAGE_SHIFT) - nr_pages; -+ // mm->locked_vm += (len >> PAGE_SHIFT) - nr_pages; -+ vx_vmlocked_add(mm, (len >> PAGE_SHIFT) - nr_pages); - } else if ((flags & MAP_POPULATE) && !(flags & MAP_NONBLOCK)) - make_pages_present(addr, addr + len); - return addr; -@@ -1592,9 +1594,9 @@ static int acct_stack_growth(struct vm_a - return -ENOMEM; - - /* Ok, everything looks good - let it rip */ -- mm->total_vm += grow; -+ vx_vmpages_add(mm, grow); - if (vma->vm_flags & VM_LOCKED) -- mm->locked_vm += grow; -+ vx_vmlocked_add(mm, grow); - vm_stat_account(mm, vma->vm_flags, vma->vm_file, grow); - return 0; - } -@@ -1769,7 +1771,8 @@ static void remove_vma_list(struct mm_st - do { - long nrpages = vma_pages(vma); - -- mm->total_vm -= nrpages; -+ // mm->total_vm -= nrpages; -+ vx_vmpages_sub(mm, nrpages); - vm_stat_account(mm, vma->vm_flags, vma->vm_file, -nrpages); - vma = remove_vma(vma); - } while (vma); -@@ -1941,7 +1944,8 @@ int do_munmap(struct mm_struct *mm, unsi - struct vm_area_struct *tmp = vma; - while (tmp && tmp->vm_start < end) { - if (tmp->vm_flags & VM_LOCKED) { -- mm->locked_vm -= vma_pages(tmp); -+ // mm->locked_vm -= vma_pages(tmp); -+ vx_vmlocked_sub(mm, vma_pages(tmp)); - munlock_vma_pages_all(tmp); - } - tmp = tmp->vm_next; -@@ -2030,6 +2034,8 @@ unsigned long do_brk(unsigned long addr, - lock_limit >>= PAGE_SHIFT; - if (locked > lock_limit && !capable(CAP_IPC_LOCK)) - return -EAGAIN; -+ if (!vx_vmlocked_avail(mm, len >> PAGE_SHIFT)) -+ return -ENOMEM; - } - - /* -@@ -2056,7 +2062,8 @@ unsigned long do_brk(unsigned long addr, - if (mm->map_count > sysctl_max_map_count) - return -ENOMEM; - -- if (security_vm_enough_memory(len >> PAGE_SHIFT)) -+ if (security_vm_enough_memory(len >> PAGE_SHIFT) || -+ !vx_vmpages_avail(mm, len >> PAGE_SHIFT)) - return -ENOMEM; - - /* Can we just expand an old private anonymous mapping? */ -@@ -2082,10 +2089,13 @@ unsigned long do_brk(unsigned long addr, - vma->vm_page_prot = vm_get_page_prot(flags); - vma_link(mm, vma, prev, rb_link, rb_parent); - out: -- mm->total_vm += len >> PAGE_SHIFT; -+ // mm->total_vm += len >> PAGE_SHIFT; -+ vx_vmpages_add(mm, len >> PAGE_SHIFT); -+ - if (flags & VM_LOCKED) { - if (!mlock_vma_pages_range(vma, addr, addr + len)) -- mm->locked_vm += (len >> PAGE_SHIFT); -+ // mm->locked_vm += (len >> PAGE_SHIFT); -+ vx_vmlocked_add(mm, len >> PAGE_SHIFT); - } - return addr; - } -@@ -2129,6 +2139,11 @@ void exit_mmap(struct mm_struct *mm) - free_pgtables(tlb, vma, FIRST_USER_ADDRESS, 0); - tlb_finish_mmu(tlb, 0, end); - -+ set_mm_counter(mm, file_rss, 0); -+ set_mm_counter(mm, anon_rss, 0); -+ vx_vmpages_sub(mm, mm->total_vm); -+ vx_vmlocked_sub(mm, mm->locked_vm); -+ - /* - * Walk the list again, actually closing and freeing it, - * with preemption enabled, without holding any MM locks. -@@ -2168,7 +2183,8 @@ int insert_vm_struct(struct mm_struct * - if (__vma && __vma->vm_start < vma->vm_end) - return -ENOMEM; - if ((vma->vm_flags & VM_ACCOUNT) && -- security_vm_enough_memory_mm(mm, vma_pages(vma))) -+ (security_vm_enough_memory_mm(mm, vma_pages(vma)) || -+ !vx_vmpages_avail(mm, vma_pages(vma)))) - return -ENOMEM; - vma_link(mm, vma, prev, rb_link, rb_parent); - return 0; -@@ -2244,6 +2260,8 @@ int may_expand_vm(struct mm_struct *mm, - - if (cur + npages > lim) - return 0; -+ if (!vx_vmpages_avail(mm, npages)) -+ return 0; - return 1; - } - -@@ -2321,7 +2339,7 @@ int install_special_mapping(struct mm_st - return -ENOMEM; - } - -- mm->total_vm += len >> PAGE_SHIFT; -+ vx_vmpages_add(mm, len >> PAGE_SHIFT); - - perf_event_mmap(vma); - -diff -NurpP --minimal linux-2.6.32.1/mm/mremap.c linux-2.6.32.1-vs2.3.0.36.27/mm/mremap.c ---- linux-2.6.32.1/mm/mremap.c 2009-12-03 20:02:58.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/mm/mremap.c 2009-12-03 20:04:56.000000000 +0100 -@@ -20,6 +20,7 @@ - #include - #include - #include -+#include - - #include - #include -@@ -234,7 +235,7 @@ static unsigned long move_vma(struct vm_ - * If this were a serious issue, we'd add a flag to do_munmap(). - */ - hiwater_vm = mm->hiwater_vm; -- mm->total_vm += new_len >> PAGE_SHIFT; -+ vx_vmpages_add(mm, new_len >> PAGE_SHIFT); - vm_stat_account(mm, vma->vm_flags, vma->vm_file, new_len>>PAGE_SHIFT); - - if (do_munmap(mm, old_addr, old_len) < 0) { -@@ -252,7 +253,7 @@ static unsigned long move_vma(struct vm_ - } - - if (vm_flags & VM_LOCKED) { -- mm->locked_vm += new_len >> PAGE_SHIFT; -+ vx_vmlocked_add(mm, new_len >> PAGE_SHIFT); - if (new_len > old_len) - mlock_vma_pages_range(new_vma, new_addr + old_len, - new_addr + new_len); -@@ -363,6 +364,9 @@ unsigned long do_mremap(unsigned long ad - ret = -EAGAIN; - if (locked > lock_limit && !capable(CAP_IPC_LOCK)) - goto out; -+ if (!vx_vmlocked_avail(current->mm, -+ (new_len - old_len) >> PAGE_SHIFT)) -+ goto out; - } - if (!may_expand_vm(mm, (new_len - old_len) >> PAGE_SHIFT)) { - ret = -ENOMEM; -@@ -391,10 +395,12 @@ unsigned long do_mremap(unsigned long ad - vma_adjust(vma, vma->vm_start, - addr + new_len, vma->vm_pgoff, NULL); - -- mm->total_vm += pages; -+ // mm->total_vm += pages; -+ vx_vmpages_add(mm, pages); - vm_stat_account(mm, vma->vm_flags, vma->vm_file, pages); - if (vma->vm_flags & VM_LOCKED) { -- mm->locked_vm += pages; -+ // mm->locked_vm += pages; -+ vx_vmlocked_add(mm, pages); - mlock_vma_pages_range(vma, addr + old_len, - addr + new_len); - } -diff -NurpP --minimal linux-2.6.32.1/mm/nommu.c linux-2.6.32.1-vs2.3.0.36.27/mm/nommu.c ---- linux-2.6.32.1/mm/nommu.c 2009-12-03 20:02:58.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/mm/nommu.c 2009-12-03 20:04:56.000000000 +0100 -@@ -1346,7 +1346,7 @@ unsigned long do_mmap_pgoff(struct file - /* okay... we have a mapping; now we have to register it */ - result = vma->vm_start; - -- current->mm->total_vm += len >> PAGE_SHIFT; -+ vx_vmpages_add(current->mm, len >> PAGE_SHIFT); - - share: - add_vma_to_mm(current->mm, vma); -@@ -1606,7 +1606,7 @@ void exit_mmap(struct mm_struct *mm) - - kenter(""); - -- mm->total_vm = 0; -+ vx_vmpages_sub(mm, mm->total_vm); - - while ((vma = mm->mmap)) { - mm->mmap = vma->vm_next; -diff -NurpP --minimal linux-2.6.32.1/mm/oom_kill.c linux-2.6.32.1-vs2.3.0.36.27/mm/oom_kill.c ---- linux-2.6.32.1/mm/oom_kill.c 2009-12-03 20:02:58.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/mm/oom_kill.c 2009-12-03 22:26:55.000000000 +0100 -@@ -27,6 +27,9 @@ - #include - #include - #include -+#include -+#include -+#include - - int sysctl_panic_on_oom; - int sysctl_oom_kill_allocating_task; -@@ -186,9 +189,21 @@ unsigned long badness(struct task_struct - points >>= -(oom_adj); - } - -+ /* -+ * add points for context badness and -+ * reduce badness for processes belonging to -+ * a different context -+ */ -+ -+ points += vx_badness(p, mm); -+ -+ if ((vx_current_xid() > 1) && -+ vx_current_xid() != vx_task_xid(p)) -+ points /= 16; -+ - #ifdef DEBUG -- printk(KERN_DEBUG "OOMkill: task %d (%s) got %lu points\n", -- p->pid, p->comm, points); -+ printk(KERN_DEBUG "OOMkill: task %d:#%u (%s) got %d points\n", -+ task_pid_nr(p), p->xid, p->comm, points); - #endif - return points; - } -@@ -230,6 +245,7 @@ static struct task_struct *select_bad_pr - struct task_struct *p; - struct task_struct *chosen = NULL; - struct timespec uptime; -+ unsigned xid = vx_current_xid(); - *ppoints = 0; - - do_posix_clock_monotonic_gettime(&uptime); -@@ -242,11 +258,14 @@ static struct task_struct *select_bad_pr - */ - if (!p->mm) - continue; -- /* skip the init task */ -- if (is_global_init(p)) -+ /* skip the init task, global and per guest */ -+ if (task_is_init(p)) - continue; - if (mem && !task_in_mem_cgroup(p, mem)) - continue; -+ /* skip other guest and host processes if oom in guest */ -+ if (xid && vx_task_xid(p) != xid) -+ continue; - - /* - * This task already has access to memory reserves and is -@@ -357,8 +376,8 @@ static void __oom_kill_task(struct task_ - } - - if (verbose) -- printk(KERN_ERR "Killed process %d (%s)\n", -- task_pid_nr(p), p->comm); -+ printk(KERN_ERR "Killed process %s(%d:#%u)\n", -+ p->comm, task_pid_nr(p), p->xid); - - /* - * We give our sacrificial lamb high priority and access to -@@ -419,8 +438,8 @@ static int oom_kill_process(struct task_ - return 0; - } - -- printk(KERN_ERR "%s: kill process %d (%s) score %li or a child\n", -- message, task_pid_nr(p), p->comm, points); -+ printk(KERN_ERR "%s: kill process %s(%d:#%u) score %li or a child\n", -+ message, p->comm, task_pid_nr(p), p->xid, points); - - /* Try to kill a child first */ - list_for_each_entry(c, &p->children, sibling) { -@@ -519,6 +538,8 @@ void clear_zonelist_oom(struct zonelist - spin_unlock(&zone_scan_lock); - } - -+long vs_oom_action(unsigned int); -+ - /* - * Must be called with tasklist_lock held for read. - */ -@@ -544,7 +565,11 @@ retry: - /* Found nothing?!?! Either we hang forever, or we panic. */ - if (!p) { - read_unlock(&tasklist_lock); -- panic("Out of memory and no killable processes...\n"); -+ /* avoid panic for guest OOM */ -+ if (current->xid) -+ vs_oom_action(LINUX_REBOOT_CMD_OOM); -+ else -+ panic("Out of memory and no killable processes...\n"); - } - - if (oom_kill_process(p, gfp_mask, order, points, NULL, -diff -NurpP --minimal linux-2.6.32.1/mm/page_alloc.c linux-2.6.32.1-vs2.3.0.36.27/mm/page_alloc.c ---- linux-2.6.32.1/mm/page_alloc.c 2009-12-03 20:02:58.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/mm/page_alloc.c 2009-12-03 20:04:56.000000000 +0100 -@@ -48,6 +48,8 @@ - #include - #include - #include -+#include -+#include - #include - - #include -@@ -2130,6 +2132,9 @@ void si_meminfo(struct sysinfo *val) - val->totalhigh = totalhigh_pages; - val->freehigh = nr_free_highpages(); - val->mem_unit = PAGE_SIZE; -+ -+ if (vx_flags(VXF_VIRT_MEM, 0)) -+ vx_vsi_meminfo(val); - } - - EXPORT_SYMBOL(si_meminfo); -@@ -2150,6 +2155,9 @@ void si_meminfo_node(struct sysinfo *val - val->freehigh = 0; - #endif - val->mem_unit = PAGE_SIZE; -+ -+ if (vx_flags(VXF_VIRT_MEM, 0)) -+ vx_vsi_meminfo(val); - } - #endif - -diff -NurpP --minimal linux-2.6.32.1/mm/rmap.c linux-2.6.32.1-vs2.3.0.36.27/mm/rmap.c ---- linux-2.6.32.1/mm/rmap.c 2009-12-03 20:02:58.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/mm/rmap.c 2009-12-03 20:04:56.000000000 +0100 -@@ -55,6 +55,7 @@ - #include - #include - #include -+#include - - #include - -diff -NurpP --minimal linux-2.6.32.1/mm/shmem.c linux-2.6.32.1-vs2.3.0.36.27/mm/shmem.c ---- linux-2.6.32.1/mm/shmem.c 2009-12-03 20:02:58.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/mm/shmem.c 2009-12-03 20:04:56.000000000 +0100 -@@ -1781,7 +1781,7 @@ static int shmem_statfs(struct dentry *d - { - struct shmem_sb_info *sbinfo = SHMEM_SB(dentry->d_sb); - -- buf->f_type = TMPFS_MAGIC; -+ buf->f_type = TMPFS_SUPER_MAGIC; - buf->f_bsize = PAGE_CACHE_SIZE; - buf->f_namelen = NAME_MAX; - spin_lock(&sbinfo->stat_lock); -@@ -2346,7 +2346,7 @@ int shmem_fill_super(struct super_block - sb->s_maxbytes = SHMEM_MAX_BYTES; - sb->s_blocksize = PAGE_CACHE_SIZE; - sb->s_blocksize_bits = PAGE_CACHE_SHIFT; -- sb->s_magic = TMPFS_MAGIC; -+ sb->s_magic = TMPFS_SUPER_MAGIC; - sb->s_op = &shmem_ops; - sb->s_time_gran = 1; - #ifdef CONFIG_TMPFS_POSIX_ACL -diff -NurpP --minimal linux-2.6.32.1/mm/slab.c linux-2.6.32.1-vs2.3.0.36.27/mm/slab.c ---- linux-2.6.32.1/mm/slab.c 2009-12-03 20:02:58.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/mm/slab.c 2009-12-03 20:04:56.000000000 +0100 -@@ -431,6 +431,8 @@ static void kmem_list3_init(struct kmem_ - #define STATS_INC_FREEMISS(x) do { } while (0) - #endif - -+#include "slab_vs.h" -+ - #if DEBUG - - /* -@@ -3253,6 +3255,7 @@ retry: - - obj = slab_get_obj(cachep, slabp, nodeid); - check_slabp(cachep, slabp); -+ vx_slab_alloc(cachep, flags); - l3->free_objects--; - /* move slabp to correct slabp list: */ - list_del(&slabp->list); -@@ -3329,6 +3332,7 @@ __cache_alloc_node(struct kmem_cache *ca - /* ___cache_alloc_node can fall back to other nodes */ - ptr = ____cache_alloc_node(cachep, flags, nodeid); - out: -+ vx_slab_alloc(cachep, flags); - local_irq_restore(save_flags); - ptr = cache_alloc_debugcheck_after(cachep, flags, ptr, caller); - kmemleak_alloc_recursive(ptr, obj_size(cachep), 1, cachep->flags, -@@ -3515,6 +3519,7 @@ static inline void __cache_free(struct k - check_irq_off(); - kmemleak_free_recursive(objp, cachep->flags); - objp = cache_free_debugcheck(cachep, objp, __builtin_return_address(0)); -+ vx_slab_free(cachep); - - kmemcheck_slab_free(cachep, objp, obj_size(cachep)); - -diff -NurpP --minimal linux-2.6.32.1/mm/slab_vs.h linux-2.6.32.1-vs2.3.0.36.27/mm/slab_vs.h ---- linux-2.6.32.1/mm/slab_vs.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/mm/slab_vs.h 2009-12-03 20:04:56.000000000 +0100 -@@ -0,0 +1,29 @@ -+ -+#include -+ -+#include -+ -+static inline -+void vx_slab_alloc(struct kmem_cache *cachep, gfp_t flags) -+{ -+ int what = gfp_zone(cachep->gfpflags); -+ struct vx_info *vxi = current_vx_info(); -+ -+ if (!vxi) -+ return; -+ -+ atomic_add(cachep->buffer_size, &vxi->cacct.slab[what]); -+} -+ -+static inline -+void vx_slab_free(struct kmem_cache *cachep) -+{ -+ int what = gfp_zone(cachep->gfpflags); -+ struct vx_info *vxi = current_vx_info(); -+ -+ if (!vxi) -+ return; -+ -+ atomic_sub(cachep->buffer_size, &vxi->cacct.slab[what]); -+} -+ -diff -NurpP --minimal linux-2.6.32.1/mm/swapfile.c linux-2.6.32.1-vs2.3.0.36.27/mm/swapfile.c ---- linux-2.6.32.1/mm/swapfile.c 2009-12-03 20:02:58.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/mm/swapfile.c 2009-12-03 20:04:56.000000000 +0100 -@@ -34,6 +34,8 @@ - #include - #include - #include -+#include -+#include - - static DEFINE_SPINLOCK(swap_lock); - static unsigned int nr_swapfiles; -@@ -1680,6 +1682,8 @@ static void *swap_next(struct seq_file * - if (v == SEQ_START_TOKEN) - ptr = swap_info; - else { -+ if (vx_flags(VXF_VIRT_MEM, 0)) -+ return NULL; - ptr = v; - ptr++; - } -@@ -1707,6 +1711,16 @@ static int swap_show(struct seq_file *sw - - if (ptr == SEQ_START_TOKEN) { - seq_puts(swap,"Filename\t\t\t\tType\t\tSize\tUsed\tPriority\n"); -+ if (vx_flags(VXF_VIRT_MEM, 0)) { -+ struct sysinfo si; -+ -+ vx_vsi_swapinfo(&si); -+ if (si.totalswap < (1 << 10)) -+ return 0; -+ seq_printf(swap, "%s\t\t\t\t\t%s\t%lu\t%lu\t%d\n", -+ "hdv0", "partition", si.totalswap >> 10, -+ (si.totalswap - si.freeswap) >> 10, -1); -+ } - return 0; - } - -@@ -2064,6 +2078,8 @@ void si_swapinfo(struct sysinfo *val) - val->freeswap = nr_swap_pages + nr_to_be_unused; - val->totalswap = total_swap_pages + nr_to_be_unused; - spin_unlock(&swap_lock); -+ if (vx_flags(VXF_VIRT_MEM, 0)) -+ vx_vsi_swapinfo(val); - } - - /* -diff -NurpP --minimal linux-2.6.32.1/net/core/dev.c linux-2.6.32.1-vs2.3.0.36.27/net/core/dev.c ---- linux-2.6.32.1/net/core/dev.c 2009-12-03 20:02:59.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/net/core/dev.c 2009-12-03 20:04:56.000000000 +0100 -@@ -126,6 +126,7 @@ - #include - #include - #include -+#include - #include - - #include "net-sysfs.h" -@@ -591,7 +592,8 @@ struct net_device *__dev_get_by_name(str - hlist_for_each(p, dev_name_hash(net, name)) { - struct net_device *dev - = hlist_entry(p, struct net_device, name_hlist); -- if (!strncmp(dev->name, name, IFNAMSIZ)) -+ if (!strncmp(dev->name, name, IFNAMSIZ) && -+ nx_dev_visible(current_nx_info(), dev)) - return dev; - } - return NULL; -@@ -642,7 +644,8 @@ struct net_device *__dev_get_by_index(st - hlist_for_each(p, dev_index_hash(net, ifindex)) { - struct net_device *dev - = hlist_entry(p, struct net_device, index_hlist); -- if (dev->ifindex == ifindex) -+ if ((dev->ifindex == ifindex) && -+ nx_dev_visible(current_nx_info(), dev)) - return dev; - } - return NULL; -@@ -695,10 +698,12 @@ struct net_device *dev_getbyhwaddr(struc - - ASSERT_RTNL(); - -- for_each_netdev(net, dev) -+ for_each_netdev(net, dev) { - if (dev->type == type && -- !memcmp(dev->dev_addr, ha, dev->addr_len)) -+ !memcmp(dev->dev_addr, ha, dev->addr_len) && -+ nx_dev_visible(current_nx_info(), dev)) - return dev; -+ } - - return NULL; - } -@@ -709,9 +714,11 @@ struct net_device *__dev_getfirstbyhwtyp - struct net_device *dev; - - ASSERT_RTNL(); -- for_each_netdev(net, dev) -- if (dev->type == type) -+ for_each_netdev(net, dev) { -+ if ((dev->type == type) && -+ nx_dev_visible(current_nx_info(), dev)) - return dev; -+ } - - return NULL; - } -@@ -830,6 +837,8 @@ static int __dev_alloc_name(struct net * - continue; - if (i < 0 || i >= max_netdevices) - continue; -+ if (!nx_dev_visible(current_nx_info(), d)) -+ continue; - - /* avoid cases where sscanf is not exact inverse of printf */ - snprintf(buf, IFNAMSIZ, name, i); -@@ -2984,6 +2993,8 @@ static int dev_ifconf(struct net *net, c - - total = 0; - for_each_netdev(net, dev) { -+ if (!nx_dev_visible(current_nx_info(), dev)) -+ continue; - for (i = 0; i < NPROTO; i++) { - if (gifconf_list[i]) { - int done; -@@ -3052,6 +3063,9 @@ static void dev_seq_printf_stats(struct - { - const struct net_device_stats *stats = dev_get_stats(dev); - -+ if (!nx_dev_visible(current_nx_info(), dev)) -+ return; -+ - seq_printf(seq, "%6s:%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu " - "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n", - dev->name, stats->rx_bytes, stats->rx_packets, -@@ -5313,6 +5327,15 @@ int dev_change_net_namespace(struct net_ - goto out; - #endif - -+#ifdef CONFIG_SYSFS -+ /* Don't allow real devices to be moved when sysfs -+ * is enabled. -+ */ -+ err = -EINVAL; -+ if (dev->dev.parent) -+ goto out; -+#endif -+ - /* Ensure the device has been registrered */ - err = -EINVAL; - if (dev->reg_state != NETREG_REGISTERED) -diff -NurpP --minimal linux-2.6.32.1/net/core/rtnetlink.c linux-2.6.32.1-vs2.3.0.36.27/net/core/rtnetlink.c ---- linux-2.6.32.1/net/core/rtnetlink.c 2009-12-03 20:02:59.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/net/core/rtnetlink.c 2009-12-03 20:04:56.000000000 +0100 -@@ -688,6 +688,8 @@ static int rtnl_dump_ifinfo(struct sk_bu - - idx = 0; - for_each_netdev(net, dev) { -+ if (!nx_dev_visible(skb->sk->sk_nx_info, dev)) -+ continue; - if (idx < s_idx) - goto cont; - if (rtnl_fill_ifinfo(skb, dev, RTM_NEWLINK, -@@ -1222,6 +1224,9 @@ void rtmsg_ifinfo(int type, struct net_d - struct sk_buff *skb; - int err = -ENOBUFS; - -+ if (!nx_dev_visible(current_nx_info(), dev)) -+ return; -+ - skb = nlmsg_new(if_nlmsg_size(dev), GFP_KERNEL); - if (skb == NULL) - goto errout; -diff -NurpP --minimal linux-2.6.32.1/net/core/sock.c linux-2.6.32.1-vs2.3.0.36.27/net/core/sock.c ---- linux-2.6.32.1/net/core/sock.c 2009-12-03 20:02:59.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/net/core/sock.c 2009-12-03 20:04:56.000000000 +0100 -@@ -125,6 +125,10 @@ - #include - - #include -+#include -+#include -+#include -+#include - - #ifdef CONFIG_INET - #include -@@ -984,6 +988,8 @@ static struct sock *sk_prot_alloc(struct - if (!try_module_get(prot->owner)) - goto out_free_sec; - } -+ sock_vx_init(sk); -+ sock_nx_init(sk); - - return sk; - -@@ -1063,6 +1069,11 @@ static void __sk_free(struct sock *sk) - __func__, atomic_read(&sk->sk_omem_alloc)); - - put_net(sock_net(sk)); -+ vx_sock_dec(sk); -+ clr_vx_info(&sk->sk_vx_info); -+ sk->sk_xid = -1; -+ clr_nx_info(&sk->sk_nx_info); -+ sk->sk_nid = -1; - sk_prot_free(sk->sk_prot_creator, sk); - } - -@@ -1110,6 +1121,8 @@ struct sock *sk_clone(const struct sock - - /* SANITY */ - get_net(sock_net(newsk)); -+ sock_vx_init(newsk); -+ sock_nx_init(newsk); - sk_node_init(&newsk->sk_node); - sock_lock_init(newsk); - bh_lock_sock(newsk); -@@ -1164,6 +1177,12 @@ struct sock *sk_clone(const struct sock - smp_wmb(); - atomic_set(&newsk->sk_refcnt, 2); - -+ set_vx_info(&newsk->sk_vx_info, sk->sk_vx_info); -+ newsk->sk_xid = sk->sk_xid; -+ vx_sock_inc(newsk); -+ set_nx_info(&newsk->sk_nx_info, sk->sk_nx_info); -+ newsk->sk_nid = sk->sk_nid; -+ - /* - * Increment the counter in the same struct proto as the master - * sock (sk_refcnt_debug_inc uses newsk->sk_prot->socks, that -@@ -1882,6 +1901,12 @@ void sock_init_data(struct socket *sock, - - sk->sk_stamp = ktime_set(-1L, 0); - -+ set_vx_info(&sk->sk_vx_info, current_vx_info()); -+ sk->sk_xid = vx_current_xid(); -+ vx_sock_inc(sk); -+ set_nx_info(&sk->sk_nx_info, current_nx_info()); -+ sk->sk_nid = nx_current_nid(); -+ - /* - * Before updating sk_refcnt, we must commit prior changes to memory - * (Documentation/RCU/rculist_nulls.txt for details) -diff -NurpP --minimal linux-2.6.32.1/net/ipv4/af_inet.c linux-2.6.32.1-vs2.3.0.36.27/net/ipv4/af_inet.c ---- linux-2.6.32.1/net/ipv4/af_inet.c 2009-12-03 20:02:59.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/net/ipv4/af_inet.c 2009-12-03 20:04:56.000000000 +0100 -@@ -115,6 +115,7 @@ - #ifdef CONFIG_IP_MROUTE - #include - #endif -+#include - - - /* The inetsw table contains everything that inet_create needs to -@@ -325,9 +326,12 @@ lookup_protocol: - } - - err = -EPERM; -+ if ((protocol == IPPROTO_ICMP) && -+ nx_capable(answer->capability, NXC_RAW_ICMP)) -+ goto override; - if (answer->capability > 0 && !capable(answer->capability)) - goto out_rcu_unlock; -- -+override: - err = -EAFNOSUPPORT; - if (!inet_netns_ok(net, protocol)) - goto out_rcu_unlock; -@@ -447,6 +451,7 @@ int inet_bind(struct socket *sock, struc - struct sockaddr_in *addr = (struct sockaddr_in *)uaddr; - struct sock *sk = sock->sk; - struct inet_sock *inet = inet_sk(sk); -+ struct nx_v4_sock_addr nsa; - unsigned short snum; - int chk_addr_ret; - int err; -@@ -460,7 +465,11 @@ int inet_bind(struct socket *sock, struc - if (addr_len < sizeof(struct sockaddr_in)) - goto out; - -- chk_addr_ret = inet_addr_type(sock_net(sk), addr->sin_addr.s_addr); -+ err = v4_map_sock_addr(inet, addr, &nsa); -+ if (err) -+ goto out; -+ -+ chk_addr_ret = inet_addr_type(sock_net(sk), nsa.saddr); - - /* Not specified by any standard per-se, however it breaks too - * many applications when removed. It is unfortunate since -@@ -472,7 +481,7 @@ int inet_bind(struct socket *sock, struc - err = -EADDRNOTAVAIL; - if (!sysctl_ip_nonlocal_bind && - !(inet->freebind || inet->transparent) && -- addr->sin_addr.s_addr != htonl(INADDR_ANY) && -+ nsa.saddr != htonl(INADDR_ANY) && - chk_addr_ret != RTN_LOCAL && - chk_addr_ret != RTN_MULTICAST && - chk_addr_ret != RTN_BROADCAST) -@@ -497,7 +506,7 @@ int inet_bind(struct socket *sock, struc - if (sk->sk_state != TCP_CLOSE || inet->num) - goto out_release_sock; - -- inet->rcv_saddr = inet->saddr = addr->sin_addr.s_addr; -+ v4_set_sock_addr(inet, &nsa); - if (chk_addr_ret == RTN_MULTICAST || chk_addr_ret == RTN_BROADCAST) - inet->saddr = 0; /* Use device */ - -@@ -694,11 +703,13 @@ int inet_getname(struct socket *sock, st - peer == 1)) - return -ENOTCONN; - sin->sin_port = inet->dport; -- sin->sin_addr.s_addr = inet->daddr; -+ sin->sin_addr.s_addr = -+ nx_map_sock_lback(sk->sk_nx_info, inet->daddr); - } else { - __be32 addr = inet->rcv_saddr; - if (!addr) - addr = inet->saddr; -+ addr = nx_map_sock_lback(sk->sk_nx_info, addr); - sin->sin_port = inet->sport; - sin->sin_addr.s_addr = addr; - } -diff -NurpP --minimal linux-2.6.32.1/net/ipv4/devinet.c linux-2.6.32.1-vs2.3.0.36.27/net/ipv4/devinet.c ---- linux-2.6.32.1/net/ipv4/devinet.c 2009-12-03 20:02:59.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/net/ipv4/devinet.c 2009-12-03 20:04:56.000000000 +0100 -@@ -413,6 +413,7 @@ struct in_device *inetdev_by_index(struc - return in_dev; - } - -+ - /* Called only from RTNL semaphored context. No locks. */ - - struct in_ifaddr *inet_ifa_byprefix(struct in_device *in_dev, __be32 prefix, -@@ -653,6 +654,8 @@ int devinet_ioctl(struct net *net, unsig - *colon = ':'; - - if ((in_dev = __in_dev_get_rtnl(dev)) != NULL) { -+ struct nx_info *nxi = current_nx_info(); -+ - if (tryaddrmatch) { - /* Matthias Andree */ - /* compare label and address (4.4BSD style) */ -@@ -661,6 +664,8 @@ int devinet_ioctl(struct net *net, unsig - This is checked above. */ - for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL; - ifap = &ifa->ifa_next) { -+ if (!nx_v4_ifa_visible(nxi, ifa)) -+ continue; - if (!strcmp(ifr.ifr_name, ifa->ifa_label) && - sin_orig.sin_addr.s_addr == - ifa->ifa_address) { -@@ -673,9 +678,12 @@ int devinet_ioctl(struct net *net, unsig - comparing just the label */ - if (!ifa) { - for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL; -- ifap = &ifa->ifa_next) -+ ifap = &ifa->ifa_next) { -+ if (!nx_v4_ifa_visible(nxi, ifa)) -+ continue; - if (!strcmp(ifr.ifr_name, ifa->ifa_label)) - break; -+ } - } - } - -@@ -826,6 +834,8 @@ static int inet_gifconf(struct net_devic - goto out; - - for (; ifa; ifa = ifa->ifa_next) { -+ if (!nx_v4_ifa_visible(current_nx_info(), ifa)) -+ continue; - if (!buf) { - done += sizeof(ifr); - continue; -@@ -1174,6 +1184,7 @@ static int inet_dump_ifaddr(struct sk_bu - struct net_device *dev; - struct in_device *in_dev; - struct in_ifaddr *ifa; -+ struct sock *sk = skb->sk; - int s_ip_idx, s_idx = cb->args[0]; - - s_ip_idx = ip_idx = cb->args[1]; -@@ -1188,6 +1199,8 @@ static int inet_dump_ifaddr(struct sk_bu - - for (ifa = in_dev->ifa_list, ip_idx = 0; ifa; - ifa = ifa->ifa_next, ip_idx++) { -+ if (sk && !nx_v4_ifa_visible(sk->sk_nx_info, ifa)) -+ continue; - if (ip_idx < s_ip_idx) - continue; - if (inet_fill_ifaddr(skb, ifa, NETLINK_CB(cb->skb).pid, -diff -NurpP --minimal linux-2.6.32.1/net/ipv4/fib_hash.c linux-2.6.32.1-vs2.3.0.36.27/net/ipv4/fib_hash.c ---- linux-2.6.32.1/net/ipv4/fib_hash.c 2009-09-10 15:26:29.000000000 +0200 -+++ linux-2.6.32.1-vs2.3.0.36.27/net/ipv4/fib_hash.c 2009-12-03 20:04:56.000000000 +0100 -@@ -1021,7 +1021,7 @@ static int fib_seq_show(struct seq_file - prefix = f->fn_key; - mask = FZ_MASK(iter->zone); - flags = fib_flag_trans(fa->fa_type, mask, fi); -- if (fi) -+ if (fi && nx_dev_visible(current_nx_info(), fi->fib_dev)) - seq_printf(seq, - "%s\t%08X\t%08X\t%04X\t%d\t%u\t%d\t%08X\t%d\t%u\t%u%n", - fi->fib_dev ? fi->fib_dev->name : "*", prefix, -diff -NurpP --minimal linux-2.6.32.1/net/ipv4/inet_connection_sock.c linux-2.6.32.1-vs2.3.0.36.27/net/ipv4/inet_connection_sock.c ---- linux-2.6.32.1/net/ipv4/inet_connection_sock.c 2009-12-03 20:02:59.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/net/ipv4/inet_connection_sock.c 2009-12-03 20:04:56.000000000 +0100 -@@ -49,10 +49,40 @@ void inet_get_local_port_range(int *low, - } - EXPORT_SYMBOL(inet_get_local_port_range); - -+int ipv4_rcv_saddr_equal(const struct sock *sk1, const struct sock *sk2) -+{ -+ __be32 sk1_rcv_saddr = inet_rcv_saddr(sk1), -+ sk2_rcv_saddr = inet_rcv_saddr(sk2); -+ -+ if (inet_v6_ipv6only(sk2)) -+ return 0; -+ -+ if (sk1_rcv_saddr && -+ sk2_rcv_saddr && -+ sk1_rcv_saddr == sk2_rcv_saddr) -+ return 1; -+ -+ if (sk1_rcv_saddr && -+ !sk2_rcv_saddr && -+ v4_addr_in_nx_info(sk2->sk_nx_info, sk1_rcv_saddr, NXA_MASK_BIND)) -+ return 1; -+ -+ if (sk2_rcv_saddr && -+ !sk1_rcv_saddr && -+ v4_addr_in_nx_info(sk1->sk_nx_info, sk2_rcv_saddr, NXA_MASK_BIND)) -+ return 1; -+ -+ if (!sk1_rcv_saddr && -+ !sk2_rcv_saddr && -+ nx_v4_addr_conflict(sk1->sk_nx_info, sk2->sk_nx_info)) -+ return 1; -+ -+ return 0; -+} -+ - int inet_csk_bind_conflict(const struct sock *sk, - const struct inet_bind_bucket *tb) - { -- const __be32 sk_rcv_saddr = inet_rcv_saddr(sk); - struct sock *sk2; - struct hlist_node *node; - int reuse = sk->sk_reuse; -@@ -72,9 +102,7 @@ int inet_csk_bind_conflict(const struct - sk->sk_bound_dev_if == sk2->sk_bound_dev_if)) { - if (!reuse || !sk2->sk_reuse || - sk2->sk_state == TCP_LISTEN) { -- const __be32 sk2_rcv_saddr = inet_rcv_saddr(sk2); -- if (!sk2_rcv_saddr || !sk_rcv_saddr || -- sk2_rcv_saddr == sk_rcv_saddr) -+ if (ipv4_rcv_saddr_equal(sk, sk2)) - break; - } - } -diff -NurpP --minimal linux-2.6.32.1/net/ipv4/inet_diag.c linux-2.6.32.1-vs2.3.0.36.27/net/ipv4/inet_diag.c ---- linux-2.6.32.1/net/ipv4/inet_diag.c 2009-09-10 15:26:29.000000000 +0200 -+++ linux-2.6.32.1-vs2.3.0.36.27/net/ipv4/inet_diag.c 2009-12-03 20:04:56.000000000 +0100 -@@ -32,6 +32,8 @@ - #include - - #include -+#include -+#include - - static const struct inet_diag_handler **inet_diag_table; - -@@ -118,8 +120,8 @@ static int inet_csk_diag_fill(struct soc - - r->id.idiag_sport = inet->sport; - r->id.idiag_dport = inet->dport; -- r->id.idiag_src[0] = inet->rcv_saddr; -- r->id.idiag_dst[0] = inet->daddr; -+ r->id.idiag_src[0] = nx_map_sock_lback(sk->sk_nx_info, inet->rcv_saddr); -+ r->id.idiag_dst[0] = nx_map_sock_lback(sk->sk_nx_info, inet->daddr); - - #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) - if (r->idiag_family == AF_INET6) { -@@ -204,8 +206,8 @@ static int inet_twsk_diag_fill(struct in - r->id.idiag_cookie[1] = (u32)(((unsigned long)tw >> 31) >> 1); - r->id.idiag_sport = tw->tw_sport; - r->id.idiag_dport = tw->tw_dport; -- r->id.idiag_src[0] = tw->tw_rcv_saddr; -- r->id.idiag_dst[0] = tw->tw_daddr; -+ r->id.idiag_src[0] = nx_map_sock_lback(tw->tw_nx_info, tw->tw_rcv_saddr); -+ r->id.idiag_dst[0] = nx_map_sock_lback(tw->tw_nx_info, tw->tw_daddr); - r->idiag_state = tw->tw_substate; - r->idiag_timer = 3; - r->idiag_expires = DIV_ROUND_UP(tmo * 1000, HZ); -@@ -262,6 +264,7 @@ static int inet_diag_get_exact(struct sk - err = -EINVAL; - - if (req->idiag_family == AF_INET) { -+ /* TODO: lback */ - sk = inet_lookup(&init_net, hashinfo, req->id.idiag_dst[0], - req->id.idiag_dport, req->id.idiag_src[0], - req->id.idiag_sport, req->id.idiag_if); -@@ -504,6 +507,7 @@ static int inet_csk_diag_dump(struct soc - } else - #endif - { -+ /* TODO: lback */ - entry.saddr = &inet->rcv_saddr; - entry.daddr = &inet->daddr; - } -@@ -540,6 +544,7 @@ static int inet_twsk_diag_dump(struct in - } else - #endif - { -+ /* TODO: lback */ - entry.saddr = &tw->tw_rcv_saddr; - entry.daddr = &tw->tw_daddr; - } -@@ -586,8 +591,8 @@ static int inet_diag_fill_req(struct sk_ - - r->id.idiag_sport = inet->sport; - r->id.idiag_dport = ireq->rmt_port; -- r->id.idiag_src[0] = ireq->loc_addr; -- r->id.idiag_dst[0] = ireq->rmt_addr; -+ r->id.idiag_src[0] = nx_map_sock_lback(sk->sk_nx_info, ireq->loc_addr); -+ r->id.idiag_dst[0] = nx_map_sock_lback(sk->sk_nx_info, ireq->rmt_addr); - r->idiag_expires = jiffies_to_msecs(tmo); - r->idiag_rqueue = 0; - r->idiag_wqueue = 0; -@@ -657,6 +662,7 @@ static int inet_diag_dump_reqs(struct sk - continue; - - if (bc) { -+ /* TODO: lback */ - entry.saddr = - #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) - (entry.family == AF_INET6) ? -@@ -727,6 +733,8 @@ static int inet_diag_dump(struct sk_buff - sk_nulls_for_each(sk, node, &ilb->head) { - struct inet_sock *inet = inet_sk(sk); - -+ if (!nx_check(sk->sk_nid, VS_WATCH_P | VS_IDENT)) -+ continue; - if (num < s_num) { - num++; - continue; -@@ -793,6 +801,8 @@ skip_listen_ht: - sk_nulls_for_each(sk, node, &head->chain) { - struct inet_sock *inet = inet_sk(sk); - -+ if (!nx_check(sk->sk_nid, VS_WATCH_P | VS_IDENT)) -+ continue; - if (num < s_num) - goto next_normal; - if (!(r->idiag_states & (1 << sk->sk_state))) -@@ -817,6 +827,8 @@ next_normal: - inet_twsk_for_each(tw, node, - &head->twchain) { - -+ if (!nx_check(tw->tw_nid, VS_WATCH_P | VS_IDENT)) -+ continue; - if (num < s_num) - goto next_dying; - if (r->id.idiag_sport != tw->tw_sport && -diff -NurpP --minimal linux-2.6.32.1/net/ipv4/inet_hashtables.c linux-2.6.32.1-vs2.3.0.36.27/net/ipv4/inet_hashtables.c ---- linux-2.6.32.1/net/ipv4/inet_hashtables.c 2009-06-11 17:13:29.000000000 +0200 -+++ linux-2.6.32.1-vs2.3.0.36.27/net/ipv4/inet_hashtables.c 2009-12-03 20:04:56.000000000 +0100 -@@ -21,6 +21,7 @@ - - #include - #include -+#include - #include - - /* -@@ -134,6 +135,11 @@ static inline int compute_score(struct s - if (rcv_saddr != daddr) - return -1; - score += 2; -+ } else { -+ /* block non nx_info ips */ -+ if (!v4_addr_in_nx_info(sk->sk_nx_info, -+ daddr, NXA_MASK_BIND)) -+ return -1; - } - if (sk->sk_bound_dev_if) { - if (sk->sk_bound_dev_if != dif) -@@ -151,7 +157,6 @@ static inline int compute_score(struct s - * wildcarded during the search since they can never be otherwise. - */ - -- - struct sock *__inet_lookup_listener(struct net *net, - struct inet_hashinfo *hashinfo, - const __be32 daddr, const unsigned short hnum, -@@ -174,6 +179,7 @@ begin: - hiscore = score; - } - } -+ - /* - * if the nulls value we got at the end of this lookup is - * not the expected one, we must restart lookup. -diff -NurpP --minimal linux-2.6.32.1/net/ipv4/netfilter/nf_nat_helper.c linux-2.6.32.1-vs2.3.0.36.27/net/ipv4/netfilter/nf_nat_helper.c ---- linux-2.6.32.1/net/ipv4/netfilter/nf_nat_helper.c 2009-12-03 20:02:59.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/net/ipv4/netfilter/nf_nat_helper.c 2009-12-03 20:04:56.000000000 +0100 -@@ -19,6 +19,7 @@ - #include - - #include -+#include - #include - #include - #include -diff -NurpP --minimal linux-2.6.32.1/net/ipv4/netfilter.c linux-2.6.32.1-vs2.3.0.36.27/net/ipv4/netfilter.c ---- linux-2.6.32.1/net/ipv4/netfilter.c 2009-09-10 15:26:29.000000000 +0200 -+++ linux-2.6.32.1-vs2.3.0.36.27/net/ipv4/netfilter.c 2009-12-03 20:04:56.000000000 +0100 -@@ -4,7 +4,7 @@ - #include - #include - #include --#include -+// #include - #include - #include - #include -diff -NurpP --minimal linux-2.6.32.1/net/ipv4/raw.c linux-2.6.32.1-vs2.3.0.36.27/net/ipv4/raw.c ---- linux-2.6.32.1/net/ipv4/raw.c 2009-12-03 20:02:59.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/net/ipv4/raw.c 2009-12-03 20:04:56.000000000 +0100 -@@ -117,7 +117,7 @@ static struct sock *__raw_v4_lookup(stru - - if (net_eq(sock_net(sk), net) && inet->num == num && - !(inet->daddr && inet->daddr != raddr) && -- !(inet->rcv_saddr && inet->rcv_saddr != laddr) && -+ v4_sock_addr_match(sk->sk_nx_info, inet, laddr) && - !(sk->sk_bound_dev_if && sk->sk_bound_dev_if != dif)) - goto found; /* gotcha */ - } -@@ -383,6 +383,12 @@ static int raw_send_hdrinc(struct sock * - icmp_out_count(net, ((struct icmphdr *) - skb_transport_header(skb))->type); - -+ err = -EPERM; -+ if (!nx_check(0, VS_ADMIN) && !capable(CAP_NET_RAW) && -+ sk->sk_nx_info && -+ !v4_addr_in_nx_info(sk->sk_nx_info, iph->saddr, NXA_MASK_BIND)) -+ goto error_free; -+ - err = NF_HOOK(PF_INET, NF_INET_LOCAL_OUT, skb, NULL, rt->u.dst.dev, - dst_output); - if (err > 0) -@@ -563,6 +569,13 @@ static int raw_sendmsg(struct kiocb *ioc - } - - security_sk_classify_flow(sk, &fl); -+ if (sk->sk_nx_info) { -+ err = ip_v4_find_src(sock_net(sk), -+ sk->sk_nx_info, &rt, &fl); -+ -+ if (err) -+ goto done; -+ } - err = ip_route_output_flow(sock_net(sk), &rt, &fl, sk, 1); - } - if (err) -@@ -635,17 +648,19 @@ static int raw_bind(struct sock *sk, str - { - struct inet_sock *inet = inet_sk(sk); - struct sockaddr_in *addr = (struct sockaddr_in *) uaddr; -+ struct nx_v4_sock_addr nsa = { 0 }; - int ret = -EINVAL; - int chk_addr_ret; - - if (sk->sk_state != TCP_CLOSE || addr_len < sizeof(struct sockaddr_in)) - goto out; -- chk_addr_ret = inet_addr_type(sock_net(sk), addr->sin_addr.s_addr); -+ v4_map_sock_addr(inet, addr, &nsa); -+ chk_addr_ret = inet_addr_type(sock_net(sk), nsa.saddr); - ret = -EADDRNOTAVAIL; -- if (addr->sin_addr.s_addr && chk_addr_ret != RTN_LOCAL && -+ if (nsa.saddr && chk_addr_ret != RTN_LOCAL && - chk_addr_ret != RTN_MULTICAST && chk_addr_ret != RTN_BROADCAST) - goto out; -- inet->rcv_saddr = inet->saddr = addr->sin_addr.s_addr; -+ v4_set_sock_addr(inet, &nsa); - if (chk_addr_ret == RTN_MULTICAST || chk_addr_ret == RTN_BROADCAST) - inet->saddr = 0; /* Use device */ - sk_dst_reset(sk); -@@ -697,7 +712,8 @@ static int raw_recvmsg(struct kiocb *ioc - /* Copy the address. */ - if (sin) { - sin->sin_family = AF_INET; -- sin->sin_addr.s_addr = ip_hdr(skb)->saddr; -+ sin->sin_addr.s_addr = -+ nx_map_sock_lback(sk->sk_nx_info, ip_hdr(skb)->saddr); - sin->sin_port = 0; - memset(&sin->sin_zero, 0, sizeof(sin->sin_zero)); - } -@@ -875,7 +891,8 @@ static struct sock *raw_get_first(struct - struct hlist_node *node; - - sk_for_each(sk, node, &state->h->ht[state->bucket]) -- if (sock_net(sk) == seq_file_net(seq)) -+ if ((sock_net(sk) == seq_file_net(seq)) && -+ nx_check(sk->sk_nid, VS_WATCH_P | VS_IDENT)) - goto found; - } - sk = NULL; -@@ -891,7 +908,8 @@ static struct sock *raw_get_next(struct - sk = sk_next(sk); - try_again: - ; -- } while (sk && sock_net(sk) != seq_file_net(seq)); -+ } while (sk && ((sock_net(sk) != seq_file_net(seq)) || -+ !nx_check(sk->sk_nid, VS_WATCH_P | VS_IDENT))); - - if (!sk && ++state->bucket < RAW_HTABLE_SIZE) { - sk = sk_head(&state->h->ht[state->bucket]); -@@ -950,7 +968,10 @@ static void raw_sock_seq_show(struct seq - - seq_printf(seq, "%4d: %08X:%04X %08X:%04X" - " %02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p %d\n", -- i, src, srcp, dest, destp, sp->sk_state, -+ i, -+ nx_map_sock_lback(current_nx_info(), src), srcp, -+ nx_map_sock_lback(current_nx_info(), dest), destp, -+ sp->sk_state, - sk_wmem_alloc_get(sp), - sk_rmem_alloc_get(sp), - 0, 0L, 0, sock_i_uid(sp), 0, sock_i_ino(sp), -diff -NurpP --minimal linux-2.6.32.1/net/ipv4/tcp.c linux-2.6.32.1-vs2.3.0.36.27/net/ipv4/tcp.c ---- linux-2.6.32.1/net/ipv4/tcp.c 2009-12-03 20:02:59.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/net/ipv4/tcp.c 2009-12-03 20:04:56.000000000 +0100 -@@ -264,6 +264,7 @@ - #include - #include - #include -+#include - - #include - #include -diff -NurpP --minimal linux-2.6.32.1/net/ipv4/tcp_ipv4.c linux-2.6.32.1-vs2.3.0.36.27/net/ipv4/tcp_ipv4.c ---- linux-2.6.32.1/net/ipv4/tcp_ipv4.c 2009-12-03 20:03:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/net/ipv4/tcp_ipv4.c 2009-12-03 20:04:56.000000000 +0100 -@@ -1925,6 +1925,12 @@ static void *listening_get_next(struct s - req = req->dl_next; - while (1) { - while (req) { -+ vxdprintk(VXD_CBIT(net, 6), -+ "sk,req: %p [#%d] (from %d)", req->sk, -+ (req->sk)?req->sk->sk_nid:0, nx_current_nid()); -+ if (req->sk && -+ !nx_check(req->sk->sk_nid, VS_WATCH_P | VS_IDENT)) -+ continue; - if (req->rsk_ops->family == st->family) { - cur = req; - goto out; -@@ -1949,6 +1955,10 @@ get_req: - } - get_sk: - sk_nulls_for_each_from(sk, node) { -+ vxdprintk(VXD_CBIT(net, 6), "sk: %p [#%d] (from %d)", -+ sk, sk->sk_nid, nx_current_nid()); -+ if (!nx_check(sk->sk_nid, VS_WATCH_P | VS_IDENT)) -+ continue; - if (sk->sk_family == st->family && net_eq(sock_net(sk), net)) { - cur = sk; - goto out; -@@ -2012,6 +2022,11 @@ static void *established_get_first(struc - - spin_lock_bh(lock); - sk_nulls_for_each(sk, node, &tcp_hashinfo.ehash[st->bucket].chain) { -+ vxdprintk(VXD_CBIT(net, 6), -+ "sk,egf: %p [#%d] (from %d)", -+ sk, sk->sk_nid, nx_current_nid()); -+ if (!nx_check(sk->sk_nid, VS_WATCH_P | VS_IDENT)) -+ continue; - if (sk->sk_family != st->family || - !net_eq(sock_net(sk), net)) { - continue; -@@ -2022,6 +2037,11 @@ static void *established_get_first(struc - st->state = TCP_SEQ_STATE_TIME_WAIT; - inet_twsk_for_each(tw, node, - &tcp_hashinfo.ehash[st->bucket].twchain) { -+ vxdprintk(VXD_CBIT(net, 6), -+ "tw: %p [#%d] (from %d)", -+ tw, tw->tw_nid, nx_current_nid()); -+ if (!nx_check(tw->tw_nid, VS_WATCH_P | VS_IDENT)) -+ continue; - if (tw->tw_family != st->family || - !net_eq(twsk_net(tw), net)) { - continue; -@@ -2050,7 +2070,9 @@ static void *established_get_next(struct - tw = cur; - tw = tw_next(tw); - get_tw: -- while (tw && (tw->tw_family != st->family || !net_eq(twsk_net(tw), net))) { -+ while (tw && (tw->tw_family != st->family || -+ !net_eq(twsk_net(tw), net) || -+ !nx_check(tw->tw_nid, VS_WATCH_P | VS_IDENT))) { - tw = tw_next(tw); - } - if (tw) { -@@ -2073,6 +2095,11 @@ get_tw: - sk = sk_nulls_next(sk); - - sk_nulls_for_each_from(sk, node) { -+ vxdprintk(VXD_CBIT(net, 6), -+ "sk,egn: %p [#%d] (from %d)", -+ sk, sk->sk_nid, nx_current_nid()); -+ if (!nx_check(sk->sk_nid, VS_WATCH_P | VS_IDENT)) -+ continue; - if (sk->sk_family == st->family && net_eq(sock_net(sk), net)) - goto found; - } -@@ -2224,9 +2251,9 @@ static void get_openreq4(struct sock *sk - seq_printf(f, "%4d: %08X:%04X %08X:%04X" - " %02X %08X:%08X %02X:%08lX %08X %5d %8d %u %d %p%n", - i, -- ireq->loc_addr, -+ nx_map_sock_lback(current_nx_info(), ireq->loc_addr), - ntohs(inet_sk(sk)->sport), -- ireq->rmt_addr, -+ nx_map_sock_lback(current_nx_info(), ireq->rmt_addr), - ntohs(ireq->rmt_port), - TCP_SYN_RECV, - 0, 0, /* could print option size, but that is af dependent. */ -@@ -2269,7 +2296,10 @@ static void get_tcp4_sock(struct sock *s - - seq_printf(f, "%4d: %08X:%04X %08X:%04X %02X %08X:%08X %02X:%08lX " - "%08X %5d %8d %lu %d %p %lu %lu %u %u %d%n", -- i, src, srcp, dest, destp, sk->sk_state, -+ i, -+ nx_map_sock_lback(current_nx_info(), src), srcp, -+ nx_map_sock_lback(current_nx_info(), dest), destp, -+ sk->sk_state, - tp->write_seq - tp->snd_una, - sk->sk_state == TCP_LISTEN ? sk->sk_ack_backlog : - (tp->rcv_nxt - tp->copied_seq), -@@ -2305,7 +2335,10 @@ static void get_timewait4_sock(struct in - - seq_printf(f, "%4d: %08X:%04X %08X:%04X" - " %02X %08X:%08X %02X:%08lX %08X %5d %8d %d %d %p%n", -- i, src, srcp, dest, destp, tw->tw_substate, 0, 0, -+ i, -+ nx_map_sock_lback(current_nx_info(), src), srcp, -+ nx_map_sock_lback(current_nx_info(), dest), destp, -+ tw->tw_substate, 0, 0, - 3, jiffies_to_clock_t(ttd), 0, 0, 0, 0, - atomic_read(&tw->tw_refcnt), tw, len); - } -diff -NurpP --minimal linux-2.6.32.1/net/ipv4/tcp_minisocks.c linux-2.6.32.1-vs2.3.0.36.27/net/ipv4/tcp_minisocks.c ---- linux-2.6.32.1/net/ipv4/tcp_minisocks.c 2009-12-03 20:03:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/net/ipv4/tcp_minisocks.c 2009-12-03 20:04:56.000000000 +0100 -@@ -26,6 +26,10 @@ - #include - #include - -+#include -+#include -+#include -+ - #ifdef CONFIG_SYSCTL - #define SYNC_INIT 0 /* let the user enable it */ - #else -@@ -294,6 +298,11 @@ void tcp_time_wait(struct sock *sk, int - tcptw->tw_ts_recent = tp->rx_opt.ts_recent; - tcptw->tw_ts_recent_stamp = tp->rx_opt.ts_recent_stamp; - -+ tw->tw_xid = sk->sk_xid; -+ tw->tw_vx_info = NULL; -+ tw->tw_nid = sk->sk_nid; -+ tw->tw_nx_info = NULL; -+ - #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) - if (tw->tw_family == PF_INET6) { - struct ipv6_pinfo *np = inet6_sk(sk); -diff -NurpP --minimal linux-2.6.32.1/net/ipv4/udp.c linux-2.6.32.1-vs2.3.0.36.27/net/ipv4/udp.c ---- linux-2.6.32.1/net/ipv4/udp.c 2009-12-03 20:03:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/net/ipv4/udp.c 2009-12-03 20:04:56.000000000 +0100 -@@ -224,14 +224,7 @@ fail: - } - EXPORT_SYMBOL(udp_lib_get_port); - --static int ipv4_rcv_saddr_equal(const struct sock *sk1, const struct sock *sk2) --{ -- struct inet_sock *inet1 = inet_sk(sk1), *inet2 = inet_sk(sk2); -- -- return (!ipv6_only_sock(sk2) && -- (!inet1->rcv_saddr || !inet2->rcv_saddr || -- inet1->rcv_saddr == inet2->rcv_saddr)); --} -+extern int ipv4_rcv_saddr_equal(const struct sock *, const struct sock *); - - int udp_v4_get_port(struct sock *sk, unsigned short snum) - { -@@ -253,6 +246,11 @@ static inline int compute_score(struct s - if (inet->rcv_saddr != daddr) - return -1; - score += 2; -+ } else { -+ /* block non nx_info ips */ -+ if (!v4_addr_in_nx_info(sk->sk_nx_info, -+ daddr, NXA_MASK_BIND)) -+ return -1; - } - if (inet->daddr) { - if (inet->daddr != saddr) -@@ -273,6 +271,7 @@ static inline int compute_score(struct s - return score; - } - -+ - /* UDP is nearly always wildcards out the wazoo, it makes no sense to try - * harder than this. -DaveM - */ -@@ -294,6 +293,11 @@ begin: - sk_nulls_for_each_rcu(sk, node, &hslot->head) { - score = compute_score(sk, net, saddr, hnum, sport, - daddr, dport, dif); -+ /* FIXME: disabled? -+ if (score == 9) { -+ result = sk; -+ break; -+ } else */ - if (score > badness) { - result = sk; - badness = score; -@@ -307,6 +311,7 @@ begin: - if (get_nulls_value(node) != hash) - goto begin; - -+ - if (result) { - if (unlikely(!atomic_inc_not_zero(&result->sk_refcnt))) - result = NULL; -@@ -316,6 +321,7 @@ begin: - goto begin; - } - } -+ - rcu_read_unlock(); - return result; - } -@@ -358,7 +364,7 @@ static inline struct sock *udp_v4_mcast_ - s->sk_hash != hnum || - (inet->daddr && inet->daddr != rmt_addr) || - (inet->dport != rmt_port && inet->dport) || -- (inet->rcv_saddr && inet->rcv_saddr != loc_addr) || -+ !v4_sock_addr_match(sk->sk_nx_info, inet, loc_addr) || - ipv6_only_sock(s) || - (s->sk_bound_dev_if && s->sk_bound_dev_if != dif)) - continue; -@@ -707,8 +713,13 @@ int udp_sendmsg(struct kiocb *iocb, stru - { .sport = inet->sport, - .dport = dport } } }; - struct net *net = sock_net(sk); -+ struct nx_info *nxi = sk->sk_nx_info; - - security_sk_classify_flow(sk, &fl); -+ err = ip_v4_find_src(net, nxi, &rt, &fl); -+ if (err) -+ goto out; -+ - err = ip_route_output_flow(net, &rt, &fl, sk, 1); - if (err) { - if (err == -ENETUNREACH) -@@ -988,7 +999,8 @@ try_again: - if (sin) { - sin->sin_family = AF_INET; - sin->sin_port = udp_hdr(skb)->source; -- sin->sin_addr.s_addr = ip_hdr(skb)->saddr; -+ sin->sin_addr.s_addr = nx_map_sock_lback( -+ skb->sk->sk_nx_info, ip_hdr(skb)->saddr); - memset(sin->sin_zero, 0, sizeof(sin->sin_zero)); - } - if (inet->cmsg_flags) -@@ -1627,6 +1639,8 @@ static struct sock *udp_get_first(struct - sk_nulls_for_each(sk, node, &hslot->head) { - if (!net_eq(sock_net(sk), net)) - continue; -+ if (!nx_check(sk->sk_nid, VS_WATCH_P | VS_IDENT)) -+ continue; - if (sk->sk_family == state->family) - goto found; - } -@@ -1644,7 +1658,9 @@ static struct sock *udp_get_next(struct - - do { - sk = sk_nulls_next(sk); -- } while (sk && (!net_eq(sock_net(sk), net) || sk->sk_family != state->family)); -+ } while (sk && (!net_eq(sock_net(sk), net) || -+ sk->sk_family != state->family || -+ !nx_check(sk->sk_nid, VS_WATCH_P | VS_IDENT))); - - if (!sk) { - if (state->bucket < UDP_HTABLE_SIZE) -@@ -1751,7 +1767,10 @@ static void udp4_format_sock(struct sock - - seq_printf(f, "%4d: %08X:%04X %08X:%04X" - " %02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p %d%n", -- bucket, src, srcp, dest, destp, sp->sk_state, -+ bucket, -+ nx_map_sock_lback(current_nx_info(), src), srcp, -+ nx_map_sock_lback(current_nx_info(), dest), destp, -+ sp->sk_state, - sk_wmem_alloc_get(sp), - sk_rmem_alloc_get(sp), - 0, 0L, 0, sock_i_uid(sp), 0, sock_i_ino(sp), -diff -NurpP --minimal linux-2.6.32.1/net/ipv6/addrconf.c linux-2.6.32.1-vs2.3.0.36.27/net/ipv6/addrconf.c ---- linux-2.6.32.1/net/ipv6/addrconf.c 2009-12-03 20:03:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/net/ipv6/addrconf.c 2009-12-03 20:04:56.000000000 +0100 -@@ -86,6 +86,8 @@ - - #include - #include -+#include -+#include - - /* Set to 3 to get tracing... */ - #define ACONF_DEBUG 2 -@@ -1119,7 +1121,7 @@ out: - - int ipv6_dev_get_saddr(struct net *net, struct net_device *dst_dev, - const struct in6_addr *daddr, unsigned int prefs, -- struct in6_addr *saddr) -+ struct in6_addr *saddr, struct nx_info *nxi) - { - struct ipv6_saddr_score scores[2], - *score = &scores[0], *hiscore = &scores[1]; -@@ -1192,6 +1194,8 @@ int ipv6_dev_get_saddr(struct net *net, - dev->name); - continue; - } -+ if (!v6_addr_in_nx_info(nxi, &score->ifa->addr, -1)) -+ continue; - - score->rule = -1; - bitmap_zero(score->scorebits, IPV6_SADDR_RULE_MAX); -@@ -3000,7 +3004,10 @@ static void if6_seq_stop(struct seq_file - static int if6_seq_show(struct seq_file *seq, void *v) - { - struct inet6_ifaddr *ifp = (struct inet6_ifaddr *)v; -- seq_printf(seq, "%pi6 %02x %02x %02x %02x %8s\n", -+ -+ if (nx_check(0, VS_ADMIN|VS_WATCH) || -+ v6_addr_in_nx_info(current_nx_info(), &ifp->addr, -1)) -+ seq_printf(seq, "%pi6 %02x %02x %02x %02x %8s\n", - &ifp->addr, - ifp->idev->dev->ifindex, - ifp->prefix_len, -@@ -3497,6 +3504,12 @@ static int inet6_dump_addr(struct sk_buf - struct ifmcaddr6 *ifmca; - struct ifacaddr6 *ifaca; - struct net *net = sock_net(skb->sk); -+ struct nx_info *nxi = skb->sk ? skb->sk->sk_nx_info : NULL; -+ -+ /* disable ipv6 on non v6 guests */ -+ if (nxi && !nx_info_has_v6(nxi)) -+ return skb->len; -+ - - s_idx = cb->args[0]; - s_ip_idx = ip_idx = cb->args[1]; -@@ -3518,6 +3531,8 @@ static int inet6_dump_addr(struct sk_buf - ifa = ifa->if_next, ip_idx++) { - if (ip_idx < s_ip_idx) - continue; -+ if (!v6_addr_in_nx_info(nxi, &ifa->addr, -1)) -+ continue; - err = inet6_fill_ifaddr(skb, ifa, - NETLINK_CB(cb->skb).pid, - cb->nlh->nlmsg_seq, -@@ -3531,6 +3546,8 @@ static int inet6_dump_addr(struct sk_buf - ifmca = ifmca->next, ip_idx++) { - if (ip_idx < s_ip_idx) - continue; -+ if (!v6_addr_in_nx_info(nxi, &ifmca->mca_addr, -1)) -+ continue; - err = inet6_fill_ifmcaddr(skb, ifmca, - NETLINK_CB(cb->skb).pid, - cb->nlh->nlmsg_seq, -@@ -3544,6 +3561,8 @@ static int inet6_dump_addr(struct sk_buf - ifaca = ifaca->aca_next, ip_idx++) { - if (ip_idx < s_ip_idx) - continue; -+ if (!v6_addr_in_nx_info(nxi, &ifaca->aca_addr, -1)) -+ continue; - err = inet6_fill_ifacaddr(skb, ifaca, - NETLINK_CB(cb->skb).pid, - cb->nlh->nlmsg_seq, -@@ -3830,12 +3849,19 @@ static int inet6_dump_ifinfo(struct sk_b - int s_idx = cb->args[0]; - struct net_device *dev; - struct inet6_dev *idev; -+ struct nx_info *nxi = skb->sk ? skb->sk->sk_nx_info : NULL; -+ -+ /* FIXME: maybe disable ipv6 on non v6 guests? -+ if (skb->sk && skb->sk->sk_vx_info) -+ return skb->len; */ - - read_lock(&dev_base_lock); - idx = 0; - for_each_netdev(net, dev) { - if (idx < s_idx) - goto cont; -+ if (!v6_dev_in_nx_info(dev, nxi)) -+ goto cont; - if ((idev = in6_dev_get(dev)) == NULL) - goto cont; - err = inet6_fill_ifinfo(skb, idev, NETLINK_CB(cb->skb).pid, -diff -NurpP --minimal linux-2.6.32.1/net/ipv6/af_inet6.c linux-2.6.32.1-vs2.3.0.36.27/net/ipv6/af_inet6.c ---- linux-2.6.32.1/net/ipv6/af_inet6.c 2009-12-03 20:03:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/net/ipv6/af_inet6.c 2009-12-03 20:04:56.000000000 +0100 -@@ -41,6 +41,8 @@ - #include - #include - #include -+#include -+#include - - #include - #include -@@ -158,9 +160,12 @@ lookup_protocol: - } - - err = -EPERM; -+ if ((protocol == IPPROTO_ICMPV6) && -+ nx_capable(answer->capability, NXC_RAW_ICMP)) -+ goto override; - if (answer->capability > 0 && !capable(answer->capability)) - goto out_rcu_unlock; -- -+override: - sock->ops = answer->ops; - answer_prot = answer->prot; - answer_no_check = answer->no_check; -@@ -259,6 +264,7 @@ int inet6_bind(struct socket *sock, stru - struct inet_sock *inet = inet_sk(sk); - struct ipv6_pinfo *np = inet6_sk(sk); - struct net *net = sock_net(sk); -+ struct nx_v6_sock_addr nsa; - __be32 v4addr = 0; - unsigned short snum; - int addr_type = 0; -@@ -270,6 +276,11 @@ int inet6_bind(struct socket *sock, stru - - if (addr_len < SIN6_LEN_RFC2133) - return -EINVAL; -+ -+ err = v6_map_sock_addr(inet, addr, &nsa); -+ if (err) -+ return err; -+ - addr_type = ipv6_addr_type(&addr->sin6_addr); - if ((addr_type & IPV6_ADDR_MULTICAST) && sock->type == SOCK_STREAM) - return -EINVAL; -@@ -301,6 +312,7 @@ int inet6_bind(struct socket *sock, stru - /* Reproduce AF_INET checks to make the bindings consitant */ - v4addr = addr->sin6_addr.s6_addr32[3]; - chk_addr_ret = inet_addr_type(net, v4addr); -+ - if (!sysctl_ip_nonlocal_bind && - !(inet->freebind || inet->transparent) && - v4addr != htonl(INADDR_ANY) && -@@ -310,6 +322,10 @@ int inet6_bind(struct socket *sock, stru - err = -EADDRNOTAVAIL; - goto out; - } -+ if (!v4_addr_in_nx_info(sk->sk_nx_info, v4addr, NXA_MASK_BIND)) { -+ err = -EADDRNOTAVAIL; -+ goto out; -+ } - } else { - if (addr_type != IPV6_ADDR_ANY) { - struct net_device *dev = NULL; -@@ -335,6 +351,11 @@ int inet6_bind(struct socket *sock, stru - } - } - -+ if (!v6_addr_in_nx_info(sk->sk_nx_info, &addr->sin6_addr, -1)) { -+ err = -EADDRNOTAVAIL; -+ goto out; -+ } -+ - /* ipv4 addr of the socket is invalid. Only the - * unspecified and mapped address have a v4 equivalent. - */ -@@ -353,6 +374,8 @@ int inet6_bind(struct socket *sock, stru - } - } - -+ v6_set_sock_addr(inet, &nsa); -+ - inet->rcv_saddr = v4addr; - inet->saddr = v4addr; - -@@ -448,9 +471,11 @@ int inet6_getname(struct socket *sock, s - return -ENOTCONN; - sin->sin6_port = inet->dport; - ipv6_addr_copy(&sin->sin6_addr, &np->daddr); -+ /* FIXME: remap lback? */ - if (np->sndflow) - sin->sin6_flowinfo = np->flow_label; - } else { -+ /* FIXME: remap lback? */ - if (ipv6_addr_any(&np->rcv_saddr)) - ipv6_addr_copy(&sin->sin6_addr, &np->saddr); - else -diff -NurpP --minimal linux-2.6.32.1/net/ipv6/fib6_rules.c linux-2.6.32.1-vs2.3.0.36.27/net/ipv6/fib6_rules.c ---- linux-2.6.32.1/net/ipv6/fib6_rules.c 2009-09-10 15:26:30.000000000 +0200 -+++ linux-2.6.32.1-vs2.3.0.36.27/net/ipv6/fib6_rules.c 2009-12-03 20:04:56.000000000 +0100 -@@ -96,7 +96,7 @@ static int fib6_rule_action(struct fib_r - if (ipv6_dev_get_saddr(net, - ip6_dst_idev(&rt->u.dst)->dev, - &flp->fl6_dst, srcprefs, -- &saddr)) -+ &saddr, NULL)) - goto again; - if (!ipv6_prefix_equal(&saddr, &r->src.addr, - r->src.plen)) -diff -NurpP --minimal linux-2.6.32.1/net/ipv6/inet6_hashtables.c linux-2.6.32.1-vs2.3.0.36.27/net/ipv6/inet6_hashtables.c ---- linux-2.6.32.1/net/ipv6/inet6_hashtables.c 2009-03-24 14:22:46.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/net/ipv6/inet6_hashtables.c 2009-12-03 20:04:56.000000000 +0100 -@@ -16,6 +16,7 @@ - - #include - #include -+#include - - #include - #include -@@ -76,7 +77,6 @@ struct sock *__inet6_lookup_established( - unsigned int slot = hash & (hashinfo->ehash_size - 1); - struct inet_ehash_bucket *head = &hashinfo->ehash[slot]; - -- - rcu_read_lock(); - begin: - sk_nulls_for_each_rcu(sk, node, &head->chain) { -@@ -88,7 +88,7 @@ begin: - sock_put(sk); - goto begin; - } -- goto out; -+ goto out; - } - } - if (get_nulls_value(node) != slot) -@@ -134,6 +134,9 @@ static int inline compute_score(struct s - if (!ipv6_addr_equal(&np->rcv_saddr, daddr)) - return -1; - score++; -+ } else { -+ if (!v6_addr_in_nx_info(sk->sk_nx_info, daddr, -1)) -+ return -1; - } - if (sk->sk_bound_dev_if) { - if (sk->sk_bound_dev_if != dif) -diff -NurpP --minimal linux-2.6.32.1/net/ipv6/ip6_output.c linux-2.6.32.1-vs2.3.0.36.27/net/ipv6/ip6_output.c ---- linux-2.6.32.1/net/ipv6/ip6_output.c 2009-12-03 20:03:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/net/ipv6/ip6_output.c 2009-12-03 20:04:56.000000000 +0100 -@@ -934,7 +934,7 @@ static int ip6_dst_lookup_tail(struct so - err = ipv6_dev_get_saddr(net, ip6_dst_idev(*dst)->dev, - &fl->fl6_dst, - sk ? inet6_sk(sk)->srcprefs : 0, -- &fl->fl6_src); -+ &fl->fl6_src, sk->sk_nx_info); - if (err) - goto out_err_release; - } -diff -NurpP --minimal linux-2.6.32.1/net/ipv6/Kconfig linux-2.6.32.1-vs2.3.0.36.27/net/ipv6/Kconfig ---- linux-2.6.32.1/net/ipv6/Kconfig 2009-09-10 15:26:30.000000000 +0200 -+++ linux-2.6.32.1-vs2.3.0.36.27/net/ipv6/Kconfig 2009-12-03 20:04:56.000000000 +0100 -@@ -4,8 +4,8 @@ - - # IPv6 as module will cause a CRASH if you try to unload it - menuconfig IPV6 -- tristate "The IPv6 protocol" -- default m -+ bool "The IPv6 protocol" -+ default n - ---help--- - This is complemental support for the IP version 6. - You will still be able to do traditional IPv4 networking as well. -diff -NurpP --minimal linux-2.6.32.1/net/ipv6/ndisc.c linux-2.6.32.1-vs2.3.0.36.27/net/ipv6/ndisc.c ---- linux-2.6.32.1/net/ipv6/ndisc.c 2009-12-03 20:03:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/net/ipv6/ndisc.c 2009-12-03 20:04:56.000000000 +0100 -@@ -589,7 +589,7 @@ static void ndisc_send_na(struct net_dev - } else { - if (ipv6_dev_get_saddr(dev_net(dev), dev, daddr, - inet6_sk(dev_net(dev)->ipv6.ndisc_sk)->srcprefs, -- &tmpaddr)) -+ &tmpaddr, NULL /* FIXME: ? */ )) - return; - src_addr = &tmpaddr; - } -diff -NurpP --minimal linux-2.6.32.1/net/ipv6/raw.c linux-2.6.32.1-vs2.3.0.36.27/net/ipv6/raw.c ---- linux-2.6.32.1/net/ipv6/raw.c 2009-12-03 20:03:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/net/ipv6/raw.c 2009-12-03 20:04:56.000000000 +0100 -@@ -29,6 +29,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -281,6 +282,13 @@ static int rawv6_bind(struct sock *sk, s - } - } - -+ if (!v6_addr_in_nx_info(sk->sk_nx_info, &addr->sin6_addr, -1)) { -+ err = -EADDRNOTAVAIL; -+ if (dev) -+ dev_put(dev); -+ goto out; -+ } -+ - /* ipv4 addr of the socket is invalid. Only the - * unspecified and mapped address have a v4 equivalent. - */ -diff -NurpP --minimal linux-2.6.32.1/net/ipv6/route.c linux-2.6.32.1-vs2.3.0.36.27/net/ipv6/route.c ---- linux-2.6.32.1/net/ipv6/route.c 2009-12-03 20:03:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/net/ipv6/route.c 2009-12-03 20:04:56.000000000 +0100 -@@ -2257,7 +2257,8 @@ static int rt6_fill_node(struct net *net - struct inet6_dev *idev = ip6_dst_idev(&rt->u.dst); - struct in6_addr saddr_buf; - if (ipv6_dev_get_saddr(net, idev ? idev->dev : NULL, -- dst, 0, &saddr_buf) == 0) -+ dst, 0, &saddr_buf, -+ (skb->sk ? skb->sk->sk_nx_info : NULL)) == 0) - NLA_PUT(skb, RTA_PREFSRC, 16, &saddr_buf); - } - -diff -NurpP --minimal linux-2.6.32.1/net/ipv6/tcp_ipv6.c linux-2.6.32.1-vs2.3.0.36.27/net/ipv6/tcp_ipv6.c ---- linux-2.6.32.1/net/ipv6/tcp_ipv6.c 2009-12-03 20:03:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/net/ipv6/tcp_ipv6.c 2009-12-03 20:04:56.000000000 +0100 -@@ -68,6 +68,7 @@ - - #include - #include -+#include - - static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb); - static void tcp_v6_reqsk_send_ack(struct sock *sk, struct sk_buff *skb, -@@ -156,8 +157,15 @@ static int tcp_v6_connect(struct sock *s - * connect() to INADDR_ANY means loopback (BSD'ism). - */ - -- if(ipv6_addr_any(&usin->sin6_addr)) -- usin->sin6_addr.s6_addr[15] = 0x1; -+ if(ipv6_addr_any(&usin->sin6_addr)) { -+ struct nx_info *nxi = sk->sk_nx_info; -+ -+ if (nxi && nx_info_has_v6(nxi)) -+ /* FIXME: remap lback? */ -+ usin->sin6_addr = nxi->v6.ip; -+ else -+ usin->sin6_addr.s6_addr[15] = 0x1; -+ } - - addr_type = ipv6_addr_type(&usin->sin6_addr); - -diff -NurpP --minimal linux-2.6.32.1/net/ipv6/udp.c linux-2.6.32.1-vs2.3.0.36.27/net/ipv6/udp.c ---- linux-2.6.32.1/net/ipv6/udp.c 2009-12-03 20:03:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/net/ipv6/udp.c 2009-12-03 20:04:56.000000000 +0100 -@@ -47,6 +47,7 @@ - - #include - #include -+#include - #include "udp_impl.h" - - int ipv6_rcv_saddr_equal(const struct sock *sk, const struct sock *sk2) -@@ -61,24 +62,49 @@ int ipv6_rcv_saddr_equal(const struct so - int addr_type2 = sk2_rcv_saddr6 ? ipv6_addr_type(sk2_rcv_saddr6) : IPV6_ADDR_MAPPED; - - /* if both are mapped, treat as IPv4 */ -- if (addr_type == IPV6_ADDR_MAPPED && addr_type2 == IPV6_ADDR_MAPPED) -- return (!sk2_ipv6only && -+ if (addr_type == IPV6_ADDR_MAPPED && addr_type2 == IPV6_ADDR_MAPPED) { -+ if (!sk2_ipv6only && - (!sk_rcv_saddr || !sk2_rcv_saddr || -- sk_rcv_saddr == sk2_rcv_saddr)); -+ sk_rcv_saddr == sk2_rcv_saddr)) -+ goto vs_v4; -+ else -+ return 0; -+ } - - if (addr_type2 == IPV6_ADDR_ANY && - !(sk2_ipv6only && addr_type == IPV6_ADDR_MAPPED)) -- return 1; -+ goto vs; - - if (addr_type == IPV6_ADDR_ANY && - !(sk_ipv6only && addr_type2 == IPV6_ADDR_MAPPED)) -- return 1; -+ goto vs; - - if (sk2_rcv_saddr6 && - ipv6_addr_equal(sk_rcv_saddr6, sk2_rcv_saddr6)) -- return 1; -+ goto vs; - - return 0; -+ -+vs_v4: -+ if (!sk_rcv_saddr && !sk2_rcv_saddr) -+ return nx_v4_addr_conflict(sk->sk_nx_info, sk2->sk_nx_info); -+ if (!sk2_rcv_saddr) -+ return v4_addr_in_nx_info(sk->sk_nx_info, sk2_rcv_saddr, -1); -+ if (!sk_rcv_saddr) -+ return v4_addr_in_nx_info(sk2->sk_nx_info, sk_rcv_saddr, -1); -+ return 1; -+vs: -+ if (addr_type2 == IPV6_ADDR_ANY && addr_type == IPV6_ADDR_ANY) -+ return nx_v6_addr_conflict(sk->sk_nx_info, sk2->sk_nx_info); -+ else if (addr_type2 == IPV6_ADDR_ANY) -+ return v6_addr_in_nx_info(sk2->sk_nx_info, sk_rcv_saddr6, -1); -+ else if (addr_type == IPV6_ADDR_ANY) { -+ if (addr_type2 == IPV6_ADDR_MAPPED) -+ return nx_v4_addr_conflict(sk->sk_nx_info, sk2->sk_nx_info); -+ else -+ return v6_addr_in_nx_info(sk->sk_nx_info, sk2_rcv_saddr6, -1); -+ } -+ return 1; - } - - int udp_v6_get_port(struct sock *sk, unsigned short snum) -@@ -109,6 +135,10 @@ static inline int compute_score(struct s - if (!ipv6_addr_equal(&np->rcv_saddr, daddr)) - return -1; - score++; -+ } else { -+ /* block non nx_info ips */ -+ if (!v6_addr_in_nx_info(sk->sk_nx_info, daddr, -1)) -+ return -1; - } - if (!ipv6_addr_any(&np->daddr)) { - if (!ipv6_addr_equal(&np->daddr, saddr)) -diff -NurpP --minimal linux-2.6.32.1/net/ipv6/xfrm6_policy.c linux-2.6.32.1-vs2.3.0.36.27/net/ipv6/xfrm6_policy.c ---- linux-2.6.32.1/net/ipv6/xfrm6_policy.c 2009-12-03 20:03:00.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/net/ipv6/xfrm6_policy.c 2009-12-03 20:04:56.000000000 +0100 -@@ -63,7 +63,7 @@ static int xfrm6_get_saddr(struct net *n - dev = ip6_dst_idev(dst)->dev; - ipv6_dev_get_saddr(dev_net(dev), dev, - (struct in6_addr *)&daddr->a6, 0, -- (struct in6_addr *)&saddr->a6); -+ (struct in6_addr *)&saddr->a6, NULL); - dst_release(dst); - return 0; - } -diff -NurpP --minimal linux-2.6.32.1/net/netlink/af_netlink.c linux-2.6.32.1-vs2.3.0.36.27/net/netlink/af_netlink.c ---- linux-2.6.32.1/net/netlink/af_netlink.c 2009-12-03 20:03:01.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/net/netlink/af_netlink.c 2009-12-03 20:04:56.000000000 +0100 -@@ -55,6 +55,9 @@ - #include - #include - #include -+#include -+#include -+#include - - #include - #include -@@ -1899,6 +1902,8 @@ static struct sock *netlink_seq_socket_i - sk_for_each(s, node, &hash->table[j]) { - if (sock_net(s) != seq_file_net(seq)) - continue; -+ if (!nx_check(s->sk_nid, VS_WATCH_P | VS_IDENT)) -+ continue; - if (off == pos) { - iter->link = i; - iter->hash_idx = j; -@@ -1933,7 +1938,8 @@ static void *netlink_seq_next(struct seq - s = v; - do { - s = sk_next(s); -- } while (s && sock_net(s) != seq_file_net(seq)); -+ } while (s && (sock_net(s) != seq_file_net(seq) || -+ !nx_check(s->sk_nid, VS_WATCH_P | VS_IDENT))); - if (s) - return s; - -@@ -1945,7 +1951,8 @@ static void *netlink_seq_next(struct seq - - for (; j <= hash->mask; j++) { - s = sk_head(&hash->table[j]); -- while (s && sock_net(s) != seq_file_net(seq)) -+ while (s && (sock_net(s) != seq_file_net(seq) || -+ !nx_check(s->sk_nid, VS_WATCH_P | VS_IDENT))) - s = sk_next(s); - if (s) { - iter->link = i; -diff -NurpP --minimal linux-2.6.32.1/net/sctp/ipv6.c linux-2.6.32.1-vs2.3.0.36.27/net/sctp/ipv6.c ---- linux-2.6.32.1/net/sctp/ipv6.c 2009-12-03 20:03:01.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/net/sctp/ipv6.c 2009-12-03 20:04:56.000000000 +0100 -@@ -316,7 +316,8 @@ static void sctp_v6_get_saddr(struct sct - dst ? ip6_dst_idev(dst)->dev : NULL, - &daddr->v6.sin6_addr, - inet6_sk(&sk->inet.sk)->srcprefs, -- &saddr->v6.sin6_addr); -+ &saddr->v6.sin6_addr, -+ asoc->base.sk->sk_nx_info); - SCTP_DEBUG_PRINTK("saddr from ipv6_get_saddr: %pI6\n", - &saddr->v6.sin6_addr); - return; -diff -NurpP --minimal linux-2.6.32.1/net/socket.c linux-2.6.32.1-vs2.3.0.36.27/net/socket.c ---- linux-2.6.32.1/net/socket.c 2009-12-03 20:03:01.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/net/socket.c 2009-12-03 20:04:56.000000000 +0100 -@@ -96,6 +96,10 @@ - - #include - #include -+#include -+#include -+#include -+#include - - static int sock_no_open(struct inode *irrelevant, struct file *dontcare); - static ssize_t sock_aio_read(struct kiocb *iocb, const struct iovec *iov, -@@ -559,7 +563,7 @@ static inline int __sock_sendmsg(struct - struct msghdr *msg, size_t size) - { - struct sock_iocb *si = kiocb_to_siocb(iocb); -- int err; -+ int err, len; - - si->sock = sock; - si->scm = NULL; -@@ -570,7 +574,22 @@ static inline int __sock_sendmsg(struct - if (err) - return err; - -- return sock->ops->sendmsg(iocb, sock, msg, size); -+ len = sock->ops->sendmsg(iocb, sock, msg, size); -+ if (sock->sk) { -+ if (len == size) -+ vx_sock_send(sock->sk, size); -+ else -+ vx_sock_fail(sock->sk, size); -+ } -+ vxdprintk(VXD_CBIT(net, 7), -+ "__sock_sendmsg: %p[%p,%p,%p;%d/%d]:%d/%d", -+ sock, sock->sk, -+ (sock->sk)?sock->sk->sk_nx_info:0, -+ (sock->sk)?sock->sk->sk_vx_info:0, -+ (sock->sk)?sock->sk->sk_xid:0, -+ (sock->sk)?sock->sk->sk_nid:0, -+ (unsigned int)size, len); -+ return len; - } - - int sock_sendmsg(struct socket *sock, struct msghdr *msg, size_t size) -@@ -671,7 +690,7 @@ EXPORT_SYMBOL_GPL(__sock_recv_timestamp) - static inline int __sock_recvmsg(struct kiocb *iocb, struct socket *sock, - struct msghdr *msg, size_t size, int flags) - { -- int err; -+ int err, len; - struct sock_iocb *si = kiocb_to_siocb(iocb); - - si->sock = sock; -@@ -684,7 +703,18 @@ static inline int __sock_recvmsg(struct - if (err) - return err; - -- return sock->ops->recvmsg(iocb, sock, msg, size, flags); -+ len = sock->ops->recvmsg(iocb, sock, msg, size, flags); -+ if ((len >= 0) && sock->sk) -+ vx_sock_recv(sock->sk, len); -+ vxdprintk(VXD_CBIT(net, 7), -+ "__sock_recvmsg: %p[%p,%p,%p;%d/%d]:%d/%d", -+ sock, sock->sk, -+ (sock->sk)?sock->sk->sk_nx_info:0, -+ (sock->sk)?sock->sk->sk_vx_info:0, -+ (sock->sk)?sock->sk->sk_xid:0, -+ (sock->sk)?sock->sk->sk_nid:0, -+ (unsigned int)size, len); -+ return len; - } - - int sock_recvmsg(struct socket *sock, struct msghdr *msg, -@@ -1155,6 +1185,13 @@ static int __sock_create(struct net *net - if (type < 0 || type >= SOCK_MAX) - return -EINVAL; - -+ if (!nx_check(0, VS_ADMIN)) { -+ if (family == PF_INET && !current_nx_info_has_v4()) -+ return -EAFNOSUPPORT; -+ if (family == PF_INET6 && !current_nx_info_has_v6()) -+ return -EAFNOSUPPORT; -+ } -+ - /* Compatibility. - - This uglymoron is moved from INET layer to here to avoid -@@ -1287,6 +1324,7 @@ SYSCALL_DEFINE3(socket, int, family, int - if (retval < 0) - goto out; - -+ set_bit(SOCK_USER_SOCKET, &sock->flags); - retval = sock_map_fd(sock, flags & (O_CLOEXEC | O_NONBLOCK)); - if (retval < 0) - goto out_release; -@@ -1328,10 +1366,12 @@ SYSCALL_DEFINE4(socketpair, int, family, - err = sock_create(family, type, protocol, &sock1); - if (err < 0) - goto out; -+ set_bit(SOCK_USER_SOCKET, &sock1->flags); - - err = sock_create(family, type, protocol, &sock2); - if (err < 0) - goto out_release_1; -+ set_bit(SOCK_USER_SOCKET, &sock2->flags); - - err = sock1->ops->socketpair(sock1, sock2); - if (err < 0) -diff -NurpP --minimal linux-2.6.32.1/net/sunrpc/auth.c linux-2.6.32.1-vs2.3.0.36.27/net/sunrpc/auth.c ---- linux-2.6.32.1/net/sunrpc/auth.c 2009-12-03 20:03:01.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/net/sunrpc/auth.c 2009-12-03 20:04:56.000000000 +0100 -@@ -14,6 +14,7 @@ - #include - #include - #include -+#include - - #ifdef RPC_DEBUG - # define RPCDBG_FACILITY RPCDBG_AUTH -@@ -360,6 +361,7 @@ rpcauth_lookupcred(struct rpc_auth *auth - memset(&acred, 0, sizeof(acred)); - acred.uid = cred->fsuid; - acred.gid = cred->fsgid; -+ acred.tag = dx_current_tag(); - acred.group_info = get_group_info(((struct cred *)cred)->group_info); - - ret = auth->au_ops->lookup_cred(auth, &acred, flags); -@@ -400,6 +402,7 @@ rpcauth_bind_root_cred(struct rpc_task * - struct auth_cred acred = { - .uid = 0, - .gid = 0, -+ .tag = dx_current_tag(), - }; - struct rpc_cred *ret; - -diff -NurpP --minimal linux-2.6.32.1/net/sunrpc/auth_unix.c linux-2.6.32.1-vs2.3.0.36.27/net/sunrpc/auth_unix.c ---- linux-2.6.32.1/net/sunrpc/auth_unix.c 2008-12-25 00:26:37.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/net/sunrpc/auth_unix.c 2009-12-03 20:04:56.000000000 +0100 -@@ -11,12 +11,14 @@ - #include - #include - #include -+#include - - #define NFS_NGROUPS 16 - - struct unx_cred { - struct rpc_cred uc_base; - gid_t uc_gid; -+ tag_t uc_tag; - gid_t uc_gids[NFS_NGROUPS]; - }; - #define uc_uid uc_base.cr_uid -@@ -78,6 +80,7 @@ unx_create_cred(struct rpc_auth *auth, s - groups = NFS_NGROUPS; - - cred->uc_gid = acred->gid; -+ cred->uc_tag = acred->tag; - for (i = 0; i < groups; i++) - cred->uc_gids[i] = GROUP_AT(acred->group_info, i); - if (i < NFS_NGROUPS) -@@ -119,7 +122,9 @@ unx_match(struct auth_cred *acred, struc - unsigned int i; - - -- if (cred->uc_uid != acred->uid || cred->uc_gid != acred->gid) -+ if (cred->uc_uid != acred->uid || -+ cred->uc_gid != acred->gid || -+ cred->uc_tag != acred->tag) - return 0; - - if (acred->group_info != NULL) -@@ -142,7 +147,7 @@ unx_marshal(struct rpc_task *task, __be3 - struct rpc_clnt *clnt = task->tk_client; - struct unx_cred *cred = container_of(task->tk_msg.rpc_cred, struct unx_cred, uc_base); - __be32 *base, *hold; -- int i; -+ int i, tag; - - *p++ = htonl(RPC_AUTH_UNIX); - base = p++; -@@ -152,9 +157,12 @@ unx_marshal(struct rpc_task *task, __be3 - * Copy the UTS nodename captured when the client was created. - */ - p = xdr_encode_array(p, clnt->cl_nodename, clnt->cl_nodelen); -+ tag = task->tk_client->cl_tag; - -- *p++ = htonl((u32) cred->uc_uid); -- *p++ = htonl((u32) cred->uc_gid); -+ *p++ = htonl((u32) TAGINO_UID(tag, -+ cred->uc_uid, cred->uc_tag)); -+ *p++ = htonl((u32) TAGINO_GID(tag, -+ cred->uc_gid, cred->uc_tag)); - hold = p++; - for (i = 0; i < 16 && cred->uc_gids[i] != (gid_t) NOGROUP; i++) - *p++ = htonl((u32) cred->uc_gids[i]); -diff -NurpP --minimal linux-2.6.32.1/net/sunrpc/clnt.c linux-2.6.32.1-vs2.3.0.36.27/net/sunrpc/clnt.c ---- linux-2.6.32.1/net/sunrpc/clnt.c 2009-12-03 20:03:01.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/net/sunrpc/clnt.c 2009-12-03 20:04:56.000000000 +0100 -@@ -33,6 +33,7 @@ - #include - #include - #include -+#include - - #include - #include -@@ -358,6 +359,9 @@ struct rpc_clnt *rpc_create(struct rpc_c - if (!(args->flags & RPC_CLNT_CREATE_QUIET)) - clnt->cl_chatty = 1; - -+ /* TODO: handle RPC_CLNT_CREATE_TAGGED -+ if (args->flags & RPC_CLNT_CREATE_TAGGED) -+ clnt->cl_tag = 1; */ - return clnt; - } - EXPORT_SYMBOL_GPL(rpc_create); -diff -NurpP --minimal linux-2.6.32.1/net/unix/af_unix.c linux-2.6.32.1-vs2.3.0.36.27/net/unix/af_unix.c ---- linux-2.6.32.1/net/unix/af_unix.c 2009-12-03 20:03:01.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/net/unix/af_unix.c 2009-12-03 20:04:56.000000000 +0100 -@@ -114,6 +114,8 @@ - #include - #include - #include -+#include -+#include - - static struct hlist_head unix_socket_table[UNIX_HASH_SIZE + 1]; - static DEFINE_SPINLOCK(unix_table_lock); -@@ -258,6 +260,8 @@ static struct sock *__unix_find_socket_b - if (!net_eq(sock_net(s), net)) - continue; - -+ if (!nx_check(s->sk_nid, VS_WATCH_P | VS_IDENT)) -+ continue; - if (u->addr->len == len && - !memcmp(u->addr->name, sunname, len)) - goto found; -@@ -2114,6 +2118,8 @@ static struct sock *unix_seq_idx(struct - for (s = first_unix_socket(&iter->i); s; s = next_unix_socket(&iter->i, s)) { - if (sock_net(s) != seq_file_net(seq)) - continue; -+ if (!nx_check(s->sk_nid, VS_WATCH_P | VS_IDENT)) -+ continue; - if (off == pos) - return s; - ++off; -@@ -2138,7 +2144,8 @@ static void *unix_seq_next(struct seq_fi - sk = first_unix_socket(&iter->i); - else - sk = next_unix_socket(&iter->i, sk); -- while (sk && (sock_net(sk) != seq_file_net(seq))) -+ while (sk && (sock_net(sk) != seq_file_net(seq) || -+ !nx_check(sk->sk_nid, VS_WATCH_P | VS_IDENT))) - sk = next_unix_socket(&iter->i, sk); - return sk; - } -diff -NurpP --minimal linux-2.6.32.1/net/x25/af_x25.c linux-2.6.32.1-vs2.3.0.36.27/net/x25/af_x25.c ---- linux-2.6.32.1/net/x25/af_x25.c 2009-12-03 20:03:01.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/net/x25/af_x25.c 2009-12-03 20:04:56.000000000 +0100 -@@ -519,7 +519,10 @@ static int x25_create(struct net *net, s - - x25 = x25_sk(sk); - -- sock_init_data(sock, sk); -+ sk->sk_socket = sock; -+ sk->sk_type = sock->type; -+ sk->sk_sleep = &sock->wait; -+ sock->sk = sk; - - x25_init_timers(sk); - -diff -NurpP --minimal linux-2.6.32.1/scripts/checksyscalls.sh linux-2.6.32.1-vs2.3.0.36.27/scripts/checksyscalls.sh ---- linux-2.6.32.1/scripts/checksyscalls.sh 2009-09-10 15:26:31.000000000 +0200 -+++ linux-2.6.32.1-vs2.3.0.36.27/scripts/checksyscalls.sh 2009-12-03 20:04:56.000000000 +0100 -@@ -194,7 +194,6 @@ cat << EOF - #define __IGNORE_afs_syscall - #define __IGNORE_getpmsg - #define __IGNORE_putpmsg --#define __IGNORE_vserver - EOF - } - -diff -NurpP --minimal linux-2.6.32.1/security/commoncap.c linux-2.6.32.1-vs2.3.0.36.27/security/commoncap.c ---- linux-2.6.32.1/security/commoncap.c 2009-12-03 20:03:02.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/security/commoncap.c 2009-12-03 20:04:56.000000000 +0100 -@@ -27,6 +27,7 @@ - #include - #include - #include -+#include - - /* - * If a non-root user executes a setuid-root binary in -@@ -52,7 +53,7 @@ static void warn_setuid_and_fcaps_mixed( - - int cap_netlink_send(struct sock *sk, struct sk_buff *skb) - { -- NETLINK_CB(skb).eff_cap = current_cap(); -+ NETLINK_CB(skb).eff_cap = vx_mbcaps(current_cap()); - return 0; - } - -@@ -62,6 +63,7 @@ int cap_netlink_recv(struct sk_buff *skb - return -EPERM; - return 0; - } -+ - EXPORT_SYMBOL(cap_netlink_recv); - - /** -@@ -82,7 +84,22 @@ EXPORT_SYMBOL(cap_netlink_recv); - int cap_capable(struct task_struct *tsk, const struct cred *cred, int cap, - int audit) - { -- return cap_raised(cred->cap_effective, cap) ? 0 : -EPERM; -+ struct vx_info *vxi = tsk->vx_info; -+ -+#if 0 -+ printk("cap_capable() VXF_STATE_SETUP = %llx, raised = %x, eff = %08x:%08x\n", -+ vx_info_flags(vxi, VXF_STATE_SETUP, 0), -+ cap_raised(tsk->cap_effective, cap), -+ tsk->cap_effective.cap[1], tsk->cap_effective.cap[0]); -+#endif -+ -+ /* special case SETUP */ -+ if (vx_info_flags(vxi, VXF_STATE_SETUP, 0) && -+ /* FIXME: maybe use cred instead? */ -+ cap_raised(tsk->cred->cap_effective, cap)) -+ return 0; -+ -+ return vx_cap_raised(vxi, cred->cap_effective, cap) ? 0 : -EPERM; - } - - /** -@@ -618,7 +635,7 @@ int cap_inode_setxattr(struct dentry *de - - if (!strncmp(name, XATTR_SECURITY_PREFIX, - sizeof(XATTR_SECURITY_PREFIX) - 1) && -- !capable(CAP_SYS_ADMIN)) -+ !vx_capable(CAP_SYS_ADMIN, VXC_FS_SECURITY)) - return -EPERM; - return 0; - } -@@ -962,7 +979,8 @@ error: - */ - int cap_syslog(int type) - { -- if ((type != 3 && type != 10) && !capable(CAP_SYS_ADMIN)) -+ if ((type != 3 && type != 10) && -+ !vx_capable(CAP_SYS_ADMIN, VXC_SYSLOG)) - return -EPERM; - return 0; - } -diff -NurpP --minimal linux-2.6.32.1/security/selinux/hooks.c linux-2.6.32.1-vs2.3.0.36.27/security/selinux/hooks.c ---- linux-2.6.32.1/security/selinux/hooks.c 2009-12-03 20:03:02.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/security/selinux/hooks.c 2009-12-03 20:04:56.000000000 +0100 -@@ -64,7 +64,6 @@ - #include - #include - #include /* for Unix socket types */ --#include /* for Unix socket types */ - #include - #include - #include -diff -NurpP --minimal linux-2.6.32.1/security/selinux/include/av_permissions.h linux-2.6.32.1-vs2.3.0.36.27/security/selinux/include/av_permissions.h ---- linux-2.6.32.1/security/selinux/include/av_permissions.h 2009-12-03 20:03:02.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/security/selinux/include/av_permissions.h 2009-12-03 20:04:56.000000000 +0100 -@@ -565,6 +565,7 @@ - #define CAPABILITY__SETFCAP 0x80000000UL - #define CAPABILITY2__MAC_OVERRIDE 0x00000001UL - #define CAPABILITY2__MAC_ADMIN 0x00000002UL -+#define CAPABILITY2__CONTEXT 0x00000004UL - #define NETLINK_ROUTE_SOCKET__IOCTL 0x00000001UL - #define NETLINK_ROUTE_SOCKET__READ 0x00000002UL - #define NETLINK_ROUTE_SOCKET__WRITE 0x00000004UL -diff -NurpP --minimal linux-2.6.32.1/security/selinux/include/av_perm_to_string.h linux-2.6.32.1-vs2.3.0.36.27/security/selinux/include/av_perm_to_string.h ---- linux-2.6.32.1/security/selinux/include/av_perm_to_string.h 2009-12-03 20:03:02.000000000 +0100 -+++ linux-2.6.32.1-vs2.3.0.36.27/security/selinux/include/av_perm_to_string.h 2009-12-03 20:04:56.000000000 +0100 -@@ -142,6 +142,7 @@ - S_(SECCLASS_CAPABILITY, CAPABILITY__SETFCAP, "setfcap") - S_(SECCLASS_CAPABILITY2, CAPABILITY2__MAC_OVERRIDE, "mac_override") - S_(SECCLASS_CAPABILITY2, CAPABILITY2__MAC_ADMIN, "mac_admin") -+ S_(SECCLASS_CAPABILITY2, CAPABILITY2__CONTEXT, "context") - S_(SECCLASS_NETLINK_ROUTE_SOCKET, NETLINK_ROUTE_SOCKET__NLMSG_READ, "nlmsg_read") - S_(SECCLASS_NETLINK_ROUTE_SOCKET, NETLINK_ROUTE_SOCKET__NLMSG_WRITE, "nlmsg_write") - S_(SECCLASS_NETLINK_FIREWALL_SOCKET, NETLINK_FIREWALL_SOCKET__NLMSG_READ, "nlmsg_read") diff --git a/debian/patches/features/all/wireless-report-reasonable-bitrate-for-MCS-rates-th.patch b/debian/patches/features/all/wireless-report-reasonable-bitrate-for-MCS-rates-th.patch deleted file mode 100644 index 918386703..000000000 --- a/debian/patches/features/all/wireless-report-reasonable-bitrate-for-MCS-rates-th.patch +++ /dev/null @@ -1,147 +0,0 @@ -From 254416aae70ab2e6b57fd79782c8a67196234d02 Mon Sep 17 00:00:00 2001 -From: John W. Linville -Date: Wed, 9 Dec 2009 16:43:52 -0500 -Subject: [PATCH] wireless: report reasonable bitrate for MCS rates through wext - -Previously, cfg80211 had reported "0" for MCS (i.e. 802.11n) bitrates -through the wireless extensions interface. However, nl80211 was -converting MCS rates into a reasonable bitrate number. This patch moves -the nl80211 code to cfg80211 where it is now shared between both the -nl80211 interface and the wireless extensions interface. - -Signed-off-by: John W. Linville ---- - net/wireless/core.h | 2 ++ - net/wireless/nl80211.c | 37 ++----------------------------------- - net/wireless/util.c | 33 +++++++++++++++++++++++++++++++++ - net/wireless/wext-compat.c | 5 +---- - 4 files changed, 38 insertions(+), 39 deletions(-) - -diff --git a/net/wireless/core.h b/net/wireless/core.h -index 4ef3efc..35b7121 100644 ---- a/net/wireless/core.h -+++ b/net/wireless/core.h -@@ -378,6 +378,8 @@ int rdev_set_freq(struct cfg80211_registered_device *rdev, - struct wireless_dev *for_wdev, - int freq, enum nl80211_channel_type channel_type); - -+u16 cfg80211_calculate_bitrate(struct rate_info *rate); -+ - #ifdef CONFIG_CFG80211_DEVELOPER_WARNINGS - #define CFG80211_DEV_WARN_ON(cond) WARN_ON(cond) - #else -diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c -index a602843..7cb0d64 100644 ---- a/net/wireless/nl80211.c -+++ b/net/wireless/nl80211.c -@@ -1637,39 +1637,6 @@ static int parse_station_flags(struct genl_info *info, - return 0; - } - --static u16 nl80211_calculate_bitrate(struct rate_info *rate) --{ -- int modulation, streams, bitrate; -- -- if (!(rate->flags & RATE_INFO_FLAGS_MCS)) -- return rate->legacy; -- -- /* the formula below does only work for MCS values smaller than 32 */ -- if (rate->mcs >= 32) -- return 0; -- -- modulation = rate->mcs & 7; -- streams = (rate->mcs >> 3) + 1; -- -- bitrate = (rate->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH) ? -- 13500000 : 6500000; -- -- if (modulation < 4) -- bitrate *= (modulation + 1); -- else if (modulation == 4) -- bitrate *= (modulation + 2); -- else -- bitrate *= (modulation + 3); -- -- bitrate *= streams; -- -- if (rate->flags & RATE_INFO_FLAGS_SHORT_GI) -- bitrate = (bitrate / 9) * 10; -- -- /* do NOT round down here */ -- return (bitrate + 50000) / 100000; --} -- - static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq, - int flags, struct net_device *dev, - u8 *mac_addr, struct station_info *sinfo) -@@ -1716,8 +1683,8 @@ static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq, - if (!txrate) - goto nla_put_failure; - -- /* nl80211_calculate_bitrate will return 0 for mcs >= 32 */ -- bitrate = nl80211_calculate_bitrate(&sinfo->txrate); -+ /* cfg80211_calculate_bitrate will return 0 for mcs >= 32 */ -+ bitrate = cfg80211_calculate_bitrate(&sinfo->txrate); - if (bitrate > 0) - NLA_PUT_U16(msg, NL80211_RATE_INFO_BITRATE, bitrate); - -diff --git a/net/wireless/util.c b/net/wireless/util.c -index 59361fd..a3c841a 100644 ---- a/net/wireless/util.c -+++ b/net/wireless/util.c -@@ -720,3 +720,36 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev, - - return err; - } -+ -+u16 cfg80211_calculate_bitrate(struct rate_info *rate) -+{ -+ int modulation, streams, bitrate; -+ -+ if (!(rate->flags & RATE_INFO_FLAGS_MCS)) -+ return rate->legacy; -+ -+ /* the formula below does only work for MCS values smaller than 32 */ -+ if (rate->mcs >= 32) -+ return 0; -+ -+ modulation = rate->mcs & 7; -+ streams = (rate->mcs >> 3) + 1; -+ -+ bitrate = (rate->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH) ? -+ 13500000 : 6500000; -+ -+ if (modulation < 4) -+ bitrate *= (modulation + 1); -+ else if (modulation == 4) -+ bitrate *= (modulation + 2); -+ else -+ bitrate *= (modulation + 3); -+ -+ bitrate *= streams; -+ -+ if (rate->flags & RATE_INFO_FLAGS_SHORT_GI) -+ bitrate = (bitrate / 9) * 10; -+ -+ /* do NOT round down here */ -+ return (bitrate + 50000) / 100000; -+} -diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c -index 584eb48..2fa8de1 100644 ---- a/net/wireless/wext-compat.c -+++ b/net/wireless/wext-compat.c -@@ -1256,10 +1256,7 @@ int cfg80211_wext_giwrate(struct net_device *dev, - if (!(sinfo.filled & STATION_INFO_TX_BITRATE)) - return -EOPNOTSUPP; - -- rate->value = 0; -- -- if (!(sinfo.txrate.flags & RATE_INFO_FLAGS_MCS)) -- rate->value = 100000 * sinfo.txrate.legacy; -+ rate->value = 100000 * cfg80211_calculate_bitrate(&sinfo.txrate); - - return 0; - } --- -1.5.6.5 - diff --git a/debian/patches/features/arm/dns323-rev-b1-poweroff.patch b/debian/patches/features/arm/dns323-rev-b1-poweroff.patch deleted file mode 100644 index 1f6804594..000000000 --- a/debian/patches/features/arm/dns323-rev-b1-poweroff.patch +++ /dev/null @@ -1,106 +0,0 @@ -From: Erik Benada -Date: Sun, 24 Jan 2010 21:43:04 +0000 (-0800) -Subject: [ARM] orion5x: D-link DNS-323 rev. B1 power-off -X-Git-Tag: v2.6.33-rc6~10^2~2^2 -X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=cf11052a95275c942c1f45ea5fde43ce45bbba6d;hp=e9cfa167b6b598a364c53459bee93b508f073c65 - -[ARM] orion5x: D-link DNS-323 rev. B1 power-off - -This patch fixes power LED blinking and power-off on DNS-323 rev. B1. - -GPIO pin 3 has to be set to 1 to stop power LED blinking and to allow the LED to be controlled via leds-gpio. This pin has to be also set to 1 for power-off to work. -To power-off the rev. B1 machine, pin 8 has to be set to 1 and then set to 0 to do actual power-off. - -Tested on my DNS-323 rev. B1 - -Signed-off-by: Erik Benada -Signed-off-by: Nicolas Pitre ---- - -diff --git a/arch/arm/mach-orion5x/dns323-setup.c b/arch/arm/mach-orion5x/dns323-setup.c -index b31ca4c..8f159db 100644 ---- a/arch/arm/mach-orion5x/dns323-setup.c -+++ b/arch/arm/mach-orion5x/dns323-setup.c -@@ -12,6 +12,7 @@ - - #include - #include -+#include - #include - #include - #include -@@ -32,6 +33,7 @@ - - #define DNS323_GPIO_LED_RIGHT_AMBER 1 - #define DNS323_GPIO_LED_LEFT_AMBER 2 -+#define DNS323_GPIO_SYSTEM_UP 3 - #define DNS323_GPIO_LED_POWER 5 - #define DNS323_GPIO_OVERTEMP 6 - #define DNS323_GPIO_RTC 7 -@@ -239,7 +241,7 @@ static struct gpio_led dns323_leds[] = { - { - .name = "power:blue", - .gpio = DNS323_GPIO_LED_POWER, -- .active_low = 1, -+ .default_state = LEDS_GPIO_DEFSTATE_ON, - }, { - .name = "right:amber", - .gpio = DNS323_GPIO_LED_RIGHT_AMBER, -@@ -334,7 +336,7 @@ static struct orion5x_mpp_mode dns323_mv88f5182_mpp_modes[] __initdata = { - { 0, MPP_UNUSED }, - { 1, MPP_GPIO }, /* right amber LED (sata ch0) */ - { 2, MPP_GPIO }, /* left amber LED (sata ch1) */ -- { 3, MPP_UNUSED }, -+ { 3, MPP_GPIO }, /* system up flag */ - { 4, MPP_GPIO }, /* power button LED */ - { 5, MPP_GPIO }, /* power button LED */ - { 6, MPP_GPIO }, /* GMT G751-2f overtemp */ -@@ -372,13 +374,23 @@ static struct i2c_board_info __initdata dns323_i2c_devices[] = { - }, - }; - --/* DNS-323 specific power off method */ --static void dns323_power_off(void) -+/* DNS-323 rev. A specific power off method */ -+static void dns323a_power_off(void) - { - pr_info("%s: triggering power-off...\n", __func__); - gpio_set_value(DNS323_GPIO_POWER_OFF, 1); - } - -+/* DNS-323 rev B specific power off method */ -+static void dns323b_power_off(void) -+{ -+ pr_info("%s: triggering power-off...\n", __func__); -+ /* Pin has to be changed to 1 and back to 0 to do actual power off. */ -+ gpio_set_value(DNS323_GPIO_POWER_OFF, 1); -+ mdelay(100); -+ gpio_set_value(DNS323_GPIO_POWER_OFF, 0); -+} -+ - static void __init dns323_init(void) - { - /* Setup basic Orion functions. Need to be called early. */ -@@ -424,11 +436,20 @@ static void __init dns323_init(void) - if (dns323_dev_id() == MV88F5182_DEV_ID) - orion5x_sata_init(&dns323_sata_data); - -- /* register dns323 specific power-off method */ -+ /* The 5182 has flag to indicate the system is up. Without this flag -+ * set, power LED will flash and cannot be controlled via leds-gpio. -+ */ -+ if (dns323_dev_id() == MV88F5182_DEV_ID) -+ gpio_set_value(DNS323_GPIO_SYSTEM_UP, 1); -+ -+ /* Register dns323 specific power-off method */ - if (gpio_request(DNS323_GPIO_POWER_OFF, "POWEROFF") != 0 || - gpio_direction_output(DNS323_GPIO_POWER_OFF, 0) != 0) - pr_err("DNS323: failed to setup power-off GPIO\n"); -- pm_power_off = dns323_power_off; -+ if (dns323_dev_id() == MV88F5182_DEV_ID) -+ pm_power_off = dns323b_power_off; -+ else -+ pm_power_off = dns323a_power_off; - } - - /* Warning: D-Link uses a wrong mach-type (=526) in their bootloader */ diff --git a/debian/patches/features/arm/early-printk.patch b/debian/patches/features/arm/early-printk.patch deleted file mode 100644 index 8ff8ef2e8..000000000 --- a/debian/patches/features/arm/early-printk.patch +++ /dev/null @@ -1,112 +0,0 @@ -From: Catalin Marinas -Date: Wed, 9 Dec 2009 10:02:18 +0000 (+0000) -Subject: ARM: Add an earlyprintk debug console -X-Git-Tag: v2.6.33-rc1~286^2~4 -X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=93fd03a8c6728b58879f8af20ffd55d9c32a778b - -ARM: Add an earlyprintk debug console - -This patch allows an earlyprintk console if CONFIG_DEBUG_LL is enabled, -using the printch asm function. - -The patch is based on the original work by Sascha Hauer. - -Signed-off-by: Catalin Marinas -Cc: Sascha Hauer -Acked-by: Uwe Kleine-König -Acked-by: Pavel Machek ---- - -diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug -index 1a6f70e..feb7b11 100644 ---- a/arch/arm/Kconfig.debug -+++ b/arch/arm/Kconfig.debug -@@ -71,6 +71,14 @@ config DEBUG_LL - in the kernel. This is helpful if you are debugging code that - executes before the console is initialized. - -+config EARLY_PRINTK -+ bool "Early printk" -+ depends on DEBUG_LL -+ help -+ Say Y here if you want to have an early console using the -+ kernel low-level debugging functions. Add earlyprintk to your -+ kernel parameters to enable this console. -+ - config DEBUG_ICEDCC - bool "Kernel low-level debugging via EmbeddedICE DCC channel" - depends on DEBUG_LL -diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile -index 79087dd..d0e40b7 100644 ---- a/arch/arm/kernel/Makefile -+++ b/arch/arm/kernel/Makefile -@@ -52,5 +52,6 @@ endif - - head-y := head$(MMUEXT).o - obj-$(CONFIG_DEBUG_LL) += debug.o -+obj-$(CONFIG_EARLY_PRINTK) += early_printk.o - - extra-y := $(head-y) init_task.o vmlinux.lds -diff --git a/arch/arm/kernel/early_printk.c b/arch/arm/kernel/early_printk.c -new file mode 100644 -index 0000000..85aa2b2 ---- /dev/null -+++ b/arch/arm/kernel/early_printk.c -@@ -0,0 +1,57 @@ -+/* -+ * linux/arch/arm/kernel/early_printk.c -+ * -+ * Copyright (C) 2009 Sascha Hauer -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#include -+#include -+#include -+ -+extern void printch(int); -+ -+static void early_write(const char *s, unsigned n) -+{ -+ while (n-- > 0) { -+ if (*s == '\n') -+ printch('\r'); -+ printch(*s); -+ s++; -+ } -+} -+ -+static void early_console_write(struct console *con, const char *s, unsigned n) -+{ -+ early_write(s, n); -+} -+ -+static struct console early_console = { -+ .name = "earlycon", -+ .write = early_console_write, -+ .flags = CON_PRINTBUFFER | CON_BOOT, -+ .index = -1, -+}; -+ -+asmlinkage void early_printk(const char *fmt, ...) -+{ -+ char buf[512]; -+ int n; -+ va_list ap; -+ -+ va_start(ap, fmt); -+ n = vscnprintf(buf, sizeof(buf), fmt, ap); -+ early_write(buf, n); -+ va_end(ap); -+} -+ -+static int __init setup_early_printk(char *buf) -+{ -+ register_console(&early_console); -+ return 0; -+} -+ -+early_param("earlyprintk", setup_early_printk); diff --git a/debian/patches/series/2 b/debian/patches/series/2 deleted file mode 100644 index 258d18e6e..000000000 --- a/debian/patches/series/2 +++ /dev/null @@ -1,5 +0,0 @@ -+ features/all/aufs2/aufs2-20091205.patch -+ bugfix/all/atl1c-use-common_task-instead-of-reset_task-and-link.patch -+ bugfix/all/netfilter-xtables-fix-conntrack-match-v1-ipt-save-output.patch -- bugfix/arm/scsi-osd-build-fix.patch -+ bugfix/all/stable/2.6.32.1.patch diff --git a/debian/patches/series/3 b/debian/patches/series/3 deleted file mode 100644 index 38b73bc55..000000000 --- a/debian/patches/series/3 +++ /dev/null @@ -1,13 +0,0 @@ -+ features/all/input-alps-add-support-for-touchpads-with-4-directional-button.patch -+ features/all/input-alps-add-interleaved-protocol-support.patch -+ features/all/gro-Name-the-GRO-result-enumeration-type.patch -+ features/all/gro-Change-all-receive-functions-to-return-GRO-result.patch -+ features/all/ethtool-Add-reset-operation.patch -+ features/all/sfc-2.6.33-rc1.patch -- bugfix/mips/drm-ttm-build-fix.patch -+ bugfix/all/stable/2.6.32.2.patch -+ bugfix/ia64/ia64-Include-linux-personality.h-header-in-asm-fcntl.patch -- features/all/r8169-rtl8168d-1-2-request_firmware.patch -- features/all/r8169-init-phy-return-error.patch -+ features/all/r8169-rtl8168d-1-2-request_firmware-2.patch -+ bugfix/all/radeon-fix-crtc-vblank-update-for-r600.patch diff --git a/debian/patches/series/3-extra b/debian/patches/series/3-extra deleted file mode 100644 index 4808cc967..000000000 --- a/debian/patches/series/3-extra +++ /dev/null @@ -1 +0,0 @@ -+ features/all/vserver/vs2.3.0.36.27.patch featureset=vserver diff --git a/debian/patches/series/4 b/debian/patches/series/4 deleted file mode 100644 index 1322cbd11..000000000 --- a/debian/patches/series/4 +++ /dev/null @@ -1,6 +0,0 @@ -+ bugfix/all/modules-Skip-empty-section-notes.patch -+ features/arm/early-printk.patch -+ bugfix/all/via-velocity-give-rx-descriptors-later.patch -+ bugfix/all/dmfe-tulip-Let-dmfe-handle-DM910x-except-SPARC-onboard.patch -- bugfix/all/radeon-fix-crtc-vblank-update-for-r600.patch -+ bugfix/all/stable/2.6.32.3.patch diff --git a/debian/patches/series/4-extra b/debian/patches/series/4-extra deleted file mode 100644 index 0101618ea..000000000 --- a/debian/patches/series/4-extra +++ /dev/null @@ -1,2 +0,0 @@ -+ features/all/vserver/s390-buildfix.patch featureset=vserver -+ features/all/vserver/ia64-buildfix.patch featureset=vserver diff --git a/debian/patches/series/5 b/debian/patches/series/5 deleted file mode 100644 index f3637f88d..000000000 --- a/debian/patches/series/5 +++ /dev/null @@ -1,9 +0,0 @@ -+ bugfix/all/sfc-Move-PHY-software-state-initialisation.patch -+ bugfix/all/sfc-Include-XGXS-in-XMAC-link-status-check.patch -+ bugfix/all/sfc-Fix-DMA-mapping-cleanup-on-error-in-TSO.patch -+ bugfix/all/sfc-QT2025C-Work-around-PHY-bug.patch -+ bugfix/all/sfc-QT2025C-Switch-into-self-configure-mode.patch -+ bugfix/all/sfc-QT2025C-Work-around-PHY-firmware-initialisation.patch -+ bugfix/all/sfc-QT2025C-Add-error-message-for-suspected-bad-SFP-cable.patch -+ bugfix/all/sfc-Disable-TX-descriptor-prefetch-watchdog.patch -+ bugfix/all/ath5k-Fix-eeprom-checksum-check-for-custom-sized-eeproms.patch diff --git a/debian/patches/series/6 b/debian/patches/series/6 deleted file mode 100644 index a601a17f2..000000000 --- a/debian/patches/series/6 +++ /dev/null @@ -1,39 +0,0 @@ -+ bugfix/all/Documentation-3c509-document-ethtool-support.patch -+ bugfix/all/drm-i915-disable-powersave.patch -+ features/all/module-firmware/0025-tty-declare-MODULE_FIRMWARE-in-various-drivers.patch -+ features/all/module-firmware/0026-staging-declare-MODULE_FIRMWARE-in-various-drivers.patch -+ features/all/module-firmware/0027-sep-include-driver-name-in-firmware-filenames.patch -+ features/all/module-firmware/0028-sep-declare-MODULE_FIRMWARE.patch -+ features/all/module-firmware/0029-isight-firmware-declare-MODULE_FIRMWARE.patch -+ features/all/module-firmware/0030-btmrvl-sdio-declare-MODULE_FIRMWARE.patch -- features/all/drivers-staging-rt28x0sta-request_firmware.patch -+ features/all/rt28x0sta-constify-RTUSBMultiWrite-RTUSBFirmwareWrite.patch -+ features/all/rt28x0sta-use-request_firmware.patch -+ features/all/rt3090sta-use-request_firmware.patch -- bugfix/all/modules-Skip-empty-section-notes.patch -- bugfix/all/ath5k-Fix-eeprom-checksum-check-for-custom-sized-eeproms.patch -+ bugfix/all/stable/2.6.32.4.patch -+ debian/mremap-fix-conflict-between-2.6.32.4-and-vserver.patch -+ bugfix/all/e1000-enhance-fragment-detection.patch -+ bugfix/all/e1000e-enhance-fragment-detection.patch -+ bugfix/all/stable/2.6.32.5.patch -+ bugfix/all/stable/2.6.32.6.patch -+ features/all/SCSI-3w-sas-Add-new-driver-for-LSI-3ware-9750.patch -+ features/all/aufs2/aufs2-20100125.patch -+ bugfix/all/cdc_ether-Partially-revert-usbnet-Set-link-down-init.patch -- bugfix/all/DocBook-media-create-links-for-included-sources.patch -- bugfix/all/DocBook-media-copy-images-after-building-HTML.patch -- bugfix/all/atl1c-use-common_task-instead-of-reset_task-and-link.patch -- bugfix/all/atl1e-remove-broken-tsov6.patch -- bugfix/all/netfilter-xtables-fix-conntrack-match-v1-ipt-save-output.patch -- features/all/input-alps-add-interleaved-protocol-support.patch -- bugfix/all/sfc-Fix-DMA-mapping-cleanup-on-error-in-TSO.patch -- features/all/input-alps-add-support-for-touchpads-with-4-directional-button.patch -+ bugfix/all/stable/2.6.32.7.patch -+ features/all/input-alps-add-support-for-touchpads-with-4-directional-button-2.patch -+ debian/sched-fix-conflict-between-2.6.32.7-and-vserver.patch -+ bugfix/all/sfc-Fix-polling-for-slow-MCDI-operations.patch -+ bugfix/all/sfc-Fix-conditions-for-MDIO-self-test.patch -+ bugfix/all/sfc-QT202x-Remove-unreliable-MMD-check.patch -+ bugfix/all/sfc-Add-workspace-for-GMAC-bug-workaround.patch -+ bugfix/all/sfc-Use-fixed-size-buffers-for-MCDI-NVRAM-requests.patch diff --git a/debian/patches/series/7 b/debian/patches/series/7 deleted file mode 100644 index af2ac9995..000000000 --- a/debian/patches/series/7 +++ /dev/null @@ -1,4 +0,0 @@ -+ bugfix/all/clocksource-events-Fix-fallout-of-generic-code-changes.patch -+ bugfix/all/fdpic-respect-pt_gnu_stack-exec-protection-markings-when-creating-nommu-stack.patch -+ bugfix/all/split-flush_old_exec-into-two-functions.patch -+ bugfix/all/Fix-flush_old_exec-setup_new_exec-split.patch diff --git a/debian/patches/series/8 b/debian/patches/series/8 deleted file mode 100644 index c534052b7..000000000 --- a/debian/patches/series/8 +++ /dev/null @@ -1,15 +0,0 @@ -+ bugfix/all/cxusb-select-lgs8gxx.patch -+ bugfix/x86/kvm-pit-control-word-is-write-only.patch -+ features/arm/dns323-rev-b1-poweroff.patch -- bugfix/all/Fix-flush_old_exec-setup_new_exec-split.patch -- bugfix/all/split-flush_old_exec-into-two-functions.patch -- bugfix/all/fdpic-respect-pt_gnu_stack-exec-protection-markings-when-creating-nommu-stack.patch -- bugfix/all/clocksource-events-Fix-fallout-of-generic-code-changes.patch -- bugfix/all/e1000e-enhance-fragment-detection.patch -- bugfix/all/e1000-enhance-fragment-detection.patch -+ bugfix/all/stable/2.6.32.8.patch -+ bugfix/all/fix-potential-crash-with-sys_move_pages.patch -+ bugfix/x86/kvm-fix-memory-access-during-x86-emulation.patch -+ bugfix/x86/kvm-Check-IOPL-level-during-io-instruction-emulation.patch -+ bugfix/x86/kvm-Fix-popf-emulation.patch -+ bugfix/x86/kvm-Check-CPL-level-during-privilege-instruction-emulation.patch diff --git a/debian/patches/series/9 b/debian/patches/series/9 deleted file mode 100644 index 9ebdf8aad..000000000 --- a/debian/patches/series/9 +++ /dev/null @@ -1,10 +0,0 @@ -+ bugfix/all/cxusb-dont-select-lgs8gl5.patch -+ debian/sysrq-mask.patch -+ features/all/macvlan-Copy-functions-from-2.6.33-net-core-dev-c.patch -+ features/all/macvlan-Precise-RX-stats-accounting.patch -+ features/all/macvlan-cleanup-rx-statistics.patch -+ features/all/macvlan-implement-bridge-VEPA-and-private-mode.patch -+ features/all/macvlan-export-macvlan-mode-through-netlink.patch -+ features/all/hwmon-Add-driver-for-VIA-CPU-core-temperature.patch -+ features/all/wireless-report-reasonable-bitrate-for-MCS-rates-th.patch -+ bugfix/all/efifb_fix_v2.patch diff --git a/debian/patches/series/base b/debian/patches/series/base index 0c4689b24..616459eb8 100644 --- a/debian/patches/series/base +++ b/debian/patches/series/base @@ -2,28 +2,23 @@ + debian/kernelvariables.patch + debian/doc-build-parallel.patch + debian/scripts-kconfig-reportoldconfig.patch -+ debian/arch-mips-not-embedded.patch + debian/drivers-ata-ata_piix-postpone-pata.patch + debian/drivers-ata-pata_sis-postpone-pata.patch + features/all/drivers-infiniband-hw-ipath-iba7220-use-request_firmware.patch + features/all/drivers-media-dvb-usb-af9005-request_firmware.patch -+ features/all/drivers-staging-rt28x0sta-request_firmware.patch + +# FIXME: fails to apply +# + features/all/drivers-staging-rt28x0sta-request_firmware.patch + features/all/export-unionfs-symbols.patch + features/all/lgs8gxx-lgs8g75-request_firmware.patch -+ features/all/r8169-init-phy-return-error.patch -+ features/all/r8169-rtl8168d-1-2-request_firmware.patch +# FIXME: fails to apply +#+ features/all/r8169-rtl8168d-1-2-request_firmware.patch + features/all/sound-pci-cs46xx-request_firmware.patch +# FIXME: 2.6.33 tree # patches from aufs2 repository, with s/EXPORT_SYMBOL/&_GPL/ -+ features/all/aufs2/aufs2-base.patch -+ features/all/aufs2/aufs2-standalone.patch -+ features/all/aufs2/aufs2-kbuild.patch -# content of fs/ and include/ from aufs2 repository -+ features/all/aufs2/aufs2-add.patch -# mark as staging/crap -+ features/all/aufs2/mark-as-staging.patch # content of src/ from speakup package; generated with: # diff -ur --unidirectional-new-file nonexistent src | filterdiff --strip=1 --addoldprefix=a/drivers/staging/speakup/ --addnewprefix=b/drivers/staging/speakup/ @@ -34,7 +29,8 @@ #+ bugfix/ia64/hardcode-arch-script-output.patch + bugfix/mips/disable-advansys.patch + bugfix/arm/disable-scsi_acard.patch -+ bugfix/mips/disable-werror.patch +# FIXME: no longer applies +#+ bugfix/mips/disable-werror.patch + bugfix/fix-hifn_795X-divdi3.patch + bugfix/powerpc/mm-mol.patch + bugfix/powerpc/lpar-console.patch @@ -42,42 +38,38 @@ #+ features/sparc/video-sunxvr500-intergraph.patch + bugfix/all/drivers-scsi-qla1280-request-firmware-unlocked.patch + debian/dfsg/radeon-add-clarifying-comment-to-r600-blit.patch -+ features/arm/compression-use-generic-gzip.patch -+ features/arm/compression-add-lzmo.patch -+ features/arm/openrd-client.patch -+ features/arm/ts41x.patch -+ bugfix/arm/scsi-osd-build-fix.patch -+ bugfix/mips/drm-ttm-build-fix.patch -+ bugfix/all/DocBook-media-copy-images-after-building-HTML.patch -+ bugfix/all/DocBook-media-create-links-for-included-sources.patch -+ features/all/mmc-parameter-set-whether-cards-are-assumed-removable.patch +# FIXME: no longer applies +#+ features/arm/compression-use-generic-gzip.patch +#+ features/arm/compression-add-lzmo.patch +#+ features/arm/openrd-client.patch +#+ features/arm/ts41x.patch +#+ features/all/mmc-parameter-set-whether-cards-are-assumed-removable.patch -+ features/all/module-firmware/0001-netxen-module-firmware-hints.patch -+ features/all/module-firmware/0002-netx-declare-MODULE_FIRMWARE.patch -+ features/all/module-firmware/0003-solos-pci-declare-MODULE_FIRMWARE.patch -+ features/all/module-firmware/0004-ambassador-declare-MODULE_FIRMWARE.patch -+ features/all/module-firmware/0005-bnx2x-declare-MODULE_FIRMWARE.patch -+ features/all/module-firmware/0006-cxgb3-declare-MODULE_FIRMWARE.patch -+ features/all/module-firmware/0007-myri10ge-declare-MODULE_FIRMWARE.patch -+ features/all/module-firmware/0008-spider-net-declare-MODULE_FIRMWARE.patch -+ features/all/module-firmware/0009-tms380tr-declare-MODULE_FIRMWARE.patch -+ features/all/module-firmware/0010-pcnet-cs-declare-MODULE_FIRMWARE.patch -+ features/all/module-firmware/0011-speedfax-declare-MODULE_FIRMWARE.patch -+ features/all/module-firmware/0012-at76c50x-usb-declare-MODULE_FIRMWARE.patch -+ features/all/module-firmware/0013-atmel-declare-MODULE_FIRMWARE.patch -+ features/all/module-firmware/0014-ipw2100-declare-MODULE_FIRMWARE.patch -+ features/all/module-firmware/0015-ipw2200-declare-MODULE_FIRMWARE.patch -+ features/all/module-firmware/0016-iwmc3200wifi-declare-MODULE_FIRMWARE.patch -+ features/all/module-firmware/0017-libertas-declare-MODULE_FIRMWARE.patch -+ features/all/module-firmware/0018-libertas_tf_usb-declare-MODULE_FIRMWARE.patch -+ features/all/module-firmware/0019-mwl8k-declare-MODULE_FIRMWARE.patch -+ features/all/module-firmware/0020-orinoco-declare-MODULE_FIRMWARE.patch -+ features/all/module-firmware/0021-prism54-declare-MODULE_FIRMWARE.patch -+ features/all/module-firmware/0022-wl12xx-declare-MODULE_FIRMWARE.patch -+ features/all/module-firmware/0023-zd1201-declare-MODULE_FIRMWARE.patch -+ features/all/module-firmware/0024-zd1211rw-declare-MODULE_FIRMWARE.patch +#+ bugfix/all/usbnet-link-down-initially-for-drivers-that-update.patch +#+ features/all/i915-autoload-without-CONFIG_DRM_I915_KMS.patch -+ bugfix/all/atl1e-remove-broken-tsov6.patch -+ features/all/atl1e-allow-offload-disable.patch -+ bugfix/all/usbnet-link-down-initially-for-drivers-that-update.patch -+ features/all/i915-autoload-without-CONFIG_DRM_I915_KMS.patch ++ bugfix/ia64/ia64-Include-linux-personality.h-header-in-asm-fcntl.patch +# FIXME +#+ features/all/r8169-rtl8168d-1-2-request_firmware-2.patch + ++ bugfix/all/drm-i915-disable-powersave.patch +# FIXME: +#- features/all/drivers-staging-rt28x0sta-request_firmware.patch +#+ features/all/rt28x0sta-constify-RTUSBMultiWrite-RTUSBFirmwareWrite.patch +#+ features/all/rt28x0sta-use-request_firmware.patch +#+ features/all/rt3090sta-use-request_firmware.patch +#+ features/all/input-alps-add-support-for-touchpads-with-4-directional-button-2.patch + + ++ bugfix/all/cxusb-select-lgs8gxx.patch +# FIXME: +#+ bugfix/x86/kvm-pit-control-word-is-write-only.patch +#+ bugfix/x86/kvm-fix-memory-access-during-x86-emulation.patch +#+ bugfix/x86/kvm-Check-IOPL-level-during-io-instruction-emulation.patch +#+ bugfix/x86/kvm-Fix-popf-emulation.patch +#+ bugfix/x86/kvm-Check-CPL-level-during-privilege-instruction-emulation.patch + + ++ bugfix/all/cxusb-dont-select-lgs8gl5.patch ++ debian/sysrq-mask.patch ++ bugfix/all/efifb_fix_v2.patch diff --git a/debian/patches/series/orig-0 b/debian/patches/series/orig-0 index 9286a900c..60463aa37 100644 --- a/debian/patches/series/orig-0 +++ b/debian/patches/series/orig-0 @@ -5,7 +5,6 @@ + debian/dfsg/drivers-staging-otus-disable.patch + debian/dfsg/drivers-staging-rt2860-disable.patch + debian/dfsg/drivers-staging-rt2870-disable.patch -+ debian/dfsg/drivers-staging-rt3090-disable.patch + debian/dfsg/drivers-staging-rtl8192su-disable.patch + debian/dfsg/firmware-cleanup.patch + debian/dfsg/lgs8gxx-lgs8g75-disable.patch From c56c0d544deed6c75bcabe9733c7c02cdd0cec33 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Thu, 18 Feb 2010 13:49:31 +0000 Subject: [PATCH 02/71] Fix patch context for 2.6.33-rc8 svn path=/dists/trunk/linux-2.6/; revision=15186 --- .../debian/scripts-kconfig-reportoldconfig.patch | 3 +-- .../features/all/speakup/speakup-kbuild.patch | 14 +++++++------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/debian/patches/debian/scripts-kconfig-reportoldconfig.patch b/debian/patches/debian/scripts-kconfig-reportoldconfig.patch index 89185f836..ef3b86484 100644 --- a/debian/patches/debian/scripts-kconfig-reportoldconfig.patch +++ b/debian/patches/debian/scripts-kconfig-reportoldconfig.patch @@ -11,7 +11,7 @@ index 999e8a7..3b5d4ba 100644 ifdef KBUILD_KCONFIG Kconfig := $(KBUILD_KCONFIG) -@@ -26,10 +26,16 @@ config: $(obj)/conf +@@ -26,9 +26,15 @@ config: $(obj)/conf oldconfig: $(obj)/conf $< -o $(Kconfig) @@ -19,7 +19,6 @@ index 999e8a7..3b5d4ba 100644 + $< -R $(Kconfig) + silentoldconfig: $(obj)/conf - $(Q)mkdir -p include/generated $< -s $(Kconfig) +updateoldconfig: $(obj)/conf diff --git a/debian/patches/features/all/speakup/speakup-kbuild.patch b/debian/patches/features/all/speakup/speakup-kbuild.patch index aec7a485a..565daf859 100644 --- a/debian/patches/features/all/speakup/speakup-kbuild.patch +++ b/debian/patches/features/all/speakup/speakup-kbuild.patch @@ -3,10 +3,10 @@ Subject: [PATCH] speakup: integrate into kbuild --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig -@@ -126,6 +126,8 @@ - source "drivers/staging/netwave/Kconfig" +@@ -124,6 +124,8 @@ + source "drivers/staging/sep/Kconfig" - source "drivers/staging/sm7xx/Kconfig" + source "drivers/staging/iio/Kconfig" + +source "drivers/staging/speakup/Kconfig" @@ -14,10 +14,10 @@ Subject: [PATCH] speakup: integrate into kbuild endif # STAGING --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile -@@ -45,3 +45,4 @@ - obj-$(CONFIG_PCMCIA_WAVELAN) += wavelan/ - obj-$(CONFIG_PCMCIA_NETWAVE) += netwave/ - obj-$(CONFIG_FB_SM7XX) += sm7xx/ +@@ -44,3 +44,4 @@ + obj-$(CONFIG_RAR_REGISTER) += rar/ + obj-$(CONFIG_DX_SEP) += sep/ + obj-$(CONFIG_IIO) += iio/ +obj-$(CONFIG_SPEAKUP) += speakup/ --- a/drivers/staging/speakup/Kbuild +++ b/drivers/staging/speakup/Kbuild From 4f1c2925f3b097cf455ed39767e56e8396e6f102 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Thu, 18 Feb 2010 13:49:59 +0000 Subject: [PATCH 03/71] Update rt28x0sta firmware loader patch for 2.6.33-rc8 svn path=/dists/trunk/linux-2.6/; revision=15187 --- .../all/rt28x0sta-use-request_firmware.patch | 252 +++++------ .../all/rt3090sta-use-request_firmware.patch | 426 ------------------ 2 files changed, 122 insertions(+), 556 deletions(-) delete mode 100644 debian/patches/features/all/rt3090sta-use-request_firmware.patch diff --git a/debian/patches/features/all/rt28x0sta-use-request_firmware.patch b/debian/patches/features/all/rt28x0sta-use-request_firmware.patch index 72984d982..6c7ef5c4e 100644 --- a/debian/patches/features/all/rt28x0sta-use-request_firmware.patch +++ b/debian/patches/features/all/rt28x0sta-use-request_firmware.patch @@ -1,7 +1,5 @@ -From 96fa9ac6fbf64117221dcfcdcc03f64d77ae6901 Mon Sep 17 00:00:00 2001 From: Ben Hutchings -Date: Sun, 28 Jun 2009 15:51:07 +0100 -Subject: [PATCH] rt{2860,2870}sta: Use request_firmware() to load firmware +Subject: [PATCH] Staging: rt{2860,2870}sta: Use request_firmware() to load firmware When originally introduced into staging, these drivers had custom firmware-loading code which checked a version number and CRC at the @@ -12,92 +10,88 @@ The removed firmware will be added to the linux-firmware.git repository. Based on work by Darren Salt . ---- - drivers/staging/rt2860/Kconfig | 3 +- - drivers/staging/rt2860/common/rtmp_init.c | 144 +++++++++++++++++----------- - drivers/staging/rt2860/rt_linux.c | 3 + - drivers/staging/rt2860/rtmp.h | 1 + - drivers/staging/rt2870/Kconfig | 3 +- - 5 files changed, 95 insertions(+), 59 deletions(-) -diff --git a/drivers/staging/rt2860/Kconfig b/drivers/staging/rt2860/Kconfig -index 6dff527..b98aba7 100644 --- a/drivers/staging/rt2860/Kconfig +++ b/drivers/staging/rt2860/Kconfig -@@ -1,6 +1,7 @@ - config RT2860 - tristate "Ralink 2860 wireless support" -- depends on BROKEN +@@ -3,6 +3,8 @@ config RT2860 depends on PCI && X86 && WLAN + select WIRELESS_EXT + select WEXT_PRIV + select CRC_CCITT + select FW_LOADER ---help--- - This is an experimental driver for the Ralink 2860 wireless chip. -diff --git a/drivers/staging/rt2860/common/rtmp_init.c b/drivers/staging/rt2860/common/rtmp_init.c -index 20c2ce2..a575f4f 100644 ---- a/drivers/staging/rt2860/common/rtmp_init.c -+++ b/drivers/staging/rt2860/common/rtmp_init.c -@@ -38,14 +38,8 @@ - Jan Lee 2006-09-15 RT2860. Change for 802.11n , EEPROM, Led, BA, HT. - */ - #include "../rt_config.h" --#ifdef RT2860 + This is an experimental driver for the Ralink 2860 and 3090 + wireless chips. +--- a/drivers/staging/rt2860/common/rtmp_mcu.c ++++ b/drivers/staging/rt2860/common/rtmp_mcu.c +@@ -37,35 +37,38 @@ + + #include "../rt_config.h" + +-#if defined(RT2860) || defined(RT3090) -#include "firmware.h" --#include +-#include "../../rt3090/firmware.h" -#endif -#ifdef RT2870 --/* New firmware handles both RT2870 and RT3070. */ -#include "../../rt3070/firmware.h" +-#include "firmware_3070.h" -#endif -+#include +- +-#include +#include ++#include - UCHAR BIT8[] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80}; - ULONG BIT32[] = {0x00000001, 0x00000002, 0x00000004, 0x00000008, -@@ -174,23 +168,25 @@ RTMP_REG_PAIR STAMACRegTable[] = { - #define NUM_STA_MAC_REG_PARMS (sizeof(STAMACRegTable) / sizeof(RTMP_REG_PAIR)) - - #ifdef RT2870 --// --// RT2870 Firmware Spec only used 1 oct for version expression --// + #ifdef RTMP_MAC_USB +-/* */ +-/* RT2870 Firmware Spec only used 1 oct for version expression */ +-/* */ -#define FIRMWARE_MINOR_VERSION 7 +-#endif /* RTMP_MAC_USB // */ --#endif // RT2870 // +-/* New 8k byte firmware size for RT3071/RT3072 */ +-#define FIRMWAREIMAGE_MAX_LENGTH 0x2000 +-#define FIRMWAREIMAGE_LENGTH (sizeof (FirmwareImage) / sizeof(u8)) +-#define FIRMWARE_MAJOR_VERSION 0 +#define FIRMWAREIMAGE_LENGTH 0x1000 --// New 8k byte firmware size for RT3071/RT3072 --#define FIRMWAREIMAGE_MAX_LENGTH 0x2000 --#define FIRMWAREIMAGE_LENGTH (sizeof (FirmwareImage) / sizeof(UCHAR)) --#define FIRMWARE_MAJOR_VERSION 0 -+#define FIRMWARE_2870_MIN_VERSION 12 -+#define FIRMWARE_2870_FILENAME "rt2870.bin" /* for RT2870/RT3070 */ +-#define FIRMWAREIMAGEV1_LENGTH 0x1000 +-#define FIRMWAREIMAGEV2_LENGTH 0x1000 ++#define FIRMWARE_2870_MIN_VERSION 12 ++#define FIRMWARE_2870_FILENAME "rt2870.bin" +MODULE_FIRMWARE(FIRMWARE_2870_FILENAME); --#define FIRMWAREIMAGEV1_LENGTH 0x1000 --#define FIRMWAREIMAGEV2_LENGTH 0x1000 -+#define FIRMWARE_3071_MIN_VERSION 2 -+#define FIRMWARE_3071_FILENAME "rt3071.bin" /* for RT3071/RT3072 */ +-#ifdef RTMP_MAC_PCI +-#define FIRMWARE_MINOR_VERSION 2 +-#endif /* RTMP_MAC_PCI // */ ++#define FIRMWARE_3070_MIN_VERSION 17 ++#define FIRMWARE_3070_FILENAME "rt3070.bin" ++MODULE_FIRMWARE(FIRMWARE_3070_FILENAME); ++ ++#define FIRMWARE_3071_MIN_VERSION 17 ++#define FIRMWARE_3071_FILENAME "rt3071.bin" /* for RT3071/RT3072 */ +MODULE_FIRMWARE(FIRMWARE_3071_FILENAME); + -+#else /* RT2860 */ ++#else /* RTMP_MAC_PCI */ + +#define FIRMWAREIMAGE_LENGTH 0x2000 + -+#define FIRMWARE_2860_MIN_VERSION 11 -+#define FIRMWARE_2860_FILENAME "rt2860.bin" ++#define FIRMWARE_2860_MIN_VERSION 11 ++#define FIRMWARE_2860_FILENAME "rt2860.bin" +MODULE_FIRMWARE(FIRMWARE_2860_FILENAME); ++ ++#define FIRMWARE_3090_MIN_VERSION 19 ++#define FIRMWARE_3090_FILENAME "rt3090.bin" /* for RT3090/RT3390 */ ++MODULE_FIRMWARE(FIRMWARE_3090_FILENAME); ++ ++#endif --#ifdef RT2860 --#define FIRMWARE_MINOR_VERSION 2 - #endif + /* + ======================================================================== +@@ -90,6 +93,78 @@ int RtmpAsicEraseFirmware(struct rt_rtmp_adapter *pAd) + return 0; + } - -@@ -2955,6 +2951,70 @@ VOID NICEraseFirmware( - - }/* End of NICEraseFirmware */ - -+static const struct firmware *rtmp_get_firmware(PRTMP_ADAPTER adapter) ++static const struct firmware *rtmp_get_firmware(struct rt_rtmp_adapter *adapter) +{ + const char *name; + const struct firmware *fw = NULL; @@ -108,19 +102,27 @@ index 20c2ce2..a575f4f 100644 + if (adapter->firmware) + return adapter->firmware; + -+#ifdef RT2870 ++#ifdef RTMP_MAC_USB + if (IS_RT3071(adapter)) { + name = FIRMWARE_3071_FILENAME; + min_version = FIRMWARE_3071_MIN_VERSION; ++ } else if (IS_RT3070(adapter)) { ++ name = FIRMWARE_3070_FILENAME; ++ min_version = FIRMWARE_3070_MIN_VERSION; + } else { + name = FIRMWARE_2870_FILENAME; + min_version = FIRMWARE_2870_MIN_VERSION; + } -+ dev = &((POS_COOKIE)adapter->OS_Cookie)->pUsb_Dev->dev; -+#else /* RT2860 */ -+ name = FIRMWARE_2860_FILENAME; -+ min_version = FIRMWARE_2860_MIN_VERSION; -+ dev = &((POS_COOKIE)adapter->OS_Cookie)->pci_dev->dev; ++ dev = &((struct os_cookie *)adapter->OS_Cookie)->pUsb_Dev->dev; ++#else /* RTMP_MAC_PCI */ ++ if (IS_RT3090(adapter) || IS_RT3390(adapter)) { ++ name = FIRMWARE_3090_FILENAME; ++ min_version = FIRMWARE_3090_MIN_VERSION; ++ } else { ++ name = FIRMWARE_2860_FILENAME; ++ min_version = FIRMWARE_2860_MIN_VERSION; ++ } ++ dev = &((struct os_cookie *)adapter->OS_Cookie)->pci_dev->dev; +#endif + + err = request_firmware(&fw, name, dev); @@ -164,61 +166,59 @@ index 20c2ce2..a575f4f 100644 /* ======================================================================== -@@ -2975,46 +3035,16 @@ VOID NICEraseFirmware( - NDIS_STATUS NICLoadFirmware( - IN PRTMP_ADAPTER pAd) +@@ -109,46 +184,16 @@ int RtmpAsicEraseFirmware(struct rt_rtmp_adapter *pAd) + */ + int RtmpAsicLoadFirmware(struct rt_rtmp_adapter *pAd) { -+ const struct firmware *fw; - NDIS_STATUS Status = NDIS_STATUS_SUCCESS; -- PUCHAR pFirmwareImage; -- ULONG FileLength, Index; -- //ULONG firm; -+ ULONG Index; - UINT32 MacReg = 0; --#ifdef RT2870 -- UINT32 Version = (pAd->MACVersion >> 16); --#endif // RT2870 // +- ++ const struct firmware *fw; + int Status = NDIS_STATUS_SUCCESS; +- u8 *pFirmwareImage = NULL; +- unsigned long FileLength, Index; ++ unsigned long Index; + u32 MacReg = 0; +-#ifdef RTMP_MAC_USB +- u32 Version = (pAd->MACVersion >> 16); +-#endif -- pFirmwareImage = FirmwareImage; -- FileLength = sizeof(FirmwareImage); --#ifdef RT2870 -- // New 8k byte firmware size for RT3071/RT3072 -- //printk("Usb Chip\n"); -- if (FIRMWAREIMAGE_LENGTH == FIRMWAREIMAGE_MAX_LENGTH) -- //The firmware image consists of two parts. One is the origianl and the other is the new. -- //Use Second Part +- /* New 8k byte firmware size for RT3071/RT3072 */ - { -- if ((Version != 0x2860) && (Version != 0x2872) && (Version != 0x3070)) -- { // Use Firmware V2. -- //printk("KH:Use New Version,part2\n"); -- pFirmwareImage = (PUCHAR)&FirmwareImage[FIRMWAREIMAGEV1_LENGTH]; -- FileLength = FIRMWAREIMAGEV2_LENGTH; +-#ifdef RTMP_MAC_PCI +- if (IS_RT3090(pAd) || IS_RT3390(pAd)) { +- pFirmwareImage = FirmwareImage_3090; +- FileLength = FIRMWAREIMAGE_MAX_LENGTH; +- } else { +- pFirmwareImage = FirmwareImage_2860; +- FileLength = FIRMWAREIMAGE_MAX_LENGTH; - } -- else -- { -- //printk("KH:Use New Version,part1\n"); -- pFirmwareImage = FirmwareImage; +-#endif /* RTMP_MAC_PCI // */ +-#ifdef RTMP_MAC_USB +- /* the firmware image consists of two parts */ +- if ((Version != 0x2860) && (Version != 0x2872) && (Version != 0x3070)) { /* use the second part */ +- /*printk("KH:Use New Version,part2\n"); */ +- pFirmwareImage = +- (u8 *)& +- FirmwareImage_3070[FIRMWAREIMAGEV1_LENGTH]; +- FileLength = FIRMWAREIMAGEV2_LENGTH; +- } else { +- /*printk("KH:Use New Version,part1\n"); */ +- if (Version == 0x3070) +- pFirmwareImage = FirmwareImage_3070; +- else +- pFirmwareImage = FirmwareImage_2870; - FileLength = FIRMWAREIMAGEV1_LENGTH; - } +-#endif /* RTMP_MAC_USB // */ - } -- else -- { -- DBGPRINT(RT_DEBUG_ERROR, ("KH: bin file should be 8KB.\n")); -- Status = NDIS_STATUS_FAILURE; -- } -- --#endif // RT2870 // + fw = rtmp_get_firmware(pAd); + if (!fw) + return NDIS_STATUS_FAILURE; -- RT28XX_WRITE_FIRMWARE(pAd, pFirmwareImage, FileLength); -+ RT28XX_WRITE_FIRMWARE(pAd, fw->data, FIRMWAREIMAGE_LENGTH); +- RTMP_WRITE_FIRMWARE(pAd, pFirmwareImage, FileLength); ++ RTMP_WRITE_FIRMWARE(pAd, fw->data, FIRMWAREIMAGE_LENGTH); /* check if MCU is ready */ Index = 0; -diff --git a/drivers/staging/rt2860/rt_linux.c b/drivers/staging/rt2860/rt_linux.c -index ed27b85..4f730ff 100644 --- a/drivers/staging/rt2860/rt_linux.c +++ b/drivers/staging/rt2860/rt_linux.c @@ -25,6 +25,7 @@ @@ -229,40 +229,32 @@ index ed27b85..4f730ff 100644 #include #include "rt_config.h" -@@ -299,6 +300,8 @@ VOID RTMPFreeAdapter( +@@ -260,6 +261,8 @@ void RTMPFreeAdapter(struct rt_rtmp_adapter *pAd) NdisFreeSpinLock(&pAd->irq_lock); + release_firmware(pAd->firmware); + - vfree(pAd); // pci_free_consistent(os_cookie->pci_dev,sizeof(RTMP_ADAPTER),pAd,os_cookie->pAd_pa); - kfree(os_cookie); - } -diff --git a/drivers/staging/rt2860/rtmp.h b/drivers/staging/rt2860/rtmp.h -index d283256..2a56821 100644 + vfree(pAd); /* pci_free_consistent(os_cookie->pci_dev,sizeof(struct rt_rtmp_adapter),pAd,os_cookie->pAd_pa); */ + if (os_cookie) + kfree(os_cookie); --- a/drivers/staging/rt2860/rtmp.h +++ b/drivers/staging/rt2860/rtmp.h -@@ -2522,6 +2522,7 @@ typedef struct _RTMP_ADAPTER - PVOID OS_Cookie; // save specific structure relative to OS - PNET_DEV net_dev; - ULONG VirtualIfCnt; -+ const struct firmware *firmware; +@@ -1719,6 +1719,7 @@ struct rt_rtmp_adapter { + void *OS_Cookie; /* save specific structure relative to OS */ + struct net_device *net_dev; + unsigned long VirtualIfCnt; ++ const struct firmware *firmware; - #ifdef RT2860 - USHORT LnkCtrlBitMask; -diff --git a/drivers/staging/rt2870/Kconfig b/drivers/staging/rt2870/Kconfig -index 05ee373..a0c9eb3 100644 + struct rt_rtmp_chip_op chipOps; + u16 ThisTbttNumToNextWakeUp; --- a/drivers/staging/rt2870/Kconfig +++ b/drivers/staging/rt2870/Kconfig -@@ -1,6 +1,7 @@ - config RT2870 - tristate "Ralink 2870/3070 wireless support" -- depends on BROKEN +@@ -3,5 +3,7 @@ config RT2870 depends on USB && X86 && WLAN + select WIRELESS_EXT + select WEXT_PRIV + select CRC_CCITT + select FW_LOADER ---help--- This is an experimental driver for the Ralink xx70 wireless chips. --- -1.6.6 - diff --git a/debian/patches/features/all/rt3090sta-use-request_firmware.patch b/debian/patches/features/all/rt3090sta-use-request_firmware.patch deleted file mode 100644 index 06e4fe97e..000000000 --- a/debian/patches/features/all/rt3090sta-use-request_firmware.patch +++ /dev/null @@ -1,426 +0,0 @@ -From fbc0964ef80092b2f2d18a13f4f95c8806e4fe72 Mon Sep 17 00:00:00 2001 -From: Ben Hutchings -Date: Sun, 17 Jan 2010 16:22:36 +0000 -Subject: [PATCH] rt3090sta: Use request_firmware() to load firmware - -Based on work by Darren Salt . ---- - drivers/staging/rt3090/Kconfig | 3 +- - drivers/staging/rt3090/common/rtmp_mcu.c | 333 ++++++------------------------ - drivers/staging/rt3090/rt_linux.c | 2 + - drivers/staging/rt3090/rtmp.h | 1 + - 4 files changed, 65 insertions(+), 274 deletions(-) - -diff --git a/drivers/staging/rt3090/Kconfig b/drivers/staging/rt3090/Kconfig -index 8ba68b0..e4a2e0f 100644 ---- a/drivers/staging/rt3090/Kconfig -+++ b/drivers/staging/rt3090/Kconfig -@@ -1,6 +1,7 @@ - config RT3090 - tristate "Ralink 3090 wireless support" -- depends on BROKEN - depends on PCI && X86 && WLAN -+ select CRC_CCITT -+ select FW_LOADER - ---help--- - This is an experimental driver for the Ralink 3090 wireless chip. -diff --git a/drivers/staging/rt3090/common/rtmp_mcu.c b/drivers/staging/rt3090/common/rtmp_mcu.c -index 23f785a..b142442 100644 ---- a/drivers/staging/rt3090/common/rtmp_mcu.c -+++ b/drivers/staging/rt3090/common/rtmp_mcu.c -@@ -36,73 +36,14 @@ - */ - - #include "../rt_config.h" --#include "../firmware.h" -+#include -+#include - --//#define BIN_IN_FILE /* use *.bin firmware */ -+#define FIRMWAREIMAGE_LENGTH 0x2000 - -- --// New 8k byte firmware size for RT3071/RT3072 --#define FIRMWAREIMAGE_MAX_LENGTH 0x2000 --#define FIRMWAREIMAGE_LENGTH (sizeof (FirmwareImage) / sizeof(UCHAR)) --#define FIRMWARE_MAJOR_VERSION 0 -- --#define FIRMWAREIMAGEV1_LENGTH 0x1000 --#define FIRMWAREIMAGEV2_LENGTH 0x1000 -- --#ifdef RTMP_MAC_PCI --#define FIRMWARE_MINOR_VERSION 2 --#endif // RTMP_MAC_PCI // -- --const unsigned short ccitt_16Table[] = { -- 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, -- 0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF, -- 0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, -- 0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE, -- 0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485, -- 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D, -- 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4, -- 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC, -- 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823, -- 0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B, -- 0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, -- 0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A, -- 0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41, -- 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49, -- 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70, -- 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78, -- 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F, -- 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067, -- 0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, -- 0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256, -- 0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, -- 0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, -- 0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C, -- 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634, -- 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB, -- 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3, -- 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A, -- 0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92, -- 0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, -- 0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1, -- 0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8, -- 0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0 --}; --#define ByteCRC16(v, crc) \ -- (unsigned short)((crc << 8) ^ ccitt_16Table[((crc >> 8) ^ (v)) & 255]) -- --unsigned char BitReverse(unsigned char x) --{ -- int i; -- unsigned char Temp=0; -- for(i=0; ; i++) -- { -- if(x & 0x80) Temp |= 0x80; -- if(i==7) break; -- x <<= 1; -- Temp >>= 1; -- } -- return Temp; --} -+#define FIRMWARE_3090_MIN_VERSION 19 -+#define FIRMWARE_3090_FILENAME "rt3090.bin" -+MODULE_FIRMWARE(FIRMWARE_3090_FILENAME); - - - /* -@@ -129,6 +70,55 @@ INT RtmpAsicEraseFirmware( - return 0; - } - -+static const struct firmware *rtmp_get_firmware(PRTMP_ADAPTER adapter) -+{ -+ const char *name = FIRMWARE_3090_FILENAME; -+ const struct firmware *fw = NULL; -+ u8 min_version = FIRMWARE_3090_MIN_VERSION; -+ struct device *dev = &((POS_COOKIE)adapter->OS_Cookie)->pci_dev->dev; -+ int err; -+ -+ if (adapter->firmware) -+ return adapter->firmware; -+ -+ err = request_firmware(&fw, name, dev); -+ if (err) { -+ dev_err(dev, "firmware file %s request failed (%d)\n", -+ name, err); -+ return NULL; -+ } -+ -+ if (fw->size < FIRMWAREIMAGE_LENGTH) { -+ dev_err(dev, "firmware file %s size is invalid\n", name); -+ goto invalid; -+ } -+ -+ /* is it new enough? */ -+ adapter->FirmwareVersion = fw->data[FIRMWAREIMAGE_LENGTH - 3]; -+ if (adapter->FirmwareVersion < min_version) { -+ dev_err(dev, -+ "firmware file %s is too old;" -+ " driver requires v%d or later\n", -+ name, min_version); -+ goto invalid; -+ } -+ -+ /* is the internal CRC correct? */ -+ if (crc_ccitt(0xffff, fw->data, FIRMWAREIMAGE_LENGTH - 2) != -+ (fw->data[FIRMWAREIMAGE_LENGTH - 2] | -+ (fw->data[FIRMWAREIMAGE_LENGTH - 1] << 8))) { -+ dev_err(dev, "firmware file %s failed internal CRC\n", name); -+ goto invalid; -+ } -+ -+ adapter->firmware = fw; -+ return fw; -+ -+invalid: -+ release_firmware(fw); -+ return NULL; -+} -+ - /* - ======================================================================== - -@@ -149,219 +139,16 @@ INT RtmpAsicEraseFirmware( - NDIS_STATUS RtmpAsicLoadFirmware( - IN PRTMP_ADAPTER pAd) - { --#ifdef BIN_IN_FILE --#define NICLF_DEFAULT_USE() \ -- flg_default_firm_use = TRUE; \ -- DBGPRINT(RT_DEBUG_OFF, ("%s - Use default firmware!\n", __FUNCTION__)); -- -+ const struct firmware *fw; - NDIS_STATUS Status = NDIS_STATUS_SUCCESS; -- PUCHAR src; -- RTMP_OS_FD srcf; -- INT retval, i; -- PUCHAR pFirmwareImage; -- INT FileLength = 0; -- UINT32 MacReg; - ULONG Index; -- ULONG firm; -- BOOLEAN flg_default_firm_use = FALSE; -- RTMP_OS_FS_INFO osFSInfo; -- -- DBGPRINT(RT_DEBUG_TRACE, ("===> %s\n", __FUNCTION__)); -- -- /* init */ -- pFirmwareImage = NULL; -- src = RTMP_FIRMWARE_FILE_NAME; -- -- RtmpOSFSInfoChange(&osFSInfo, TRUE); -- -- pAd->FirmwareVersion = (FIRMWARE_MAJOR_VERSION << 8) + \ -- FIRMWARE_MINOR_VERSION; -- -- -- /* allocate firmware buffer */ -- pFirmwareImage = kmalloc(MAX_FIRMWARE_IMAGE_SIZE, MEM_ALLOC_FLAG); -- if (pFirmwareImage == NULL) -- { -- /* allocate fail, use default firmware array in firmware.h */ -- DBGPRINT(RT_DEBUG_ERROR, ("%s - Allocate memory fail!\n", __FUNCTION__)); -- NICLF_DEFAULT_USE(); -- } -- else -- { -- /* allocate ok! zero the firmware buffer */ -- memset(pFirmwareImage, 0x00, MAX_FIRMWARE_IMAGE_SIZE); -- } /* End of if */ -- -- -- /* if ok, read firmware file from *.bin file */ -- if (flg_default_firm_use == FALSE) -- { -- do -- { -- /* open the bin file */ -- srcf = RtmpOSFileOpen(src, O_RDONLY, 0); -- -- if (IS_FILE_OPEN_ERR(srcf)) -- { -- DBGPRINT(RT_DEBUG_ERROR, ("%s - Error opening file %s\n", __FUNCTION__, src)); -- NICLF_DEFAULT_USE(); -- break; -- } -- -- -- /* read the firmware from the file *.bin */ -- FileLength = RtmpOSFileRead(srcf, pFirmwareImage, MAX_FIRMWARE_IMAGE_SIZE); -- if (FileLength != MAX_FIRMWARE_IMAGE_SIZE) -- { -- DBGPRINT(RT_DEBUG_ERROR, ("%s: error file length (=%d) in RT2860AP.BIN\n", -- __FUNCTION__, FileLength)); -- NICLF_DEFAULT_USE(); -- break; -- } -- else -- { -- PUCHAR ptr = pFirmwareImage; -- USHORT crc = 0xffff; -- -- -- /* calculate firmware CRC */ -- for(i=0; i<(MAX_FIRMWARE_IMAGE_SIZE-2); i++, ptr++) -- crc = ByteCRC16(BitReverse(*ptr), crc); -- /* End of for */ -- -- if ((pFirmwareImage[MAX_FIRMWARE_IMAGE_SIZE-2] != \ -- (UCHAR)BitReverse((UCHAR)(crc>>8))) || -- (pFirmwareImage[MAX_FIRMWARE_IMAGE_SIZE-1] != \ -- (UCHAR)BitReverse((UCHAR)crc))) -- { -- /* CRC fail */ -- DBGPRINT(RT_DEBUG_ERROR, ("%s: CRC = 0x%02x 0x%02x " -- "error, should be 0x%02x 0x%02x\n", -- __FUNCTION__, -- pFirmwareImage[MAX_FIRMWARE_IMAGE_SIZE-2], -- pFirmwareImage[MAX_FIRMWARE_IMAGE_SIZE-1], -- (UCHAR)(crc>>8), (UCHAR)(crc))); -- NICLF_DEFAULT_USE(); -- break; -- } -- else -- { -- /* firmware is ok */ -- pAd->FirmwareVersion = \ -- (pFirmwareImage[MAX_FIRMWARE_IMAGE_SIZE-4] << 8) + -- pFirmwareImage[MAX_FIRMWARE_IMAGE_SIZE-3]; -- -- /* check if firmware version of the file is too old */ -- if ((pAd->FirmwareVersion) < \ -- ((FIRMWARE_MAJOR_VERSION << 8) + -- FIRMWARE_MINOR_VERSION)) -- { -- DBGPRINT(RT_DEBUG_ERROR, ("%s: firmware version too old!\n", __FUNCTION__)); -- NICLF_DEFAULT_USE(); -- break; -- } /* End of if */ -- } /* End of if */ -- -- DBGPRINT(RT_DEBUG_TRACE, -- ("NICLoadFirmware: CRC ok, ver=%d.%d\n", -- pFirmwareImage[MAX_FIRMWARE_IMAGE_SIZE-4], -- pFirmwareImage[MAX_FIRMWARE_IMAGE_SIZE-3])); -- } /* End of if (FileLength == MAX_FIRMWARE_IMAGE_SIZE) */ -- break; -- } while(TRUE); -- -- /* close firmware file */ -- if (IS_FILE_OPEN_ERR(srcf)) -- ; -- else -- { -- retval = RtmpOSFileClose(srcf); -- if (retval) -- { -- DBGPRINT(RT_DEBUG_ERROR, ("--> Error %d closing %s\n", -retval, src)); -- } -- } -- } -- -- -- /* write firmware to ASIC */ -- if (flg_default_firm_use == TRUE) -- { -- /* use default fimeware, free allocated buffer */ -- if (pFirmwareImage != NULL) -- kfree(pFirmwareImage); -- /* End of if */ -- -- /* use default *.bin array */ -- pFirmwareImage = FirmwareImage; -- FileLength = sizeof(FirmwareImage); -- } /* End of if */ -- -- /* enable Host program ram write selection */ -- RTMP_IO_WRITE32(pAd, PBF_SYS_CTRL, 0x10000); -- -- for(i=0; iMACVersion >> 16); -- -- pFirmwareImage = FirmwareImage; -- FileLength = sizeof(FirmwareImage); -- -- // New 8k byte firmware size for RT3071/RT3072 -- //DBGPRINT(RT_DEBUG_TRACE, ("Usb Chip\n")); -- if (FIRMWAREIMAGE_LENGTH == FIRMWAREIMAGE_MAX_LENGTH) -- //The firmware image consists of two parts. One is the origianl and the other is the new. -- //Use Second Part -- { --#ifdef RTMP_MAC_PCI -- if ((Version == 0x2860) || IS_RT3090(pAd)||IS_RT3390(pAd)) -- { -- pFirmwareImage = FirmwareImage; -- FileLength = FIRMWAREIMAGE_LENGTH; -- } --#endif // RTMP_MAC_PCI // -- } -- else -- { -- DBGPRINT(RT_DEBUG_ERROR, ("KH: bin file should be 8KB.\n")); -- Status = NDIS_STATUS_FAILURE; -- } -- - -- RTMP_WRITE_FIRMWARE(pAd, pFirmwareImage, FileLength); -+ fw = rtmp_get_firmware(pAd); -+ if (!fw) -+ return NDIS_STATUS_FAILURE; - --#endif -+ RTMP_WRITE_FIRMWARE(pAd, fw->data, FIRMWAREIMAGE_LENGTH); - - /* check if MCU is ready */ - Index = 0; -diff --git a/drivers/staging/rt3090/rt_linux.c b/drivers/staging/rt3090/rt_linux.c -index 9b94aa6..7077a9a 100644 ---- a/drivers/staging/rt3090/rt_linux.c -+++ b/drivers/staging/rt3090/rt_linux.c -@@ -25,6 +25,7 @@ - ************************************************************************* - */ - -+#include - #include - #include "rt_config.h" - -@@ -299,6 +300,7 @@ NdisFreeSpinLock(&pAd->McuCmdLock); - - NdisFreeSpinLock(&pAd->irq_lock); - -+ release_firmware(pAd->firmware); - - vfree(pAd); // pci_free_consistent(os_cookie->pci_dev,sizeof(RTMP_ADAPTER),pAd,os_cookie->pAd_pa); - if (os_cookie) -diff --git a/drivers/staging/rt3090/rtmp.h b/drivers/staging/rt3090/rtmp.h -index 8ef6d0b..8348277 100644 ---- a/drivers/staging/rt3090/rtmp.h -+++ b/drivers/staging/rt3090/rtmp.h -@@ -2202,6 +2202,7 @@ struct _RTMP_ADAPTER - PVOID OS_Cookie; // save specific structure relative to OS - PNET_DEV net_dev; - ULONG VirtualIfCnt; -+ const struct firmware *firmware; - - RTMP_CHIP_OP chipOps; - USHORT ThisTbttNumToNextWakeUp; --- -1.6.6 - From ac3dbf96fd1936d06e5a5d4646f2d4a6e26279f2 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Thu, 18 Feb 2010 13:57:06 +0000 Subject: [PATCH 04/71] Reenable rt28x0sta firmware loader patch svn path=/dists/trunk/linux-2.6/; revision=15188 --- debian/patches/series/base | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/debian/patches/series/base b/debian/patches/series/base index 616459eb8..bc9edd724 100644 --- a/debian/patches/series/base +++ b/debian/patches/series/base @@ -9,8 +9,7 @@ + features/all/drivers-infiniband-hw-ipath-iba7220-use-request_firmware.patch + features/all/drivers-media-dvb-usb-af9005-request_firmware.patch -# FIXME: fails to apply -# + features/all/drivers-staging-rt28x0sta-request_firmware.patch ++ features/all/drivers-staging-rt28x0sta-request_firmware.patch + features/all/export-unionfs-symbols.patch + features/all/lgs8gxx-lgs8g75-request_firmware.patch # FIXME: fails to apply From b138e8096203744764b31eab1fb545c34ad7724d Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Thu, 18 Feb 2010 13:59:57 +0000 Subject: [PATCH 05/71] Reenable r8169 firmware loader patch svn path=/dists/trunk/linux-2.6/; revision=15189 --- debian/patches/series/base | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/debian/patches/series/base b/debian/patches/series/base index bc9edd724..b993eca8a 100644 --- a/debian/patches/series/base +++ b/debian/patches/series/base @@ -12,8 +12,7 @@ + features/all/drivers-staging-rt28x0sta-request_firmware.patch + features/all/export-unionfs-symbols.patch + features/all/lgs8gxx-lgs8g75-request_firmware.patch -# FIXME: fails to apply -#+ features/all/r8169-rtl8168d-1-2-request_firmware.patch ++ features/all/r8169-rtl8168d-1-2-request_firmware-2.patch + features/all/sound-pci-cs46xx-request_firmware.patch # FIXME: 2.6.33 tree @@ -48,8 +47,6 @@ #+ features/all/i915-autoload-without-CONFIG_DRM_I915_KMS.patch + bugfix/ia64/ia64-Include-linux-personality.h-header-in-asm-fcntl.patch -# FIXME -#+ features/all/r8169-rtl8168d-1-2-request_firmware-2.patch + bugfix/all/drm-i915-disable-powersave.patch # FIXME: From dced2bc8d0eff66f143025c519beb63f514fe7f3 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Thu, 18 Feb 2010 14:01:17 +0000 Subject: [PATCH 06/71] Remove fix to usbnet; merged upstream svn path=/dists/trunk/linux-2.6/; revision=15190 --- ...wn-initially-for-drivers-that-update.patch | 112 ------------------ debian/patches/series/base | 1 - 2 files changed, 113 deletions(-) delete mode 100644 debian/patches/bugfix/all/usbnet-link-down-initially-for-drivers-that-update.patch diff --git a/debian/patches/bugfix/all/usbnet-link-down-initially-for-drivers-that-update.patch b/debian/patches/bugfix/all/usbnet-link-down-initially-for-drivers-that-update.patch deleted file mode 100644 index 802fd108e..000000000 --- a/debian/patches/bugfix/all/usbnet-link-down-initially-for-drivers-that-update.patch +++ /dev/null @@ -1,112 +0,0 @@ -From: Ben Hutchings -Subject: [PATCH] usbnet: Set link down initially for drivers that update link state - -Some usbnet drivers update link state while others do not due to -hardware limitations. Add a flag to distinguish those that do, and -set the link down initially for their devices. - -This is intended to fix this bug: http://bugs.debian.org/444043 - ---- a/drivers/net/usb/asix.c -+++ b/drivers/net/usb/asix.c -@@ -1327,7 +1327,7 @@ static const struct driver_info ax8817x_info = { - .status = asix_status, - .link_reset = ax88172_link_reset, - .reset = ax88172_link_reset, -- .flags = FLAG_ETHER, -+ .flags = FLAG_ETHER | FLAG_LINK_INTR, - .data = 0x00130103, - }; - -@@ -1337,7 +1337,7 @@ static const struct driver_info dlink_dub_e100_info = { - .status = asix_status, - .link_reset = ax88172_link_reset, - .reset = ax88172_link_reset, -- .flags = FLAG_ETHER, -+ .flags = FLAG_ETHER | FLAG_LINK_INTR, - .data = 0x009f9d9f, - }; - -@@ -1347,7 +1347,7 @@ static const struct driver_info netgear_fa120_info = { - .status = asix_status, - .link_reset = ax88172_link_reset, - .reset = ax88172_link_reset, -- .flags = FLAG_ETHER, -+ .flags = FLAG_ETHER | FLAG_LINK_INTR, - .data = 0x00130103, - }; - -@@ -1357,7 +1357,7 @@ static const struct driver_info hawking_uf200_info = { - .status = asix_status, - .link_reset = ax88172_link_reset, - .reset = ax88172_link_reset, -- .flags = FLAG_ETHER, -+ .flags = FLAG_ETHER | FLAG_LINK_INTR, - .data = 0x001f1d1f, - }; - -@@ -1367,7 +1367,7 @@ static const struct driver_info ax88772_info = { - .status = asix_status, - .link_reset = ax88772_link_reset, - .reset = ax88772_link_reset, -- .flags = FLAG_ETHER | FLAG_FRAMING_AX, -+ .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR, - .rx_fixup = asix_rx_fixup, - .tx_fixup = asix_tx_fixup, - }; -@@ -1378,7 +1378,7 @@ static const struct driver_info ax88178_info = { - .status = asix_status, - .link_reset = ax88178_link_reset, - .reset = ax88178_link_reset, -- .flags = FLAG_ETHER | FLAG_FRAMING_AX, -+ .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR, - .rx_fixup = asix_rx_fixup, - .tx_fixup = asix_tx_fixup, - }; ---- a/drivers/net/usb/cdc_ether.c -+++ b/drivers/net/usb/cdc_ether.c -@@ -413,7 +413,7 @@ static int cdc_bind(struct usbnet *dev, struct usb_interface *intf) - - static const struct driver_info cdc_info = { - .description = "CDC Ethernet Device", -- .flags = FLAG_ETHER, -+ .flags = FLAG_ETHER | FLAG_LINK_INTR, - // .check_connect = cdc_check_connect, - .bind = cdc_bind, - .unbind = usbnet_cdc_unbind, ---- a/drivers/net/usb/dm9601.c -+++ b/drivers/net/usb/dm9601.c -@@ -611,7 +611,7 @@ static int dm9601_link_reset(struct usbnet *dev) - - static const struct driver_info dm9601_info = { - .description = "Davicom DM9601 USB Ethernet", -- .flags = FLAG_ETHER, -+ .flags = FLAG_ETHER | FLAG_LINK_INTR, - .bind = dm9601_bind, - .rx_fixup = dm9601_rx_fixup, - .tx_fixup = dm9601_tx_fixup, ---- a/drivers/net/usb/usbnet.c -+++ b/drivers/net/usb/usbnet.c -@@ -1352,9 +1352,11 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod) - // ok, it's ready to go. - usb_set_intfdata (udev, dev); - -- // start as if the link is up - netif_device_attach (net); - -+ if (dev->driver_info->flags & FLAG_LINK_INTR) -+ netif_carrier_off(net); -+ - return 0; - - out3: ---- a/include/linux/usb/usbnet.h -+++ b/include/linux/usb/usbnet.h -@@ -92,6 +92,7 @@ struct driver_info { - #define FLAG_AVOID_UNLINK_URBS 0x0100 /* don't unlink urbs at usbnet_stop() */ - #define FLAG_SEND_ZLP 0x0200 /* hw requires ZLPs are sent */ - -+#define FLAG_LINK_INTR 0x0800 /* updates link (carrier) status */ - - /* init device ... can sleep, or cause probe() failure */ - int (*bind)(struct usbnet *, struct usb_interface *); diff --git a/debian/patches/series/base b/debian/patches/series/base index b993eca8a..6f371bcc7 100644 --- a/debian/patches/series/base +++ b/debian/patches/series/base @@ -43,7 +43,6 @@ #+ features/arm/ts41x.patch #+ features/all/mmc-parameter-set-whether-cards-are-assumed-removable.patch -#+ bugfix/all/usbnet-link-down-initially-for-drivers-that-update.patch #+ features/all/i915-autoload-without-CONFIG_DRM_I915_KMS.patch + bugfix/ia64/ia64-Include-linux-personality.h-header-in-asm-fcntl.patch From aa2b0b9995ffb8ee9fd7896dd5924d77d7ea5a5b Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Thu, 18 Feb 2010 14:03:40 +0000 Subject: [PATCH 07/71] Restore MODULE_FIRMWARE declaration patches not merged upstream in 2.6.33 svn path=/dists/trunk/linux-2.6/; revision=15191 --- ...e-MODULE_FIRMWARE-in-various-drivers.patch | 69 +++++++++++++ ...e-MODULE_FIRMWARE-in-various-drivers.patch | 97 +++++++++++++++++++ ...de-driver-name-in-firmware-filenames.patch | 29 ++++++ .../0028-sep-declare-MODULE_FIRMWARE.patch | 26 +++++ ...ght-firmware-declare-MODULE_FIRMWARE.patch | 25 +++++ debian/patches/series/base | 6 ++ 6 files changed, 252 insertions(+) create mode 100644 debian/patches/features/all/module-firmware/0025-tty-declare-MODULE_FIRMWARE-in-various-drivers.patch create mode 100644 debian/patches/features/all/module-firmware/0026-staging-declare-MODULE_FIRMWARE-in-various-drivers.patch create mode 100644 debian/patches/features/all/module-firmware/0027-sep-include-driver-name-in-firmware-filenames.patch create mode 100644 debian/patches/features/all/module-firmware/0028-sep-declare-MODULE_FIRMWARE.patch create mode 100644 debian/patches/features/all/module-firmware/0029-isight-firmware-declare-MODULE_FIRMWARE.patch diff --git a/debian/patches/features/all/module-firmware/0025-tty-declare-MODULE_FIRMWARE-in-various-drivers.patch b/debian/patches/features/all/module-firmware/0025-tty-declare-MODULE_FIRMWARE-in-various-drivers.patch new file mode 100644 index 000000000..682aaa799 --- /dev/null +++ b/debian/patches/features/all/module-firmware/0025-tty-declare-MODULE_FIRMWARE-in-various-drivers.patch @@ -0,0 +1,69 @@ +Based on: + +From: Ben Hutchings +Subject: [PATCH] tty: declare MODULE_FIRMWARE in various drivers + +--- a/drivers/char/cyclades.c ++++ b/drivers/char/cyclades.c +@@ -4195,3 +4195,4 @@ module_exit(cy_cleanup_module); + MODULE_LICENSE("GPL"); + MODULE_VERSION(CY_VERSION); + MODULE_ALIAS_CHARDEV_MAJOR(CYCLADES_MAJOR); ++MODULE_FIRMWARE("cyzfirm.bin"); +--- a/drivers/char/ip2/ip2main.c ++++ b/drivers/char/ip2/ip2main.c +@@ -3196,3 +3196,5 @@ static struct pci_device_id ip2main_pci_tbl[] __devinitdata = { + }; + + MODULE_DEVICE_TABLE(pci, ip2main_pci_tbl); ++ ++MODULE_FIRMWARE("intelliport2.bin"); +--- a/drivers/char/isicom.c ++++ b/drivers/char/isicom.c +@@ -1720,3 +1720,8 @@ module_exit(isicom_exit); + MODULE_AUTHOR("MultiTech"); + MODULE_DESCRIPTION("Driver for the ISI series of cards by MultiTech"); + MODULE_LICENSE("GPL"); ++MODULE_FIRMWARE("isi608.bin"); ++MODULE_FIRMWARE("isi608em.bin"); ++MODULE_FIRMWARE("isi616em.bin"); ++MODULE_FIRMWARE("isi4608.bin"); ++MODULE_FIRMWARE("isi4616.bin"); +--- a/drivers/char/moxa.c ++++ b/drivers/char/moxa.c +@@ -172,6 +172,9 @@ static unsigned int numports[MAX_BOARDS]; + MODULE_AUTHOR("William Chen"); + MODULE_DESCRIPTION("MOXA Intellio Family Multiport Board Device Driver"); + MODULE_LICENSE("GPL"); ++MODULE_FIRMWARE("c218tunx.cod"); ++MODULE_FIRMWARE("cp204unx.cod"); ++MODULE_FIRMWARE("c320tunx.cod"); + #ifdef MODULE + module_param_array(type, uint, NULL, 0); + MODULE_PARM_DESC(type, "card type: C218=2, C320=4"); +--- a/drivers/serial/icom.c ++++ b/drivers/serial/icom.c +@@ -1654,4 +1654,6 @@ MODULE_DESCRIPTION("IBM iSeries Serial IOA driver"); + MODULE_SUPPORTED_DEVICE + ("IBM iSeries 2745, 2771, 2772, 2742, 2793 and 2805 Communications adapters"); + MODULE_LICENSE("GPL"); +- ++MODULE_FIRMWARE("icom_call_setup.bin"); ++MODULE_FIRMWARE("icom_res_dce.bin"); ++MODULE_FIRMWARE("icom_asc.bin"); +--- a/drivers/usb/serial/keyspan_pda.c ++++ b/drivers/usb/serial/keyspan_pda.c +@@ -789,6 +789,13 @@ static int keyspan_pda_fake_startup(struct usb_serial *serial) + return 1; + } + ++#ifdef KEYSPAN ++MODULE_FIRMWARE("keyspan_pda/keyspan_pda.fw"); ++#endif ++#ifdef XIRCOM ++MODULE_FIRMWARE("keyspan_pda/xircom_pgs.fw"); ++#endif ++ + static int keyspan_pda_startup(struct usb_serial *serial) + { + diff --git a/debian/patches/features/all/module-firmware/0026-staging-declare-MODULE_FIRMWARE-in-various-drivers.patch b/debian/patches/features/all/module-firmware/0026-staging-declare-MODULE_FIRMWARE-in-various-drivers.patch new file mode 100644 index 000000000..4f423034f --- /dev/null +++ b/debian/patches/features/all/module-firmware/0026-staging-declare-MODULE_FIRMWARE-in-various-drivers.patch @@ -0,0 +1,97 @@ +Based on: + +From: Ben Hutchings +Subject: [PATCH] staging: declare MODULE_FIRMWARE in various drivers + +--- a/drivers/staging/comedi/drivers/jr3_pci.c ++++ b/drivers/staging/comedi/drivers/jr3_pci.c +@@ -954,6 +954,8 @@ out: + return result; + } + ++MODULE_FIRMWARE("comedi/jr3pci.idm"); ++ + static int jr3_pci_detach(struct comedi_device *dev) + { + int i; +--- a/drivers/staging/go7007/go7007-driver.c ++++ b/drivers/staging/go7007/go7007-driver.c +@@ -128,6 +128,8 @@ static int go7007_load_encoder(struct go7007 *go) + return rv; + } + ++MODULE_FIRMWARE("go7007fw.bin"); ++ + /* + * Boot the encoder and register the I2C adapter if requested. Do the + * minimum initialization necessary, since the board-specific code may +--- a/drivers/staging/go7007/go7007-usb.c ++++ b/drivers/staging/go7007/go7007-usb.c +@@ -444,6 +444,8 @@ static struct go7007_usb_board board_sensoray_2250 = { + }, + }; + ++MODULE_FIRMWARE("go7007tv.bin"); ++ + static struct usb_device_id go7007_usb_id_table[] = { + { + .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION | +--- a/drivers/staging/go7007/saa7134-go7007.c ++++ b/drivers/staging/go7007/saa7134-go7007.c +@@ -84,6 +84,7 @@ static struct go7007_board_info board_voyager = { + }, + }, + }; ++MODULE_FIRMWARE("go7007tv.bin"); + + /********************* Driver for GPIO HPI interface *********************/ + +--- a/drivers/staging/rtl8192e/r819xE_firmware.c ++++ b/drivers/staging/rtl8192e/r819xE_firmware.c +@@ -365,3 +365,7 @@ download_firmware_fail: + return rt_status; + + } ++ ++MODULE_FIRMWARE("RTL8192E/boot.img"); ++MODULE_FIRMWARE("RTL8192E/main.img"); ++MODULE_FIRMWARE("RTL8192E/data.img"); +--- a/drivers/staging/rtl8192su/r8192S_firmware.c ++++ b/drivers/staging/rtl8192su/r8192S_firmware.c +@@ -538,3 +538,4 @@ bool FirmwareDownload92S(struct net_device *dev) + return rtStatus; + } + ++MODULE_FIRMWARE("RTL8192SU/rtl8192sfw.bin"); +--- a/drivers/staging/slicoss/slicoss.c ++++ b/drivers/staging/slicoss/slicoss.c +@@ -1866,6 +1866,9 @@ static int slic_card_download_gbrcv(struct adapter *adapter) + return 0; + } + ++MODULE_FIRMWARE("slicoss/oasisrcvucode.sys"); ++MODULE_FIRMWARE("slicoss/gbrcvucode.sys"); ++ + static int slic_card_download(struct adapter *adapter) + { + const struct firmware *fw; +@@ -1977,6 +1980,9 @@ static int slic_card_download(struct adapter *adapter) + return STATUS_SUCCESS; + } + ++MODULE_FIRMWARE("slicoss/oasisdownload.sys"); ++MODULE_FIRMWARE("slicoss/gbdownload.sys"); ++ + static void slic_adapter_set_hwaddr(struct adapter *adapter) + { + struct sliccard *card = adapter->card; +--- a/drivers/staging/wlan-ng/prism2fw.c ++++ b/drivers/staging/wlan-ng/prism2fw.c +@@ -53,6 +53,7 @@ + /* Local Constants */ + + #define PRISM2_USB_FWFILE "prism2_ru.fw" ++MODULE_FIRMWARE(PRISM2_USB_FWFILE); + + #define S3DATA_MAX 5000 + #define S3PLUG_MAX 200 diff --git a/debian/patches/features/all/module-firmware/0027-sep-include-driver-name-in-firmware-filenames.patch b/debian/patches/features/all/module-firmware/0027-sep-include-driver-name-in-firmware-filenames.patch new file mode 100644 index 000000000..789841e23 --- /dev/null +++ b/debian/patches/features/all/module-firmware/0027-sep-include-driver-name-in-firmware-filenames.patch @@ -0,0 +1,29 @@ +From 9210aeb3bd3ad862f2063b7128ba4b33799b4092 Mon Sep 17 00:00:00 2001 +From: Ben Hutchings +Date: Sat, 7 Nov 2009 20:09:26 +0000 +Subject: [PATCH] sep: include driver name in firmware filenames + +The current names "cache.image.bin" and "resident.image.bin" are far +too generic. +--- + drivers/staging/sep/sep_driver.c | 4 ++-- + 1 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/staging/sep/sep_driver.c b/drivers/staging/sep/sep_driver.c +index e7bc9ec..6b763b7 100644 +--- a/drivers/staging/sep/sep_driver.c ++++ b/drivers/staging/sep/sep_driver.c +@@ -182,8 +182,8 @@ static DECLARE_WAIT_QUEUE_HEAD(sep_event); + static int sep_load_firmware(struct sep_device *sep) + { + const struct firmware *fw; +- char *cache_name = "cache.image.bin"; +- char *res_name = "resident.image.bin"; ++ char *cache_name = "sep/cache.image.bin"; ++ char *res_name = "sep/resident.image.bin"; + int error; + + edbg("SEP Driver:rar_virtual is %p\n", sep->rar_addr); +-- +1.6.6 + diff --git a/debian/patches/features/all/module-firmware/0028-sep-declare-MODULE_FIRMWARE.patch b/debian/patches/features/all/module-firmware/0028-sep-declare-MODULE_FIRMWARE.patch new file mode 100644 index 000000000..4c06ba3de --- /dev/null +++ b/debian/patches/features/all/module-firmware/0028-sep-declare-MODULE_FIRMWARE.patch @@ -0,0 +1,26 @@ +From 94820c94108bf46801939d3e342e9a07a81da64e Mon Sep 17 00:00:00 2001 +From: Ben Hutchings +Date: Sat, 7 Nov 2009 20:10:23 +0000 +Subject: [PATCH] sep: declare MODULE_FIRMWARE + +--- + drivers/staging/sep/sep_driver.c | 3 +++ + 1 files changed, 3 insertions(+), 0 deletions(-) + +diff --git a/drivers/staging/sep/sep_driver.c b/drivers/staging/sep/sep_driver.c +index 6b763b7..916a9c1 100644 +--- a/drivers/staging/sep/sep_driver.c ++++ b/drivers/staging/sep/sep_driver.c +@@ -222,6 +222,9 @@ static int sep_load_firmware(struct sep_device *sep) + return 0; + } + ++MODULE_FIRMWARE("sep/cache.image.bin"); ++MODULE_FIRMWARE("sep/resident.image.bin"); ++ + /** + * sep_map_and_alloc_shared_area - allocate shared block + * @sep: security processor +-- +1.6.6 + diff --git a/debian/patches/features/all/module-firmware/0029-isight-firmware-declare-MODULE_FIRMWARE.patch b/debian/patches/features/all/module-firmware/0029-isight-firmware-declare-MODULE_FIRMWARE.patch new file mode 100644 index 000000000..548c290bd --- /dev/null +++ b/debian/patches/features/all/module-firmware/0029-isight-firmware-declare-MODULE_FIRMWARE.patch @@ -0,0 +1,25 @@ +From 34e37eaacc94a27d50151d1ab4fae67f1c3ffda5 Mon Sep 17 00:00:00 2001 +From: Ben Hutchings +Date: Sat, 7 Nov 2009 20:21:37 +0000 +Subject: [PATCH] isight-firmware: declare MODULE_FIRMWARE + +--- + drivers/usb/misc/isight_firmware.c | 2 ++ + 1 files changed, 2 insertions(+), 0 deletions(-) + +diff --git a/drivers/usb/misc/isight_firmware.c b/drivers/usb/misc/isight_firmware.c +index b897f65..1a88e27 100644 +--- a/drivers/usb/misc/isight_firmware.c ++++ b/drivers/usb/misc/isight_firmware.c +@@ -112,6 +112,8 @@ out: + return ret; + } + ++MODULE_FIRMWARE("isight.fw"); ++ + static void isight_firmware_disconnect(struct usb_interface *intf) + { + } +-- +1.6.6 + diff --git a/debian/patches/series/base b/debian/patches/series/base index 6f371bcc7..c50cf85a0 100644 --- a/debian/patches/series/base +++ b/debian/patches/series/base @@ -15,6 +15,12 @@ + features/all/r8169-rtl8168d-1-2-request_firmware-2.patch + features/all/sound-pci-cs46xx-request_firmware.patch ++ features/all/module-firmware/0025-tty-declare-MODULE_FIRMWARE-in-various-drivers.patch ++ features/all/module-firmware/0026-staging-declare-MODULE_FIRMWARE-in-various-drivers.patch ++ features/all/module-firmware/0027-sep-include-driver-name-in-firmware-filenames.patch ++ features/all/module-firmware/0028-sep-declare-MODULE_FIRMWARE.patch ++ features/all/module-firmware/0029-isight-firmware-declare-MODULE_FIRMWARE.patch + # FIXME: 2.6.33 tree # patches from aufs2 repository, with s/EXPORT_SYMBOL/&_GPL/ From e85eebcdbb112163285011619302d5d566e73879 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Thu, 18 Feb 2010 14:10:37 +0000 Subject: [PATCH 08/71] Update cxusb Kconfig selection fixes for 2.6.33 svn path=/dists/trunk/linux-2.6/; revision=15192 --- ...-required-frontend-and-tuner-modules.patch | 35 +++++++++++++++++++ .../all/cxusb-dont-select-lgs8gl5.patch | 10 ------ .../bugfix/all/cxusb-select-lgs8gxx.patch | 10 ------ debian/patches/series/base | 4 +-- 4 files changed, 36 insertions(+), 23 deletions(-) create mode 100644 debian/patches/bugfix/all/cxusb-Select-all-required-frontend-and-tuner-modules.patch delete mode 100644 debian/patches/bugfix/all/cxusb-dont-select-lgs8gl5.patch delete mode 100644 debian/patches/bugfix/all/cxusb-select-lgs8gxx.patch diff --git a/debian/patches/bugfix/all/cxusb-Select-all-required-frontend-and-tuner-modules.patch b/debian/patches/bugfix/all/cxusb-Select-all-required-frontend-and-tuner-modules.patch new file mode 100644 index 000000000..a1e184e4c --- /dev/null +++ b/debian/patches/bugfix/all/cxusb-Select-all-required-frontend-and-tuner-modules.patch @@ -0,0 +1,35 @@ +Subject: [PATCH] cxusb: Select all required frontend and tuner modules +From: Ben Hutchings +Date: Thu, 11 Feb 2010 02:57:18 +0000 + +cxusb uses the atbm8830 and lgs8gxx (not lgs8gl5) frontends and the +max2165 tuner, so it needs to select them. + +Signed-off-by: Ben Hutchings +Cc: stable@kernel.org +--- + drivers/media/dvb/dvb-usb/Kconfig | 4 +++- + 1 files changed, 3 insertions(+), 1 deletions(-) + +diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig +index 1b24989..465295b 100644 +--- a/drivers/media/dvb/dvb-usb/Kconfig ++++ b/drivers/media/dvb/dvb-usb/Kconfig +@@ -112,11 +112,13 @@ config DVB_USB_CXUSB + select DVB_MT352 if !DVB_FE_CUSTOMISE + select DVB_ZL10353 if !DVB_FE_CUSTOMISE + select DVB_DIB7000P if !DVB_FE_CUSTOMISE +- select DVB_LGS8GL5 if !DVB_FE_CUSTOMISE + select DVB_TUNER_DIB0070 if !DVB_FE_CUSTOMISE ++ select DVB_ATBM8830 if !DVB_FE_CUSTOMISE ++ select DVB_LGS8GXX if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_XC2028 if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE ++ select MEDIA_TUNER_MAX2165 if !MEDIA_TUNER_CUSTOMISE + help + Say Y here to support the Conexant USB2.0 hybrid reference design. + Currently, only DVB and ATSC modes are supported, analog mode +-- +1.6.6 + diff --git a/debian/patches/bugfix/all/cxusb-dont-select-lgs8gl5.patch b/debian/patches/bugfix/all/cxusb-dont-select-lgs8gl5.patch deleted file mode 100644 index 7786a63cf..000000000 --- a/debian/patches/bugfix/all/cxusb-dont-select-lgs8gl5.patch +++ /dev/null @@ -1,10 +0,0 @@ ---- a/drivers/media/dvb/dvb-usb/Kconfig -+++ b/drivers/media/dvb/dvb-usb/Kconfig -@@ -112,7 +112,6 @@ - select DVB_MT352 if !DVB_FE_CUSTOMISE - select DVB_ZL10353 if !DVB_FE_CUSTOMISE - select DVB_DIB7000P if !DVB_FE_CUSTOMISE -- select DVB_LGS8GL5 if !DVB_FE_CUSTOMISE - select DVB_LGS8GXX if !DVB_FE_CUSTOMISE - select DVB_TUNER_DIB0070 if !DVB_FE_CUSTOMISE - select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMISE diff --git a/debian/patches/bugfix/all/cxusb-select-lgs8gxx.patch b/debian/patches/bugfix/all/cxusb-select-lgs8gxx.patch deleted file mode 100644 index cf4674031..000000000 --- a/debian/patches/bugfix/all/cxusb-select-lgs8gxx.patch +++ /dev/null @@ -1,10 +0,0 @@ ---- a/drivers/media/dvb/dvb-usb/Kconfig -+++ b/drivers/media/dvb/dvb-usb/Kconfig -@@ -113,6 +113,7 @@ - select DVB_ZL10353 if !DVB_FE_CUSTOMISE - select DVB_DIB7000P if !DVB_FE_CUSTOMISE - select DVB_LGS8GL5 if !DVB_FE_CUSTOMISE -+ select DVB_LGS8GXX if !DVB_FE_CUSTOMISE - select DVB_TUNER_DIB0070 if !DVB_FE_CUSTOMISE - select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_XC2028 if !MEDIA_TUNER_CUSTOMISE diff --git a/debian/patches/series/base b/debian/patches/series/base index c50cf85a0..43fa1fbe9 100644 --- a/debian/patches/series/base +++ b/debian/patches/series/base @@ -61,8 +61,8 @@ #+ features/all/rt3090sta-use-request_firmware.patch #+ features/all/input-alps-add-support-for-touchpads-with-4-directional-button-2.patch ++ bugfix/all/cxusb-Select-all-required-frontend-and-tuner-modules.patch -+ bugfix/all/cxusb-select-lgs8gxx.patch # FIXME: #+ bugfix/x86/kvm-pit-control-word-is-write-only.patch #+ bugfix/x86/kvm-fix-memory-access-during-x86-emulation.patch @@ -70,7 +70,5 @@ #+ bugfix/x86/kvm-Fix-popf-emulation.patch #+ bugfix/x86/kvm-Check-CPL-level-during-privilege-instruction-emulation.patch - -+ bugfix/all/cxusb-dont-select-lgs8gl5.patch + debian/sysrq-mask.patch + bugfix/all/efifb_fix_v2.patch From f080ccd8c7aa9e6910f3df1d2cfbdce7bef21e92 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Thu, 18 Feb 2010 14:12:00 +0000 Subject: [PATCH 09/71] Remove commented-out references to obsolete patches svn path=/dists/trunk/linux-2.6/; revision=15193 --- debian/patches/series/base | 4 ---- 1 file changed, 4 deletions(-) diff --git a/debian/patches/series/base b/debian/patches/series/base index 43fa1fbe9..e17e94217 100644 --- a/debian/patches/series/base +++ b/debian/patches/series/base @@ -55,10 +55,6 @@ + bugfix/all/drm-i915-disable-powersave.patch # FIXME: -#- features/all/drivers-staging-rt28x0sta-request_firmware.patch -#+ features/all/rt28x0sta-constify-RTUSBMultiWrite-RTUSBFirmwareWrite.patch -#+ features/all/rt28x0sta-use-request_firmware.patch -#+ features/all/rt3090sta-use-request_firmware.patch #+ features/all/input-alps-add-support-for-touchpads-with-4-directional-button-2.patch + bugfix/all/cxusb-Select-all-required-frontend-and-tuner-modules.patch From b5cb9fb9489dd10ffaa90effdd36d1ed1f79b252 Mon Sep 17 00:00:00 2001 From: Maximilian Attems Date: Thu, 18 Feb 2010 16:47:58 +0000 Subject: [PATCH 10/71] Revert "Fix patch context for 2.6.33-rc8" this applies to 2.6.33-rc8, so this reverts commit c20fd20178e727e31442527c886204ec6ff50fd1. svn path=/dists/trunk/linux-2.6/; revision=15196 --- .../debian/scripts-kconfig-reportoldconfig.patch | 3 ++- .../features/all/speakup/speakup-kbuild.patch | 14 +++++++------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/debian/patches/debian/scripts-kconfig-reportoldconfig.patch b/debian/patches/debian/scripts-kconfig-reportoldconfig.patch index ef3b86484..89185f836 100644 --- a/debian/patches/debian/scripts-kconfig-reportoldconfig.patch +++ b/debian/patches/debian/scripts-kconfig-reportoldconfig.patch @@ -11,7 +11,7 @@ index 999e8a7..3b5d4ba 100644 ifdef KBUILD_KCONFIG Kconfig := $(KBUILD_KCONFIG) -@@ -26,9 +26,15 @@ config: $(obj)/conf +@@ -26,10 +26,16 @@ config: $(obj)/conf oldconfig: $(obj)/conf $< -o $(Kconfig) @@ -19,6 +19,7 @@ index 999e8a7..3b5d4ba 100644 + $< -R $(Kconfig) + silentoldconfig: $(obj)/conf + $(Q)mkdir -p include/generated $< -s $(Kconfig) +updateoldconfig: $(obj)/conf diff --git a/debian/patches/features/all/speakup/speakup-kbuild.patch b/debian/patches/features/all/speakup/speakup-kbuild.patch index 565daf859..aec7a485a 100644 --- a/debian/patches/features/all/speakup/speakup-kbuild.patch +++ b/debian/patches/features/all/speakup/speakup-kbuild.patch @@ -3,10 +3,10 @@ Subject: [PATCH] speakup: integrate into kbuild --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig -@@ -124,6 +124,8 @@ - source "drivers/staging/sep/Kconfig" +@@ -126,6 +126,8 @@ + source "drivers/staging/netwave/Kconfig" - source "drivers/staging/iio/Kconfig" + source "drivers/staging/sm7xx/Kconfig" + +source "drivers/staging/speakup/Kconfig" @@ -14,10 +14,10 @@ Subject: [PATCH] speakup: integrate into kbuild endif # STAGING --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile -@@ -44,3 +44,4 @@ - obj-$(CONFIG_RAR_REGISTER) += rar/ - obj-$(CONFIG_DX_SEP) += sep/ - obj-$(CONFIG_IIO) += iio/ +@@ -45,3 +45,4 @@ + obj-$(CONFIG_PCMCIA_WAVELAN) += wavelan/ + obj-$(CONFIG_PCMCIA_NETWAVE) += netwave/ + obj-$(CONFIG_FB_SM7XX) += sm7xx/ +obj-$(CONFIG_SPEAKUP) += speakup/ --- a/drivers/staging/speakup/Kbuild +++ b/drivers/staging/speakup/Kbuild From dab4a833c2e1cddfa30a017a29085ec29e0f4e4d Mon Sep 17 00:00:00 2001 From: Maximilian Attems Date: Thu, 18 Feb 2010 16:55:46 +0000 Subject: [PATCH 11/71] drop squeeze workaround as suggested by Ben Hutchings. svn path=/dists/trunk/linux-2.6/; revision=15197 --- .../all/drm-i915-disable-powersave.patch | 28 ------------------- debian/patches/series/base | 1 - 2 files changed, 29 deletions(-) delete mode 100644 debian/patches/bugfix/all/drm-i915-disable-powersave.patch diff --git a/debian/patches/bugfix/all/drm-i915-disable-powersave.patch b/debian/patches/bugfix/all/drm-i915-disable-powersave.patch deleted file mode 100644 index 3f044bf43..000000000 --- a/debian/patches/bugfix/all/drm-i915-disable-powersave.patch +++ /dev/null @@ -1,28 +0,0 @@ -From 3d8aef4fa23bfed8ba72442eb2845d3ee17dcdf5 Mon Sep 17 00:00:00 2001 -From: Julien Cristau -Date: Wed, 13 Jan 2010 18:56:00 +0000 -Subject: [PATCH] i915: disable powersave by default - -It's b0rked in 2.6.32, at least on 945GM. - -Fixes http://bugs.debian.org/564807 among others. ---- - drivers/gpu/drm/i915/i915_drv.c | 2 +- - 1 files changed, 1 insertions(+), 1 deletions(-) - -diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c -index 7f436ec..8ac8abc 100644 ---- a/drivers/gpu/drm/i915/i915_drv.c -+++ b/drivers/gpu/drm/i915/i915_drv.c -@@ -43,7 +43,7 @@ module_param_named(modeset, i915_modeset, int, 0400); - unsigned int i915_fbpercrtc = 0; - module_param_named(fbpercrtc, i915_fbpercrtc, int, 0400); - --unsigned int i915_powersave = 1; -+unsigned int i915_powersave = 0; - module_param_named(powersave, i915_powersave, int, 0400); - - static struct drm_driver driver; --- -1.6.6 - diff --git a/debian/patches/series/base b/debian/patches/series/base index e17e94217..f41958677 100644 --- a/debian/patches/series/base +++ b/debian/patches/series/base @@ -53,7 +53,6 @@ + bugfix/ia64/ia64-Include-linux-personality.h-header-in-asm-fcntl.patch -+ bugfix/all/drm-i915-disable-powersave.patch # FIXME: #+ features/all/input-alps-add-support-for-touchpads-with-4-directional-button-2.patch From b8657a348ece9f07750e3d074ce6dbdd38659944 Mon Sep 17 00:00:00 2001 From: Maximilian Attems Date: Thu, 18 Feb 2010 18:19:08 +0000 Subject: [PATCH 12/71] nuke stray patch merged 2.6.33-rc1 noticed by Julien Cristau svn path=/dists/trunk/linux-2.6/; revision=15199 --- ...ntel-agp-Clear-entire-GTT-on-startup.patch | 59 ------------------- 1 file changed, 59 deletions(-) delete mode 100644 debian/patches/bugfix/all/intel-agp-Clear-entire-GTT-on-startup.patch diff --git a/debian/patches/bugfix/all/intel-agp-Clear-entire-GTT-on-startup.patch b/debian/patches/bugfix/all/intel-agp-Clear-entire-GTT-on-startup.patch deleted file mode 100644 index b7b2ee610..000000000 --- a/debian/patches/bugfix/all/intel-agp-Clear-entire-GTT-on-startup.patch +++ /dev/null @@ -1,59 +0,0 @@ -From fc61901373987ad61851ed001fe971f3ee8d96a3 Mon Sep 17 00:00:00 2001 -From: David Woodhouse -Date: Wed, 2 Dec 2009 11:00:05 +0000 -Subject: [PATCH] agp/intel-agp: Clear entire GTT on startup - -Some BIOSes fail to initialise the GTT, which will cause DMA faults when -the IOMMU is enabled. We need to clear the whole thing to point at the -scratch page, not just the part that Linux is going to use. - -Signed-off-by: David Woodhouse -[anholt: Note that this may also help with stability in the presence of -driver bugs, by not drawing to memory we don't own] -Signed-off-by: Eric Anholt ---- - drivers/char/agp/intel-agp.c | 7 ++++++- - 1 files changed, 6 insertions(+), 1 deletions(-) - -diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c -index 37cb4e2..33b4853 100644 ---- a/drivers/char/agp/intel-agp.c -+++ b/drivers/char/agp/intel-agp.c -@@ -176,6 +176,7 @@ static struct _intel_private { - * popup and for the GTT. - */ - int gtt_entries; /* i830+ */ -+ int gtt_total_size; - union { - void __iomem *i9xx_flush_page; - void *i8xx_flush_page; -@@ -1151,7 +1152,7 @@ static int intel_i915_configure(void) - readl(intel_private.registers+I810_PGETBL_CTL); /* PCI Posting. */ - - if (agp_bridge->driver->needs_scratch_page) { -- for (i = intel_private.gtt_entries; i < current_size->num_entries; i++) { -+ for (i = intel_private.gtt_entries; i < intel_private.gtt_total_size; i++) { - writel(agp_bridge->scratch_page, intel_private.gtt+i); - } - readl(intel_private.gtt+i-1); /* PCI Posting. */ -@@ -1312,6 +1313,8 @@ static int intel_i915_create_gatt_table(struct agp_bridge_data *bridge) - if (!intel_private.gtt) - return -ENOMEM; - -+ intel_private.gtt_total_size = gtt_map_size / 4; -+ - temp &= 0xfff80000; - - intel_private.registers = ioremap(temp, 128 * 4096); -@@ -1398,6 +1401,8 @@ static int intel_i965_create_gatt_table(struct agp_bridge_data *bridge) - if (!intel_private.gtt) - return -ENOMEM; - -+ intel_private.gtt_total_size = gtt_size / 4; -+ - intel_private.registers = ioremap(temp, 128 * 4096); - if (!intel_private.registers) { - iounmap(intel_private.gtt); --- -1.6.5.7 - From d88a3c35f3a9409dc5ad0d1b47a589de5fdc8e2c Mon Sep 17 00:00:00 2001 From: Maximilian Attems Date: Thu, 18 Feb 2010 18:23:53 +0000 Subject: [PATCH 13/71] clear confusion on old rt28x0sta patches use updated one, nuke old one. svn path=/dists/trunk/linux-2.6/; revision=15200 --- ...s-staging-rt28x0sta-request_firmware.patch | 211 ------------------ debian/patches/series/base | 2 +- 2 files changed, 1 insertion(+), 212 deletions(-) delete mode 100644 debian/patches/features/all/drivers-staging-rt28x0sta-request_firmware.patch diff --git a/debian/patches/features/all/drivers-staging-rt28x0sta-request_firmware.patch b/debian/patches/features/all/drivers-staging-rt28x0sta-request_firmware.patch deleted file mode 100644 index c143f69eb..000000000 --- a/debian/patches/features/all/drivers-staging-rt28x0sta-request_firmware.patch +++ /dev/null @@ -1,211 +0,0 @@ -From 3b25874ebf3f8a675da0e2a2ae358f76ae67141d Mon Sep 17 00:00:00 2001 -From: Ben Hutchings -Date: Sun, 28 Jun 2009 15:51:07 +0100 -Subject: [PATCH 08/24] rt2860/2870/3070: use the firmware loader interface and library CRC code - -Based on work by Darren Salt . ---- - drivers/staging/rt2860/Kconfig | 3 +- - drivers/staging/rt2860/common/rtmp_init.c | 100 ++++++++++++++++++----------- - drivers/staging/rt2870/Kconfig | 3 +- - drivers/staging/rt3090/Kconfig | 2 + - 4 files changed, 68 insertions(+), 40 deletions(-) - -diff --git a/drivers/staging/rt2860/Kconfig b/drivers/staging/rt2860/Kconfig -index 6dff527..b98aba7 100644 ---- a/drivers/staging/rt2860/Kconfig -+++ b/drivers/staging/rt2860/Kconfig -@@ -1,6 +1,7 @@ - config RT2860 - tristate "Ralink 2860 wireless support" -- depends on BROKEN - depends on PCI && X86 && WLAN -+ select CRC_CCITT -+ select FW_LOADER - ---help--- - This is an experimental driver for the Ralink 2860 wireless chip. -diff --git a/drivers/staging/rt2860/common/rtmp_init.c b/drivers/staging/rt2860/common/rtmp_init.c -index 20c2ce2..916be2f 100644 ---- a/drivers/staging/rt2860/common/rtmp_init.c -+++ b/drivers/staging/rt2860/common/rtmp_init.c -@@ -38,14 +38,8 @@ - Jan Lee 2006-09-15 RT2860. Change for 802.11n , EEPROM, Led, BA, HT. - */ - #include "../rt_config.h" --#ifdef RT2860 --#include "firmware.h" --#include --#endif --#ifdef RT2870 --/* New firmware handles both RT2870 and RT3070. */ --#include "../../rt3070/firmware.h" --#endif -+#include -+#include - - UCHAR BIT8[] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80}; - ULONG BIT32[] = {0x00000001, 0x00000002, 0x00000004, 0x00000008, -@@ -178,12 +172,14 @@ RTMP_REG_PAIR STAMACRegTable[] = { - // RT2870 Firmware Spec only used 1 oct for version expression - // - #define FIRMWARE_MINOR_VERSION 7 -- -+#define FW_FILENAME_V1 "rt2870.bin" -+#define FW_FILENAME_V2 "rt3071.bin" -+MODULE_FIRMWARE(FW_FILENAME_V1); -+MODULE_FIRMWARE(FW_FILENAME_V2); - #endif // RT2870 // - - // New 8k byte firmware size for RT3071/RT3072 - #define FIRMWAREIMAGE_MAX_LENGTH 0x2000 --#define FIRMWAREIMAGE_LENGTH (sizeof (FirmwareImage) / sizeof(UCHAR)) - #define FIRMWARE_MAJOR_VERSION 0 - - #define FIRMWAREIMAGEV1_LENGTH 0x1000 -@@ -191,6 +187,8 @@ RTMP_REG_PAIR STAMACRegTable[] = { - - #ifdef RT2860 - #define FIRMWARE_MINOR_VERSION 2 -+#define FW_FILENAME "rt2860.bin" -+MODULE_FIRMWARE(FW_FILENAME); - #endif - - -@@ -2976,45 +2974,65 @@ NDIS_STATUS NICLoadFirmware( - IN PRTMP_ADAPTER pAd) - { - NDIS_STATUS Status = NDIS_STATUS_SUCCESS; -- PUCHAR pFirmwareImage; - ULONG FileLength, Index; -- //ULONG firm; - UINT32 MacReg = 0; - #ifdef RT2870 - UINT32 Version = (pAd->MACVersion >> 16); - #endif // RT2870 // -+ struct device *dev; -+ const struct firmware *fw = NULL; -+ const char *name; -+ int err; - -- pFirmwareImage = FirmwareImage; -- FileLength = sizeof(FirmwareImage); -+#ifdef RT2860 -+ dev = &((POS_COOKIE)pAd->OS_Cookie)->pci_dev->dev; -+ name = FW_FILENAME; -+ FileLength = MAX_FIRMWARE_IMAGE_SIZE; -+#endif - #ifdef RT2870 -- // New 8k byte firmware size for RT3071/RT3072 -- //printk("Usb Chip\n"); -- if (FIRMWAREIMAGE_LENGTH == FIRMWAREIMAGE_MAX_LENGTH) -- //The firmware image consists of two parts. One is the origianl and the other is the new. -- //Use Second Part -- { -- if ((Version != 0x2860) && (Version != 0x2872) && (Version != 0x3070)) -- { // Use Firmware V2. -- //printk("KH:Use New Version,part2\n"); -- pFirmwareImage = (PUCHAR)&FirmwareImage[FIRMWAREIMAGEV1_LENGTH]; -- FileLength = FIRMWAREIMAGEV2_LENGTH; -- } -- else -- { -- //printk("KH:Use New Version,part1\n"); -- pFirmwareImage = FirmwareImage; -- FileLength = FIRMWAREIMAGEV1_LENGTH; -- } -+ dev = &((POS_COOKIE)pAd->OS_Cookie)->pUsb_Dev->dev; -+ if (Version == 0x2860 || Version == 0x2872 || Version == 0x3070) { -+ name = FW_FILENAME_V1; -+ FileLength = FIRMWAREIMAGEV1_LENGTH; -+ } else { -+ name = FW_FILENAME_V2; -+ FileLength = FIRMWAREIMAGEV2_LENGTH; - } -- else -- { -- DBGPRINT(RT_DEBUG_ERROR, ("KH: bin file should be 8KB.\n")); -- Status = NDIS_STATUS_FAILURE; -+#endif -+ -+ err = request_firmware(&fw, name, dev); -+ if (err) { -+ dev_err(dev, "firmware file %s request failed (%d)\n", -+ name, err); -+ goto fail; - } - --#endif // RT2870 // -+ if (fw->size != FileLength) { -+ dev_err(dev, "firmware file %s size is wrong\n", name); -+ goto fail; -+ } -+ -+ /* is it new enough? */ -+ pAd->FirmwareVersion = (fw->data[fw->size - 4] << 8 | -+ fw->data[fw->size - 3]); - -- RT28XX_WRITE_FIRMWARE(pAd, pFirmwareImage, FileLength); -+ if (pAd->FirmwareVersion < -+ (FIRMWARE_MAJOR_VERSION << 8 | FIRMWARE_MINOR_VERSION)) { -+ dev_err(dev, "rt28x0sta: firmware file %s is too old\n", -+ name); -+ goto fail; -+ } -+ -+ /* is the internal CRC correct? */ -+ if (crc_ccitt(0xffff, fw->data, fw->size - 2) != -+ (fw->data[fw->size - 2] | (fw->data[fw->size - 1] << 8))) { -+ dev_err(dev, "firmware file %s failed internal CRC\n", name); -+ goto fail; -+ } -+ -+ RT28XX_WRITE_FIRMWARE(pAd, fw->data, fw->size); -+ -+ release_firmware(fw); - - /* check if MCU is ready */ - Index = 0; -@@ -3034,9 +3052,15 @@ NDIS_STATUS NICLoadFirmware( - DBGPRINT(RT_DEBUG_ERROR, ("NICLoadFirmware: MCU is not ready\n\n\n")); - } /* End of if */ - -+out: - DBGPRINT(RT_DEBUG_TRACE, - ("<=== %s (status=%d)\n", __func__, Status)); - return Status; -+ -+fail: -+ release_firmware(fw); -+ Status = NDIS_STATUS_FAILURE; -+ goto out; - } /* End of NICLoadFirmware */ - - -diff --git a/drivers/staging/rt2870/Kconfig b/drivers/staging/rt2870/Kconfig -index 05ee373..a0c9eb3 100644 ---- a/drivers/staging/rt2870/Kconfig -+++ b/drivers/staging/rt2870/Kconfig -@@ -1,6 +1,7 @@ - config RT2870 - tristate "Ralink 2870/3070 wireless support" -- depends on BROKEN - depends on USB && X86 && WLAN -+ select CRC_CCITT -+ select FW_LOADER - ---help--- - This is an experimental driver for the Ralink xx70 wireless chips. -diff --git a/drivers/staging/rt3090/Kconfig b/drivers/staging/rt3090/Kconfig -index 8ba68b0..7a59f34 100644 ---- a/drivers/staging/rt3090/Kconfig -+++ b/drivers/staging/rt3090/Kconfig -@@ -2,5 +2,7 @@ config RT3090 - tristate "Ralink 3090 wireless support" - depends on BROKEN - depends on PCI && X86 && WLAN -+ select CRC_CCITT -+ select FW_LOADER - ---help--- - This is an experimental driver for the Ralink 3090 wireless chip. --- -1.6.5.2 - diff --git a/debian/patches/series/base b/debian/patches/series/base index f41958677..af2df820a 100644 --- a/debian/patches/series/base +++ b/debian/patches/series/base @@ -9,7 +9,7 @@ + features/all/drivers-infiniband-hw-ipath-iba7220-use-request_firmware.patch + features/all/drivers-media-dvb-usb-af9005-request_firmware.patch -+ features/all/drivers-staging-rt28x0sta-request_firmware.patch ++ features/all/rt28x0sta-use-request_firmware.patch + features/all/export-unionfs-symbols.patch + features/all/lgs8gxx-lgs8g75-request_firmware.patch + features/all/r8169-rtl8168d-1-2-request_firmware-2.patch From 22bce40804710b463430c26c51203df2c28c362f Mon Sep 17 00:00:00 2001 From: Maximilian Attems Date: Thu, 18 Feb 2010 18:27:12 +0000 Subject: [PATCH 14/71] Revert "Reenable r8169 firmware loader patch" patch not yet updated to 2.6.33-rc8 This reverts commit r15189 or 74c87e625d2d6e2cd0f8ce17420f5b573a778887. svn path=/dists/trunk/linux-2.6/; revision=15201 --- debian/patches/series/base | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/debian/patches/series/base b/debian/patches/series/base index af2df820a..97d2cf1f9 100644 --- a/debian/patches/series/base +++ b/debian/patches/series/base @@ -12,7 +12,8 @@ + features/all/rt28x0sta-use-request_firmware.patch + features/all/export-unionfs-symbols.patch + features/all/lgs8gxx-lgs8g75-request_firmware.patch -+ features/all/r8169-rtl8168d-1-2-request_firmware-2.patch +# FIXME: fails to apply +#+ features/all/r8169-rtl8168d-1-2-request_firmware.patch + features/all/sound-pci-cs46xx-request_firmware.patch + features/all/module-firmware/0025-tty-declare-MODULE_FIRMWARE-in-various-drivers.patch @@ -52,6 +53,8 @@ #+ features/all/i915-autoload-without-CONFIG_DRM_I915_KMS.patch + bugfix/ia64/ia64-Include-linux-personality.h-header-in-asm-fcntl.patch +# FIXME +#+ features/all/r8169-rtl8168d-1-2-request_firmware-2.patch # FIXME: #+ features/all/input-alps-add-support-for-touchpads-with-4-directional-button-2.patch From 6589d8c0a0caab575226b8c8c362967fba017062 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Fri, 19 Feb 2010 00:37:57 +0000 Subject: [PATCH 15/71] Update firmware files to be removed from drivers/staging svn path=/dists/trunk/linux-2.6/; revision=15204 --- debian/patches/debian/dfsg/files-1 | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/debian/patches/debian/dfsg/files-1 b/debian/patches/debian/dfsg/files-1 index 0fa2b765d..c96713c82 100644 --- a/debian/patches/debian/dfsg/files-1 +++ b/debian/patches/debian/dfsg/files-1 @@ -50,19 +50,22 @@ unifdef drivers/net/r8169.c -UREMOVE_DFSG rm drivers/staging/otus/hal/hp*fw*.c* -rm drivers/staging/rt2860/common/firmware.h +rm drivers/staging/rt2860/common/firmware*.h rm drivers/staging/rt3070/firmware.h rm drivers/staging/rt3090/firmware.h -rm drivers/staging/rtl8192su/r8192S_FwImgDTM.h rm drivers/staging/rtl8192su/r8192SU_HWImg.c -rm drivers/staging/rtl8192su/r819xU_firmware_img.c + +rm drivers/staging/rtl8192u/r819xU_firmware_img.c rm drivers/staging/sxg/sxgphycode-1.2.h rm drivers/staging/vt6656/firmware.c +rm drivers/staging/wlags49_h2/ap_*.c +rm drivers/staging/wlags49_h2/sta_*.c + rm sound/pci/cs46xx/cs46xx_image.h rm sound/pci/cs46xx/imgs From 4f7028d8b0b699bb359a5fc5c1bc27789f211686 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Fri, 19 Feb 2010 00:44:35 +0000 Subject: [PATCH 16/71] Remove bugfix/sparc/drivers_net-broken.patch; SPARC32 is broken in general svn path=/dists/trunk/linux-2.6/; revision=15205 --- .../patches/bugfix/sparc/drivers_net-broken.patch | 13 ------------- debian/patches/series/base | 1 - 2 files changed, 14 deletions(-) delete mode 100644 debian/patches/bugfix/sparc/drivers_net-broken.patch diff --git a/debian/patches/bugfix/sparc/drivers_net-broken.patch b/debian/patches/bugfix/sparc/drivers_net-broken.patch deleted file mode 100644 index a3a009def..000000000 --- a/debian/patches/bugfix/sparc/drivers_net-broken.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig -index 8aa8dd0..f3b61ce 100644 ---- a/drivers/net/Kconfig -+++ b/drivers/net/Kconfig -@@ -2484,7 +2484,7 @@ config MYRI10GE - - config NETXEN_NIC - tristate "NetXen Multi port (1/10) Gigabit Ethernet NIC" -- depends on PCI -+ depends on PCI && (!SPARC32 || BROKEN) - help - This enables the support for NetXen's Gigabit Ethernet card. - diff --git a/debian/patches/series/base b/debian/patches/series/base index 97d2cf1f9..295c64ef6 100644 --- a/debian/patches/series/base +++ b/debian/patches/series/base @@ -30,7 +30,6 @@ + features/all/speakup/speakup-add.patch + features/all/speakup/speakup-kbuild.patch -+ bugfix/sparc/drivers_net-broken.patch #+ bugfix/ia64/hardcode-arch-script-output.patch + bugfix/mips/disable-advansys.patch + bugfix/arm/disable-scsi_acard.patch From 5c83dccf90c198c9af927a9d1c44c5f3d6b16c0f Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Fri, 19 Feb 2010 02:00:53 +0000 Subject: [PATCH 17/71] Fix up bugfix/mips/disable-werror.patch for 2.6.33-rc8 svn path=/dists/trunk/linux-2.6/; revision=15206 --- debian/patches/bugfix/mips/disable-werror.patch | 6 ++++-- debian/patches/series/base | 3 +-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/debian/patches/bugfix/mips/disable-werror.patch b/debian/patches/bugfix/mips/disable-werror.patch index 8bf19be6b..efe0664ab 100644 --- a/debian/patches/bugfix/mips/disable-werror.patch +++ b/debian/patches/bugfix/mips/disable-werror.patch @@ -8,8 +8,10 @@ arch/mips/kernel/../../../fs/binfmt_elf.c:1202: warning: ‘word’ may be used --- a/arch/mips/kernel/Makefile 2009-02-16 11:25:13.000000000 +0000 +++ b/arch/mips/kernel/Makefile 2009-02-16 11:25:23.000000000 +0000 -@@ -89,4 +89,3 @@ +@@ -100,6 +100,5 @@ - obj-$(CONFIG_HAVE_STD_PC_SERIAL_PORT) += 8250-platform.o + obj-$(CONFIG_MIPS_CPUFREQ) += cpufreq/ -EXTRA_CFLAGS += -Werror + + CPPFLAGS_vmlinux.lds := $(KBUILD_CFLAGS) diff --git a/debian/patches/series/base b/debian/patches/series/base index 295c64ef6..0f5a19ff7 100644 --- a/debian/patches/series/base +++ b/debian/patches/series/base @@ -33,8 +33,7 @@ #+ bugfix/ia64/hardcode-arch-script-output.patch + bugfix/mips/disable-advansys.patch + bugfix/arm/disable-scsi_acard.patch -# FIXME: no longer applies -#+ bugfix/mips/disable-werror.patch ++ bugfix/mips/disable-werror.patch + bugfix/fix-hifn_795X-divdi3.patch + bugfix/powerpc/mm-mol.patch + bugfix/powerpc/lpar-console.patch From 3312a8a8d2ab0ad3aca4236fcb3bd78816e3a385 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Fri, 19 Feb 2010 02:04:25 +0000 Subject: [PATCH 18/71] Fix up features/all/r8169-rtl8168d-1-2-request_firmware-2.patch for 2.6.33-rc8 svn path=/dists/trunk/linux-2.6/; revision=15207 --- .../all/r8169-rtl8168d-1-2-request_firmware-2.patch | 10 +++++----- debian/patches/series/base | 3 +-- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/debian/patches/features/all/r8169-rtl8168d-1-2-request_firmware-2.patch b/debian/patches/features/all/r8169-rtl8168d-1-2-request_firmware-2.patch index 63a0ca08d..3926b4ac4 100644 --- a/debian/patches/features/all/r8169-rtl8168d-1-2-request_firmware-2.patch +++ b/debian/patches/features/all/r8169-rtl8168d-1-2-request_firmware-2.patch @@ -7,7 +7,7 @@ firmware loader. --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig -@@ -2170,6 +2170,7 @@ config R8169 +@@ -2172,6 +2172,7 @@ config R8169 depends on PCI select CRC32 select MII @@ -48,7 +48,7 @@ firmware loader. + static void rtl8169s_hw_phy_config(void __iomem *ioaddr) { - struct phy_reg phy_reg_init[] = { + static const struct phy_reg phy_reg_init[] = { @@ -1691,7 +1709,7 @@ static void rtl8168c_4_hw_phy_config(void __iomem *ioaddr) rtl8168c_3_hw_phy_config(ioaddr); } @@ -56,7 +56,7 @@ firmware loader. -static void rtl8168d_1_hw_phy_config(void __iomem *ioaddr) +static void rtl8168d_1_hw_phy_config(struct rtl8169_private *tp) { - static struct phy_reg phy_reg_init_0[] = { + static const struct phy_reg phy_reg_init_0[] = { { 0x1f, 0x0001 }, @@ -1719,6 +1737,8 @@ static void rtl8168d_1_hw_phy_config(void __iomem *ioaddr) { 0x05, 0x8332 }, @@ -88,7 +88,7 @@ firmware loader. + +static void rtl8168d_2_hw_phy_config(struct rtl8169_private *tp) { - static struct phy_reg phy_reg_init_0[] = { + static const struct phy_reg phy_reg_init_0[] = { { 0x1f, 0x0001 }, @@ -1808,6 +1836,8 @@ static void rtl8168d_2_hw_phy_config(void __iomem *ioaddr) { 0x05, 0x8332 }, @@ -119,7 +119,7 @@ firmware loader. + static void rtl8168d_3_hw_phy_config(void __iomem *ioaddr) { - struct phy_reg phy_reg_init[] = { + static const struct phy_reg phy_reg_init[] = { @@ -2001,10 +2039,10 @@ static int rtl_hw_phy_config(struct net_device *dev) rtl8168cp_2_hw_phy_config(ioaddr); break; diff --git a/debian/patches/series/base b/debian/patches/series/base index 0f5a19ff7..59427d87f 100644 --- a/debian/patches/series/base +++ b/debian/patches/series/base @@ -12,8 +12,7 @@ + features/all/rt28x0sta-use-request_firmware.patch + features/all/export-unionfs-symbols.patch + features/all/lgs8gxx-lgs8g75-request_firmware.patch -# FIXME: fails to apply -#+ features/all/r8169-rtl8168d-1-2-request_firmware.patch ++ features/all/r8169-rtl8168d-1-2-request_firmware.patch + features/all/sound-pci-cs46xx-request_firmware.patch + features/all/module-firmware/0025-tty-declare-MODULE_FIRMWARE-in-various-drivers.patch From e9c01fc8713046f0ef5e8a55d27edfe3c85c96f1 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Fri, 19 Feb 2010 02:13:30 +0000 Subject: [PATCH 19/71] Remove bugfix/fix-hifn_795X-divdi3.patch; fixed properly upstream in 2.6.25 svn path=/dists/trunk/linux-2.6/; revision=15208 --- .../patches/bugfix/fix-hifn_795X-divdi3.patch | 54 ------------------- debian/patches/series/base | 1 - 2 files changed, 55 deletions(-) delete mode 100644 debian/patches/bugfix/fix-hifn_795X-divdi3.patch diff --git a/debian/patches/bugfix/fix-hifn_795X-divdi3.patch b/debian/patches/bugfix/fix-hifn_795X-divdi3.patch deleted file mode 100644 index 422059dc4..000000000 --- a/debian/patches/bugfix/fix-hifn_795X-divdi3.patch +++ /dev/null @@ -1,54 +0,0 @@ -On Tue, Feb 26, 2008 at 01:21:00PM +0100, Martin Michlmayr wrote: -> With 2.6.25-rc3 and a config file with -> -> CONFIG_CRYPTO_DEV_HIFN_795X=m -> CONFIG_CRYPTO_DEV_HIFN_795X_RNG=y -> -> I get the following build error on at least ARM and MIPS: -> -> Building modules, stage 2. -> MODPOST 759 modules -> ERROR: "__divdi3" [drivers/crypto/hifn_795x.ko] undefined! - -Fix below. - -> Martin Michlmayr - -cu -Adrian - - -<-- snip --> - - -Using ndelay() with a 64bit variable as parameter can result in build -errors like the following on some 32bit systems when it results in a -64bit division: - -<-- snip --> - - ... - MODPOST 759 modules -ERROR: "__divdi3" [drivers/crypto/hifn_795x.ko] undefined! - -<-- snip --> - -Reported by Martin Michlmayr. - -Signed-off-by: Adrian Bunk - ---- - -40b45041ddc587c20b872a86a6a36952c28b02c7 diff --git a/drivers/crypto/hifn_795x.c b/drivers/crypto/hifn_795x.c -index 3110bf7..b1541c6 100644 ---- a/drivers/crypto/hifn_795x.c -+++ b/drivers/crypto/hifn_795x.c -@@ -807,7 +807,7 @@ static int hifn_rng_data_present(struct hwrng *rng, int wait) - return 1; - if (!wait) - return 0; -- ndelay(nsec); -+ ndelay((u32)nsec); - return 1; - } - diff --git a/debian/patches/series/base b/debian/patches/series/base index 59427d87f..b05049662 100644 --- a/debian/patches/series/base +++ b/debian/patches/series/base @@ -33,7 +33,6 @@ + bugfix/mips/disable-advansys.patch + bugfix/arm/disable-scsi_acard.patch + bugfix/mips/disable-werror.patch -+ bugfix/fix-hifn_795X-divdi3.patch + bugfix/powerpc/mm-mol.patch + bugfix/powerpc/lpar-console.patch #+ bugfix/all/wireless-regulatory-default-EU.patch From b0b9c56b31ad36c962d80fbdfa8869abf73d370c Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Fri, 19 Feb 2010 02:27:34 +0000 Subject: [PATCH 20/71] Apply the still-existing version of the r8169 patch svn path=/dists/trunk/linux-2.6/; revision=15209 --- debian/patches/series/base | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/debian/patches/series/base b/debian/patches/series/base index b05049662..af83019f8 100644 --- a/debian/patches/series/base +++ b/debian/patches/series/base @@ -12,7 +12,7 @@ + features/all/rt28x0sta-use-request_firmware.patch + features/all/export-unionfs-symbols.patch + features/all/lgs8gxx-lgs8g75-request_firmware.patch -+ features/all/r8169-rtl8168d-1-2-request_firmware.patch ++ features/all/r8169-rtl8168d-1-2-request_firmware-2.patch + features/all/sound-pci-cs46xx-request_firmware.patch + features/all/module-firmware/0025-tty-declare-MODULE_FIRMWARE-in-various-drivers.patch @@ -49,8 +49,6 @@ #+ features/all/i915-autoload-without-CONFIG_DRM_I915_KMS.patch + bugfix/ia64/ia64-Include-linux-personality.h-header-in-asm-fcntl.patch -# FIXME -#+ features/all/r8169-rtl8168d-1-2-request_firmware-2.patch # FIXME: #+ features/all/input-alps-add-support-for-touchpads-with-4-directional-button-2.patch From a06eaf2f6457144e662c296b88cbfc4a3fcaf933 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Fri, 19 Feb 2010 02:28:30 +0000 Subject: [PATCH 21/71] Fix up features/sparc/video-sunxvr500-intergraph.patch for 2.6.33-rc8 svn path=/dists/trunk/linux-2.6/; revision=15210 --- .../sparc/video-sunxvr500-intergraph.patch | 14 +------------- debian/patches/series/base | 2 +- 2 files changed, 2 insertions(+), 14 deletions(-) diff --git a/debian/patches/features/sparc/video-sunxvr500-intergraph.patch b/debian/patches/features/sparc/video-sunxvr500-intergraph.patch index f56431dde..dc03e6058 100644 --- a/debian/patches/features/sparc/video-sunxvr500-intergraph.patch +++ b/debian/patches/features/sparc/video-sunxvr500-intergraph.patch @@ -5,19 +5,7 @@ diff -aur a/drivers/video/sunxvr500.c b/drivers/video/sunxvr500.c static struct pci_device_id e3d_pci_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_3DLABS, 0x7a0), }, -+ { PCI_DEVICE(PCI_VENDOR_ID_IGRAPH, 0x7a0), }, ++ { PCI_DEVICE(0x1091, 0x7a0), }, { PCI_DEVICE(PCI_VENDOR_ID_3DLABS, 0x7a2), }, { .vendor = PCI_VENDOR_ID_3DLABS, .device = PCI_ANY_ID, -diff -aur a/include/linux/pci_ids.h b/include/linux/pci_ids.h ---- a/include/linux/pci_ids.h 2008-11-20 18:02:37.000000000 -0500 -+++ b/include/linux/pci_ids.h 2008-12-01 15:43:04.000000000 -0500 -@@ -930,6 +930,8 @@ - #define PCI_DEVICE_ID_SUN_TOMATILLO 0xa801 - #define PCI_DEVICE_ID_SUN_CASSINI 0xabba - -+#define PCI_VENDOR_ID_IGRAPH 0x1091 -+ - #define PCI_VENDOR_ID_CMD 0x1095 - #define PCI_DEVICE_ID_CMD_643 0x0643 - #define PCI_DEVICE_ID_CMD_646 0x0646 diff --git a/debian/patches/series/base b/debian/patches/series/base index af83019f8..af7562535 100644 --- a/debian/patches/series/base +++ b/debian/patches/series/base @@ -36,7 +36,7 @@ + bugfix/powerpc/mm-mol.patch + bugfix/powerpc/lpar-console.patch #+ bugfix/all/wireless-regulatory-default-EU.patch -#+ features/sparc/video-sunxvr500-intergraph.patch ++ features/sparc/video-sunxvr500-intergraph.patch + bugfix/all/drivers-scsi-qla1280-request-firmware-unlocked.patch + debian/dfsg/radeon-add-clarifying-comment-to-r600-blit.patch # FIXME: no longer applies From 1464d2624e3377f9685ad80b586ae3ddd9540aec Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Fri, 19 Feb 2010 03:09:21 +0000 Subject: [PATCH 22/71] Remove ARM compression patches applied upstream svn path=/dists/trunk/linux-2.6/; revision=15212 --- .../features/arm/compression-add-lzmo.patch | 51 ---- .../arm/compression-use-generic-gzip.patch | 281 ------------------ debian/patches/series/base | 2 - 3 files changed, 334 deletions(-) delete mode 100644 debian/patches/features/arm/compression-add-lzmo.patch delete mode 100644 debian/patches/features/arm/compression-use-generic-gzip.patch diff --git a/debian/patches/features/arm/compression-add-lzmo.patch b/debian/patches/features/arm/compression-add-lzmo.patch deleted file mode 100644 index f141a95ad..000000000 --- a/debian/patches/features/arm/compression-add-lzmo.patch +++ /dev/null @@ -1,51 +0,0 @@ -diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig -index 95b9905..a42793b 100644 ---- a/arch/arm/Kconfig -+++ b/arch/arm/Kconfig -@@ -19,6 +19,7 @@ config ARM - select HAVE_FUNCTION_TRACER if (!XIP_KERNEL) - select HAVE_GENERIC_DMA_COHERENT - select HAVE_KERNEL_GZIP -+ select HAVE_KERNEL_LZMA - help - The ARM series is a line of low-power-consumption RISC chip designs - licensed by ARM Ltd and targeted at embedded applications and -diff --git a/arch/arm/boot/compressed/Makefile b/arch/arm/boot/compressed/Makefile -index 10f1173..e538d3d 100644 ---- a/arch/arm/boot/compressed/Makefile -+++ b/arch/arm/boot/compressed/Makefile -@@ -64,6 +64,7 @@ endif - SEDFLAGS = s/TEXT_START/$(ZTEXTADDR)/;s/BSS_START/$(ZBSSADDR)/ - - suffix_$(CONFIG_KERNEL_GZIP) = gzip -+suffix_$(CONFIG_KERNEL_LZMA) = lzma - - targets := vmlinux vmlinux.lds \ - piggy.$(suffix_y) piggy.$(suffix_y).o \ -diff --git a/arch/arm/boot/compressed/misc.c b/arch/arm/boot/compressed/misc.c -index 669b1b5..efef261 100644 ---- a/arch/arm/boot/compressed/misc.c -+++ b/arch/arm/boot/compressed/misc.c -@@ -237,6 +237,10 @@ static unsigned long free_mem_end_ptr; - #include "../../../../lib/decompress_inflate.c" - #endif - -+#ifdef CONFIG_KERNEL_LZMA -+#include "../../../../lib/decompress_unlzma.c" -+#endif -+ - #ifndef arch_error - #define arch_error(x) - #endif -diff --git a/arch/arm/boot/compressed/piggy.lzma.S b/arch/arm/boot/compressed/piggy.lzma.S -new file mode 100644 -index 0000000..d7e69cf ---- /dev/null -+++ b/arch/arm/boot/compressed/piggy.lzma.S -@@ -0,0 +1,6 @@ -+ .section .piggydata,#alloc -+ .globl input_data -+input_data: -+ .incbin "arch/arm/boot/compressed/piggy.lzma" -+ .globl input_data_end -+input_data_end: diff --git a/debian/patches/features/arm/compression-use-generic-gzip.patch b/debian/patches/features/arm/compression-use-generic-gzip.patch deleted file mode 100644 index 5ba5c6e6b..000000000 --- a/debian/patches/features/arm/compression-use-generic-gzip.patch +++ /dev/null @@ -1,281 +0,0 @@ -diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig -index 1c4119c..95b9905 100644 ---- a/arch/arm/Kconfig -+++ b/arch/arm/Kconfig -@@ -18,6 +18,7 @@ config ARM - select HAVE_KRETPROBES if (HAVE_KPROBES) - select HAVE_FUNCTION_TRACER if (!XIP_KERNEL) - select HAVE_GENERIC_DMA_COHERENT -+ select HAVE_KERNEL_GZIP - help - The ARM series is a line of low-power-consumption RISC chip designs - licensed by ARM Ltd and targeted at embedded applications and -diff --git a/arch/arm/boot/compressed/Makefile b/arch/arm/boot/compressed/Makefile -index ce39dc5..10f1173 100644 ---- a/arch/arm/boot/compressed/Makefile -+++ b/arch/arm/boot/compressed/Makefile -@@ -63,8 +63,11 @@ endif - - SEDFLAGS = s/TEXT_START/$(ZTEXTADDR)/;s/BSS_START/$(ZBSSADDR)/ - --targets := vmlinux vmlinux.lds piggy.gz piggy.o font.o font.c \ -- head.o misc.o $(OBJS) -+suffix_$(CONFIG_KERNEL_GZIP) = gzip -+ -+targets := vmlinux vmlinux.lds \ -+ piggy.$(suffix_y) piggy.$(suffix_y).o \ -+ font.o font.c head.o misc.o $(OBJS) - - ifeq ($(CONFIG_FUNCTION_TRACER),y) - ORIG_CFLAGS := $(KBUILD_CFLAGS) -@@ -87,22 +90,31 @@ endif - ifneq ($(PARAMS_PHYS),) - LDFLAGS_vmlinux += --defsym params_phys=$(PARAMS_PHYS) - endif --LDFLAGS_vmlinux += -p --no-undefined -X \ -- $(shell $(CC) $(KBUILD_CFLAGS) --print-libgcc-file-name) -T -+# ? -+LDFLAGS_vmlinux += -p -+# Report unresolved symbol references -+LDFLAGS_vmlinux += --no-undefined -+# Delete all temporary local symbols -+LDFLAGS_vmlinux += -X -+# Next argument is a linker script -+LDFLAGS_vmlinux += -T -+ -+# For __aeabi_uidivmod -+lib1funcs = arch/$(SRCARCH)/lib/lib1funcs.o - - # Don't allow any static data in misc.o, which - # would otherwise mess up our GOT table - CFLAGS_misc.o := -Dstatic= - --$(obj)/vmlinux: $(obj)/vmlinux.lds $(obj)/$(HEAD) $(obj)/piggy.o \ -- $(addprefix $(obj)/, $(OBJS)) FORCE -+$(obj)/vmlinux: $(obj)/vmlinux.lds $(obj)/$(HEAD) $(obj)/piggy.$(suffix_y).o \ -+ $(addprefix $(obj)/, $(OBJS)) $(lib1funcs) FORCE - $(call if_changed,ld) - @: - --$(obj)/piggy.gz: $(obj)/../Image FORCE -- $(call if_changed,gzip) -+$(obj)/piggy.$(suffix_y): $(obj)/../Image FORCE -+ $(call if_changed,$(suffix_y)) - --$(obj)/piggy.o: $(obj)/piggy.gz FORCE -+$(obj)/piggy.$(suffix_y).o: $(obj)/piggy.$(suffix_y) FORCE - - CFLAGS_font.o := -Dstatic= - -diff --git a/arch/arm/boot/compressed/misc.c b/arch/arm/boot/compressed/misc.c -index 17153b5..669b1b5 100644 ---- a/arch/arm/boot/compressed/misc.c -+++ b/arch/arm/boot/compressed/misc.c -@@ -18,10 +18,15 @@ - - unsigned int __machine_arch_type; - -+#define _LINUX_STRING_H_ -+ - #include /* for inline */ - #include /* for size_t */ - #include /* for NULL */ - #include -+#include -+ -+#include - - #ifdef STANDALONE_DEBUG - #define putstr printf -@@ -188,34 +193,8 @@ static inline __ptr_t memcpy(__ptr_t __dest, __const __ptr_t __src, - /* - * gzip delarations - */ --#define OF(args) args - #define STATIC static - --typedef unsigned char uch; --typedef unsigned short ush; --typedef unsigned long ulg; -- --#define WSIZE 0x8000 /* Window size must be at least 32k, */ -- /* and a power of two */ -- --static uch *inbuf; /* input buffer */ --static uch window[WSIZE]; /* Sliding window buffer */ -- --static unsigned insize; /* valid bytes in inbuf */ --static unsigned inptr; /* index of next byte to be processed in inbuf */ --static unsigned outcnt; /* bytes in output buffer */ -- --/* gzip flag byte */ --#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */ --#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */ --#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ --#define ORIG_NAME 0x08 /* bit 3 set: original file name present */ --#define COMMENT 0x10 /* bit 4 set: file comment present */ --#define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */ --#define RESERVED 0xC0 /* bit 6,7: reserved */ -- --#define get_byte() (inptr < insize ? inbuf[inptr++] : fill_inbuf()) -- - /* Diagnostic functions */ - #ifdef DEBUG - # define Assert(cond,msg) {if(!(cond)) error(msg);} -@@ -233,24 +212,20 @@ static unsigned outcnt; /* bytes in output buffer */ - # define Tracecv(c,x) - #endif - --static int fill_inbuf(void); --static void flush_window(void); - static void error(char *m); - - extern char input_data[]; - extern char input_data_end[]; - --static uch *output_data; --static ulg output_ptr; --static ulg bytes_out; -+static unsigned char *output_data; -+static unsigned long output_ptr; - - static void error(char *m); - - static void putstr(const char *); - --extern int end; --static ulg free_mem_ptr; --static ulg free_mem_end_ptr; -+static unsigned long free_mem_ptr; -+static unsigned long free_mem_end_ptr; - - #ifdef STANDALONE_DEBUG - #define NO_INFLATE_MALLOC -@@ -258,46 +233,9 @@ static ulg free_mem_end_ptr; - - #define ARCH_HAS_DECOMP_WDOG - --#include "../../../../lib/inflate.c" -- --/* =========================================================================== -- * Fill the input buffer. This is called only when the buffer is empty -- * and at least one byte is really needed. -- */ --int fill_inbuf(void) --{ -- if (insize != 0) -- error("ran out of input data"); -- -- inbuf = input_data; -- insize = &input_data_end[0] - &input_data[0]; -- -- inptr = 1; -- return inbuf[0]; --} -- --/* =========================================================================== -- * Write the output window window[0..outcnt-1] and update crc and bytes_out. -- * (Used for the decompressed data only.) -- */ --void flush_window(void) --{ -- ulg c = crc; -- unsigned n; -- uch *in, *out, ch; -- -- in = window; -- out = &output_data[output_ptr]; -- for (n = 0; n < outcnt; n++) { -- ch = *out++ = *in++; -- c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8); -- } -- crc = c; -- bytes_out += (ulg)outcnt; -- output_ptr += (ulg)outcnt; -- outcnt = 0; -- putstr("."); --} -+#ifdef CONFIG_KERNEL_GZIP -+#include "../../../../lib/decompress_inflate.c" -+#endif - - #ifndef arch_error - #define arch_error(x) -@@ -314,22 +252,33 @@ static void error(char *x) - while(1); /* Halt */ - } - -+asmlinkage void __div0(void) -+{ -+ error("Attempting division by 0!"); -+} -+ - #ifndef STANDALONE_DEBUG - --ulg --decompress_kernel(ulg output_start, ulg free_mem_ptr_p, ulg free_mem_ptr_end_p, -- int arch_id) -+unsigned long -+decompress_kernel(unsigned long output_start, unsigned long free_mem_ptr_p, -+ unsigned long free_mem_ptr_end_p, -+ int arch_id) - { -- output_data = (uch *)output_start; /* Points to kernel start */ -+ unsigned char *tmp; -+ -+ output_data = (unsigned char *)output_start; - free_mem_ptr = free_mem_ptr_p; - free_mem_end_ptr = free_mem_ptr_end_p; - __machine_arch_type = arch_id; - - arch_decomp_setup(); - -- makecrc(); -+ tmp = (unsigned char *) (((unsigned long)input_data_end) - 4); -+ output_ptr = get_unaligned_le32(tmp); -+ - putstr("Uncompressing Linux..."); -- gunzip(); -+ decompress(input_data, input_data_end - input_data, -+ NULL, NULL, output_data, NULL, error); - putstr(" done, booting the kernel.\n"); - return output_ptr; - } -@@ -341,11 +290,10 @@ int main() - { - output_data = output_buffer; - -- makecrc(); - putstr("Uncompressing Linux..."); -- gunzip(); -+ decompress(input_data, input_data_end - input_data, -+ NULL, NULL, output_data, NULL, error); - putstr("done.\n"); - return 0; - } - #endif -- -diff --git a/arch/arm/boot/compressed/piggy.S b/arch/arm/boot/compressed/piggy.S -deleted file mode 100644 -index 54c9518..0000000 ---- a/arch/arm/boot/compressed/piggy.S -+++ /dev/null -@@ -1,6 +0,0 @@ -- .section .piggydata,#alloc -- .globl input_data --input_data: -- .incbin "arch/arm/boot/compressed/piggy.gz" -- .globl input_data_end --input_data_end: -diff --git a/arch/arm/boot/compressed/piggy.gzip.S b/arch/arm/boot/compressed/piggy.gzip.S -new file mode 100644 -index 0000000..a68adf9 ---- /dev/null -+++ b/arch/arm/boot/compressed/piggy.gzip.S -@@ -0,0 +1,6 @@ -+ .section .piggydata,#alloc -+ .globl input_data -+input_data: -+ .incbin "arch/arm/boot/compressed/piggy.gzip" -+ .globl input_data_end -+input_data_end: diff --git a/debian/patches/series/base b/debian/patches/series/base index af7562535..a5784b464 100644 --- a/debian/patches/series/base +++ b/debian/patches/series/base @@ -40,8 +40,6 @@ + bugfix/all/drivers-scsi-qla1280-request-firmware-unlocked.patch + debian/dfsg/radeon-add-clarifying-comment-to-r600-blit.patch # FIXME: no longer applies -#+ features/arm/compression-use-generic-gzip.patch -#+ features/arm/compression-add-lzmo.patch #+ features/arm/openrd-client.patch #+ features/arm/ts41x.patch #+ features/all/mmc-parameter-set-whether-cards-are-assumed-removable.patch From 51536125e9ce64f693a25004b4606874772ee38d Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Fri, 19 Feb 2010 03:24:44 +0000 Subject: [PATCH 23/71] Fix up features/arm/compression-add-lzmo.patch for 2.6.33-rc8 And fix the patch name to avoid people (like me) confusing LZMA and LZO. svn path=/dists/trunk/linux-2.6/; revision=15213 --- .../features/arm/compression-add-lzma.patch | 42 +++++++++++++++++++ debian/patches/series/base | 1 + 2 files changed, 43 insertions(+) create mode 100644 debian/patches/features/arm/compression-add-lzma.patch diff --git a/debian/patches/features/arm/compression-add-lzma.patch b/debian/patches/features/arm/compression-add-lzma.patch new file mode 100644 index 000000000..4318ad239 --- /dev/null +++ b/debian/patches/features/arm/compression-add-lzma.patch @@ -0,0 +1,42 @@ +--- a/arch/arm/Kconfig ++++ b/arch/arm/Kconfig +@@ -19,6 +19,7 @@ config ARM + select HAVE_FUNCTION_TRACER if (!XIP_KERNEL) + select HAVE_GENERIC_DMA_COHERENT + select HAVE_KERNEL_GZIP ++ select HAVE_KERNEL_LZMA + select HAVE_KERNEL_LZO + help + The ARM series is a line of low-power-consumption RISC chip designs +--- a/arch/arm/boot/compressed/Makefile ++++ b/arch/arm/boot/compressed/Makefile +@@ -64,6 +64,7 @@ endif + SEDFLAGS = s/TEXT_START/$(ZTEXTADDR)/;s/BSS_START/$(ZBSSADDR)/ + + suffix_$(CONFIG_KERNEL_GZIP) = gzip ++suffix_$(CONFIG_KERNEL_LZMA) = lzma + suffix_$(CONFIG_KERNEL_LZO) = lzo + + targets := vmlinux vmlinux.lds \ +--- a/arch/arm/boot/compressed/misc.c ++++ b/arch/arm/boot/compressed/misc.c +@@ -237,6 +237,10 @@ static unsigned long free_mem_end_ptr; + #include "../../../../lib/decompress_inflate.c" + #endif + ++#ifdef CONFIG_KERNEL_LZMA ++#include "../../../../lib/decompress_unlzma.c" ++#endif ++ + #ifdef CONFIG_KERNEL_LZO + #include "../../../../lib/decompress_unlzo.c" + #endif +--- /dev/null ++++ b/arch/arm/boot/compressed/piggy.lzma.S +@@ -0,0 +1,6 @@ ++ .section .piggydata,#alloc ++ .globl input_data ++input_data: ++ .incbin "arch/arm/boot/compressed/piggy.lzma" ++ .globl input_data_end ++input_data_end: diff --git a/debian/patches/series/base b/debian/patches/series/base index a5784b464..f165dd3b3 100644 --- a/debian/patches/series/base +++ b/debian/patches/series/base @@ -39,6 +39,7 @@ + features/sparc/video-sunxvr500-intergraph.patch + bugfix/all/drivers-scsi-qla1280-request-firmware-unlocked.patch + debian/dfsg/radeon-add-clarifying-comment-to-r600-blit.patch ++ features/arm/compression-add-lzma.patch # FIXME: no longer applies #+ features/arm/openrd-client.patch #+ features/arm/ts41x.patch From 1396aa5ae99393d90a9d550b86f9ea645923cd2c Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Fri, 19 Feb 2010 03:30:53 +0000 Subject: [PATCH 24/71] Fix up features/arm/openrd-client.patch for 2.6.33-rc8 svn path=/dists/trunk/linux-2.6/; revision=15214 --- debian/patches/features/arm/openrd-client.patch | 13 +++++++------ debian/patches/series/base | 2 +- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/debian/patches/features/arm/openrd-client.patch b/debian/patches/features/arm/openrd-client.patch index 83443e618..592638a47 100644 --- a/debian/patches/features/arm/openrd-client.patch +++ b/debian/patches/features/arm/openrd-client.patch @@ -1,6 +1,6 @@ --- a/arch/arm/mach-kirkwood/Kconfig 2009-09-25 19:49:01.000000000 +0000 +++ b/arch/arm/mach-kirkwood/Kconfig 2009-09-25 19:50:08.000000000 +0000 -@@ -44,6 +44,12 @@ +@@ -52,6 +52,12 @@ Say 'Y' here if you want your kernel to support the Marvell OpenRD Base Board. @@ -10,16 +10,17 @@ + Say 'Y' here if you want your kernel to support the + Marvell OpenRD Client Board. + - endmenu - - endif + config MACH_NETSPACE_V2 + bool "LaCie Network Space v2 NAS Board" + help --- a/arch/arm/mach-kirkwood/Makefile 2009-09-25 19:49:07.000000000 +0000 +++ b/arch/arm/mach-kirkwood/Makefile 2009-09-25 19:49:29.000000000 +0000 -@@ -7,5 +7,6 @@ - obj-$(CONFIG_MACH_SHEEVAPLUG) += sheevaplug-setup.o +@@ -8,6 +8,7 @@ obj-$(CONFIG_MACH_TS219) += ts219-setup.o + obj-$(CONFIG_MACH_TS41X) += ts41x-setup.o tsx1x-common.o obj-$(CONFIG_MACH_OPENRD_BASE) += openrd_base-setup.o +obj-$(CONFIG_MACH_OPENRD_CLIENT) += openrd_client-setup.o + obj-$(CONFIG_MACH_NETSPACE_V2) += netspace_v2-setup.o obj-$(CONFIG_CPU_IDLE) += cpuidle.o --- /dev/null 2008-06-15 07:07:41.000000000 +0000 diff --git a/debian/patches/series/base b/debian/patches/series/base index f165dd3b3..0fddb7f94 100644 --- a/debian/patches/series/base +++ b/debian/patches/series/base @@ -40,8 +40,8 @@ + bugfix/all/drivers-scsi-qla1280-request-firmware-unlocked.patch + debian/dfsg/radeon-add-clarifying-comment-to-r600-blit.patch + features/arm/compression-add-lzma.patch ++ features/arm/openrd-client.patch # FIXME: no longer applies -#+ features/arm/openrd-client.patch #+ features/arm/ts41x.patch #+ features/all/mmc-parameter-set-whether-cards-are-assumed-removable.patch From c2c00fcac619796361f7b06c5856814622e99c58 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Fri, 19 Feb 2010 03:31:48 +0000 Subject: [PATCH 25/71] Remove features/arm/ts41x.patch; applied upstream svn path=/dists/trunk/linux-2.6/; revision=15215 --- debian/patches/features/arm/ts41x.patch | 287 ------------------------ debian/patches/series/base | 1 - 2 files changed, 288 deletions(-) delete mode 100644 debian/patches/features/arm/ts41x.patch diff --git a/debian/patches/features/arm/ts41x.patch b/debian/patches/features/arm/ts41x.patch deleted file mode 100644 index f621b713c..000000000 --- a/debian/patches/features/arm/ts41x.patch +++ /dev/null @@ -1,287 +0,0 @@ -diff --git a/arch/arm/mach-kirkwood/Kconfig b/arch/arm/mach-kirkwood/Kconfig -index 0aca451..d58e8b0 100644 ---- a/arch/arm/mach-kirkwood/Kconfig -+++ b/arch/arm/mach-kirkwood/Kconfig -@@ -38,6 +38,13 @@ config MACH_TS219 - Say 'Y' here if you want your kernel to support the - QNAP TS-119 and TS-219 Turbo NAS devices. - -+config MACH_TS41X -+ bool "QNAP TS-410, TS-410U, TS-419P and TS-419U Turbo NAS" -+ help -+ Say 'Y' here if you want your kernel to support the -+ QNAP TS-410, TS-410U, TS-419P and TS-419U Turbo NAS -+ devices. -+ - config MACH_OPENRD_BASE - bool "Marvell OpenRD Base Board" - help -diff --git a/arch/arm/mach-kirkwood/Makefile b/arch/arm/mach-kirkwood/Makefile -index 80ab0ec..0c79ced 100644 ---- a/arch/arm/mach-kirkwood/Makefile -+++ b/arch/arm/mach-kirkwood/Makefile -@@ -6,6 +6,7 @@ obj-$(CONFIG_MACH_RD88F6281) += rd88f6281-setup.o - obj-$(CONFIG_MACH_MV88F6281GTW_GE) += mv88f6281gtw_ge-setup.o - obj-$(CONFIG_MACH_SHEEVAPLUG) += sheevaplug-setup.o - obj-$(CONFIG_MACH_TS219) += ts219-setup.o -+obj-$(CONFIG_MACH_TS41X) += ts41x-setup.o - obj-$(CONFIG_MACH_OPENRD_BASE) += openrd_base-setup.o - obj-$(CONFIG_MACH_OPENRD_CLIENT) += openrd_client-setup.o - - obj-$(CONFIG_CPU_IDLE) += cpuidle.o ---- /dev/null 2008-06-15 07:07:41.000000000 +0000 -+++ b/arch/arm/mach-kirkwood/ts41x-setup.c 2009-11-03 16:45:13.000000000 +0000 -@@ -0,0 +1,253 @@ -+/* -+ * -+ * QNAP TS-410, TS-410U, TS-419P and TS-419U Turbo NAS Board Setup -+ * -+ * Copyright (C) 2009 Martin Michlmayr -+ * Copyright (C) 2008 Byron Bradley -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation; either version -+ * 2 of the License, or (at your option) any later version. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "common.h" -+#include "mpp.h" -+ -+/**************************************************************************** -+ * 16 MiB NOR flash. The struct mtd_partition is not in the same order as the -+ * partitions on the device because we want to keep compatability with -+ * the QNAP firmware. -+ * Layout as used by QNAP: -+ * 0x00000000-0x00080000 : "U-Boot" -+ * 0x00200000-0x00400000 : "Kernel" -+ * 0x00400000-0x00d00000 : "RootFS" -+ * 0x00d00000-0x01000000 : "RootFS2" -+ * 0x00080000-0x000c0000 : "U-Boot Config" -+ * 0x000c0000-0x00200000 : "NAS Config" -+ * -+ * We'll use "RootFS1" instead of "RootFS" to stay compatible with the layout -+ * used by the QNAP TS-109/TS-209. -+ * -+ ***************************************************************************/ -+ -+static struct mtd_partition qnap_ts41x_partitions[] = { -+ { -+ .name = "U-Boot", -+ .size = 0x00080000, -+ .offset = 0, -+ .mask_flags = MTD_WRITEABLE, -+ }, { -+ .name = "Kernel", -+ .size = 0x00200000, -+ .offset = 0x00200000, -+ }, { -+ .name = "RootFS1", -+ .size = 0x00900000, -+ .offset = 0x00400000, -+ }, { -+ .name = "RootFS2", -+ .size = 0x00300000, -+ .offset = 0x00d00000, -+ }, { -+ .name = "U-Boot Config", -+ .size = 0x00040000, -+ .offset = 0x00080000, -+ }, { -+ .name = "NAS Config", -+ .size = 0x00140000, -+ .offset = 0x000c0000, -+ }, -+}; -+ -+static const struct flash_platform_data qnap_ts41x_flash = { -+ .type = "m25p128", -+ .name = "spi_flash", -+ .parts = qnap_ts41x_partitions, -+ .nr_parts = ARRAY_SIZE(qnap_ts41x_partitions), -+}; -+ -+static struct spi_board_info __initdata qnap_ts41x_spi_slave_info[] = { -+ { -+ .modalias = "m25p80", -+ .platform_data = &qnap_ts41x_flash, -+ .irq = -1, -+ .max_speed_hz = 20000000, -+ .bus_num = 0, -+ .chip_select = 0, -+ }, -+}; -+ -+static struct i2c_board_info __initdata qnap_ts41x_i2c_rtc = { -+ I2C_BOARD_INFO("s35390a", 0x30), -+}; -+ -+static struct mv643xx_eth_platform_data qnap_ts41x_ge00_data = { -+ .phy_addr = MV643XX_ETH_PHY_ADDR(8), -+}; -+ -+static struct mv643xx_eth_platform_data qnap_ts41x_ge01_data = { -+ .phy_addr = MV643XX_ETH_PHY_ADDR(0), -+}; -+ -+static struct mv_sata_platform_data qnap_ts41x_sata_data = { -+ .n_ports = 2, -+}; -+ -+static struct gpio_keys_button qnap_ts41x_buttons[] = { -+ { -+ .code = KEY_COPY, -+ .gpio = 43, -+ .desc = "USB Copy", -+ .active_low = 1, -+ }, -+ { -+ .code = KEY_RESTART, -+ .gpio = 37, -+ .desc = "Reset", -+ .active_low = 1, -+ }, -+}; -+ -+static struct gpio_keys_platform_data qnap_ts41x_button_data = { -+ .buttons = qnap_ts41x_buttons, -+ .nbuttons = ARRAY_SIZE(qnap_ts41x_buttons), -+}; -+ -+static struct platform_device qnap_ts41x_button_device = { -+ .name = "gpio-keys", -+ .id = -1, -+ .num_resources = 0, -+ .dev = { -+ .platform_data = &qnap_ts41x_button_data, -+ } -+}; -+ -+static unsigned int qnap_ts41x_mpp_config[] __initdata = { -+ MPP0_SPI_SCn, -+ MPP1_SPI_MOSI, -+ MPP2_SPI_SCK, -+ MPP3_SPI_MISO, -+ MPP6_SYSRST_OUTn, -+ MPP7_PEX_RST_OUTn, -+ MPP8_TW_SDA, -+ MPP9_TW_SCK, -+ MPP10_UART0_TXD, -+ MPP11_UART0_RXD, -+ MPP13_UART1_TXD, /* PIC controller */ -+ MPP14_UART1_RXD, /* PIC controller */ -+ MPP15_SATA0_ACTn, -+ MPP16_SATA1_ACTn, -+ MPP20_GE1_0, -+ MPP21_GE1_1, -+ MPP22_GE1_2, -+ MPP23_GE1_3, -+ MPP24_GE1_4, -+ MPP25_GE1_5, -+ MPP26_GE1_6, -+ MPP27_GE1_7, -+ MPP30_GE1_10, -+ MPP31_GE1_11, -+ MPP32_GE1_12, -+ MPP33_GE1_13, -+ MPP36_GPIO, /* RAM: 0: 256 MB, 1: 512 MB */ -+ MPP37_GPIO, /* Reset button */ -+ MPP43_GPIO, /* USB Copy button */ -+ MPP44_GPIO, /* Board ID: 0: TS-419U, 1: TS-419 */ -+ MPP45_GPIO, /* JP1: 0: console, 1: LCD */ -+ MPP46_GPIO, /* External SATA HDD1 error indicator */ -+ MPP47_GPIO, /* External SATA HDD2 error indicator */ -+ MPP48_GPIO, /* External SATA HDD3 error indicator */ -+ MPP49_GPIO, /* External SATA HDD4 error indicator */ -+ 0 -+}; -+ -+ -+/***************************************************************************** -+ * QNAP TS-x19 specific power off method via UART1-attached PIC -+ ****************************************************************************/ -+ -+#define UART1_REG(x) (UART1_VIRT_BASE + ((UART_##x) << 2)) -+ -+void qnap_ts41x_power_off(void) -+{ -+ /* 19200 baud divisor */ -+ const unsigned divisor = ((kirkwood_tclk + (8 * 19200)) / (16 * 19200)); -+ -+ pr_info("%s: triggering power-off...\n", __func__); -+ -+ /* hijack UART1 and reset into sane state (19200,8n1) */ -+ writel(0x83, UART1_REG(LCR)); -+ writel(divisor & 0xff, UART1_REG(DLL)); -+ writel((divisor >> 8) & 0xff, UART1_REG(DLM)); -+ writel(0x03, UART1_REG(LCR)); -+ writel(0x00, UART1_REG(IER)); -+ writel(0x00, UART1_REG(FCR)); -+ writel(0x00, UART1_REG(MCR)); -+ -+ /* send the power-off command 'A' to PIC */ -+ writel('A', UART1_REG(TX)); -+} -+ -+static void __init qnap_ts41x_init(void) -+{ -+ /* -+ * Basic setup. Needs to be called early. -+ */ -+ kirkwood_init(); -+ kirkwood_mpp_conf(qnap_ts41x_mpp_config); -+ -+ kirkwood_uart0_init(); -+ kirkwood_uart1_init(); /* A PIC controller is connected here. */ -+ spi_register_board_info(qnap_ts41x_spi_slave_info, -+ ARRAY_SIZE(qnap_ts41x_spi_slave_info)); -+ kirkwood_spi_init(); -+ kirkwood_i2c_init(); -+ i2c_register_board_info(0, &qnap_ts41x_i2c_rtc, 1); -+ kirkwood_ge00_init(&qnap_ts41x_ge00_data); -+ kirkwood_ge01_init(&qnap_ts41x_ge01_data); -+ kirkwood_sata_init(&qnap_ts41x_sata_data); -+ kirkwood_ehci_init(); -+ platform_device_register(&qnap_ts41x_button_device); -+ -+ pm_power_off = qnap_ts41x_power_off; -+ -+} -+ -+static int __init ts41x_pci_init(void) -+{ -+ if (machine_is_ts41x()) -+ kirkwood_pcie_init(); -+ -+ return 0; -+} -+subsys_initcall(ts41x_pci_init); -+ -+MACHINE_START(TS41X, "QNAP TS-41x") -+ /* Maintainer: Martin Michlmayr */ -+ .phys_io = KIRKWOOD_REGS_PHYS_BASE, -+ .io_pg_offst = ((KIRKWOOD_REGS_VIRT_BASE) >> 18) & 0xfffc, -+ .boot_params = 0x00000100, -+ .init_machine = qnap_ts41x_init, -+ .map_io = kirkwood_map_io, -+ .init_irq = kirkwood_init_irq, -+ .timer = &kirkwood_timer, -+MACHINE_END diff --git a/debian/patches/series/base b/debian/patches/series/base index 0fddb7f94..7dfa2e4c5 100644 --- a/debian/patches/series/base +++ b/debian/patches/series/base @@ -42,7 +42,6 @@ + features/arm/compression-add-lzma.patch + features/arm/openrd-client.patch # FIXME: no longer applies -#+ features/arm/ts41x.patch #+ features/all/mmc-parameter-set-whether-cards-are-assumed-removable.patch #+ features/all/i915-autoload-without-CONFIG_DRM_I915_KMS.patch From ff958ed1738f82da63fbcffe98314ce20f93d63a Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Fri, 19 Feb 2010 03:33:21 +0000 Subject: [PATCH 26/71] Remove features/all/mmc-parameter-set-whether-cards-are-assumed-removable.patch; applied upstream svn path=/dists/trunk/linux-2.6/; revision=15216 --- ...-whether-cards-are-assumed-removable.patch | 190 ------------------ debian/patches/series/base | 2 - 2 files changed, 192 deletions(-) delete mode 100644 debian/patches/features/all/mmc-parameter-set-whether-cards-are-assumed-removable.patch diff --git a/debian/patches/features/all/mmc-parameter-set-whether-cards-are-assumed-removable.patch b/debian/patches/features/all/mmc-parameter-set-whether-cards-are-assumed-removable.patch deleted file mode 100644 index 57ec4049a..000000000 --- a/debian/patches/features/all/mmc-parameter-set-whether-cards-are-assumed-removable.patch +++ /dev/null @@ -1,190 +0,0 @@ -Subject: mmc: add module parameter to set whether cards are assumed removable -From: Ben Hutchings - -Some people run general-purpose distribution kernels on netbooks with -a card that is physically non-removable or logically non-removable -(e.g. used for /home) and cannot be cleanly unmounted during suspend. -Add a module parameter to set whether cards are assumed removable or -non-removable, with the default set by CONFIG_MMC_UNSAFE_RESUME. - -In general, it is not possible to tell whether a card present in an MMC -slot after resume is the same that was there before suspend. So there are -two possible behaviours, each of which will cause data loss in some cases: - -CONFIG_MMC_UNSAFE_RESUME=n (default): Cards are assumed to be removed -during suspend. Any filesystem on them must be unmounted before suspend; -otherwise, buffered writes will be lost. - -CONFIG_MMC_UNSAFE_RESUME=y: Cards are assumed to remain present during -suspend. They must not be swapped during suspend; otherwise, buffered -writes will be flushed to the wrong card. - -Currently the choice is made at compile time and this allows that to be -overridden at module load time. - -Signed-off-by: Ben Hutchings -Cc: -Signed-off-by: Andrew Morton ---- - drivers/mmc/core/Kconfig | 4 +++- - drivers/mmc/core/core.c | 16 ++++++++++++++++ - drivers/mmc/core/core.h | 2 ++ - drivers/mmc/core/mmc.c | 23 +---------------------- - drivers/mmc/core/sd.c | 21 +-------------------- - 5 files changed, 23 insertions(+), 43 deletions(-) - -diff --git a/drivers/mmc/core/Kconfig b/drivers/mmc/core/Kconfig -index ab37a6d..bb22ffd 100644 ---- a/drivers/mmc/core/Kconfig -+++ b/drivers/mmc/core/Kconfig -@@ -3,7 +3,7 @@ - # - - config MMC_UNSAFE_RESUME -- bool "Allow unsafe resume (DANGEROUS)" -+ bool "Assume MMC/SD cards are non-removable (DANGEROUS)" - help - If you say Y here, the MMC layer will assume that all cards - stayed in their respective slots during the suspend. The -@@ -14,3 +14,5 @@ config MMC_UNSAFE_RESUME - This option is usually just for embedded systems which use - a MMC/SD card for rootfs. Most people should say N here. - -+ This option sets a default which can be overridden by the -+ module parameter "removable=0" or "removable=1". -diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c -index d98b0e2..010c964 100644 ---- a/drivers/mmc/core/core.c -+++ b/drivers/mmc/core/core.c -@@ -48,6 +48,22 @@ int use_spi_crc = 1; - module_param(use_spi_crc, bool, 0); - - /* -+ * We normally treat cards as removed during suspend if they are not -+ * known to be on a non-removable bus, to avoid the risk of writing -+ * back data to a different card after resume. Allow this to be -+ * overridden if necessary. -+ */ -+#ifdef CONFIG_MMC_UNSAFE_RESUME -+int mmc_assume_removable; -+#else -+int mmc_assume_removable = 1; -+#endif -+module_param_named(removable, mmc_assume_removable, bool, 0644); -+MODULE_PARM_DESC( -+ removable, -+ "MMC/SD cards are removable and may be removed during suspend"); -+ -+/* - * Internal function. Schedule delayed work in the MMC work queue. - */ - static int mmc_schedule_delayed_work(struct delayed_work *work, -diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h -index 1c68783..d20b7bc 100644 ---- a/drivers/mmc/core/core.h -+++ b/drivers/mmc/core/core.h -@@ -64,7 +64,9 @@ int mmc_attach_mmc(struct mmc_host *host, u32 ocr); - int mmc_attach_sd(struct mmc_host *host, u32 ocr); - int mmc_attach_sdio(struct mmc_host *host, u32 ocr); - -+/* Module parameters */ - extern int use_spi_crc; -+extern int mmc_assume_removable; - - /* Debugfs information for hosts and cards */ - void mmc_add_host_debugfs(struct mmc_host *host); -diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c -index bfefce3..c111894 100644 ---- a/drivers/mmc/core/mmc.c -+++ b/drivers/mmc/core/mmc.c -@@ -602,25 +602,6 @@ static int mmc_awake(struct mmc_host *host) - return err; - } - --#ifdef CONFIG_MMC_UNSAFE_RESUME -- --static const struct mmc_bus_ops mmc_ops = { -- .awake = mmc_awake, -- .sleep = mmc_sleep, -- .remove = mmc_remove, -- .detect = mmc_detect, -- .suspend = mmc_suspend, -- .resume = mmc_resume, -- .power_restore = mmc_power_restore, --}; -- --static void mmc_attach_bus_ops(struct mmc_host *host) --{ -- mmc_attach_bus(host, &mmc_ops); --} -- --#else -- - static const struct mmc_bus_ops mmc_ops = { - .awake = mmc_awake, - .sleep = mmc_sleep, -@@ -645,15 +626,13 @@ static void mmc_attach_bus_ops(struct mmc_host *host) - { - const struct mmc_bus_ops *bus_ops; - -- if (host->caps & MMC_CAP_NONREMOVABLE) -+ if (host->caps & MMC_CAP_NONREMOVABLE || !mmc_assume_removable) - bus_ops = &mmc_ops_unsafe; - else - bus_ops = &mmc_ops; - mmc_attach_bus(host, bus_ops); - } - --#endif -- - /* - * Starting point for MMC card init. - */ -diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c -index 10b2a4d..fdd414e 100644 ---- a/drivers/mmc/core/sd.c -+++ b/drivers/mmc/core/sd.c -@@ -606,23 +606,6 @@ static void mmc_sd_power_restore(struct mmc_host *host) - mmc_release_host(host); - } - --#ifdef CONFIG_MMC_UNSAFE_RESUME -- --static const struct mmc_bus_ops mmc_sd_ops = { -- .remove = mmc_sd_remove, -- .detect = mmc_sd_detect, -- .suspend = mmc_sd_suspend, -- .resume = mmc_sd_resume, -- .power_restore = mmc_sd_power_restore, --}; -- --static void mmc_sd_attach_bus_ops(struct mmc_host *host) --{ -- mmc_attach_bus(host, &mmc_sd_ops); --} -- --#else -- - static const struct mmc_bus_ops mmc_sd_ops = { - .remove = mmc_sd_remove, - .detect = mmc_sd_detect, -@@ -643,15 +626,13 @@ static void mmc_sd_attach_bus_ops(struct mmc_host *host) - { - const struct mmc_bus_ops *bus_ops; - -- if (host->caps & MMC_CAP_NONREMOVABLE) -+ if (host->caps & MMC_CAP_NONREMOVABLE || !mmc_assume_removable) - bus_ops = &mmc_sd_ops_unsafe; - else - bus_ops = &mmc_sd_ops; - mmc_attach_bus(host, bus_ops); - } - --#endif -- - /* - * Starting point for SD card init. - */ --- -1.6.5.3 - diff --git a/debian/patches/series/base b/debian/patches/series/base index 7dfa2e4c5..460d8b86e 100644 --- a/debian/patches/series/base +++ b/debian/patches/series/base @@ -41,8 +41,6 @@ + debian/dfsg/radeon-add-clarifying-comment-to-r600-blit.patch + features/arm/compression-add-lzma.patch + features/arm/openrd-client.patch -# FIXME: no longer applies -#+ features/all/mmc-parameter-set-whether-cards-are-assumed-removable.patch #+ features/all/i915-autoload-without-CONFIG_DRM_I915_KMS.patch From ea8710626a23f065778191b1c8436606389897da Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Fri, 19 Feb 2010 03:35:30 +0000 Subject: [PATCH 27/71] Remove features/all/input-alps-add-support-for-touchpads-with-4-directional-button-2.patch; applied upstream svn path=/dists/trunk/linux-2.6/; revision=15217 --- ...ouchpads-with-4-directional-button-2.patch | 59 ------------------- debian/patches/series/base | 3 - 2 files changed, 62 deletions(-) delete mode 100644 debian/patches/features/all/input-alps-add-support-for-touchpads-with-4-directional-button-2.patch diff --git a/debian/patches/features/all/input-alps-add-support-for-touchpads-with-4-directional-button-2.patch b/debian/patches/features/all/input-alps-add-support-for-touchpads-with-4-directional-button-2.patch deleted file mode 100644 index e4df29ab2..000000000 --- a/debian/patches/features/all/input-alps-add-support-for-touchpads-with-4-directional-button-2.patch +++ /dev/null @@ -1,59 +0,0 @@ -Based on: - -commit 71bb21b677e89a2b438b804231f92b779beda5d7 -Author: Maxim Levitsky -Date: Mon Nov 16 22:12:22 2009 -0800 - - Input: ALPS - add support for touchpads with 4-directional button - - The touchpad on Acer Aspire 5720, 5520 and some other Aspire models - (signature 0x73, 0x02, 0x50) has a button that can be rocked in 4 - different directions. Make the driver to generate BTN_0..BTN_3 events - in response. The Synaptics driver by default maps BTN_0 and BTN_1 to - up and down, so there should be no visible changes with the old setup - that generated BTN_FORWARD and BTN_BACK (also mapped to up and down). - - Signed-off-by: Maxim Levitsky - Signed-off-by: Dmitry Torokhov - -diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c -index f361106..a3f492a 100644 ---- a/drivers/input/mouse/alps.c -+++ b/drivers/input/mouse/alps.c -@@ -61,7 +61,7 @@ static const struct alps_model_info alps_model_data[] = { - /* Dell Latitude E5500, E6400, E6500, Precision M4400 */ - { { 0x62, 0x02, 0x14 }, 0xcf, 0xcf, - ALPS_PASS | ALPS_DUALPOINT | ALPS_PS2_INTERLEAVED }, -- { { 0x73, 0x02, 0x50 }, 0xcf, 0xcf, ALPS_FW_BK_1 }, /* Dell Vostro 1400 */ -+ { { 0x73, 0x02, 0x50 }, 0xcf, 0xcf, ALPS_4BTN }, /* Dell Vostro 1400 */ - }; - - /* -@@ -241,6 +241,13 @@ static void alps_process_packet(struct psmouse *psmouse) - input_report_key(dev, BTN_BACK, back); - } - -+ if (priv->i->flags & ALPS_4BTN) { -+ input_report_key(dev, BTN_0, packet[2] & 4); -+ input_report_key(dev, BTN_1, packet[0] & 0x10); -+ input_report_key(dev, BTN_2, packet[3] & 4); -+ input_report_key(dev, BTN_3, packet[0] & 0x20); -+ } -+ - input_sync(dev); - } - -@@ -689,6 +696,13 @@ int alps_init(struct psmouse *psmouse) - dev1->keybit[BIT_WORD(BTN_BACK)] |= BIT_MASK(BTN_BACK); - } - -+ if (priv->i->flags & ALPS_4BTN) { -+ dev1->keybit[BIT_WORD(BTN_0)] |= BIT_MASK(BTN_0); -+ dev1->keybit[BIT_WORD(BTN_1)] |= BIT_MASK(BTN_1); -+ dev1->keybit[BIT_WORD(BTN_2)] |= BIT_MASK(BTN_2); -+ dev1->keybit[BIT_WORD(BTN_3)] |= BIT_MASK(BTN_3); -+ } -+ - snprintf(priv->phys, sizeof(priv->phys), "%s/input1", psmouse->ps2dev.serio->phys); - dev2->phys = priv->phys; - dev2->name = (priv->i->flags & ALPS_DUALPOINT) ? "DualPoint Stick" : "PS/2 Mouse"; diff --git a/debian/patches/series/base b/debian/patches/series/base index 460d8b86e..1635e32a9 100644 --- a/debian/patches/series/base +++ b/debian/patches/series/base @@ -46,9 +46,6 @@ + bugfix/ia64/ia64-Include-linux-personality.h-header-in-asm-fcntl.patch -# FIXME: -#+ features/all/input-alps-add-support-for-touchpads-with-4-directional-button-2.patch - + bugfix/all/cxusb-Select-all-required-frontend-and-tuner-modules.patch # FIXME: From a3c69622fa2e3f622dbfb3c0b4b97d3b5a8096b9 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Fri, 19 Feb 2010 03:37:13 +0000 Subject: [PATCH 28/71] Fix up features/all/i915-autoload-without-CONFIG_DRM_I915_KMS.patch for 2.6.33-rc8 svn path=/dists/trunk/linux-2.6/; revision=15218 --- .../all/i915-autoload-without-CONFIG_DRM_I915_KMS.patch | 6 ++---- debian/patches/series/base | 2 +- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/debian/patches/features/all/i915-autoload-without-CONFIG_DRM_I915_KMS.patch b/debian/patches/features/all/i915-autoload-without-CONFIG_DRM_I915_KMS.patch index 2f70914eb..dc47804fa 100644 --- a/debian/patches/features/all/i915-autoload-without-CONFIG_DRM_I915_KMS.patch +++ b/debian/patches/features/all/i915-autoload-without-CONFIG_DRM_I915_KMS.patch @@ -1,14 +1,12 @@ -diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c -index 7f436ec..0c27723 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -52,9 +52,7 @@ static struct pci_device_id pciidlist[] = { - i915_PCI_IDS + {0, 0, 0} }; -#if defined(CONFIG_DRM_I915_KMS) MODULE_DEVICE_TABLE(pci, pciidlist); -#endif - static int i915_suspend(struct drm_device *dev, pm_message_t state) + static int i915_drm_freeze(struct drm_device *dev) { diff --git a/debian/patches/series/base b/debian/patches/series/base index 1635e32a9..cccb1513b 100644 --- a/debian/patches/series/base +++ b/debian/patches/series/base @@ -42,7 +42,7 @@ + features/arm/compression-add-lzma.patch + features/arm/openrd-client.patch -#+ features/all/i915-autoload-without-CONFIG_DRM_I915_KMS.patch ++ features/all/i915-autoload-without-CONFIG_DRM_I915_KMS.patch + bugfix/ia64/ia64-Include-linux-personality.h-header-in-asm-fcntl.patch From 7543d0002221b4e799ab511d8a0e3304df2f4f6a Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Fri, 19 Feb 2010 03:43:19 +0000 Subject: [PATCH 29/71] Fix up x86 KVM security patches for 2.6.33-rc8 svn path=/dists/trunk/linux-2.6/; revision=15219 --- ...evel-during-io-instruction-emulation.patch | 5 ++-- .../kvm-pit-control-word-is-write-only.patch | 25 ------------------- debian/patches/series/base | 10 +++----- 3 files changed, 6 insertions(+), 34 deletions(-) delete mode 100644 debian/patches/bugfix/x86/kvm-pit-control-word-is-write-only.patch diff --git a/debian/patches/bugfix/x86/kvm-Check-IOPL-level-during-io-instruction-emulation.patch b/debian/patches/bugfix/x86/kvm-Check-IOPL-level-during-io-instruction-emulation.patch index 041a506ab..ae0654ea6 100644 --- a/debian/patches/bugfix/x86/kvm-Check-IOPL-level-during-io-instruction-emulation.patch +++ b/debian/patches/bugfix/x86/kvm-Check-IOPL-level-during-io-instruction-emulation.patch @@ -61,7 +61,7 @@ diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 012dd8b..06f1b69 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c -@@ -3075,11 +3075,60 @@ static int pio_string_write(struct kvm_vcpu *vcpu) +@@ -3075,10 +3075,59 @@ static int pio_string_write(struct kvm_vcpu *vcpu) return r; } @@ -104,8 +104,7 @@ index 012dd8b..06f1b69 100644 + return true; +} + - int kvm_emulate_pio(struct kvm_vcpu *vcpu, struct kvm_run *run, int in, - int size, unsigned port) + int kvm_emulate_pio(struct kvm_vcpu *vcpu, int in, int size, unsigned port) { unsigned long val; diff --git a/debian/patches/bugfix/x86/kvm-pit-control-word-is-write-only.patch b/debian/patches/bugfix/x86/kvm-pit-control-word-is-write-only.patch deleted file mode 100644 index 768dc2d33..000000000 --- a/debian/patches/bugfix/x86/kvm-pit-control-word-is-write-only.patch +++ /dev/null @@ -1,25 +0,0 @@ -commit 336f40a728b9a4a5db5e1df5c89852c79ff95604 -Author: Marcelo Tosatti -Date: Fri Jan 29 17:28:41 2010 -0200 - - KVM: PIT: control word is write-only - - PIT control word (address 0x43) is write-only, reads are undefined. - - Cc: stable@kernel.org - Signed-off-by: Marcelo Tosatti - -diff --git a/arch/x86/kvm/i8254.c b/arch/x86/kvm/i8254.c -index caad189..6a74246 100644 ---- a/arch/x86/kvm/i8254.c -+++ b/arch/x86/kvm/i8254.c -@@ -467,6 +467,9 @@ static int pit_ioport_read(struct kvm_io_device *this, - return -EOPNOTSUPP; - - addr &= KVM_PIT_CHANNEL_MASK; -+ if (addr == 3) -+ return 0; -+ - s = &pit_state->channels[addr]; - - mutex_lock(&pit_state->lock); diff --git a/debian/patches/series/base b/debian/patches/series/base index cccb1513b..c0f5afeef 100644 --- a/debian/patches/series/base +++ b/debian/patches/series/base @@ -48,12 +48,10 @@ + bugfix/all/cxusb-Select-all-required-frontend-and-tuner-modules.patch -# FIXME: -#+ bugfix/x86/kvm-pit-control-word-is-write-only.patch -#+ bugfix/x86/kvm-fix-memory-access-during-x86-emulation.patch -#+ bugfix/x86/kvm-Check-IOPL-level-during-io-instruction-emulation.patch -#+ bugfix/x86/kvm-Fix-popf-emulation.patch -#+ bugfix/x86/kvm-Check-CPL-level-during-privilege-instruction-emulation.patch ++ bugfix/x86/kvm-fix-memory-access-during-x86-emulation.patch ++ bugfix/x86/kvm-Check-IOPL-level-during-io-instruction-emulation.patch ++ bugfix/x86/kvm-Fix-popf-emulation.patch ++ bugfix/x86/kvm-Check-CPL-level-during-privilege-instruction-emulation.patch + debian/sysrq-mask.patch + bugfix/all/efifb_fix_v2.patch From b064da610e5570d891cf861ee53b989dacdf4a07 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Fri, 19 Feb 2010 03:49:36 +0000 Subject: [PATCH 30/71] Remove features/all/export-unionfs-symbols.patch; no longer needed for Debian Live svn path=/dists/trunk/linux-2.6/; revision=15220 --- .../patches/features/all/export-unionfs-symbols.patch | 11 ----------- debian/patches/series/base | 1 - 2 files changed, 12 deletions(-) delete mode 100644 debian/patches/features/all/export-unionfs-symbols.patch diff --git a/debian/patches/features/all/export-unionfs-symbols.patch b/debian/patches/features/all/export-unionfs-symbols.patch deleted file mode 100644 index 29c7e4589..000000000 --- a/debian/patches/features/all/export-unionfs-symbols.patch +++ /dev/null @@ -1,11 +0,0 @@ -diff -Naurp linux-2.6.orig/fs/namei.c linux-2.6/fs/namei.c ---- linux-2.6.orig/fs/namei.c 2008-01-24 22:58:37.000000000 +0000 -+++ linux-2.6/fs/namei.c 2008-02-11 19:53:38.000000000 +0000 -@@ -389,6 +389,7 @@ void release_open_intent(struct nameidat - else - fput(nd->intent.open.file); - } -+EXPORT_SYMBOL_GPL(release_open_intent); - - static inline struct dentry * - do_revalidate(struct dentry *dentry, struct nameidata *nd) diff --git a/debian/patches/series/base b/debian/patches/series/base index c0f5afeef..8aba31427 100644 --- a/debian/patches/series/base +++ b/debian/patches/series/base @@ -10,7 +10,6 @@ + features/all/drivers-media-dvb-usb-af9005-request_firmware.patch + features/all/rt28x0sta-use-request_firmware.patch -+ features/all/export-unionfs-symbols.patch + features/all/lgs8gxx-lgs8g75-request_firmware.patch + features/all/r8169-rtl8168d-1-2-request_firmware-2.patch + features/all/sound-pci-cs46xx-request_firmware.patch From 146672f3193c9f5c0dcf3284d4fc26d91f8a2c00 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Fri, 19 Feb 2010 03:51:14 +0000 Subject: [PATCH 31/71] Remove unreferenced patches svn path=/dists/trunk/linux-2.6/; revision=15221 --- .../all/clockevents-Add-missing-include.patch | 37 -- ...kevents-Dont-remove-broadcast-device.patch | 45 -- ...address-mask-param-for-drm_pci_alloc.patch | 141 ------ .../all/fasync-split-fasync_helper.patch | 173 -------- ...onflict-between-2.6.32.4-and-vserver.patch | 32 -- ...-New-device-SAS2208-support-is-added.patch | 71 --- ...70-Add-support-for-D-Link-DWA-160-A2.patch | 41 -- .../all/atl1e-allow-offload-disable.patch | 30 -- ...t-for-next-generation-of-BladeEngine.patch | 54 --- ...-the-new-PCI-IDs-to-PCI_DEVICE_TABLE.patch | 32 -- ...-USB-device-ID-s-for-B-B-Electronics.patch | 66 --- ...a-Add-PCI-IDs-for-Nvidia-G2xx-series.patch | 28 -- ...-driver-for-VIA-CPU-core-temperature.patch | 417 ------------------ ...lps-add-interleaved-protocol-support.patch | 395 ----------------- ...vice-IDs-for-B-B-electronics-devices.patch | 67 --- ...d-support-for-Asus-Europa-Hybrid-DVB.patch | 114 ----- .../all/smsusb-add-5-Hauppauge-USB-IDs.patch | 45 -- ...Add-support-for-3.x-silicon-revision.patch | 40 -- ...d-PCI-device-ids-for-new-QoirQ-chips.patch | 53 --- ..._wdt-Add-support-for-Intel-Ibex-Peak.patch | 61 --- 20 files changed, 1942 deletions(-) delete mode 100644 debian/patches/bugfix/all/clockevents-Add-missing-include.patch delete mode 100644 debian/patches/bugfix/all/clockevents-Dont-remove-broadcast-device.patch delete mode 100644 debian/patches/bugfix/all/drm-remove-address-mask-param-for-drm_pci_alloc.patch delete mode 100644 debian/patches/bugfix/all/fasync-split-fasync_helper.patch delete mode 100644 debian/patches/debian/mremap-fix-conflict-between-2.6.32.4-and-vserver.patch delete mode 100644 debian/patches/features/all/SCSI-mpt2sas-New-device-SAS2208-support-is-added.patch delete mode 100644 debian/patches/features/all/ar9170-Add-support-for-D-Link-DWA-160-A2.patch delete mode 100644 debian/patches/features/all/atl1e-allow-offload-disable.patch delete mode 100644 debian/patches/features/all/be2net-Add-support-for-next-generation-of-BladeEngine.patch delete mode 100644 debian/patches/features/all/be2net-Add-the-new-PCI-IDs-to-PCI_DEVICE_TABLE.patch delete mode 100644 debian/patches/features/all/ftdi_sio-add-USB-device-ID-s-for-B-B-Electronics.patch delete mode 100644 debian/patches/features/all/hda-Add-PCI-IDs-for-Nvidia-G2xx-series.patch delete mode 100644 debian/patches/features/all/hwmon-Add-driver-for-VIA-CPU-core-temperature.patch delete mode 100644 debian/patches/features/all/input-alps-add-interleaved-protocol-support.patch delete mode 100644 debian/patches/features/all/mos7840-add-device-IDs-for-B-B-electronics-devices.patch delete mode 100644 debian/patches/features/all/saa7134-Add-support-for-Asus-Europa-Hybrid-DVB.patch delete mode 100644 debian/patches/features/all/smsusb-add-5-Hauppauge-USB-IDs.patch delete mode 100644 debian/patches/features/arm/davinci-dm646x-Add-support-for-3.x-silicon-revision.patch delete mode 100644 debian/patches/features/powerpc/fsl-Add-PCI-device-ids-for-new-QoirQ-chips.patch delete mode 100644 debian/patches/features/x86/iTCO_wdt-Add-support-for-Intel-Ibex-Peak.patch diff --git a/debian/patches/bugfix/all/clockevents-Add-missing-include.patch b/debian/patches/bugfix/all/clockevents-Add-missing-include.patch deleted file mode 100644 index d37fae45f..000000000 --- a/debian/patches/bugfix/all/clockevents-Add-missing-include.patch +++ /dev/null @@ -1,37 +0,0 @@ -From 8e1a928a2ed7e8d5cad97c8e985294b4caedd168 Mon Sep 17 00:00:00 2001 -From: H Hartley Sweeten -Date: Fri, 16 Oct 2009 18:19:01 -0400 -Subject: [PATCH] clockevents: Add missing include to pacify sparse - -Include "tick-internal.h" in order to pick up the extern function -prototype for clockevents_shutdown(). This quiets the following sparse -build noise: - - warning: symbol 'clockevents_shutdown' was not declared. Should it be static? - -Signed-off-by: H Hartley Sweeten -LKML-Reference: -Reviewed-by: Yong Zhang -Cc: johnstul@us.ibm.com -Signed-off-by: Andrew Morton -Signed-off-by: Thomas Gleixner ---- - kernel/time/clockevents.c | 2 ++ - 1 files changed, 2 insertions(+), 0 deletions(-) - -diff --git a/kernel/time/clockevents.c b/kernel/time/clockevents.c -index 05e8aee..20a8920 100644 ---- a/kernel/time/clockevents.c -+++ b/kernel/time/clockevents.c -@@ -20,6 +20,8 @@ - #include - #include - -+#include "tick-internal.h" -+ - /* The registered clock event devices */ - static LIST_HEAD(clockevent_devices); - static LIST_HEAD(clockevents_released); --- -1.6.6 - diff --git a/debian/patches/bugfix/all/clockevents-Dont-remove-broadcast-device.patch b/debian/patches/bugfix/all/clockevents-Dont-remove-broadcast-device.patch deleted file mode 100644 index ec42f9b21..000000000 --- a/debian/patches/bugfix/all/clockevents-Dont-remove-broadcast-device.patch +++ /dev/null @@ -1,45 +0,0 @@ -From ea9d8e3f45404d411c00ae67b45cc35c58265bb7 Mon Sep 17 00:00:00 2001 -From: Xiaotian Feng -Date: Thu, 7 Jan 2010 11:22:44 +0800 -Subject: [PATCH] clockevent: Don't remove broadcast device when cpu is dead - -Marc reported that the BUG_ON in clockevents_notify() triggers on his -system. This happens because the kernel tries to remove an active -clock event device (used for broadcasting) from the device list. - -The handling of devices which can be used as per cpu device and as a -global broadcast device is suboptimal. - -The simplest solution for now (and for stable) is to check whether the -device is used as global broadcast device, but this needs to be -revisited. - -[ tglx: restored the cpuweight check and massaged the changelog ] - -Reported-by: Marc Dionne -Tested-by: Marc Dionne -Signed-off-by: Xiaotian Feng -LKML-Reference: <1262834564-13033-1-git-send-email-dfeng@redhat.com> -Signed-off-by: Thomas Gleixner -Cc: stable@kernel.org ---- - kernel/time/clockevents.c | 3 ++- - 1 files changed, 2 insertions(+), 1 deletions(-) - -diff --git a/kernel/time/clockevents.c b/kernel/time/clockevents.c -index 6f740d9..d7395fd 100644 ---- a/kernel/time/clockevents.c -+++ b/kernel/time/clockevents.c -@@ -259,7 +259,8 @@ void clockevents_notify(unsigned long reason, void *arg) - cpu = *((int *)arg); - list_for_each_entry_safe(dev, tmp, &clockevent_devices, list) { - if (cpumask_test_cpu(cpu, dev->cpumask) && -- cpumask_weight(dev->cpumask) == 1) { -+ cpumask_weight(dev->cpumask) == 1 && -+ !tick_is_broadcast_device(dev)) { - BUG_ON(dev->mode != CLOCK_EVT_MODE_UNUSED); - list_del(&dev->list); - } --- -1.6.6 - diff --git a/debian/patches/bugfix/all/drm-remove-address-mask-param-for-drm_pci_alloc.patch b/debian/patches/bugfix/all/drm-remove-address-mask-param-for-drm_pci_alloc.patch deleted file mode 100644 index c70b5b78e..000000000 --- a/debian/patches/bugfix/all/drm-remove-address-mask-param-for-drm_pci_alloc.patch +++ /dev/null @@ -1,141 +0,0 @@ -From e6be8d9d17bd44061116f601fe2609b3ace7aa69 Mon Sep 17 00:00:00 2001 -From: Zhenyu Wang -Date: Tue, 5 Jan 2010 11:25:05 +0800 -Subject: [PATCH] drm: remove address mask param for drm_pci_alloc() - -drm_pci_alloc() has input of address mask for setting pci dma -mask on the device, which should be properly setup by drm driver. -And leave it as a param for drm_pci_alloc() would cause confusion -or mistake would corrupt the correct dma mask setting, as seen on -intel hw which set wrong dma mask for hw status page. So remove -it from drm_pci_alloc() function. - -Signed-off-by: Zhenyu Wang -Signed-off-by: Dave Airlie ---- - drivers/gpu/drm/ati_pcigart.c | 10 ++++++++-- - drivers/gpu/drm/drm_bufs.c | 4 ++-- - drivers/gpu/drm/drm_pci.c | 8 +------- - drivers/gpu/drm/i915/i915_dma.c | 2 +- - drivers/gpu/drm/i915/i915_gem.c | 2 +- - include/drm/drmP.h | 2 +- - 6 files changed, 14 insertions(+), 14 deletions(-) - -diff --git a/drivers/gpu/drm/ati_pcigart.c b/drivers/gpu/drm/ati_pcigart.c -index 628eae3..a1fce68 100644 ---- a/drivers/gpu/drm/ati_pcigart.c -+++ b/drivers/gpu/drm/ati_pcigart.c -@@ -39,8 +39,7 @@ static int drm_ati_alloc_pcigart_table(struct drm_device *dev, - struct drm_ati_pcigart_info *gart_info) - { - gart_info->table_handle = drm_pci_alloc(dev, gart_info->table_size, -- PAGE_SIZE, -- gart_info->table_mask); -+ PAGE_SIZE); - if (gart_info->table_handle == NULL) - return -ENOMEM; - -@@ -112,6 +111,13 @@ int drm_ati_pcigart_init(struct drm_device *dev, struct drm_ati_pcigart_info *ga - if (gart_info->gart_table_location == DRM_ATI_GART_MAIN) { - DRM_DEBUG("PCI: no table in VRAM: using normal RAM\n"); - -+ if (pci_set_dma_mask(dev->pdev, gart_info->table_mask)) { -+ DRM_ERROR("fail to set dma mask to 0x%Lx\n", -+ gart_info->table_mask); -+ ret = 1; -+ goto done; -+ } -+ - ret = drm_ati_alloc_pcigart_table(dev, gart_info); - if (ret) { - DRM_ERROR("cannot allocate PCI GART page!\n"); -diff --git a/drivers/gpu/drm/drm_bufs.c b/drivers/gpu/drm/drm_bufs.c -index 3d09e30..8417cc4 100644 ---- a/drivers/gpu/drm/drm_bufs.c -+++ b/drivers/gpu/drm/drm_bufs.c -@@ -326,7 +326,7 @@ static int drm_addmap_core(struct drm_device * dev, resource_size_t offset, - * As we're limiting the address to 2^32-1 (or less), - * casting it down to 32 bits is no problem, but we - * need to point to a 64bit variable first. */ -- dmah = drm_pci_alloc(dev, map->size, map->size, 0xffffffffUL); -+ dmah = drm_pci_alloc(dev, map->size, map->size); - if (!dmah) { - kfree(map); - return -ENOMEM; -@@ -885,7 +885,7 @@ int drm_addbufs_pci(struct drm_device * dev, struct drm_buf_desc * request) - - while (entry->buf_count < count) { - -- dmah = drm_pci_alloc(dev, PAGE_SIZE << page_order, 0x1000, 0xfffffffful); -+ dmah = drm_pci_alloc(dev, PAGE_SIZE << page_order, 0x1000); - - if (!dmah) { - /* Set count correctly so we free the proper amount. */ -diff --git a/drivers/gpu/drm/drm_pci.c b/drivers/gpu/drm/drm_pci.c -index 577094f..e68ebf9 100644 ---- a/drivers/gpu/drm/drm_pci.c -+++ b/drivers/gpu/drm/drm_pci.c -@@ -47,8 +47,7 @@ - /** - * \brief Allocate a PCI consistent memory block, for DMA. - */ --drm_dma_handle_t *drm_pci_alloc(struct drm_device * dev, size_t size, size_t align, -- dma_addr_t maxaddr) -+drm_dma_handle_t *drm_pci_alloc(struct drm_device * dev, size_t size, size_t align) - { - drm_dma_handle_t *dmah; - #if 1 -@@ -63,11 +62,6 @@ drm_dma_handle_t *drm_pci_alloc(struct drm_device * dev, size_t size, size_t ali - if (align > size) - return NULL; - -- if (pci_set_dma_mask(dev->pdev, maxaddr) != 0) { -- DRM_ERROR("Setting pci dma mask failed\n"); -- return NULL; -- } -- - dmah = kmalloc(sizeof(drm_dma_handle_t), GFP_KERNEL); - if (!dmah) - return NULL; -diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c -index 701bfea..02607ed 100644 ---- a/drivers/gpu/drm/i915/i915_dma.c -+++ b/drivers/gpu/drm/i915/i915_dma.c -@@ -123,7 +123,7 @@ static int i915_init_phys_hws(struct drm_device *dev) - drm_i915_private_t *dev_priv = dev->dev_private; - /* Program Hardware Status Page */ - dev_priv->status_page_dmah = -- drm_pci_alloc(dev, PAGE_SIZE, PAGE_SIZE, 0xffffffff); -+ drm_pci_alloc(dev, PAGE_SIZE, PAGE_SIZE); - - if (!dev_priv->status_page_dmah) { - DRM_ERROR("Can not allocate hardware status page\n"); -diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c -index 917b837..c7f0cbe 100644 ---- a/drivers/gpu/drm/i915/i915_gem.c -+++ b/drivers/gpu/drm/i915/i915_gem.c -@@ -4708,7 +4708,7 @@ int i915_gem_init_phys_object(struct drm_device *dev, - - phys_obj->id = id; - -- phys_obj->handle = drm_pci_alloc(dev, size, 0, 0xffffffff); -+ phys_obj->handle = drm_pci_alloc(dev, size, 0); - if (!phys_obj->handle) { - ret = -ENOMEM; - goto kfree_obj; -diff --git a/include/drm/drmP.h b/include/drm/drmP.h -index 71dafb6..ffac157 100644 ---- a/include/drm/drmP.h -+++ b/include/drm/drmP.h -@@ -1408,7 +1408,7 @@ extern int drm_ati_pcigart_cleanup(struct drm_device *dev, - struct drm_ati_pcigart_info * gart_info); - - extern drm_dma_handle_t *drm_pci_alloc(struct drm_device *dev, size_t size, -- size_t align, dma_addr_t maxaddr); -+ size_t align); - extern void __drm_pci_free(struct drm_device *dev, drm_dma_handle_t * dmah); - extern void drm_pci_free(struct drm_device *dev, drm_dma_handle_t * dmah); - --- -1.6.5.7 - diff --git a/debian/patches/bugfix/all/fasync-split-fasync_helper.patch b/debian/patches/bugfix/all/fasync-split-fasync_helper.patch deleted file mode 100644 index b291d2ecb..000000000 --- a/debian/patches/bugfix/all/fasync-split-fasync_helper.patch +++ /dev/null @@ -1,173 +0,0 @@ -commit 53281b6d34d44308372d16acb7fb5327609f68b6 -Author: Linus Torvalds -Date: Wed Dec 16 08:23:37 2009 -0800 - - fasync: split 'fasync_helper()' into separate add/remove functions - - Yes, the add and remove cases do share the same basic loop and the - locking, but the compiler can inline and then CSE some of the end result - anyway. And splitting it up makes the code way easier to follow, - and makes it clearer exactly what the semantics are. - - In particular, we must make sure that the FASYNC flag in file->f_flags - exactly matches the state of "is this file on any fasync list", since - not only is that flag visible to user space (F_GETFL), but we also use - that flag to check whether we need to remove any fasync entries on file - close. - - We got that wrong for the case of a mixed use of file locking (which - tries to remove any fasync entries for file leases) and fasync. - - Splitting the function up also makes it possible to do some future - optimizations without making the function even messier. In particular, - since the FASYNC flag has to match the state of "is this on a list", we - can do the following future optimizations: - - - on remove, we don't even need to get the locks and traverse the list - if FASYNC isn't set, since we can know a priori that there is no - point (this is effectively the same optimization that we already do - in __fput() wrt removing fasync on file close) - - - on add, we can use the FASYNC flag to decide whether we are changing - an existing entry or need to allocate a new one. - - but this is just the cleanup + fix for the FASYNC flag. - - Acked-by: Al Viro - Tested-by: Tavis Ormandy - Cc: Jeff Dike - Cc: Matt Mackall - Cc: stable@kernel.org - Signed-off-by: Linus Torvalds - -diff --git a/fs/fcntl.c b/fs/fcntl.c -index 2cf93ec..97e01dc 100644 ---- a/fs/fcntl.c -+++ b/fs/fcntl.c -@@ -618,60 +618,90 @@ static DEFINE_RWLOCK(fasync_lock); - static struct kmem_cache *fasync_cache __read_mostly; - - /* -- * fasync_helper() is used by almost all character device drivers -- * to set up the fasync queue. It returns negative on error, 0 if it did -- * no changes and positive if it added/deleted the entry. -+ * Remove a fasync entry. If successfully removed, return -+ * positive and clear the FASYNC flag. If no entry exists, -+ * do nothing and return 0. -+ * -+ * NOTE! It is very important that the FASYNC flag always -+ * match the state "is the filp on a fasync list". -+ * -+ * We always take the 'filp->f_lock', in since fasync_lock -+ * needs to be irq-safe. - */ --int fasync_helper(int fd, struct file * filp, int on, struct fasync_struct **fapp) -+static int fasync_remove_entry(struct file *filp, struct fasync_struct **fapp) - { - struct fasync_struct *fa, **fp; -- struct fasync_struct *new = NULL; - int result = 0; - -- if (on) { -- new = kmem_cache_alloc(fasync_cache, GFP_KERNEL); -- if (!new) -- return -ENOMEM; -+ spin_lock(&filp->f_lock); -+ write_lock_irq(&fasync_lock); -+ for (fp = fapp; (fa = *fp) != NULL; fp = &fa->fa_next) { -+ if (fa->fa_file != filp) -+ continue; -+ *fp = fa->fa_next; -+ kmem_cache_free(fasync_cache, fa); -+ filp->f_flags &= ~FASYNC; -+ result = 1; -+ break; - } -+ write_unlock_irq(&fasync_lock); -+ spin_unlock(&filp->f_lock); -+ return result; -+} -+ -+/* -+ * Add a fasync entry. Return negative on error, positive if -+ * added, and zero if did nothing but change an existing one. -+ * -+ * NOTE! It is very important that the FASYNC flag always -+ * match the state "is the filp on a fasync list". -+ */ -+static int fasync_add_entry(int fd, struct file *filp, struct fasync_struct **fapp) -+{ -+ struct fasync_struct *new, *fa, **fp; -+ int result = 0; -+ -+ new = kmem_cache_alloc(fasync_cache, GFP_KERNEL); -+ if (!new) -+ return -ENOMEM; - -- /* -- * We need to take f_lock first since it's not an IRQ-safe -- * lock. -- */ - spin_lock(&filp->f_lock); - write_lock_irq(&fasync_lock); - for (fp = fapp; (fa = *fp) != NULL; fp = &fa->fa_next) { -- if (fa->fa_file == filp) { -- if(on) { -- fa->fa_fd = fd; -- kmem_cache_free(fasync_cache, new); -- } else { -- *fp = fa->fa_next; -- kmem_cache_free(fasync_cache, fa); -- result = 1; -- } -- goto out; -- } -+ if (fa->fa_file != filp) -+ continue; -+ fa->fa_fd = fd; -+ kmem_cache_free(fasync_cache, new); -+ goto out; - } - -- if (on) { -- new->magic = FASYNC_MAGIC; -- new->fa_file = filp; -- new->fa_fd = fd; -- new->fa_next = *fapp; -- *fapp = new; -- result = 1; -- } -+ new->magic = FASYNC_MAGIC; -+ new->fa_file = filp; -+ new->fa_fd = fd; -+ new->fa_next = *fapp; -+ *fapp = new; -+ result = 1; -+ filp->f_flags |= FASYNC; -+ - out: -- if (on) -- filp->f_flags |= FASYNC; -- else -- filp->f_flags &= ~FASYNC; - write_unlock_irq(&fasync_lock); - spin_unlock(&filp->f_lock); - return result; - } - -+/* -+ * fasync_helper() is used by almost all character device drivers -+ * to set up the fasync queue, and for regular files by the file -+ * lease code. It returns negative on error, 0 if it did no changes -+ * and positive if it added/deleted the entry. -+ */ -+int fasync_helper(int fd, struct file * filp, int on, struct fasync_struct **fapp) -+{ -+ if (!on) -+ return fasync_remove_entry(filp, fapp); -+ return fasync_add_entry(fd, filp, fapp); -+} -+ - EXPORT_SYMBOL(fasync_helper); - - void __kill_fasync(struct fasync_struct *fa, int sig, int band) diff --git a/debian/patches/debian/mremap-fix-conflict-between-2.6.32.4-and-vserver.patch b/debian/patches/debian/mremap-fix-conflict-between-2.6.32.4-and-vserver.patch deleted file mode 100644 index 78a71f97e..000000000 --- a/debian/patches/debian/mremap-fix-conflict-between-2.6.32.4-and-vserver.patch +++ /dev/null @@ -1,32 +0,0 @@ -From: Ben Hutchings -Subject: [PATCH] mm/mremap: Fix conflict between 2.6.32.4 and vserver - -Make some cosmetic changes to the reworked mremap in 2.6.32.4 so that -the vserver patch will still apply (with fuzz 1). - ---- a/mm/mremap.c -+++ b/mm/mremap.c -@@ -288,11 +288,11 @@ - lock_limit = current->signal->rlim[RLIMIT_MEMLOCK].rlim_cur; - locked += new_len - old_len; - if (locked > lock_limit && !capable(CAP_IPC_LOCK)) -- goto Eagain; -+ goto out; - } -- -- if (!may_expand_vm(mm, (new_len - old_len) >> PAGE_SHIFT)) -+ if (!may_expand_vm(mm, (new_len - old_len) >> PAGE_SHIFT)) { - goto Enomem; -+ } - - if (vma->vm_flags & VM_ACCOUNT) { - unsigned long charged = (new_len - old_len) >> PAGE_SHIFT; -@@ -309,7 +309,7 @@ - return ERR_PTR(-EINVAL); - Enomem: - return ERR_PTR(-ENOMEM); --Eagain: -+out: - return ERR_PTR(-EAGAIN); - } - diff --git a/debian/patches/features/all/SCSI-mpt2sas-New-device-SAS2208-support-is-added.patch b/debian/patches/features/all/SCSI-mpt2sas-New-device-SAS2208-support-is-added.patch deleted file mode 100644 index 9fbd7acdf..000000000 --- a/debian/patches/features/all/SCSI-mpt2sas-New-device-SAS2208-support-is-added.patch +++ /dev/null @@ -1,71 +0,0 @@ -From db27136a89d061bf9dceb28953a61a8ef862ca7f Mon Sep 17 00:00:00 2001 -From: Kashyap, Desai -Date: Wed, 23 Sep 2009 17:24:27 +0530 -Subject: [PATCH] [SCSI] mpt2sas: New device SAS2208 support is added - -Added device ids range for { 0x80 - 87 } , modified mpi/mpi2_cnfg.h containing -MPI2_MFGPAGE_DEVID_SAS2208_X. - -Signed-off-by: Kashyap Desai -Signed-off-by: Eric Moore -Signed-off-by: James Bottomley ---- - drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h | 8 ++++++++ - drivers/scsi/mpt2sas/mpt2sas_scsih.c | 18 ++++++++++++++++++ - 2 files changed, 26 insertions(+), 0 deletions(-) - -diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h b/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h -index ab47c46..5af66db 100644 ---- a/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h -+++ b/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h -@@ -348,6 +348,14 @@ typedef struct _MPI2_CONFIG_REPLY - #define MPI2_MFGPAGE_DEVID_SAS2108_3 (0x0077) - #define MPI2_MFGPAGE_DEVID_SAS2116_1 (0x0064) - #define MPI2_MFGPAGE_DEVID_SAS2116_2 (0x0065) -+#define MPI2_MFGPAGE_DEVID_SAS2208_1 (0x0080) -+#define MPI2_MFGPAGE_DEVID_SAS2208_2 (0x0081) -+#define MPI2_MFGPAGE_DEVID_SAS2208_3 (0x0082) -+#define MPI2_MFGPAGE_DEVID_SAS2208_4 (0x0083) -+#define MPI2_MFGPAGE_DEVID_SAS2208_5 (0x0084) -+#define MPI2_MFGPAGE_DEVID_SAS2208_6 (0x0085) -+#define MPI2_MFGPAGE_DEVID_SAS2208_7 (0x0086) -+#define MPI2_MFGPAGE_DEVID_SAS2208_8 (0x0087) - - - /* Manufacturing Page 0 */ -diff --git a/drivers/scsi/mpt2sas/mpt2sas_scsih.c b/drivers/scsi/mpt2sas/mpt2sas_scsih.c -index efb6270..91d6115 100644 ---- a/drivers/scsi/mpt2sas/mpt2sas_scsih.c -+++ b/drivers/scsi/mpt2sas/mpt2sas_scsih.c -@@ -196,10 +196,28 @@ static struct pci_device_id scsih_pci_table[] = { - PCI_ANY_ID, PCI_ANY_ID }, - { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2108_3, - PCI_ANY_ID, PCI_ANY_ID }, -+ /* Meteor ~ 2116 */ - { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2116_1, - PCI_ANY_ID, PCI_ANY_ID }, - { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2116_2, - PCI_ANY_ID, PCI_ANY_ID }, -+ /* Thunderbolt ~ 2208 */ -+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_1, -+ PCI_ANY_ID, PCI_ANY_ID }, -+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_2, -+ PCI_ANY_ID, PCI_ANY_ID }, -+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_3, -+ PCI_ANY_ID, PCI_ANY_ID }, -+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_4, -+ PCI_ANY_ID, PCI_ANY_ID }, -+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_5, -+ PCI_ANY_ID, PCI_ANY_ID }, -+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_6, -+ PCI_ANY_ID, PCI_ANY_ID }, -+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_7, -+ PCI_ANY_ID, PCI_ANY_ID }, -+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_8, -+ PCI_ANY_ID, PCI_ANY_ID }, - {0} /* Terminating entry */ - }; - MODULE_DEVICE_TABLE(pci, scsih_pci_table); --- -1.6.5.7 - diff --git a/debian/patches/features/all/ar9170-Add-support-for-D-Link-DWA-160-A2.patch b/debian/patches/features/all/ar9170-Add-support-for-D-Link-DWA-160-A2.patch deleted file mode 100644 index 7f7e7126e..000000000 --- a/debian/patches/features/all/ar9170-Add-support-for-D-Link-DWA-160-A2.patch +++ /dev/null @@ -1,41 +0,0 @@ -From 15295380f45aa0d35665f6e5596ac98c081d95b9 Mon Sep 17 00:00:00 2001 -From: Thomas Klute -Date: Tue, 17 Nov 2009 11:58:18 +0100 -Subject: [PATCH] ar9170: Add support for D-Link DWA 160 A2 - -At least two revisions of the D-Link DWA 160 exist, called A1 and A2. A1 -(USB-ID 07d1:3c10) is already listed in usb.c as D-Link DWA 160A. A2 -(USB-ID 07d1:3a09) works if added to ar9170_usb_ids. I didn't do much -testing until now, but I was able to connect to APs using WPA or WEP and -transmit data. - -Summary: - -* Add model revision number to the comment for D-Link DWA 160 A1 (07d1:3c10) -* Add support for D-Link DWA 160 A2 (07d1:3a09) - -Signed-off-by: Thomas Klute -Signed-off-by: John W. Linville ---- - drivers/net/wireless/ath/ar9170/usb.c | 4 +++- - 1 files changed, 3 insertions(+), 1 deletions(-) - -diff --git a/drivers/net/wireless/ath/ar9170/usb.c b/drivers/net/wireless/ath/ar9170/usb.c -index 6bdcdf6..e0799d9 100644 ---- a/drivers/net/wireless/ath/ar9170/usb.c -+++ b/drivers/net/wireless/ath/ar9170/usb.c -@@ -68,8 +68,10 @@ static struct usb_device_id ar9170_usb_ids[] = { - { USB_DEVICE(0x0cf3, 0x1002) }, - /* Cace Airpcap NX */ - { USB_DEVICE(0xcace, 0x0300) }, -- /* D-Link DWA 160A */ -+ /* D-Link DWA 160 A1 */ - { USB_DEVICE(0x07d1, 0x3c10) }, -+ /* D-Link DWA 160 A2 */ -+ { USB_DEVICE(0x07d1, 0x3a09) }, - /* Netgear WNDA3100 */ - { USB_DEVICE(0x0846, 0x9010) }, - /* Netgear WN111 v2 */ --- -1.6.5.7 - diff --git a/debian/patches/features/all/atl1e-allow-offload-disable.patch b/debian/patches/features/all/atl1e-allow-offload-disable.patch deleted file mode 100644 index 98a6ea7ed..000000000 --- a/debian/patches/features/all/atl1e-allow-offload-disable.patch +++ /dev/null @@ -1,30 +0,0 @@ -From cf02d4b259a3b5fa234bf8ffa34aac9c129b0672 Mon Sep 17 00:00:00 2001 -From: Ben Hutchings -Date: Mon, 30 Nov 2009 02:57:29 +0000 -Subject: [PATCH] atl1e: Allow TX checksum offload and TSO to be disabled and reenabled - ---- - drivers/net/atl1e/atl1e_ethtool.c | 2 ++ - 1 files changed, 2 insertions(+), 0 deletions(-) - -diff --git a/drivers/net/atl1e/atl1e_ethtool.c b/drivers/net/atl1e/atl1e_ethtool.c -index 60edb9f..b0fb725 100644 ---- a/drivers/net/atl1e/atl1e_ethtool.c -+++ b/drivers/net/atl1e/atl1e_ethtool.c -@@ -394,11 +394,13 @@ static const struct ethtool_ops atl1e_ethtool_ops = { - .get_eeprom = atl1e_get_eeprom, - .set_eeprom = atl1e_set_eeprom, - .get_tx_csum = atl1e_get_tx_csum, -+ .set_tx_csum = ethtool_op_set_tx_hw_csum, - .get_sg = ethtool_op_get_sg, - .set_sg = ethtool_op_set_sg, - #ifdef NETIF_F_TSO - .get_tso = ethtool_op_get_tso, - #endif -+ .set_tso = ethtool_op_set_tso, - }; - - void atl1e_set_ethtool_ops(struct net_device *netdev) --- -1.6.5.3 - diff --git a/debian/patches/features/all/be2net-Add-support-for-next-generation-of-BladeEngine.patch b/debian/patches/features/all/be2net-Add-support-for-next-generation-of-BladeEngine.patch deleted file mode 100644 index 764d8776f..000000000 --- a/debian/patches/features/all/be2net-Add-support-for-next-generation-of-BladeEngine.patch +++ /dev/null @@ -1,54 +0,0 @@ -From 12d7ea2c5a5c87834daf9fcd920aab80ff6248b1 Mon Sep 17 00:00:00 2001 -From: Ajit Khaparde -Date: Fri, 16 Oct 2009 18:02:12 -0700 -Subject: [PATCH] be2net: Add support for next generation of BladeEngine device. - -Add new PCI ids to support next generation of BladeEngine device. - -Signed-off-by: Ajit Khaparde -Signed-off-by: David S. Miller ---- - drivers/net/benet/be.h | 15 +++++++++++++-- - 1 files changed, 13 insertions(+), 2 deletions(-) - -diff --git a/drivers/net/benet/be.h b/drivers/net/benet/be.h -index 4b61a91..ce75631 100644 ---- a/drivers/net/benet/be.h -+++ b/drivers/net/benet/be.h -@@ -35,20 +35,31 @@ - #define DRV_VER "2.101.205" - #define DRV_NAME "be2net" - #define BE_NAME "ServerEngines BladeEngine2 10Gbps NIC" -+#define BE3_NAME "ServerEngines BladeEngine3 10Gbps NIC" - #define OC_NAME "Emulex OneConnect 10Gbps NIC" -+#define OC_NAME1 "Emulex OneConnect 10Gbps NIC (be3)" - #define DRV_DESC BE_NAME "Driver" - - #define BE_VENDOR_ID 0x19a2 - #define BE_DEVICE_ID1 0x211 -+#define BE_DEVICE_ID2 0x221 - #define OC_DEVICE_ID1 0x700 - #define OC_DEVICE_ID2 0x701 -+#define OC_DEVICE_ID3 0x710 - - static inline char *nic_name(struct pci_dev *pdev) - { -- if (pdev->device == OC_DEVICE_ID1 || pdev->device == OC_DEVICE_ID2) -+ switch (pdev->device) { -+ case OC_DEVICE_ID1: -+ case OC_DEVICE_ID2: - return OC_NAME; -- else -+ case OC_DEVICE_ID3: -+ return OC_NAME1; -+ case BE_DEVICE_ID2: -+ return BE3_NAME; -+ default: - return BE_NAME; -+ } - } - - /* Number of bytes of an RX frame that are copied to skb->data */ --- -1.6.5.7 - diff --git a/debian/patches/features/all/be2net-Add-the-new-PCI-IDs-to-PCI_DEVICE_TABLE.patch b/debian/patches/features/all/be2net-Add-the-new-PCI-IDs-to-PCI_DEVICE_TABLE.patch deleted file mode 100644 index 5fb4a7b1e..000000000 --- a/debian/patches/features/all/be2net-Add-the-new-PCI-IDs-to-PCI_DEVICE_TABLE.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 59fd5d87a4243a992f3a3e69f3627cf4c509608e Mon Sep 17 00:00:00 2001 -From: Ajit Khaparde -Date: Thu, 29 Oct 2009 01:11:06 -0700 -Subject: [PATCH] be2net: Add the new PCI IDs to PCI_DEVICE_TABLE. - -This patch adds the PCI IDs for the next generation chip to the -PCI_DEVICE_ID table. - -Signed-off-by: Ajit Khaparde -Signed-off-by: David S. Miller ---- - drivers/net/benet/be_main.c | 2 ++ - 1 files changed, 2 insertions(+), 0 deletions(-) - -diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c -index 4520db7..43180dc 100644 ---- a/drivers/net/benet/be_main.c -+++ b/drivers/net/benet/be_main.c -@@ -31,8 +31,10 @@ MODULE_PARM_DESC(rx_frag_size, "Size of a fragment that holds rcvd data."); - - static DEFINE_PCI_DEVICE_TABLE(be_dev_ids) = { - { PCI_DEVICE(BE_VENDOR_ID, BE_DEVICE_ID1) }, -+ { PCI_DEVICE(BE_VENDOR_ID, BE_DEVICE_ID2) }, - { PCI_DEVICE(BE_VENDOR_ID, OC_DEVICE_ID1) }, - { PCI_DEVICE(BE_VENDOR_ID, OC_DEVICE_ID2) }, -+ { PCI_DEVICE(BE_VENDOR_ID, OC_DEVICE_ID3) }, - { 0 } - }; - MODULE_DEVICE_TABLE(pci, be_dev_ids); --- -1.6.5.7 - diff --git a/debian/patches/features/all/ftdi_sio-add-USB-device-ID-s-for-B-B-Electronics.patch b/debian/patches/features/all/ftdi_sio-add-USB-device-ID-s-for-B-B-Electronics.patch deleted file mode 100644 index 5245dba3c..000000000 --- a/debian/patches/features/all/ftdi_sio-add-USB-device-ID-s-for-B-B-Electronics.patch +++ /dev/null @@ -1,66 +0,0 @@ -From a8cbd90a0410096e152f68a4e114a8b5c7abb49b Mon Sep 17 00:00:00 2001 -From: Cliff Brake -Date: Tue, 1 Dec 2009 09:53:42 -0500 -Subject: [PATCH] USB: ftdi_sio: add USB device ID's for B&B Electronics line - -Reviewed-by: John Pilles -Signed-off-by: Cliff Brake -Signed-off-by: Greg Kroah-Hartman ---- - drivers/usb/serial/ftdi_sio.c | 14 ++++++++++++++ - drivers/usb/serial/ftdi_sio.h | 14 ++++++++++++++ - 2 files changed, 28 insertions(+), 0 deletions(-) - -diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c -index a8103e0..f99498f 100644 ---- a/drivers/usb/serial/ftdi_sio.c -+++ b/drivers/usb/serial/ftdi_sio.c -@@ -598,6 +598,20 @@ static struct usb_device_id id_table_combined [] = { - { USB_DEVICE(BANDB_VID, BANDB_USOTL4_PID) }, - { USB_DEVICE(BANDB_VID, BANDB_USTL4_PID) }, - { USB_DEVICE(BANDB_VID, BANDB_USO9ML2_PID) }, -+ { USB_DEVICE(BANDB_VID, BANDB_USOPTL4_PID) }, -+ { USB_DEVICE(BANDB_VID, BANDB_USPTL4_PID) }, -+ { USB_DEVICE(BANDB_VID, BANDB_USO9ML2DR_2_PID) }, -+ { USB_DEVICE(BANDB_VID, BANDB_USO9ML2DR_PID) }, -+ { USB_DEVICE(BANDB_VID, BANDB_USOPTL4DR2_PID) }, -+ { USB_DEVICE(BANDB_VID, BANDB_USOPTL4DR_PID) }, -+ { USB_DEVICE(BANDB_VID, BANDB_485USB9F_2W_PID) }, -+ { USB_DEVICE(BANDB_VID, BANDB_485USB9F_4W_PID) }, -+ { USB_DEVICE(BANDB_VID, BANDB_232USB9M_PID) }, -+ { USB_DEVICE(BANDB_VID, BANDB_485USBTB_2W_PID) }, -+ { USB_DEVICE(BANDB_VID, BANDB_485USBTB_4W_PID) }, -+ { USB_DEVICE(BANDB_VID, BANDB_TTL5USB9M_PID) }, -+ { USB_DEVICE(BANDB_VID, BANDB_TTL3USB9M_PID) }, -+ { USB_DEVICE(BANDB_VID, BANDB_ZZ_PROG1_USB_PID) }, - { USB_DEVICE(FTDI_VID, EVER_ECO_PRO_CDS) }, - { USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_1_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_2_PID) }, -diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h -index 6f31e0d..4586a24 100644 ---- a/drivers/usb/serial/ftdi_sio.h -+++ b/drivers/usb/serial/ftdi_sio.h -@@ -662,6 +662,20 @@ - #define BANDB_USOTL4_PID 0xAC01 /* USOTL4 Isolated RS-485 Converter */ - #define BANDB_USTL4_PID 0xAC02 /* USTL4 RS-485 Converter */ - #define BANDB_USO9ML2_PID 0xAC03 /* USO9ML2 Isolated RS-232 Converter */ -+#define BANDB_USOPTL4_PID 0xAC11 -+#define BANDB_USPTL4_PID 0xAC12 -+#define BANDB_USO9ML2DR_2_PID 0xAC16 -+#define BANDB_USO9ML2DR_PID 0xAC17 -+#define BANDB_USOPTL4DR2_PID 0xAC18 /* USOPTL4R-2 2-port Isolated RS-232 Converter */ -+#define BANDB_USOPTL4DR_PID 0xAC19 -+#define BANDB_485USB9F_2W_PID 0xAC25 -+#define BANDB_485USB9F_4W_PID 0xAC26 -+#define BANDB_232USB9M_PID 0xAC27 -+#define BANDB_485USBTB_2W_PID 0xAC33 -+#define BANDB_485USBTB_4W_PID 0xAC34 -+#define BANDB_TTL5USB9M_PID 0xAC49 -+#define BANDB_TTL3USB9M_PID 0xAC50 -+#define BANDB_ZZ_PROG1_USB_PID 0xBA02 - - /* - * RM Michaelides CANview USB (http://www.rmcan.com) --- -1.6.5.7 - diff --git a/debian/patches/features/all/hda-Add-PCI-IDs-for-Nvidia-G2xx-series.patch b/debian/patches/features/all/hda-Add-PCI-IDs-for-Nvidia-G2xx-series.patch deleted file mode 100644 index a7c06312e..000000000 --- a/debian/patches/features/all/hda-Add-PCI-IDs-for-Nvidia-G2xx-series.patch +++ /dev/null @@ -1,28 +0,0 @@ -From 6dd7dc767e35cfbb38f8c63a50b1c27acad25920 Mon Sep 17 00:00:00 2001 -From: Stefan Ringel -Date: Mon, 14 Dec 2009 11:27:11 +0100 -Subject: [PATCH] ALSA: hda - Add PCI IDs for Nvidia G2xx-series - -Signed-off-by: Stefan Ringel -Signed-off-by: Takashi Iwai ---- - sound/pci/hda/hda_intel.c | 3 +++ - 1 files changed, 3 insertions(+), 0 deletions(-) - -diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c -index e54420e..9b56f93 100644 ---- a/sound/pci/hda/hda_intel.c -+++ b/sound/pci/hda/hda_intel.c -@@ -2713,6 +2713,9 @@ static struct pci_device_id azx_ids[] = { - { PCI_DEVICE(0x10de, 0x0ac1), .driver_data = AZX_DRIVER_NVIDIA }, - { PCI_DEVICE(0x10de, 0x0ac2), .driver_data = AZX_DRIVER_NVIDIA }, - { PCI_DEVICE(0x10de, 0x0ac3), .driver_data = AZX_DRIVER_NVIDIA }, -+ { PCI_DEVICE(0x10de, 0x0be2), .driver_data = AZX_DRIVER_NVIDIA }, -+ { PCI_DEVICE(0x10de, 0x0be3), .driver_data = AZX_DRIVER_NVIDIA }, -+ { PCI_DEVICE(0x10de, 0x0be4), .driver_data = AZX_DRIVER_NVIDIA }, - { PCI_DEVICE(0x10de, 0x0d94), .driver_data = AZX_DRIVER_NVIDIA }, - { PCI_DEVICE(0x10de, 0x0d95), .driver_data = AZX_DRIVER_NVIDIA }, - { PCI_DEVICE(0x10de, 0x0d96), .driver_data = AZX_DRIVER_NVIDIA }, --- -1.6.5.7 - diff --git a/debian/patches/features/all/hwmon-Add-driver-for-VIA-CPU-core-temperature.patch b/debian/patches/features/all/hwmon-Add-driver-for-VIA-CPU-core-temperature.patch deleted file mode 100644 index 74572460a..000000000 --- a/debian/patches/features/all/hwmon-Add-driver-for-VIA-CPU-core-temperature.patch +++ /dev/null @@ -1,417 +0,0 @@ -From 70c38772aef27b01dc236fb4016261c3828df6aa Mon Sep 17 00:00:00 2001 -From: Harald Welte -Date: Wed, 16 Dec 2009 21:38:28 +0100 -Subject: [PATCH] hwmon: Add driver for VIA CPU core temperature - -This is a driver for the on-die digital temperature sensor of -VIA's recent CPU models. - -[JD: Misc clean-ups.] - -Signed-off-by: Harald Welte -Cc: Juerg Haefliger -Signed-off-by: Jean Delvare -Tested-by: Adam Nielsen ---- - drivers/hwmon/Kconfig | 8 + - drivers/hwmon/Makefile | 1 + - drivers/hwmon/via-cputemp.c | 356 +++++++++++++++++++++++++++++++++++++++++++ - 3 files changed, 365 insertions(+), 0 deletions(-) - create mode 100644 drivers/hwmon/via-cputemp.c - -diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig -index 665947f..be8eead 100644 ---- a/drivers/hwmon/Kconfig -+++ b/drivers/hwmon/Kconfig -@@ -822,6 +822,14 @@ config SENSORS_TMP421 - This driver can also be built as a module. If so, the module - will be called tmp421. - -+config SENSORS_VIA_CPUTEMP -+ tristate "VIA CPU temperature sensor" -+ depends on X86 -+ help -+ If you say yes here you get support for the temperature -+ sensor inside your CPU. Supported are all known variants of -+ the VIA C7 and Nano. -+ - config SENSORS_VIA686A - tristate "VIA686A" - depends on PCI -diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile -index da84a6a..312b7c3 100644 ---- a/drivers/hwmon/Makefile -+++ b/drivers/hwmon/Makefile -@@ -88,6 +88,7 @@ obj-$(CONFIG_SENSORS_SMSC47M192)+= smsc47m192.o - obj-$(CONFIG_SENSORS_THMC50) += thmc50.o - obj-$(CONFIG_SENSORS_TMP401) += tmp401.o - obj-$(CONFIG_SENSORS_TMP421) += tmp421.o -+obj-$(CONFIG_SENSORS_VIA_CPUTEMP)+= via-cputemp.o - obj-$(CONFIG_SENSORS_VIA686A) += via686a.o - obj-$(CONFIG_SENSORS_VT1211) += vt1211.o - obj-$(CONFIG_SENSORS_VT8231) += vt8231.o -diff --git a/drivers/hwmon/via-cputemp.c b/drivers/hwmon/via-cputemp.c -new file mode 100644 -index 0000000..7442cf7 ---- /dev/null -+++ b/drivers/hwmon/via-cputemp.c -@@ -0,0 +1,356 @@ -+/* -+ * via-cputemp.c - Driver for VIA CPU core temperature monitoring -+ * Copyright (C) 2009 VIA Technologies, Inc. -+ * -+ * based on existing coretemp.c, which is -+ * -+ * Copyright (C) 2007 Rudolf Marek -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; version 2 of the License. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -+ * 02110-1301 USA. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define DRVNAME "via_cputemp" -+ -+enum { SHOW_TEMP, SHOW_LABEL, SHOW_NAME } SHOW; -+ -+/* -+ * Functions declaration -+ */ -+ -+struct via_cputemp_data { -+ struct device *hwmon_dev; -+ const char *name; -+ u32 id; -+ u32 msr; -+}; -+ -+/* -+ * Sysfs stuff -+ */ -+ -+static ssize_t show_name(struct device *dev, struct device_attribute -+ *devattr, char *buf) -+{ -+ int ret; -+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); -+ struct via_cputemp_data *data = dev_get_drvdata(dev); -+ -+ if (attr->index == SHOW_NAME) -+ ret = sprintf(buf, "%s\n", data->name); -+ else /* show label */ -+ ret = sprintf(buf, "Core %d\n", data->id); -+ return ret; -+} -+ -+static ssize_t show_temp(struct device *dev, -+ struct device_attribute *devattr, char *buf) -+{ -+ struct via_cputemp_data *data = dev_get_drvdata(dev); -+ u32 eax, edx; -+ int err; -+ -+ err = rdmsr_safe_on_cpu(data->id, data->msr, &eax, &edx); -+ if (err) -+ return -EAGAIN; -+ -+ return sprintf(buf, "%lu\n", ((unsigned long)eax & 0xffffff) * 1000); -+} -+ -+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, -+ SHOW_TEMP); -+static SENSOR_DEVICE_ATTR(temp1_label, S_IRUGO, show_name, NULL, SHOW_LABEL); -+static SENSOR_DEVICE_ATTR(name, S_IRUGO, show_name, NULL, SHOW_NAME); -+ -+static struct attribute *via_cputemp_attributes[] = { -+ &sensor_dev_attr_name.dev_attr.attr, -+ &sensor_dev_attr_temp1_label.dev_attr.attr, -+ &sensor_dev_attr_temp1_input.dev_attr.attr, -+ NULL -+}; -+ -+static const struct attribute_group via_cputemp_group = { -+ .attrs = via_cputemp_attributes, -+}; -+ -+static int __devinit via_cputemp_probe(struct platform_device *pdev) -+{ -+ struct via_cputemp_data *data; -+ struct cpuinfo_x86 *c = &cpu_data(pdev->id); -+ int err; -+ u32 eax, edx; -+ -+ data = kzalloc(sizeof(struct via_cputemp_data), GFP_KERNEL); -+ if (!data) { -+ err = -ENOMEM; -+ dev_err(&pdev->dev, "Out of memory\n"); -+ goto exit; -+ } -+ -+ data->id = pdev->id; -+ data->name = "via_cputemp"; -+ -+ switch (c->x86_model) { -+ case 0xA: -+ /* C7 A */ -+ case 0xD: -+ /* C7 D */ -+ data->msr = 0x1169; -+ break; -+ case 0xF: -+ /* Nano */ -+ data->msr = 0x1423; -+ break; -+ default: -+ err = -ENODEV; -+ goto exit_free; -+ } -+ -+ /* test if we can access the TEMPERATURE MSR */ -+ err = rdmsr_safe_on_cpu(data->id, data->msr, &eax, &edx); -+ if (err) { -+ dev_err(&pdev->dev, -+ "Unable to access TEMPERATURE MSR, giving up\n"); -+ goto exit_free; -+ } -+ -+ platform_set_drvdata(pdev, data); -+ -+ err = sysfs_create_group(&pdev->dev.kobj, &via_cputemp_group); -+ if (err) -+ goto exit_free; -+ -+ data->hwmon_dev = hwmon_device_register(&pdev->dev); -+ if (IS_ERR(data->hwmon_dev)) { -+ err = PTR_ERR(data->hwmon_dev); -+ dev_err(&pdev->dev, "Class registration failed (%d)\n", -+ err); -+ goto exit_remove; -+ } -+ -+ return 0; -+ -+exit_remove: -+ sysfs_remove_group(&pdev->dev.kobj, &via_cputemp_group); -+exit_free: -+ platform_set_drvdata(pdev, NULL); -+ kfree(data); -+exit: -+ return err; -+} -+ -+static int __devexit via_cputemp_remove(struct platform_device *pdev) -+{ -+ struct via_cputemp_data *data = platform_get_drvdata(pdev); -+ -+ hwmon_device_unregister(data->hwmon_dev); -+ sysfs_remove_group(&pdev->dev.kobj, &via_cputemp_group); -+ platform_set_drvdata(pdev, NULL); -+ kfree(data); -+ return 0; -+} -+ -+static struct platform_driver via_cputemp_driver = { -+ .driver = { -+ .owner = THIS_MODULE, -+ .name = DRVNAME, -+ }, -+ .probe = via_cputemp_probe, -+ .remove = __devexit_p(via_cputemp_remove), -+}; -+ -+struct pdev_entry { -+ struct list_head list; -+ struct platform_device *pdev; -+ unsigned int cpu; -+}; -+ -+static LIST_HEAD(pdev_list); -+static DEFINE_MUTEX(pdev_list_mutex); -+ -+static int __cpuinit via_cputemp_device_add(unsigned int cpu) -+{ -+ int err; -+ struct platform_device *pdev; -+ struct pdev_entry *pdev_entry; -+ -+ pdev = platform_device_alloc(DRVNAME, cpu); -+ if (!pdev) { -+ err = -ENOMEM; -+ printk(KERN_ERR DRVNAME ": Device allocation failed\n"); -+ goto exit; -+ } -+ -+ pdev_entry = kzalloc(sizeof(struct pdev_entry), GFP_KERNEL); -+ if (!pdev_entry) { -+ err = -ENOMEM; -+ goto exit_device_put; -+ } -+ -+ err = platform_device_add(pdev); -+ if (err) { -+ printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n", -+ err); -+ goto exit_device_free; -+ } -+ -+ pdev_entry->pdev = pdev; -+ pdev_entry->cpu = cpu; -+ mutex_lock(&pdev_list_mutex); -+ list_add_tail(&pdev_entry->list, &pdev_list); -+ mutex_unlock(&pdev_list_mutex); -+ -+ return 0; -+ -+exit_device_free: -+ kfree(pdev_entry); -+exit_device_put: -+ platform_device_put(pdev); -+exit: -+ return err; -+} -+ -+#ifdef CONFIG_HOTPLUG_CPU -+static void via_cputemp_device_remove(unsigned int cpu) -+{ -+ struct pdev_entry *p, *n; -+ mutex_lock(&pdev_list_mutex); -+ list_for_each_entry_safe(p, n, &pdev_list, list) { -+ if (p->cpu == cpu) { -+ platform_device_unregister(p->pdev); -+ list_del(&p->list); -+ kfree(p); -+ } -+ } -+ mutex_unlock(&pdev_list_mutex); -+} -+ -+static int __cpuinit via_cputemp_cpu_callback(struct notifier_block *nfb, -+ unsigned long action, void *hcpu) -+{ -+ unsigned int cpu = (unsigned long) hcpu; -+ -+ switch (action) { -+ case CPU_ONLINE: -+ case CPU_DOWN_FAILED: -+ via_cputemp_device_add(cpu); -+ break; -+ case CPU_DOWN_PREPARE: -+ via_cputemp_device_remove(cpu); -+ break; -+ } -+ return NOTIFY_OK; -+} -+ -+static struct notifier_block via_cputemp_cpu_notifier __refdata = { -+ .notifier_call = via_cputemp_cpu_callback, -+}; -+#endif /* !CONFIG_HOTPLUG_CPU */ -+ -+static int __init via_cputemp_init(void) -+{ -+ int i, err; -+ struct pdev_entry *p, *n; -+ -+ if (cpu_data(0).x86_vendor != X86_VENDOR_CENTAUR) { -+ printk(KERN_DEBUG DRVNAME ": Not a VIA CPU\n"); -+ err = -ENODEV; -+ goto exit; -+ } -+ -+ err = platform_driver_register(&via_cputemp_driver); -+ if (err) -+ goto exit; -+ -+ for_each_online_cpu(i) { -+ struct cpuinfo_x86 *c = &cpu_data(i); -+ -+ if (c->x86 != 6) -+ continue; -+ -+ if (c->x86_model < 0x0a) -+ continue; -+ -+ if (c->x86_model > 0x0f) { -+ printk(KERN_WARNING DRVNAME ": Unknown CPU " -+ "model 0x%x\n", c->x86_model); -+ continue; -+ } -+ -+ err = via_cputemp_device_add(i); -+ if (err) -+ goto exit_devices_unreg; -+ } -+ if (list_empty(&pdev_list)) { -+ err = -ENODEV; -+ goto exit_driver_unreg; -+ } -+ -+#ifdef CONFIG_HOTPLUG_CPU -+ register_hotcpu_notifier(&via_cputemp_cpu_notifier); -+#endif -+ return 0; -+ -+exit_devices_unreg: -+ mutex_lock(&pdev_list_mutex); -+ list_for_each_entry_safe(p, n, &pdev_list, list) { -+ platform_device_unregister(p->pdev); -+ list_del(&p->list); -+ kfree(p); -+ } -+ mutex_unlock(&pdev_list_mutex); -+exit_driver_unreg: -+ platform_driver_unregister(&via_cputemp_driver); -+exit: -+ return err; -+} -+ -+static void __exit via_cputemp_exit(void) -+{ -+ struct pdev_entry *p, *n; -+#ifdef CONFIG_HOTPLUG_CPU -+ unregister_hotcpu_notifier(&via_cputemp_cpu_notifier); -+#endif -+ mutex_lock(&pdev_list_mutex); -+ list_for_each_entry_safe(p, n, &pdev_list, list) { -+ platform_device_unregister(p->pdev); -+ list_del(&p->list); -+ kfree(p); -+ } -+ mutex_unlock(&pdev_list_mutex); -+ platform_driver_unregister(&via_cputemp_driver); -+} -+ -+MODULE_AUTHOR("Harald Welte "); -+MODULE_DESCRIPTION("VIA CPU temperature monitor"); -+MODULE_LICENSE("GPL"); -+ -+module_init(via_cputemp_init) -+module_exit(via_cputemp_exit) --- -1.5.6.5 - diff --git a/debian/patches/features/all/input-alps-add-interleaved-protocol-support.patch b/debian/patches/features/all/input-alps-add-interleaved-protocol-support.patch deleted file mode 100644 index 9e02ecafd..000000000 --- a/debian/patches/features/all/input-alps-add-interleaved-protocol-support.patch +++ /dev/null @@ -1,395 +0,0 @@ -commit 1d9f26262aef6d63ff65eba0fd5f1583f342b69b -Author: Sebastian Kapfer -Date: Tue Dec 15 08:39:50 2009 -0800 - - Input: ALPS - add interleaved protocol support (Dell E6x00 series) - - Properly handle version of the protocol where standard PS/2 packets - from trackpoint are stuffed into middle (byte 3-6) of the standard - ALPS packets when both the touchpad and trackpoint are used together. - - The patch is based on work done by Matthew Chapman and additional - research done by David Kubicek and Erik Osterholm: - - https://bugs.launchpad.net/ubuntu/+source/linux/+bug/296610 - - Many thanks to David Kubicek for his efforts in researching fine points - of this new version of the protocol, especially interaction between pad - and stick in these models. - - Signed-off-by: Sebastian Kapfer - Signed-off-by: Dmitry Torokhov - -diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c -index b03e7e0..f93c2c0 100644 ---- a/drivers/input/mouse/alps.c -+++ b/drivers/input/mouse/alps.c -@@ -5,6 +5,7 @@ - * Copyright (c) 2003-2005 Peter Osterlund - * Copyright (c) 2004 Dmitry Torokhov - * Copyright (c) 2005 Vojtech Pavlik -+ * Copyright (c) 2009 Sebastian Kapfer - * - * ALPS detection, tap switching and status querying info is taken from - * tpconfig utility (by C. Scott Ananian and Bruce Kall). -@@ -28,7 +29,6 @@ - #define dbg(format, arg...) do {} while (0) - #endif - -- - #define ALPS_OLDPROTO 0x01 /* old style input */ - #define ALPS_DUALPOINT 0x02 /* touchpad has trackstick */ - #define ALPS_PASS 0x04 /* device has a pass-through port */ -@@ -37,7 +37,8 @@ - #define ALPS_FW_BK_1 0x10 /* front & back buttons present */ - #define ALPS_FW_BK_2 0x20 /* front & back buttons present */ - #define ALPS_FOUR_BUTTONS 0x40 /* 4 direction button present */ -- -+#define ALPS_PS2_INTERLEAVED 0x80 /* 3-byte PS/2 packet interleaved with -+ 6-byte ALPS packet */ - - static const struct alps_model_info alps_model_data[] = { - { { 0x32, 0x02, 0x14 }, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* Toshiba Salellite Pro M10 */ -@@ -58,7 +59,9 @@ static const struct alps_model_info alps_model_data[] = { - { { 0x20, 0x02, 0x0e }, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* XXX */ - { { 0x22, 0x02, 0x0a }, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, - { { 0x22, 0x02, 0x14 }, 0xff, 0xff, ALPS_PASS | ALPS_DUALPOINT }, /* Dell Latitude D600 */ -- { { 0x62, 0x02, 0x14 }, 0xcf, 0xcf, ALPS_PASS | ALPS_DUALPOINT }, /* Dell Latitude E6500 */ -+ /* Dell Latitude E5500, E6400, E6500, Precision M4400 */ -+ { { 0x62, 0x02, 0x14 }, 0xcf, 0xcf, -+ ALPS_PASS | ALPS_DUALPOINT | ALPS_PS2_INTERLEAVED }, - { { 0x73, 0x02, 0x50 }, 0xcf, 0xcf, ALPS_FOUR_BUTTONS }, /* Dell Vostro 1400 */ - }; - -@@ -69,20 +72,88 @@ static const struct alps_model_info alps_model_data[] = { - */ - - /* -- * ALPS abolute Mode - new format -+ * PS/2 packet format -+ * -+ * byte 0: 0 0 YSGN XSGN 1 M R L -+ * byte 1: X7 X6 X5 X4 X3 X2 X1 X0 -+ * byte 2: Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0 -+ * -+ * Note that the device never signals overflow condition. -+ * -+ * ALPS absolute Mode - new format - * - * byte 0: 1 ? ? ? 1 ? ? ? - * byte 1: 0 x6 x5 x4 x3 x2 x1 x0 -- * byte 2: 0 x10 x9 x8 x7 ? fin ges -+ * byte 2: 0 x10 x9 x8 x7 ? fin ges - * byte 3: 0 y9 y8 y7 1 M R L - * byte 4: 0 y6 y5 y4 y3 y2 y1 y0 - * byte 5: 0 z6 z5 z4 z3 z2 z1 z0 - * -+ * Dualpoint device -- interleaved packet format -+ * -+ * byte 0: 1 1 0 0 1 1 1 1 -+ * byte 1: 0 x6 x5 x4 x3 x2 x1 x0 -+ * byte 2: 0 x10 x9 x8 x7 0 fin ges -+ * byte 3: 0 0 YSGN XSGN 1 1 1 1 -+ * byte 4: X7 X6 X5 X4 X3 X2 X1 X0 -+ * byte 5: Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0 -+ * byte 6: 0 y9 y8 y7 1 m r l -+ * byte 7: 0 y6 y5 y4 y3 y2 y1 y0 -+ * byte 8: 0 z6 z5 z4 z3 z2 z1 z0 -+ * -+ * CAPITALS = stick, miniscules = touchpad -+ * - * ?'s can have different meanings on different models, - * such as wheel rotation, extra buttons, stick buttons - * on a dualpoint, etc. - */ - -+static bool alps_is_valid_first_byte(const struct alps_model_info *model, -+ unsigned char data) -+{ -+ return (data & model->mask0) == model->byte0; -+} -+ -+static void alps_report_buttons(struct psmouse *psmouse, -+ struct input_dev *dev1, struct input_dev *dev2, -+ int left, int right, int middle) -+{ -+ struct alps_data *priv = psmouse->private; -+ const struct alps_model_info *model = priv->i; -+ -+ if (model->flags & ALPS_PS2_INTERLEAVED) { -+ struct input_dev *dev; -+ -+ /* -+ * If shared button has already been reported on the -+ * other device (dev2) then this event should be also -+ * sent through that device. -+ */ -+ dev = test_bit(BTN_LEFT, dev2->key) ? dev2 : dev1; -+ input_report_key(dev, BTN_LEFT, left); -+ -+ dev = test_bit(BTN_RIGHT, dev2->key) ? dev2 : dev1; -+ input_report_key(dev, BTN_RIGHT, right); -+ -+ dev = test_bit(BTN_MIDDLE, dev2->key) ? dev2 : dev1; -+ input_report_key(dev, BTN_MIDDLE, middle); -+ -+ /* -+ * Sync the _other_ device now, we'll do the first -+ * device later once we report the rest of the events. -+ */ -+ input_sync(dev2); -+ } else { -+ /* -+ * For devices with non-interleaved packets we know what -+ * device buttons belong to so we can simply report them. -+ */ -+ input_report_key(dev1, BTN_LEFT, left); -+ input_report_key(dev1, BTN_RIGHT, right); -+ input_report_key(dev1, BTN_MIDDLE, middle); -+ } -+} -+ - static void alps_process_packet(struct psmouse *psmouse) - { - struct alps_data *priv = psmouse->private; -@@ -93,18 +164,6 @@ static void alps_process_packet(struct psmouse *psmouse) - int x, y, z, ges, fin, left, right, middle; - int back = 0, forward = 0; - -- if ((packet[0] & 0xc8) == 0x08) { /* 3-byte PS/2 packet */ -- input_report_key(dev2, BTN_LEFT, packet[0] & 1); -- input_report_key(dev2, BTN_RIGHT, packet[0] & 2); -- input_report_key(dev2, BTN_MIDDLE, packet[0] & 4); -- input_report_rel(dev2, REL_X, -- packet[1] ? packet[1] - ((packet[0] << 4) & 0x100) : 0); -- input_report_rel(dev2, REL_Y, -- packet[2] ? ((packet[0] << 3) & 0x100) - packet[2] : 0); -- input_sync(dev2); -- return; -- } -- - if (model->flags & ALPS_OLDPROTO) { - left = packet[2] & 0x10; - right = packet[2] & 0x08; -@@ -140,18 +199,13 @@ static void alps_process_packet(struct psmouse *psmouse) - input_report_rel(dev2, REL_X, (x > 383 ? (x - 768) : x)); - input_report_rel(dev2, REL_Y, -(y > 255 ? (y - 512) : y)); - -- input_report_key(dev2, BTN_LEFT, left); -- input_report_key(dev2, BTN_RIGHT, right); -- input_report_key(dev2, BTN_MIDDLE, middle); -+ alps_report_buttons(psmouse, dev2, dev, left, right, middle); - -- input_sync(dev); - input_sync(dev2); - return; - } - -- input_report_key(dev, BTN_LEFT, left); -- input_report_key(dev, BTN_RIGHT, right); -- input_report_key(dev, BTN_MIDDLE, middle); -+ alps_report_buttons(psmouse, dev, dev2, left, right, middle); - - /* Convert hardware tap to a reasonable Z value */ - if (ges && !fin) -@@ -202,25 +256,168 @@ static void alps_process_packet(struct psmouse *psmouse) - input_sync(dev); - } - -+static void alps_report_bare_ps2_packet(struct psmouse *psmouse, -+ unsigned char packet[], -+ bool report_buttons) -+{ -+ struct alps_data *priv = psmouse->private; -+ struct input_dev *dev2 = priv->dev2; -+ -+ if (report_buttons) -+ alps_report_buttons(psmouse, dev2, psmouse->dev, -+ packet[0] & 1, packet[0] & 2, packet[0] & 4); -+ -+ input_report_rel(dev2, REL_X, -+ packet[1] ? packet[1] - ((packet[0] << 4) & 0x100) : 0); -+ input_report_rel(dev2, REL_Y, -+ packet[2] ? ((packet[0] << 3) & 0x100) - packet[2] : 0); -+ -+ input_sync(dev2); -+} -+ -+static psmouse_ret_t alps_handle_interleaved_ps2(struct psmouse *psmouse) -+{ -+ struct alps_data *priv = psmouse->private; -+ -+ if (psmouse->pktcnt < 6) -+ return PSMOUSE_GOOD_DATA; -+ -+ if (psmouse->pktcnt == 6) { -+ /* -+ * Start a timer to flush the packet if it ends up last -+ * 6-byte packet in the stream. Timer needs to fire -+ * psmouse core times out itself. 20 ms should be enough -+ * to decide if we are getting more data or not. -+ */ -+ mod_timer(&priv->timer, jiffies + msecs_to_jiffies(20)); -+ return PSMOUSE_GOOD_DATA; -+ } -+ -+ del_timer(&priv->timer); -+ -+ if (psmouse->packet[6] & 0x80) { -+ -+ /* -+ * Highest bit is set - that means we either had -+ * complete ALPS packet and this is start of the -+ * next packet or we got garbage. -+ */ -+ -+ if (((psmouse->packet[3] | -+ psmouse->packet[4] | -+ psmouse->packet[5]) & 0x80) || -+ (!alps_is_valid_first_byte(priv->i, psmouse->packet[6]))) { -+ dbg("refusing packet %x %x %x %x " -+ "(suspected interleaved ps/2)\n", -+ psmouse->packet[3], psmouse->packet[4], -+ psmouse->packet[5], psmouse->packet[6]); -+ return PSMOUSE_BAD_DATA; -+ } -+ -+ alps_process_packet(psmouse); -+ -+ /* Continue with the next packet */ -+ psmouse->packet[0] = psmouse->packet[6]; -+ psmouse->pktcnt = 1; -+ -+ } else { -+ -+ /* -+ * High bit is 0 - that means that we indeed got a PS/2 -+ * packet in the middle of ALPS packet. -+ * -+ * There is also possibility that we got 6-byte ALPS -+ * packet followed by 3-byte packet from trackpoint. We -+ * can not distinguish between these 2 scenarios but -+ * becase the latter is unlikely to happen in course of -+ * normal operation (user would need to press all -+ * buttons on the pad and start moving trackpoint -+ * without touching the pad surface) we assume former. -+ * Even if we are wrong the wost thing that would happen -+ * the cursor would jump but we should not get protocol -+ * desynchronization. -+ */ -+ -+ alps_report_bare_ps2_packet(psmouse, &psmouse->packet[3], -+ false); -+ -+ /* -+ * Continue with the standard ALPS protocol handling, -+ * but make sure we won't process it as an interleaved -+ * packet again, which may happen if all buttons are -+ * pressed. To avoid this let's reset the 4th bit which -+ * is normally 1. -+ */ -+ psmouse->packet[3] = psmouse->packet[6] & 0xf7; -+ psmouse->pktcnt = 4; -+ } -+ -+ return PSMOUSE_GOOD_DATA; -+} -+ -+static void alps_flush_packet(unsigned long data) -+{ -+ struct psmouse *psmouse = (struct psmouse *)data; -+ -+ serio_pause_rx(psmouse->ps2dev.serio); -+ -+ if (psmouse->pktcnt == 6) { -+ -+ /* -+ * We did not any more data in reasonable amount of time. -+ * Validate the last 3 bytes and process as a standard -+ * ALPS packet. -+ */ -+ if ((psmouse->packet[3] | -+ psmouse->packet[4] | -+ psmouse->packet[5]) & 0x80) { -+ dbg("refusing packet %x %x %x " -+ "(suspected interleaved ps/2)\n", -+ psmouse->packet[3], psmouse->packet[4], -+ psmouse->packet[5]); -+ } else { -+ alps_process_packet(psmouse); -+ } -+ psmouse->pktcnt = 0; -+ } -+ -+ serio_continue_rx(psmouse->ps2dev.serio); -+} -+ - static psmouse_ret_t alps_process_byte(struct psmouse *psmouse) - { - struct alps_data *priv = psmouse->private; -+ const struct alps_model_info *model = priv->i; - - if ((psmouse->packet[0] & 0xc8) == 0x08) { /* PS/2 packet */ - if (psmouse->pktcnt == 3) { -- alps_process_packet(psmouse); -+ alps_report_bare_ps2_packet(psmouse, psmouse->packet, -+ true); - return PSMOUSE_FULL_PACKET; - } - return PSMOUSE_GOOD_DATA; - } - -- if ((psmouse->packet[0] & priv->i->mask0) != priv->i->byte0) -+ /* Check for PS/2 packet stuffed in the middle of ALPS packet. */ -+ -+ if ((model->flags & ALPS_PS2_INTERLEAVED) && -+ psmouse->pktcnt >= 4 && (psmouse->packet[3] & 0x0f) == 0x0f) { -+ return alps_handle_interleaved_ps2(psmouse); -+ } -+ -+ if (!alps_is_valid_first_byte(model, psmouse->packet[0])) { -+ dbg("refusing packet[0] = %x (mask0 = %x, byte0 = %x)\n", -+ psmouse->packet[0], model->mask0, model->byte0); - return PSMOUSE_BAD_DATA; -+ } - - /* Bytes 2 - 6 should have 0 in the highest bit */ - if (psmouse->pktcnt >= 2 && psmouse->pktcnt <= 6 && -- (psmouse->packet[psmouse->pktcnt - 1] & 0x80)) -+ (psmouse->packet[psmouse->pktcnt - 1] & 0x80)) { -+ dbg("refusing packet[%i] = %x\n", -+ psmouse->pktcnt - 1, psmouse->packet[psmouse->pktcnt - 1]); - return PSMOUSE_BAD_DATA; -+ } - - if (psmouse->pktcnt == 6) { - alps_process_packet(psmouse); -@@ -459,6 +656,7 @@ static void alps_disconnect(struct psmouse *psmouse) - struct alps_data *priv = psmouse->private; - - psmouse_reset(psmouse); -+ del_timer_sync(&priv->timer); - input_unregister_device(priv->dev2); - kfree(priv); - } -@@ -476,6 +674,8 @@ int alps_init(struct psmouse *psmouse) - goto init_fail; - - priv->dev2 = dev2; -+ setup_timer(&priv->timer, alps_flush_packet, (unsigned long)psmouse); -+ - psmouse->private = priv; - - model = alps_get_model(psmouse, &version); -diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h -index bc87936..904ed8b 100644 ---- a/drivers/input/mouse/alps.h -+++ b/drivers/input/mouse/alps.h -@@ -23,6 +23,7 @@ struct alps_data { - char phys[32]; /* Phys */ - const struct alps_model_info *i;/* Info */ - int prev_fin; /* Finger bit from previous packet */ -+ struct timer_list timer; - }; - - #ifdef CONFIG_MOUSE_PS2_ALPS diff --git a/debian/patches/features/all/mos7840-add-device-IDs-for-B-B-electronics-devices.patch b/debian/patches/features/all/mos7840-add-device-IDs-for-B-B-electronics-devices.patch deleted file mode 100644 index bd1bdefe3..000000000 --- a/debian/patches/features/all/mos7840-add-device-IDs-for-B-B-electronics-devices.patch +++ /dev/null @@ -1,67 +0,0 @@ -From acf509ae28301d78b022c534c26b1e4765c18f2b Mon Sep 17 00:00:00 2001 -From: Cliff Brake -Date: Tue, 1 Dec 2009 09:53:43 -0500 -Subject: [PATCH] USB: mos7840: add device IDs for B&B electronics devices - -Reviewed-by: John Pilles -Signed-off-by: Cliff Brake -Signed-off-by: Greg Kroah-Hartman ---- - drivers/usb/serial/mos7840.c | 24 +++++++++++++++++++++--- - 1 files changed, 21 insertions(+), 3 deletions(-) - -diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c -index f11abf5..485fa9c 100644 ---- a/drivers/usb/serial/mos7840.c -+++ b/drivers/usb/serial/mos7840.c -@@ -121,8 +121,14 @@ - * moschip_id_table_combined - */ - #define USB_VENDOR_ID_BANDB 0x0856 --#define BANDB_DEVICE_ID_USOPTL4_4 0xAC44 -+#define BANDB_DEVICE_ID_USO9ML2_2 0xAC22 -+#define BANDB_DEVICE_ID_USO9ML2_4 0xAC24 -+#define BANDB_DEVICE_ID_US9ML2_2 0xAC29 -+#define BANDB_DEVICE_ID_US9ML2_4 0xAC30 -+#define BANDB_DEVICE_ID_USPTL4_2 0xAC31 -+#define BANDB_DEVICE_ID_USPTL4_4 0xAC32 - #define BANDB_DEVICE_ID_USOPTL4_2 0xAC42 -+#define BANDB_DEVICE_ID_USOPTL4_4 0xAC44 - - /* This driver also supports - * ATEN UC2324 device using Moschip MCS7840 -@@ -177,8 +183,14 @@ - static struct usb_device_id moschip_port_id_table[] = { - {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7840)}, - {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7820)}, -- {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_4)}, -+ {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_2)}, -+ {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_4)}, -+ {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_US9ML2_2)}, -+ {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_US9ML2_4)}, -+ {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USPTL4_2)}, -+ {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USPTL4_4)}, - {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_2)}, -+ {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_4)}, - {USB_DEVICE(USB_VENDOR_ID_ATENINTL, ATENINTL_DEVICE_ID_UC2324)}, - {USB_DEVICE(USB_VENDOR_ID_ATENINTL, ATENINTL_DEVICE_ID_UC2322)}, - {} /* terminating entry */ -@@ -187,8 +199,14 @@ static struct usb_device_id moschip_port_id_table[] = { - static __devinitdata struct usb_device_id moschip_id_table_combined[] = { - {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7840)}, - {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7820)}, -- {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_4)}, -+ {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_2)}, -+ {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_4)}, -+ {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_US9ML2_2)}, -+ {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_US9ML2_4)}, -+ {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USPTL4_2)}, -+ {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USPTL4_4)}, - {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_2)}, -+ {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_4)}, - {USB_DEVICE(USB_VENDOR_ID_ATENINTL, ATENINTL_DEVICE_ID_UC2324)}, - {USB_DEVICE(USB_VENDOR_ID_ATENINTL, ATENINTL_DEVICE_ID_UC2322)}, - {} /* terminating entry */ --- -1.6.5.7 - diff --git a/debian/patches/features/all/saa7134-Add-support-for-Asus-Europa-Hybrid-DVB.patch b/debian/patches/features/all/saa7134-Add-support-for-Asus-Europa-Hybrid-DVB.patch deleted file mode 100644 index dbc32bbc5..000000000 --- a/debian/patches/features/all/saa7134-Add-support-for-Asus-Europa-Hybrid-DVB.patch +++ /dev/null @@ -1,114 +0,0 @@ -From e3c6e1aaa5db7822524f5b1355960fd732910068 Mon Sep 17 00:00:00 2001 -From: Danny Wood -Date: Sun, 20 Sep 2009 12:14:21 -0300 -Subject: [PATCH] V4L/DVB (13168): Add support for Asus Europa Hybrid DVB-T card (SAA7134 SubVendor ID: 0x1043 Device ID: 0x4847) - -Adds the device IDs and driver linking to allow the Asus Europa DVB-T -card to operate with these drivers. -The device has a SAA7134 chipset with a TD1316 Hybrid Tuner. -All inputs work on the card including switching between DVB-T and -Analogue TV, there is also no IR with this card. - -[mchehab@redhat.com: CodingStyle fixes] - -Signed-off-by: Danny Wood -Signed-off-by: Mauro Carvalho Chehab ---- - Documentation/video4linux/CARDLIST.saa7134 | 1 + - drivers/media/video/saa7134/saa7134-cards.c | 31 +++++++++++++++++++++++++++ - drivers/media/video/saa7134/saa7134-dvb.c | 1 + - drivers/media/video/saa7134/saa7134.h | 1 + - 4 files changed, 34 insertions(+), 0 deletions(-) - -diff --git a/Documentation/video4linux/CARDLIST.saa7134 b/Documentation/video4linux/CARDLIST.saa7134 -index 2620d60..94e255a 100644 ---- a/Documentation/video4linux/CARDLIST.saa7134 -+++ b/Documentation/video4linux/CARDLIST.saa7134 -@@ -172,3 +172,4 @@ - 171 -> Beholder BeholdTV X7 [5ace:7595] - 172 -> RoverMedia TV Link Pro FM [19d1:0138] - 173 -> Zolid Hybrid TV Tuner PCI [1131:2004] -+174 -> Asus Europa Hybrid OEM [1043:4847] -diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c -index 7de7f1f..bdb6138 100644 ---- a/drivers/media/video/saa7134/saa7134-cards.c -+++ b/drivers/media/video/saa7134/saa7134-cards.c -@@ -5280,6 +5280,30 @@ struct saa7134_board saa7134_boards[] = { - .amux = TV, - }, - }, -+ [SAA7134_BOARD_ASUS_EUROPA_HYBRID] = { -+ .name = "Asus Europa Hybrid OEM", -+ .audio_clock = 0x00187de7, -+ .tuner_type = TUNER_PHILIPS_TD1316, -+ .radio_type = UNSET, -+ .tuner_addr = 0x61, -+ .radio_addr = ADDR_UNSET, -+ .tda9887_conf = TDA9887_PRESENT | TDA9887_PORT1_ACTIVE, -+ .mpeg = SAA7134_MPEG_DVB, -+ .inputs = { { -+ .name = name_tv, -+ .vmux = 3, -+ .amux = TV, -+ .tv = 1, -+ }, { -+ .name = name_comp1, -+ .vmux = 4, -+ .amux = LINE2, -+ }, { -+ .name = name_svideo, -+ .vmux = 8, -+ .amux = LINE2, -+ } }, -+ }, - - }; - -@@ -6419,6 +6443,12 @@ struct pci_device_id saa7134_pci_tbl[] = { - .subdevice = 0x2004, - .driver_data = SAA7134_BOARD_ZOLID_HYBRID_PCI, - }, { -+ .vendor = PCI_VENDOR_ID_PHILIPS, -+ .device = PCI_DEVICE_ID_PHILIPS_SAA7134, -+ .subvendor = 0x1043, -+ .subdevice = 0x4847, -+ .driver_data = SAA7134_BOARD_ASUS_EUROPA_HYBRID, -+ }, { - /* --- boards without eeprom + subsystem ID --- */ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, -@@ -7080,6 +7110,7 @@ int saa7134_board_init2(struct saa7134_dev *dev) - /* break intentionally omitted */ - case SAA7134_BOARD_VIDEOMATE_DVBT_300: - case SAA7134_BOARD_ASUS_EUROPA2_HYBRID: -+ case SAA7134_BOARD_ASUS_EUROPA_HYBRID: - { - - /* The Philips EUROPA based hybrid boards have the tuner -diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c -index 96d3668..cd31284 100644 ---- a/drivers/media/video/saa7134/saa7134-dvb.c -+++ b/drivers/media/video/saa7134/saa7134-dvb.c -@@ -1131,6 +1131,7 @@ static int dvb_init(struct saa7134_dev *dev) - break; - case SAA7134_BOARD_PHILIPS_EUROPA: - case SAA7134_BOARD_VIDEOMATE_DVBT_300: -+ case SAA7134_BOARD_ASUS_EUROPA_HYBRID: - fe0->dvb.frontend = dvb_attach(tda10046_attach, - &philips_europa_config, - &dev->i2c_adap); -diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h -index f8697d4..94e1a3b 100644 ---- a/drivers/media/video/saa7134/saa7134.h -+++ b/drivers/media/video/saa7134/saa7134.h -@@ -297,6 +297,7 @@ struct saa7134_format { - #define SAA7134_BOARD_BEHOLD_X7 171 - #define SAA7134_BOARD_ROVERMEDIA_LINK_PRO_FM 172 - #define SAA7134_BOARD_ZOLID_HYBRID_PCI 173 -+#define SAA7134_BOARD_ASUS_EUROPA_HYBRID 174 - - #define SAA7134_MAXBOARDS 32 - #define SAA7134_INPUT_MAX 8 --- -1.6.5.7 - diff --git a/debian/patches/features/all/smsusb-add-5-Hauppauge-USB-IDs.patch b/debian/patches/features/all/smsusb-add-5-Hauppauge-USB-IDs.patch deleted file mode 100644 index 03202f9bb..000000000 --- a/debian/patches/features/all/smsusb-add-5-Hauppauge-USB-IDs.patch +++ /dev/null @@ -1,45 +0,0 @@ -From 20d15a200d34cfb7141fb4558895d7d5233db84b Mon Sep 17 00:00:00 2001 -From: Michael Krufky -Date: Mon, 30 Nov 2009 18:22:10 -0300 -Subject: [PATCH] V4L/DVB (13569): smsusb: add autodetection support for five additional Hauppauge USB IDs - -Add support for five new Hauppauge Device USB IDs: - -2040:b980 -2040:b990 -2040:c010 -2040:c080 -2040:c090 - -Signed-off-by: Michael Krufky -Signed-off-by: Mauro Carvalho Chehab ---- - drivers/media/dvb/siano/smsusb.c | 10 ++++++++++ - 1 files changed, 10 insertions(+), 0 deletions(-) - -diff --git a/drivers/media/dvb/siano/smsusb.c b/drivers/media/dvb/siano/smsusb.c -index 8f88a58..6b03dbf 100644 ---- a/drivers/media/dvb/siano/smsusb.c -+++ b/drivers/media/dvb/siano/smsusb.c -@@ -533,8 +533,18 @@ struct usb_device_id smsusb_id_table[] = { - .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, - { USB_DEVICE(0x2040, 0xb910), - .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, -+ { USB_DEVICE(0x2040, 0xb980), -+ .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, -+ { USB_DEVICE(0x2040, 0xb990), -+ .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, - { USB_DEVICE(0x2040, 0xc000), - .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, -+ { USB_DEVICE(0x2040, 0xc010), -+ .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, -+ { USB_DEVICE(0x2040, 0xc080), -+ .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, -+ { USB_DEVICE(0x2040, 0xc090), -+ .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, - { } /* Terminating entry */ - }; - --- -1.6.5.7 - diff --git a/debian/patches/features/arm/davinci-dm646x-Add-support-for-3.x-silicon-revision.patch b/debian/patches/features/arm/davinci-dm646x-Add-support-for-3.x-silicon-revision.patch deleted file mode 100644 index 00efd1981..000000000 --- a/debian/patches/features/arm/davinci-dm646x-Add-support-for-3.x-silicon-revision.patch +++ /dev/null @@ -1,40 +0,0 @@ -From f63dd12da29f47c37bbc093abec098538e04357c Mon Sep 17 00:00:00 2001 -From: Hemant Pedanekar -Date: Wed, 2 Sep 2009 16:49:35 +0530 -Subject: [PATCH] davinci: dm646x: Add support for 3.x silicon revision - -DM6467 silicon revisions 3.x have variant field in JTAGID register as '1'. -This path adds entry for the same in dm646x_ids to be able to boot on boards -with 3.x revision chips. - -Also modifies name for 'variant=0' (revisions 1.0, 1.1). - -Signed-off-by: Hemant Pedanekar -Signed-off-by: Kevin Hilman ---- - arch/arm/mach-davinci/dm646x.c | 9 ++++++++- - 1 files changed, 8 insertions(+), 1 deletions(-) - -diff --git a/arch/arm/mach-davinci/dm646x.c b/arch/arm/mach-davinci/dm646x.c -index 0976049..36e4fb4 100644 ---- a/arch/arm/mach-davinci/dm646x.c -+++ b/arch/arm/mach-davinci/dm646x.c -@@ -789,7 +789,14 @@ static struct davinci_id dm646x_ids[] = { - .part_no = 0xb770, - .manufacturer = 0x017, - .cpu_id = DAVINCI_CPU_ID_DM6467, -- .name = "dm6467", -+ .name = "dm6467_rev1.x", -+ }, -+ { -+ .variant = 0x1, -+ .part_no = 0xb770, -+ .manufacturer = 0x017, -+ .cpu_id = DAVINCI_CPU_ID_DM6467, -+ .name = "dm6467_rev3.x", - }, - }; - --- -1.6.5.7 - diff --git a/debian/patches/features/powerpc/fsl-Add-PCI-device-ids-for-new-QoirQ-chips.patch b/debian/patches/features/powerpc/fsl-Add-PCI-device-ids-for-new-QoirQ-chips.patch deleted file mode 100644 index eabba438f..000000000 --- a/debian/patches/features/powerpc/fsl-Add-PCI-device-ids-for-new-QoirQ-chips.patch +++ /dev/null @@ -1,53 +0,0 @@ -Based on: - -From: Kumar Gala -Subject: [PATCH] powerpc/fsl: Add PCI device ids for new QoirQ chips - ---- a/arch/powerpc/sysdev/fsl_pci.c -+++ b/arch/powerpc/sysdev/fsl_pci.c -@@ -392,8 +392,22 @@ DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8536, quirk_fsl_pcie_header); - DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8641, quirk_fsl_pcie_header); - DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8641D, quirk_fsl_pcie_header); - DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8610, quirk_fsl_pcie_header); -+DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P1011E, quirk_fsl_pcie_header); -+DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P1011, quirk_fsl_pcie_header); -+DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P1013E, quirk_fsl_pcie_header); -+DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P1013, quirk_fsl_pcie_header); -+DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P1020E, quirk_fsl_pcie_header); -+DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P1020, quirk_fsl_pcie_header); -+DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P1022E, quirk_fsl_pcie_header); -+DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P1022, quirk_fsl_pcie_header); -+DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P2010E, quirk_fsl_pcie_header); -+DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P2010, quirk_fsl_pcie_header); - DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P2020E, quirk_fsl_pcie_header); - DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P2020, quirk_fsl_pcie_header); -+DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P4040E, quirk_fsl_pcie_header); -+DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P4040, quirk_fsl_pcie_header); -+DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P4080E, quirk_fsl_pcie_header); -+DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P4080, quirk_fsl_pcie_header); - #endif /* CONFIG_PPC_85xx || CONFIG_PPC_86xx */ - - #if defined(CONFIG_PPC_83xx) || defined(CONFIG_PPC_MPC512x) ---- a/include/linux/pci_ids.h -+++ b/include/linux/pci_ids.h -@@ -2288,6 +2288,20 @@ - #define PCI_DEVICE_ID_MPC8536 0x0051 - #define PCI_DEVICE_ID_P2020E 0x0070 - #define PCI_DEVICE_ID_P2020 0x0071 -+#define PCI_DEVICE_ID_P2010E 0x0078 -+#define PCI_DEVICE_ID_P2010 0x0079 -+#define PCI_DEVICE_ID_P1020E 0x0100 -+#define PCI_DEVICE_ID_P1020 0x0101 -+#define PCI_DEVICE_ID_P1011E 0x0108 -+#define PCI_DEVICE_ID_P1011 0x0109 -+#define PCI_DEVICE_ID_P1022E 0x0110 -+#define PCI_DEVICE_ID_P1022 0x0111 -+#define PCI_DEVICE_ID_P1013E 0x0118 -+#define PCI_DEVICE_ID_P1013 0x0119 -+#define PCI_DEVICE_ID_P4080E 0x0400 -+#define PCI_DEVICE_ID_P4080 0x0401 -+#define PCI_DEVICE_ID_P4040E 0x0408 -+#define PCI_DEVICE_ID_P4040 0x0409 - #define PCI_DEVICE_ID_MPC8641 0x7010 - #define PCI_DEVICE_ID_MPC8641D 0x7011 - #define PCI_DEVICE_ID_MPC8610 0x7018 diff --git a/debian/patches/features/x86/iTCO_wdt-Add-support-for-Intel-Ibex-Peak.patch b/debian/patches/features/x86/iTCO_wdt-Add-support-for-Intel-Ibex-Peak.patch deleted file mode 100644 index 689747dd4..000000000 --- a/debian/patches/features/x86/iTCO_wdt-Add-support-for-Intel-Ibex-Peak.patch +++ /dev/null @@ -1,61 +0,0 @@ -From 79e8941dda254505bb8af37b3a009165dfb7e98a Mon Sep 17 00:00:00 2001 -From: Seth Heasley -Date: Wed, 11 Nov 2009 02:24:01 +0100 -Subject: [PATCH] [WATCHDOG] iTCO_wdt: Add support for Intel Ibex Peak - -Add the Intel Ibex Peak (PCH) Device IDs to iTCO_wdt.c. - -Signed-off-by: Seth Heasley -Signed-off-by: Wim Van Sebroeck ---- - drivers/watchdog/iTCO_wdt.c | 13 ++++++++++++- - 1 files changed, 12 insertions(+), 1 deletions(-) - -diff --git a/drivers/watchdog/iTCO_wdt.c b/drivers/watchdog/iTCO_wdt.c -index 6a51edd..4bd3877 100644 ---- a/drivers/watchdog/iTCO_wdt.c -+++ b/drivers/watchdog/iTCO_wdt.c -@@ -54,7 +54,9 @@ - * 82801JIB (ICH10) : document number 319973-002, 319974-002, - * 82801JIR (ICH10R) : document number 319973-002, 319974-002, - * 82801JD (ICH10D) : document number 319973-002, 319974-002, -- * 82801JDO (ICH10DO) : document number 319973-002, 319974-002 -+ * 82801JDO (ICH10DO) : document number 319973-002, 319974-002, -+ * 5 Series (PCH) : document number 322169-001, 322170-001, -+ * 3400 Series (PCH) : document number 322169-001, 322170-001 - */ - - /* -@@ -122,6 +124,9 @@ enum iTCO_chipsets { - TCO_ICH10R, /* ICH10R */ - TCO_ICH10D, /* ICH10D */ - TCO_ICH10DO, /* ICH10DO */ -+ TCO_PCH, /* PCH Desktop Full Featured */ -+ TCO_PCHM, /* PCH Mobile Full Featured */ -+ TCO_PCHMSFF, /* PCH Mobile SFF Full Featured */ - }; - - static struct { -@@ -162,6 +167,9 @@ static struct { - {"ICH10R", 2}, - {"ICH10D", 2}, - {"ICH10DO", 2}, -+ {"PCH Desktop Full Featured", 2}, -+ {"PCH Mobile Full Featured", 2}, -+ {"PCH Mobile SFF Full Featured", 2}, - {NULL, 0} - }; - -@@ -230,6 +238,9 @@ static struct pci_device_id iTCO_wdt_pci_tbl[] = { - { ITCO_PCI_DEVICE(0x3a16, TCO_ICH10R)}, - { ITCO_PCI_DEVICE(0x3a1a, TCO_ICH10D)}, - { ITCO_PCI_DEVICE(0x3a14, TCO_ICH10DO)}, -+ { ITCO_PCI_DEVICE(0x3b00, TCO_PCH)}, -+ { ITCO_PCI_DEVICE(0x3b01, TCO_PCHM)}, -+ { ITCO_PCI_DEVICE(0x3b0d, TCO_PCHMSFF)}, - { 0, }, /* End of list */ - }; - MODULE_DEVICE_TABLE(pci, iTCO_wdt_pci_tbl); --- -1.6.5.7 - From 50ceb9a3868fe5ba52661f6565d5412109b71ed6 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Fri, 19 Feb 2010 03:53:50 +0000 Subject: [PATCH 32/71] Fix up features/all/rt28x0sta-constify-RTUSBMultiWrite-RTUSBFirmwareWrite.patch for 2.6.33-rc8 svn path=/dists/trunk/linux-2.6/; revision=15222 --- ...y-RTUSBMultiWrite-RTUSBFirmwareWrite.patch | 120 +++++++++--------- debian/patches/series/base | 1 + 2 files changed, 59 insertions(+), 62 deletions(-) diff --git a/debian/patches/features/all/rt28x0sta-constify-RTUSBMultiWrite-RTUSBFirmwareWrite.patch b/debian/patches/features/all/rt28x0sta-constify-RTUSBMultiWrite-RTUSBFirmwareWrite.patch index 3683eb3da..1ff6caf8b 100644 --- a/debian/patches/features/all/rt28x0sta-constify-RTUSBMultiWrite-RTUSBFirmwareWrite.patch +++ b/debian/patches/features/all/rt28x0sta-constify-RTUSBMultiWrite-RTUSBFirmwareWrite.patch @@ -1,91 +1,87 @@ -From 6c628a539fe6953bfe6112d75c7fbb1f9409a086 Mon Sep 17 00:00:00 2001 +From fb9c62c3bbf88aa3a3c9bb0c9feb26740eb29ddf Mon Sep 17 00:00:00 2001 From: Ben Hutchings -Date: Sun, 28 Jun 2009 15:49:17 +0100 -Subject: [PATCH] rt2870sta: constify RTUSBMultiWrite(), RTUSBFirmwareWrite() +Date: Mon, 18 Jan 2010 02:50:24 +0000 +Subject: [PATCH] Staging: rt2870sta: constify RTUSBMultiWrite(), RTUSBFirmwareWrite() These functions do not modify the data they are passed. + +Signed-off-by: Ben Hutchings +Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rt2860/rtmp.h | 6 +++--- drivers/staging/rt2870/common/rtusb_io.c | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/staging/rt2860/rtmp.h b/drivers/staging/rt2860/rtmp.h -index 90fd40f..d283256 100644 +index c50abf4..6c6503d 100644 --- a/drivers/staging/rt2860/rtmp.h +++ b/drivers/staging/rt2860/rtmp.h -@@ -6095,13 +6095,13 @@ NTSTATUS RTUSBMultiRead( - NTSTATUS RTUSBMultiWrite( - IN PRTMP_ADAPTER pAd, - IN USHORT Offset, -- IN PUCHAR pData, -+ IN const u8 *pData, - IN USHORT length); +@@ -4043,10 +4043,10 @@ int RTUSBMultiRead(struct rt_rtmp_adapter *pAd, + u16 Offset, u8 *pData, u16 length); - NTSTATUS RTUSBMultiWrite_OneByte( - IN PRTMP_ADAPTER pAd, - IN USHORT Offset, -- IN PUCHAR pData); -+ IN const u8 *pData); + int RTUSBMultiWrite(struct rt_rtmp_adapter *pAd, +- u16 Offset, u8 *pData, u16 length); ++ u16 Offset, const u8 *pData, u16 length); - NTSTATUS RTUSBReadBBPRegister( - IN PRTMP_ADAPTER pAd, -@@ -6220,7 +6220,7 @@ NTSTATUS RTUSBFirmwareRun( + int RTUSBMultiWrite_OneByte(struct rt_rtmp_adapter *pAd, +- u16 Offset, u8 *pData); ++ u16 Offset, const u8 *pData); - NTSTATUS RTUSBFirmwareWrite( - IN PRTMP_ADAPTER pAd, -- IN PUCHAR pFwImage, -+ IN const u8 *pFwImage, - IN ULONG FwLen); + int RTUSBReadBBPRegister(struct rt_rtmp_adapter *pAd, + u8 Id, u8 *pValue); +@@ -4112,7 +4112,7 @@ int RTUSBSingleWrite(struct rt_rtmp_adapter *pAd, + u16 Offset, u16 Value); + + int RTUSBFirmwareWrite(struct rt_rtmp_adapter *pAd, +- u8 *pFwImage, unsigned long FwLen); ++ const u8 *pFwImage, unsigned long FwLen); + + int RTUSBVenderReset(struct rt_rtmp_adapter *pAd); - NTSTATUS RTUSBFirmwareOpmode( diff --git a/drivers/staging/rt2870/common/rtusb_io.c b/drivers/staging/rt2870/common/rtusb_io.c -index 1d69590..1f776c4 100644 +index 34443f2..cf0d2f5 100644 --- a/drivers/staging/rt2870/common/rtusb_io.c +++ b/drivers/staging/rt2870/common/rtusb_io.c -@@ -92,7 +92,7 @@ NTSTATUS RTUSBFirmwareRun( +@@ -84,7 +84,7 @@ static int RTUSBFirmwareRun(struct rt_rtmp_adapter *pAd) + ======================================================================== */ - NTSTATUS RTUSBFirmwareWrite( - IN PRTMP_ADAPTER pAd, -- IN PUCHAR pFwImage, -+ IN const u8 *pFwImage, - IN ULONG FwLen) + int RTUSBFirmwareWrite(struct rt_rtmp_adapter *pAd, +- u8 *pFwImage, unsigned long FwLen) ++ const u8 *pFwImage, unsigned long FwLen) { - UINT32 MacReg; -@@ -224,7 +224,7 @@ NTSTATUS RTUSBMultiRead( - NTSTATUS RTUSBMultiWrite_OneByte( - IN PRTMP_ADAPTER pAd, - IN USHORT Offset, -- IN PUCHAR pData) -+ IN const u8 *pData) + u32 MacReg; + int Status; +@@ -167,7 +167,7 @@ int RTUSBMultiRead(struct rt_rtmp_adapter *pAd, + ======================================================================== + */ + int RTUSBMultiWrite_OneByte(struct rt_rtmp_adapter *pAd, +- u16 Offset, u8 *pData) ++ u16 Offset, const u8 *pData) { - NTSTATUS Status; + int Status; -@@ -236,7 +236,7 @@ NTSTATUS RTUSBMultiWrite_OneByte( - 0x6, - 0, - Offset, -- pData, -+ (u8 *)pData, - 1); +@@ -175,18 +175,18 @@ int RTUSBMultiWrite_OneByte(struct rt_rtmp_adapter *pAd, + Status = RTUSB_VendorRequest(pAd, + USBD_TRANSFER_DIRECTION_OUT, + DEVICE_VENDOR_REQUEST_OUT, +- 0x6, 0, Offset, pData, 1); ++ 0x6, 0, Offset, (u8 *)pData, 1); return Status; -@@ -245,14 +245,14 @@ NTSTATUS RTUSBMultiWrite_OneByte( - NTSTATUS RTUSBMultiWrite( - IN PRTMP_ADAPTER pAd, - IN USHORT Offset, -- IN PUCHAR pData, -+ IN const u8 *pData, - IN USHORT length) + } + + int RTUSBMultiWrite(struct rt_rtmp_adapter *pAd, +- u16 Offset, u8 *pData, u16 length) ++ u16 Offset, const u8 *pData, u16 length) { - NTSTATUS Status; + int Status; + u16 index = 0, Value; +- u8 *pSrc = pData; ++ const u8 *pSrc = pData; + u16 resude = 0; - USHORT index = 0,Value; -- PUCHAR pSrc = pData; -+ const u8 *pSrc = pData; - USHORT resude = 0; - - resude = length % 2; + resude = length % 2; -- -1.6.6 +1.6.6.2 diff --git a/debian/patches/series/base b/debian/patches/series/base index 8aba31427..33d9147c7 100644 --- a/debian/patches/series/base +++ b/debian/patches/series/base @@ -9,6 +9,7 @@ + features/all/drivers-infiniband-hw-ipath-iba7220-use-request_firmware.patch + features/all/drivers-media-dvb-usb-af9005-request_firmware.patch ++ features/all/rt28x0sta-constify-RTUSBMultiWrite-RTUSBFirmwareWrite.patch + features/all/rt28x0sta-use-request_firmware.patch + features/all/lgs8gxx-lgs8g75-request_firmware.patch + features/all/r8169-rtl8168d-1-2-request_firmware-2.patch From c5e0cfebb26f0fe89f554a46d9be530bbf5ee25c Mon Sep 17 00:00:00 2001 From: Maximilian Attems Date: Fri, 19 Feb 2010 10:04:58 +0000 Subject: [PATCH 33/71] nuke mol patch upstream seems pretty inactive these days, also we no longer add gratious exports for oot foo. get stuff into staging.. svn path=/dists/trunk/linux-2.6/; revision=15223 --- debian/patches/bugfix/powerpc/mm-mol.patch | 12 ------------ debian/patches/series/base | 1 - 2 files changed, 13 deletions(-) delete mode 100644 debian/patches/bugfix/powerpc/mm-mol.patch diff --git a/debian/patches/bugfix/powerpc/mm-mol.patch b/debian/patches/bugfix/powerpc/mm-mol.patch deleted file mode 100644 index c71c19e12..000000000 --- a/debian/patches/bugfix/powerpc/mm-mol.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff --git a/arch/powerpc/kernel/ppc_ksyms.c b/arch/powerpc/kernel/ppc_ksyms.c -index c6b1aa3..455fb38 100644 ---- a/arch/powerpc/kernel/ppc_ksyms.c -+++ b/arch/powerpc/kernel/ppc_ksyms.c -@@ -189,6 +189,7 @@ EXPORT_SYMBOL(set_context); - extern long mol_trampoline; - EXPORT_SYMBOL(mol_trampoline); /* For MOL */ - EXPORT_SYMBOL(flush_hash_pages); /* For MOL */ -+EXPORT_SYMBOL(handle_mm_fault); /* For MOL */ - #ifdef CONFIG_SMP - extern int mmu_hash_lock; - EXPORT_SYMBOL(mmu_hash_lock); /* For MOL */ diff --git a/debian/patches/series/base b/debian/patches/series/base index 33d9147c7..1734d9ddd 100644 --- a/debian/patches/series/base +++ b/debian/patches/series/base @@ -33,7 +33,6 @@ + bugfix/mips/disable-advansys.patch + bugfix/arm/disable-scsi_acard.patch + bugfix/mips/disable-werror.patch -+ bugfix/powerpc/mm-mol.patch + bugfix/powerpc/lpar-console.patch #+ bugfix/all/wireless-regulatory-default-EU.patch + features/sparc/video-sunxvr500-intergraph.patch From 54feffabb22787f0ec2640a77ff21f7c9ab0f35d Mon Sep 17 00:00:00 2001 From: Maximilian Attems Date: Fri, 19 Feb 2010 11:13:43 +0000 Subject: [PATCH 34/71] topconfig enable bunch of evident new modular drivers as highlight maybe DVB_FIREDTV, DRDB and NOUVEAU. svn path=/dists/trunk/linux-2.6/; revision=15224 --- debian/changelog | 11 +++++++ debian/config/config | 46 +++++++++++++++++++++++++++++ debian/config/kernelarch-x86/config | 1 + 3 files changed, 58 insertions(+) diff --git a/debian/changelog b/debian/changelog index 4fc13835b..15da27d30 100644 --- a/debian/changelog +++ b/debian/changelog @@ -2,6 +2,17 @@ linux-2.6 (2.6.33~rc8-1~experimental.1) UNRELEASED; urgency=low * New upstream release. + [ maximilian attems] + * [topconfig] set BLK_DEV_DRBD, DRM_NOUVEAU, DRM_NOUVEAU_BACKLIGHT, + DRM_VMWGFX, SENSORS_LM73, SENSORS_AMC682, SENSORS_LIS3_I2C, + SENSORS_MC13783_ADC, TOUCHSCREEN_DYNAPRO, TOUCHSCREEN_MC13783, + GIGASET_CAPI, LEDS_DAC124S085, LEDS_INTEL_SS4200, LEDS_INTEL_SS4200, + DVB_FIREDTV, DVB_USB_EC168, SOC_CAMERA_MT9T112, SOC_CAMERA_OV9640, + USB_GSPCA_PAC7302, USB_GSPCA_STV0680, AD525X_DPOT, CAN_MCP251X, + RT2800PCI, REGULATOR_MAX8660, RTC_DRV_BQ32K, RTC_DRV_MSM6242, + RTC_DRV_RP5C01, VMWARE_PVSCSI, SCSI_PM8001. + * [x86] set CS5535_MFGPT. + -- maximilian attems Mon, 15 Feb 2010 23:54:52 +0200 linux-2.6 (2.6.32-9) UNRELEASED; urgency=low diff --git a/debian/config/config b/debian/config/config index e48cfb2f8..07bdfdd8a 100644 --- a/debian/config/config +++ b/debian/config/config @@ -197,6 +197,12 @@ CONFIG_ATA_OVER_ETH=m CONFIG_VIRTIO_BLK=m # CONFIG_BLK_DEV_HD is not set +## +## file: drivers/block/drbd/Kconfig +## +CONFIG_BLK_DEV_DRBD=m +# CONFIG_DRBD_FAULT_INJECTION is not set + ## ## file: drivers/bluetooth/Kconfig ## @@ -323,6 +329,17 @@ CONFIG_DRM_SAVAGE=m ## # CONFIG_DRM_RADEON_KMS is not set +## +## file: drivers/gpu/drm/radeon/Kconfig +## +CONFIG_DRM_NOUVEAU=m +CONFIG_DRM_NOUVEAU_BACKLIGHT=y + +## +## file: drivers/gpu/drm/vmwgfx/Kconfig +## +CONFIG_DRM_VMWGFX=m + ## ## file: drivers/hid/Kconfig ## @@ -370,6 +387,7 @@ CONFIG_SENSORS_CORETEMP=m CONFIG_SENSORS_IBMAEM=m CONFIG_SENSORS_IBMPEX=m CONFIG_SENSORS_LM70=m +CONFIG_SENSORS_LM73=m CONFIG_SENSORS_LM93=m CONFIG_SENSORS_LTC4215=m CONFIG_SENSORS_LTC4245=m @@ -380,6 +398,7 @@ CONFIG_SENSORS_PC87427=m CONFIG_SENSORS_DME1737=m CONFIG_SENSORS_SMSC47M192=m CONFIG_SENSORS_ADS7828=m +CONFIG_SENSORS_AMC6821=m CONFIG_SENSORS_THMC50=m CONFIG_SENSORS_TMP401=m CONFIG_SENSORS_TMP421=m @@ -393,7 +412,9 @@ CONFIG_SENSORS_W83L786NG=m CONFIG_SENSORS_W83627EHF=m CONFIG_SENSORS_WM831X=m CONFIG_SENSORS_WM8350=m +CONFIG_SENSORS_LIS3_I2C=m CONFIG_SENSORS_APPLESMC=m +CONFIG_SENSORS_MC13783_ADC=m CONFIG_SENSORS_ATK0110=m CONFIG_SENSORS_LIS3LV02D=m @@ -600,6 +621,7 @@ CONFIG_MOUSE_SYNAPTICS_I2C=m CONFIG_TOUCHSCREEN_ADS7846=m CONFIG_TOUCHSCREEN_AD7877=m CONFIG_TOUCHSCREEN_AD7879_I2C=m +CONFIG_TOUCHSCREEN_DYNAPRO=m CONFIG_TOUCHSCREEN_EETI=m CONFIG_TOUCHSCREEN_FUJITSU=m CONFIG_TOUCHSCREEN_GUNZE=m @@ -619,6 +641,7 @@ CONFIG_TOUCHSCREEN_WM9705=y CONFIG_TOUCHSCREEN_WM9712=y CONFIG_TOUCHSCREEN_WM9713=y CONFIG_TOUCHSCREEN_USB_COMPOSITE=m +CONFIG_TOUCHSCREEN_MC13783=m CONFIG_TOUCHSCREEN_USB_EGALAX=y CONFIG_TOUCHSCREEN_USB_PANJIT=y CONFIG_TOUCHSCREEN_USB_3M=y @@ -641,6 +664,7 @@ CONFIG_CAPI_TRACE=y ## file: drivers/isdn/gigaset/Kconfig ## CONFIG_ISDN_DRV_GIGASET=m +CONFIG_GIGASET_CAPI=y CONFIG_GIGASET_BASE=m CONFIG_GIGASET_M105=m CONFIG_GIGASET_M101=m @@ -684,7 +708,9 @@ CONFIG_LEDS_PCA955X=m CONFIG_LEDS_WM831X_STATUS=m CONFIG_LEDS_WM8350=m CONFIG_LEDS_DAC124S085=m +CONFIG_LEDS_DAC124S085=m CONFIG_LEDS_BD2802=m +CONFIG_LEDS_INTEL_SS4200=m CONFIG_LEDS_TRIGGERS=y CONFIG_LEDS_TRIGGER_TIMER=m CONFIG_LEDS_TRIGGER_IDE_DISK=y @@ -767,6 +793,11 @@ CONFIG_DVB_BT8XX=m ## CONFIG_DVB_DM1105=m +## +## file: drivers/media/dvb/firewire/Kconfig +## +CONFIG_DVB_FIREDTV=m + ## ## file: drivers/media/dvb/dvb-usb/Kconfig ## @@ -799,6 +830,7 @@ CONFIG_DVB_USB_DTV5100=m CONFIG_DVB_USB_AF9015=m CONFIG_DVB_USB_CE6230=m CONFIG_DVB_USB_FRIIO=m +CONFIG_DVB_USB_EC168=m ## ## file: drivers/media/dvb/frontends/Kconfig @@ -957,10 +989,13 @@ CONFIG_SOC_CAMERA=m CONFIG_SOC_CAMERA_MT9M001=m CONFIG_SOC_CAMERA_MT9M111=m CONFIG_SOC_CAMERA_MT9T031=m +CONFIG_SOC_CAMERA_MT9T112=m CONFIG_SOC_CAMERA_MT9V022=m +CONFIG_SOC_CAMERA_RJ54N1=m CONFIG_SOC_CAMERA_TW9910=m CONFIG_SOC_CAMERA_PLATFORM=m CONFIG_SOC_CAMERA_OV772X=m +CONFIG_SOC_CAMERA_OV9640=m CONFIG_VIDEO_SH_MOBILE_CEU=m CONFIG_V4L_USB_DRIVERS=y CONFIG_VIDEO_OVCAMCHIP=m @@ -1044,6 +1079,7 @@ CONFIG_USB_GSPCA_MR97310A=m CONFIG_USB_GSPCA_OV519=m CONFIG_USB_GSPCA_OV534=m CONFIG_USB_GSPCA_PAC207=m +CONFIG_USB_GSPCA_PAC7302=m CONFIG_USB_GSPCA_PAC7311=m CONFIG_USB_GSPCA_SN9C20X=m CONFIG_USB_GSPCA_SN9C20X_EVDEV=y @@ -1058,6 +1094,7 @@ CONFIG_USB_GSPCA_SPCA561=m CONFIG_USB_GSPCA_SQ905=m CONFIG_USB_GSPCA_SQ905C=m CONFIG_USB_GSPCA_STK014=m +CONFIG_USB_GSPCA_STV0680=m CONFIG_USB_GSPCA_SUNPLUS=m CONFIG_USB_GSPCA_T613=m CONFIG_USB_GSPCA_TV8532=m @@ -1218,6 +1255,7 @@ CONFIG_AB3100_OTP=m ## file: drivers/misc/Kconfig ## CONFIG_MISC_DEVICES=y +CONFIG_AD525X_DPOT=m CONFIG_SGI_IOC4=m CONFIG_TIFM_CORE=m CONFIG_TIFM_7XX1=m @@ -1463,6 +1501,7 @@ CONFIG_BE2NET=m CONFIG_CAN_VCAN=m CONFIG_CAN_DEV=m CONFIG_CAN_CALC_BITTIMING=y +CONFIG_CAN_MCP251X=m # CONFIG_CAN_DEBUG_DEVICES is not set ## @@ -1738,6 +1777,7 @@ CONFIG_RT2X00=m CONFIG_RT2400PCI=m CONFIG_RT2500PCI=m CONFIG_RT61PCI=m +CONFIG_RT2800PCI=m CONFIG_RT2500USB=m CONFIG_RT73USB=m CONFIG_RT2800USB=m @@ -1858,6 +1898,7 @@ CONFIG_REGULATOR_FIXED_VOLTAGE=m CONFIG_REGULATOR_USERSPACE_CONSUMER=m CONFIG_REGULATOR_BQ24022=m CONFIG_REGULATOR_MAX1586=m +CONFIG_REGULATOR_MAX8660=m CONFIG_REGULATOR_WM831X=m CONFIG_REGULATOR_WM8350=m CONFIG_REGULATOR_WM8400=m @@ -1891,6 +1932,7 @@ CONFIG_RTC_DRV_PCF8563=m CONFIG_RTC_DRV_PCF8583=m CONFIG_RTC_DRV_M41T80=m # CONFIG_RTC_DRV_M41T80_WDT is not set +CONFIG_RTC_DRV_BQ32K=m CONFIG_RTC_DRV_S35390A=m CONFIG_RTC_DRV_FM3130=m CONFIG_RTC_DRV_RX8581=m @@ -1912,7 +1954,9 @@ CONFIG_RTC_DRV_STK17TA8=m CONFIG_RTC_DRV_M48T86=m CONFIG_RTC_DRV_M48T35=m CONFIG_RTC_DRV_M48T59=m +CONFIG_RTC_DRV_MSM6242=m CONFIG_RTC_DRV_BQ4802=m +CONFIG_RTC_DRV_RP5C01=m CONFIG_RTC_DRV_V3020=m CONFIG_RTC_DRV_WM831X=m CONFIG_RTC_DRV_WM8350=m @@ -1959,6 +2003,7 @@ CONFIG_SCSI_AIC7XXX_OLD=m CONFIG_SCSI_ADVANSYS=m # CONFIG_SCSI_ARCMSR_AER is not set CONFIG_SCSI_HPTIOP=m +CONFIG_VMWARE_PVSCSI=m CONFIG_LIBFC=m CONFIG_FCOE=m CONFIG_FCOE_FNIC=m @@ -1973,6 +2018,7 @@ CONFIG_SCSI_LPFC=m # CONFIG_SCSI_LPFC_DEBUG_FS is not set # CONFIG_SCSI_DEBUG is not set CONFIG_SCSI_PMCRAID=m +CONFIG_SCSI_PM8001=m CONFIG_SCSI_SRP=m CONFIG_SCSI_BFA_FC=m diff --git a/debian/config/kernelarch-x86/config b/debian/config/kernelarch-x86/config index f856f41c9..87798ea5d 100644 --- a/debian/config/kernelarch-x86/config +++ b/debian/config/kernelarch-x86/config @@ -681,6 +681,7 @@ CONFIG_I2O_PROC=m ## CONFIG_IBM_ASM=m CONFIG_PHANTOM=m +CONFIG_CS5535_MFGPT=m CONFIG_HP_ILO=m CONFIG_DELL_LAPTOP=m From 5eb6171b0ae9633fa9c10e8d15ff8c36be5171b2 Mon Sep 17 00:00:00 2001 From: Maximilian Attems Date: Fri, 19 Feb 2010 11:33:26 +0000 Subject: [PATCH 35/71] disble 2 staging drivers upfront broken not using request_firmware() svn path=/dists/trunk/linux-2.6/; revision=15225 --- .../dfsg/drivers-staging-wlags49_h2-disable.patch | 12 ++++++++++++ .../dfsg/drivers-staging-wlags49_h25-disable.patch | 12 ++++++++++++ debian/patches/series/orig-0 | 2 ++ 3 files changed, 26 insertions(+) create mode 100644 debian/patches/debian/dfsg/drivers-staging-wlags49_h2-disable.patch create mode 100644 debian/patches/debian/dfsg/drivers-staging-wlags49_h25-disable.patch diff --git a/debian/patches/debian/dfsg/drivers-staging-wlags49_h2-disable.patch b/debian/patches/debian/dfsg/drivers-staging-wlags49_h2-disable.patch new file mode 100644 index 000000000..89cbd4899 --- /dev/null +++ b/debian/patches/debian/dfsg/drivers-staging-wlags49_h2-disable.patch @@ -0,0 +1,12 @@ +diff --git a/drivers/staging/wlags49_h2/Kconfig b/drivers/staging/wlags49_h2/Kconfig +index 92053fe..b99b1b1 100644 +--- a/drivers/staging/wlags49_h2/Kconfig ++++ b/drivers/staging/wlags49_h2/Kconfig +@@ -1,6 +1,7 @@ + config WLAGS49_H2 + tristate "Agere Systems HERMES II Wireless PC Card Model 0110" + depends on WLAN_80211 && WIRELESS_EXT && PCMCIA ++ depends on BROKEN + select WEXT_SPY + ---help--- + Driver for wireless cards using Agere's HERMES II chipset diff --git a/debian/patches/debian/dfsg/drivers-staging-wlags49_h25-disable.patch b/debian/patches/debian/dfsg/drivers-staging-wlags49_h25-disable.patch new file mode 100644 index 000000000..29fa8cfc8 --- /dev/null +++ b/debian/patches/debian/dfsg/drivers-staging-wlags49_h25-disable.patch @@ -0,0 +1,12 @@ +diff --git a/drivers/staging/wlags49_h25/Kconfig b/drivers/staging/wlags49_h25/Kconfig +index 304a8c9..24365a8 100644 +--- a/drivers/staging/wlags49_h25/Kconfig ++++ b/drivers/staging/wlags49_h25/Kconfig +@@ -1,6 +1,7 @@ + config WLAGS49_H25 + tristate "Linksys HERMES II.5 WCF54G_Wireless-G_CompactFlash_Card" + depends on WLAN_80211 && WIRELESS_EXT && PCMCIA ++ depends on BROKEN + select WEXT_SPY + ---help--- + Driver for wireless cards using Agere's HERMES II.5 chipset diff --git a/debian/patches/series/orig-0 b/debian/patches/series/orig-0 index 60463aa37..19f74f401 100644 --- a/debian/patches/series/orig-0 +++ b/debian/patches/series/orig-0 @@ -6,6 +6,8 @@ + debian/dfsg/drivers-staging-rt2860-disable.patch + debian/dfsg/drivers-staging-rt2870-disable.patch + debian/dfsg/drivers-staging-rtl8192su-disable.patch ++ debian/dfsg/drivers-staging-wlags49_h2-disable.patch ++ debian/dfsg/drivers-staging-wlags49_h25-disable.patch + debian/dfsg/firmware-cleanup.patch + debian/dfsg/lgs8gxx-lgs8g75-disable.patch + debian/dfsg/r8169-rtl8168d-1-2-disable.patch From 8b3944278aa5fc2bb7d4c3064ec1b812f4d4d3a1 Mon Sep 17 00:00:00 2001 From: Maximilian Attems Date: Fri, 19 Feb 2010 11:56:26 +0000 Subject: [PATCH 36/71] topconfig, x86 set a bunch more evident drivers nothing to exciting.. svn path=/dists/trunk/linux-2.6/; revision=15226 --- debian/changelog | 7 +++++-- debian/config/config | 23 ++++++++++++++++++++++- debian/config/kernelarch-x86/config | 7 +++++++ 3 files changed, 34 insertions(+), 3 deletions(-) diff --git a/debian/changelog b/debian/changelog index 15da27d30..cfb1c4c7e 100644 --- a/debian/changelog +++ b/debian/changelog @@ -10,8 +10,11 @@ linux-2.6 (2.6.33~rc8-1~experimental.1) UNRELEASED; urgency=low DVB_FIREDTV, DVB_USB_EC168, SOC_CAMERA_MT9T112, SOC_CAMERA_OV9640, USB_GSPCA_PAC7302, USB_GSPCA_STV0680, AD525X_DPOT, CAN_MCP251X, RT2800PCI, REGULATOR_MAX8660, RTC_DRV_BQ32K, RTC_DRV_MSM6242, - RTC_DRV_RP5C01, VMWARE_PVSCSI, SCSI_PM8001. - * [x86] set CS5535_MFGPT. + RTC_DRV_RP5C01, VMWARE_PVSCSI, SCSI_PM8001, WIMAX_IWMC3200_SDIO, + INPUT_SPARSEKMAP, SERIO_ALTERA_PS2, MANTIS_CORE, DVB_MANTIS, + DVB_HOPPER. + * [x86] set CS5535_MFGPT, SENSORS_K10TEMP, GEODE_WDT, MSI_WMI, + TOSHIBA_BT_RFKILL, ACPI_CMPC, CRYPTO_GHASH_CLMUL_NI_INTE. -- maximilian attems Mon, 15 Feb 2010 23:54:52 +0200 diff --git a/debian/config/config b/debian/config/config index 07bdfdd8a..a5a4b74ae 100644 --- a/debian/config/config +++ b/debian/config/config @@ -259,6 +259,11 @@ CONFIG_TCG_NSC=m CONFIG_TCG_ATMEL=m CONFIG_TCG_INFINEON=m +## +## file: drivers/clocksource/Kconfig +## +CONFIG_CS5535_CLOCK_EVENT_SRC=m + ## ## file: drivers/connector/Kconfig ## @@ -538,6 +543,7 @@ CONFIG_INFINIBAND_SRP=m CONFIG_INPUT=y CONFIG_INPUT_FF_MEMLESS=m # CONFIG_INPUT_POLLDEV is not set +CONFIG_INPUT_SPARSEKMAP=m CONFIG_INPUT_MOUSEDEV=y CONFIG_INPUT_MOUSEDEV_PSAUX=y CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 @@ -615,6 +621,11 @@ CONFIG_MOUSE_PS2_SENTELIC=y # CONFIG_MOUSE_PS2_TOUCHKIT is not set CONFIG_MOUSE_SYNAPTICS_I2C=m +## +## file: drivers/input/serio/Kconfig +## +CONFIG_SERIO_ALTERA_PS2=m + ## ## file: drivers/input/touchscreen/Kconfig ## @@ -708,7 +719,7 @@ CONFIG_LEDS_PCA955X=m CONFIG_LEDS_WM831X_STATUS=m CONFIG_LEDS_WM8350=m CONFIG_LEDS_DAC124S085=m -CONFIG_LEDS_DAC124S085=m +CONFIG_LEDS_REGULATOR=m CONFIG_LEDS_BD2802=m CONFIG_LEDS_INTEL_SS4200=m CONFIG_LEDS_TRIGGERS=y @@ -881,6 +892,13 @@ CONFIG_DVB_ISL6421=m CONFIG_DVB_LGS8GXX=m CONFIG_DVB_DUMMY_FE=m +## +## file: drivers/media/dvb/mantis/Kconfig +## +CONFIG_MANTIS_CORE=m +CONFIG_DVB_MANTIS=m +CONFIG_DVB_HOPPER=m + ## ## file: drivers/media/dvb/pluto2/Kconfig ## @@ -1648,6 +1666,7 @@ CONFIG_WAN_ROUTER_DRIVERS=m ## file: drivers/net/wimax/i2400m/Kconfig ## CONFIG_WIMAX_I2400M_USB=m +CONFIG_WIMAX_IWMC3200_SDIO=y CONFIG_WIMAX_I2400M_SDIO=m CONFIG_WIMAX_I2400M_DEBUG_LEVEL=8 @@ -3907,6 +3926,7 @@ CONFIG_CFG80211=m CONFIG_CFG80211_DEFAULT_PS=y # CONFIG_CFG80211_DEBUGFS is not set CONFIG_WIRELESS_OLD_REGULATORY=y +CONFIG_CFG80211_WEXT=y CONFIG_WIRELESS_EXT=y # CONFIG_WIRELESS_EXT_SYSFS is not set CONFIG_LIB80211=m @@ -4037,6 +4057,7 @@ CONFIG_SND_VIRTUOSO=m CONFIG_SND_HDA_HWDEP=y CONFIG_SND_HDA_RECONFIG=y CONFIG_SND_HDA_INPUT_BEEP=y +CONFIG_SND_HDA_INPUT_BEEP_MODE=1 CONFIG_SND_HDA_INPUT_JACK=y CONFIG_SND_HDA_PATCH_LOADER=y CONFIG_SND_HDA_CODEC_REALTEK=y diff --git a/debian/config/kernelarch-x86/config b/debian/config/kernelarch-x86/config index 87798ea5d..601f14ded 100644 --- a/debian/config/kernelarch-x86/config +++ b/debian/config/kernelarch-x86/config @@ -115,6 +115,7 @@ CONFIG_XEN=y ## file: crypto/Kconfig ## CONFIG_CRYPTO_CRC32C_INTEL=m +CONFIG_CRYPTO_GHASH_CLMUL_NI_INTEL=m ## ## file: drivers/acpi/Kconfig @@ -382,6 +383,7 @@ CONFIG_SENSORS_ADM1025=m CONFIG_SENSORS_ADM1026=m CONFIG_SENSORS_ADM1031=m CONFIG_SENSORS_K8TEMP=m +CONFIG_SENSORS_K10TEMP=m CONFIG_SENSORS_ASB100=m CONFIG_SENSORS_DS1621=m CONFIG_SENSORS_F71805F=m @@ -972,6 +974,7 @@ CONFIG_ACERHDF=m CONFIG_DELL_WMI=m CONFIG_SONYPI_COMPAT=y CONFIG_THINKPAD_ACPI=m +CONFIG_THINKPAD_ACPI_ALSA_SUPPORT=y # CONFIG_THINKPAD_ACPI_DEBUGFACILITIES is not set # CONFIG_THINKPAD_ACPI_DEBUG is not set # CONFIG_THINKPAD_ACPI_UNSAFE_LEDS is not set @@ -979,10 +982,13 @@ CONFIG_THINKPAD_ACPI_VIDEO=y CONFIG_THINKPAD_ACPI_HOTKEY_POLL=y # CONFIG_INTEL_MENLOW is not set CONFIG_EEEPC_LAPTOP=m +CONFIG_MSI_WMI=m CONFIG_ACPI_WMI=m CONFIG_ACPI_ASUS=m CONFIG_TOPSTAR_LAPTOP=m CONFIG_ACPI_TOSHIBA=m +CONFIG_TOSHIBA_BT_RFKILL=m +CONFIG_ACPI_CMPC=m ## ## file: drivers/pnp/Kconfig @@ -1245,6 +1251,7 @@ CONFIG_ACQUIRE_WDT=m CONFIG_ADVANTECH_WDT=m CONFIG_ALIM1535_WDT=m CONFIG_ALIM7101_WDT=m +CONFIG_GEODE_WDT=m CONFIG_SC520_WDT=m CONFIG_EUROTECH_WDT=m CONFIG_IB700_WDT=m From 5dac9272dbe80bb3d3d53237e377ee062ddb327f Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Sat, 20 Feb 2010 05:27:26 +0000 Subject: [PATCH 37/71] Add link to arch scripts in linux-kbuild from linux-headers packages svn path=/dists/trunk/linux-2.6/; revision=15242 --- debian/rules.real | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/debian/rules.real b/debian/rules.real index 3c014820b..29534e519 100644 --- a/debian/rules.real +++ b/debian/rules.real @@ -208,6 +208,10 @@ install-headers_$(ARCH)_$(FEATURESET): $(STAMPS_DIR)/source_$(ARCH)_$(FEATURESET cpio -pd --preserve-modification-time '$(CURDIR)/$(DIR)' ln -s /usr/lib/$(PACKAGE_NAME_KBUILD)/{Kbuild,scripts} $(DIR) + if [ -d $(SOURCE_DIR)/arch/$(KERNEL_ARCH)/scripts ]; then \ + ln -s /usr/lib/$(PACKAGE_NAME_KBUILD)/arch/$(KERNEL_ARCH)/scripts \ + $(DIR)/arch/$(KERNEL_ARCH); \ + fi +$(MAKE_SELF) install-base From 4b24757ebe3df9627e897c9e0cc8cbb2197aed0a Mon Sep 17 00:00:00 2001 From: Martin Michlmayr Date: Sun, 21 Feb 2010 15:32:40 +0000 Subject: [PATCH 38/71] needed for 2.6.34 svn path=/dists/trunk/linux-2.6/; revision=15253 --- debian/config/armel/config.kirkwood | 1 + 1 file changed, 1 insertion(+) diff --git a/debian/config/armel/config.kirkwood b/debian/config/armel/config.kirkwood index a17aed502..2bc0ed87e 100644 --- a/debian/config/armel/config.kirkwood +++ b/debian/config/armel/config.kirkwood @@ -60,6 +60,7 @@ CONFIG_MACH_RD88F6281=y CONFIG_MACH_SHEEVAPLUG=y CONFIG_MACH_TS219=y CONFIG_MACH_TS41X=y +CONFIG_MACH_OPENRD=y CONFIG_MACH_OPENRD_BASE=y CONFIG_MACH_OPENRD_CLIENT=y From c027d2347c0d393a1bb5b28667ca4fe120d53a41 Mon Sep 17 00:00:00 2001 From: Maximilian Attems Date: Wed, 24 Feb 2010 20:44:15 +0000 Subject: [PATCH 39/71] update to 2.6.33 disable 2 patches, one merged for sure so nuke orig taball generation without changes. svn path=/dists/trunk/linux-2.6/; revision=15270 --- debian/changelog | 2 +- debian/patches/bugfix/all/efifb_fix_v2.patch | 54 -------------------- debian/patches/series/base | 4 +- 3 files changed, 3 insertions(+), 57 deletions(-) delete mode 100644 debian/patches/bugfix/all/efifb_fix_v2.patch diff --git a/debian/changelog b/debian/changelog index cfb1c4c7e..b5b08b5f3 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,4 +1,4 @@ -linux-2.6 (2.6.33~rc8-1~experimental.1) UNRELEASED; urgency=low +linux-2.6 (2.6.33-1~experimental.1) UNRELEASED; urgency=low * New upstream release. diff --git a/debian/patches/bugfix/all/efifb_fix_v2.patch b/debian/patches/bugfix/all/efifb_fix_v2.patch deleted file mode 100644 index 7291cfd19..000000000 --- a/debian/patches/bugfix/all/efifb_fix_v2.patch +++ /dev/null @@ -1,54 +0,0 @@ -From: Marcin Slusarz -Subject: [PATCH] efifb: fix framebuffer handoff - -Commit 4410f3910947dcea8672280b3adecd53cec4e85e -(fbdev: add support for handoff from firmware to hw framebuffers) -for unknown reason didn't add fb_destroy operation to efifb. -Change aperture_size to match size passed to request_mem_region. - -See: http://bugzilla.kernel.org/show_bug.cgi?id=15151 - -Reported-by: Alex Zhavnerchik -Tested-by: Alex Zhavnerchik -Cc: Dave Airlie -Cc: linux-fbdev@vger.kernel.org -Cc: dri-devel@lists.sourceforge.net -Signed-off-by: Marcin Slusarz ---- - drivers/video/efifb.c | 11 ++++++++++- - 1 files changed, 10 insertions(+), 1 deletions(-) - -diff --git a/drivers/video/efifb.c b/drivers/video/efifb.c -index eb12182..d25df51 100644 ---- a/drivers/video/efifb.c -+++ b/drivers/video/efifb.c -@@ -161,8 +161,17 @@ static int efifb_setcolreg(unsigned regno, unsigned red, unsigned green, - return 0; - } - -+static void efifb_destroy(struct fb_info *info) -+{ -+ if (info->screen_base) -+ iounmap(info->screen_base); -+ release_mem_region(info->aperture_base, info->aperture_size); -+ framebuffer_release(info); -+} -+ - static struct fb_ops efifb_ops = { - .owner = THIS_MODULE, -+ .fb_destroy = efifb_destroy, - .fb_setcolreg = efifb_setcolreg, - .fb_fillrect = cfb_fillrect, - .fb_copyarea = cfb_copyarea, -@@ -281,7 +290,7 @@ static int __init efifb_probe(struct platform_device *dev) - info->par = NULL; - - info->aperture_base = efifb_fix.smem_start; -- info->aperture_size = size_total; -+ info->aperture_size = size_remap; - - info->screen_base = ioremap(efifb_fix.smem_start, efifb_fix.smem_len); - if (!info->screen_base) { --- -1.6.6 - diff --git a/debian/patches/series/base b/debian/patches/series/base index 1734d9ddd..6a537950d 100644 --- a/debian/patches/series/base +++ b/debian/patches/series/base @@ -45,7 +45,8 @@ + bugfix/ia64/ia64-Include-linux-personality.h-header-in-asm-fcntl.patch -+ bugfix/all/cxusb-Select-all-required-frontend-and-tuner-modules.patch +# FIXME: check +#+ bugfix/all/cxusb-Select-all-required-frontend-and-tuner-modules.patch + bugfix/x86/kvm-fix-memory-access-during-x86-emulation.patch + bugfix/x86/kvm-Check-IOPL-level-during-io-instruction-emulation.patch @@ -53,4 +54,3 @@ + bugfix/x86/kvm-Check-CPL-level-during-privilege-instruction-emulation.patch + debian/sysrq-mask.patch -+ bugfix/all/efifb_fix_v2.patch From 2b9b4f709ac636651e13dffd23e96c107ecf7108 Mon Sep 17 00:00:00 2001 From: Maximilian Attems Date: Wed, 24 Feb 2010 20:48:28 +0000 Subject: [PATCH 40/71] nuke other 2.6.33 merged patch thanks Ben. :) svn path=/dists/trunk/linux-2.6/; revision=15271 --- ...-required-frontend-and-tuner-modules.patch | 35 ------------------- debian/patches/series/base | 3 -- 2 files changed, 38 deletions(-) delete mode 100644 debian/patches/bugfix/all/cxusb-Select-all-required-frontend-and-tuner-modules.patch diff --git a/debian/patches/bugfix/all/cxusb-Select-all-required-frontend-and-tuner-modules.patch b/debian/patches/bugfix/all/cxusb-Select-all-required-frontend-and-tuner-modules.patch deleted file mode 100644 index a1e184e4c..000000000 --- a/debian/patches/bugfix/all/cxusb-Select-all-required-frontend-and-tuner-modules.patch +++ /dev/null @@ -1,35 +0,0 @@ -Subject: [PATCH] cxusb: Select all required frontend and tuner modules -From: Ben Hutchings -Date: Thu, 11 Feb 2010 02:57:18 +0000 - -cxusb uses the atbm8830 and lgs8gxx (not lgs8gl5) frontends and the -max2165 tuner, so it needs to select them. - -Signed-off-by: Ben Hutchings -Cc: stable@kernel.org ---- - drivers/media/dvb/dvb-usb/Kconfig | 4 +++- - 1 files changed, 3 insertions(+), 1 deletions(-) - -diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig -index 1b24989..465295b 100644 ---- a/drivers/media/dvb/dvb-usb/Kconfig -+++ b/drivers/media/dvb/dvb-usb/Kconfig -@@ -112,11 +112,13 @@ config DVB_USB_CXUSB - select DVB_MT352 if !DVB_FE_CUSTOMISE - select DVB_ZL10353 if !DVB_FE_CUSTOMISE - select DVB_DIB7000P if !DVB_FE_CUSTOMISE -- select DVB_LGS8GL5 if !DVB_FE_CUSTOMISE - select DVB_TUNER_DIB0070 if !DVB_FE_CUSTOMISE -+ select DVB_ATBM8830 if !DVB_FE_CUSTOMISE -+ select DVB_LGS8GXX if !DVB_FE_CUSTOMISE - select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_XC2028 if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE -+ select MEDIA_TUNER_MAX2165 if !MEDIA_TUNER_CUSTOMISE - help - Say Y here to support the Conexant USB2.0 hybrid reference design. - Currently, only DVB and ATSC modes are supported, analog mode --- -1.6.6 - diff --git a/debian/patches/series/base b/debian/patches/series/base index 6a537950d..434034b05 100644 --- a/debian/patches/series/base +++ b/debian/patches/series/base @@ -45,9 +45,6 @@ + bugfix/ia64/ia64-Include-linux-personality.h-header-in-asm-fcntl.patch -# FIXME: check -#+ bugfix/all/cxusb-Select-all-required-frontend-and-tuner-modules.patch - + bugfix/x86/kvm-fix-memory-access-during-x86-emulation.patch + bugfix/x86/kvm-Check-IOPL-level-during-io-instruction-emulation.patch + bugfix/x86/kvm-Fix-popf-emulation.patch From 1010d1cd17e65c891ea5666dcb5ada359571a110 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Thu, 25 Feb 2010 04:11:39 +0000 Subject: [PATCH 41/71] Use libata-based drivers for most PATA controllers (Closes: #444182) Add transition script to linux-base and make all images depend on it svn path=/dists/trunk/linux-2.6/; revision=15272 --- debian/changelog | 26 + debian/config/kernelarch-x86/config | 44 +- debian/linux-base.postinst | 1470 +++++++++++++++++ .../drivers-ata-ata_piix-postpone-pata.patch | 53 - .../drivers-ata-pata_sis-postpone-pata.patch | 69 - .../piix-disable-redundant-devids.patch | 37 + debian/patches/series/base | 3 +- debian/rules.real | 3 +- debian/templates/control.image.type-plain.in | 2 +- debian/templates/control.main.in | 2 +- 10 files changed, 1560 insertions(+), 149 deletions(-) create mode 100644 debian/linux-base.postinst delete mode 100644 debian/patches/debian/drivers-ata-ata_piix-postpone-pata.patch delete mode 100644 debian/patches/debian/drivers-ata-pata_sis-postpone-pata.patch create mode 100644 debian/patches/debian/piix-disable-redundant-devids.patch diff --git a/debian/changelog b/debian/changelog index b5b08b5f3..ab43c1e4f 100644 --- a/debian/changelog +++ b/debian/changelog @@ -16,6 +16,32 @@ linux-2.6 (2.6.33-1~experimental.1) UNRELEASED; urgency=low * [x86] set CS5535_MFGPT, SENSORS_K10TEMP, GEODE_WDT, MSI_WMI, TOSHIBA_BT_RFKILL, ACPI_CMPC, CRYPTO_GHASH_CLMUL_NI_INTE. + [ Ben Hutchings ] + * Use libata-based drivers for most PATA controllers (Closes: #444182): + - pata_triflex replaces triflex + - pata_atiixp replaces atiixp + - pata_ns87415 replaces ns87415 + - pata_sc1200 replaces sc1200 + - pata_cs5536 replaces cs5536 + - pata_amd replaces amd74xx + - pata_sis replaces sis5513 + - pata_rz1000 replaces rz1000 + - pata_efar replaces slc90e66 + - pata_pdc202xx_old replaces pdc202xx_old + - pata_pdc2027x replaces pdc202xx_new + - pata_cs5520 replaces cs5520 + - pata_cs5530 replaces cs5530 + - pata_cmd64x replaces cmd64x + - pata_sil680 replaces siimage + - pata_ali replaces alim15x3 + - pata_via replaces via82cxxx + - pata_serverworks replaces serverworks + - pata_artop replaces aec62xx + - pata_it821x replaces it821x + - ata_piix, pata_oldpiix, pata_mpiix mostly replace piix + - ata_generic, pata_ns87410, pata_netcell replace ide-pci-generic + * Add libata transition script + -- maximilian attems Mon, 15 Feb 2010 23:54:52 +0200 linux-2.6 (2.6.32-9) UNRELEASED; urgency=low diff --git a/debian/config/kernelarch-x86/config b/debian/config/kernelarch-x86/config index 601f14ded..be3d04b8a 100644 --- a/debian/config/kernelarch-x86/config +++ b/debian/config/kernelarch-x86/config @@ -145,7 +145,26 @@ CONFIG_ACPI_SBS=m ## ## file: drivers/ata/Kconfig ## -# CONFIG_PATA_SIS is not set +CONFIG_PATA_ALI=m +CONFIG_PATA_AMD=m +CONFIG_PATA_ATIIXP=m +CONFIG_PATA_CMD64X=m +CONFIG_PATA_CS5520=m +CONFIG_PATA_CS5530=m +CONFIG_PATA_EFAR=m +CONFIG_PATA_TRIFLEX=m +CONFIG_PATA_MPIIX=m +CONFIG_PATA_OLDPIIX=m +CONFIG_PATA_NETCELL=m +CONFIG_PATA_NS87410=m +CONFIG_PATA_NS87415=m +CONFIG_PATA_PDC_OLD=m +CONFIG_PATA_RZ1000=m +CONFIG_PATA_SC1200=m +CONFIG_PATA_SERVERWORKS=m +CONFIG_PATA_PDC2027X=m +CONFIG_PATA_SIL680=m +CONFIG_PATA_VIA=m ## ## file: drivers/atm/Kconfig @@ -455,36 +474,17 @@ CONFIG_IDE_GD=m CONFIG_BLK_DEV_IDECS=m CONFIG_BLK_DEV_IDECD=m CONFIG_BLK_DEV_IDETAPE=m -CONFIG_BLK_DEV_IDEACPI=y +# CONFIG_BLK_DEV_IDEACPI is not set CONFIG_IDE_GENERIC=m -CONFIG_BLK_DEV_CMD640=y +# CONFIG_BLK_DEV_CMD640 is not set # CONFIG_BLK_DEV_CMD640_ENHANCED is not set CONFIG_BLK_DEV_IDEPNP=y # CONFIG_BLK_DEV_OFFBOARD is not set -CONFIG_BLK_DEV_GENERIC=m CONFIG_BLK_DEV_OPTI621=m -CONFIG_BLK_DEV_RZ1000=m -CONFIG_BLK_DEV_AEC62XX=m -CONFIG_BLK_DEV_ALI15X3=m -CONFIG_BLK_DEV_AMD74XX=m -CONFIG_BLK_DEV_ATIIXP=m -CONFIG_BLK_DEV_CMD64X=m -CONFIG_BLK_DEV_TRIFLEX=m CONFIG_BLK_DEV_CY82C693=m -CONFIG_BLK_DEV_CS5520=m -CONFIG_BLK_DEV_CS5530=m CONFIG_BLK_DEV_HPT366=m -CONFIG_BLK_DEV_SC1200=m CONFIG_BLK_DEV_PIIX=m -CONFIG_BLK_DEV_NS87415=m -CONFIG_BLK_DEV_PDC202XX_OLD=m -CONFIG_BLK_DEV_PDC202XX_NEW=m -CONFIG_BLK_DEV_SVWKS=m -CONFIG_BLK_DEV_SIIMAGE=m -CONFIG_BLK_DEV_SIS5513=m -CONFIG_BLK_DEV_SLC90E66=m CONFIG_BLK_DEV_TRM290=m -CONFIG_BLK_DEV_VIA82CXXX=m ## ## file: drivers/input/Kconfig diff --git a/debian/linux-base.postinst b/debian/linux-base.postinst new file mode 100644 index 000000000..f84327208 --- /dev/null +++ b/debian/linux-base.postinst @@ -0,0 +1,1470 @@ +#!/usr/bin/perl + +# Copyright 2009-2010 Ben Hutchings +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +use strict; +use warnings; +use AptPkg::Config; +use Debconf::Client::ConfModule ':all'; +use FileHandle; +use POSIX (); + +package DebianKernel::DiskId; + +### utility + +sub id_to_path { + my ($id) = @_; + $id =~ m|^/| + or $id =~ s{^(LABEL|UUID)=}{'/dev/disk/by-' . lc($1) . '/'}x + or die "Could not map id $id to path"; + return $id; +} + +### /etc/fstab + +sub fstab_next { + # Based on my_getmntent() in mount_mntent.c + + my ($file) = @_; + my $text = <$file>; + unless (defined($text)) { + return (); + } + + my $line = $text; + $line =~ s/\r?\n$//; + $line =~ s/^[ \t]*//; + if ($line =~ /^(#|$)/) { + return ($text); + } else { + return ($text, + map({ s/\\([0-7][0-7][0-7])/chr(oct($1) & 0xff)/eg; $_; } + split(/[ \t]+/, $line))); + } +} + +sub fstab_list { + my ($file) = @_; + my @bdevs; + while (1) { + my ($text, $bdev) = fstab_next($file); + last unless defined($text); + if (defined($bdev)) { + push @bdevs, $bdev; + } + } + return @bdevs; +} + +sub fstab_update { + my ($old, $new, $map) = @_; + while (1) { + my ($text, $bdev) = fstab_next($old); + last unless defined($text); + if (defined($bdev) && defined(my $id = $map->{$bdev})) { + $text =~ s/^(\s*\S+)(.*)/# $1$2\n$id$2/; + } + $new->print("$text"); + } +} + +### Kernel parameters + +sub kernel_list { + my ($cmd_line) = @_; + return ($cmd_line =~ /\broot=(\S+)/) ? ($1) : (); +} + +sub kernel_update { + my ($cmd_line, $map) = @_; + if ($cmd_line =~ /\broot=(\S+)/ && defined(my $id = $map->{$1})) { + $cmd_line =~ s/\broot=(\S+)/root=$id/; + return $cmd_line; + } else { + return undef; + } +} + +### shell script variable assignment + +# Maintains enough context to find statement boundaries, and can parse +# variable definitions that do not include substitutions. I think. + +sub shellvars_next { + my ($file) = @_; + my $text = ''; + my @context = (''); + my $first = 1; + my $in_value = 0; + my ($name, $value); + my $unhandled = 0; + + LINE: + while (<$file>) { + $text .= $_; + + # variable assignment + if ($first && m/^\s*([A-Za-z_][A-Za-z0-9_]*)=/g) { + $name = $1; + $value = ''; + $in_value = 1; + } + + while (/\G(.*?)([#`'"(){}\s]|\\.|\$[({]?)/gs) { + my $end_pos = pos; + my $special = $2; + + if ($in_value) { + # add non-special characters to the value verbatim + $value .= $1; + } + + if ($context[$#context] eq '') { + # space outside quotes or brackets ends the value + if ($special =~ /^\s/) { + $in_value = 0; + if ($special eq "\n") { + last LINE; + } + } + # something else after the value means this is a command + # with an environment override, not a variable definition + elsif (defined($name) && !$in_value) { + $unhandled = 1; + } + } + + # in single-quoted string + if ($context[$#context] eq "'") { + # only the terminating single-quote is special + if ($special eq "'") { + pop @context; + } else { + $value .= $special; + } + } + # backslash escape + elsif ($special =~ /^\\/) { + if ($in_value && $special ne "\\\n") { + $value .= substr($special, 1, 1); + } + } + # in backtick substitution + elsif ($context[$#context] eq '`') { + # backtick does not participate in nesting, so only the + # terminating backtick should be considered special + if ($special eq '`') { + pop @context; + } + } + # comment + elsif ($context[$#context] !~ /^['"]/ && $special eq '#') { + # ignore rest of the physical line, except the new-line + pos = $end_pos; + /\G.*/g; + next; + } + # start of backtick substitution + elsif ($special eq '`') { + push @context, '`'; + $unhandled = 1; + } + # start of single/double-quoted string + elsif ($special =~ /^['"]/ && $context[$#context] !~ /^['"]/) { + push @context, $special; + } + # end of double-quoted string + elsif ($special eq '"' && $context[$#context] eq '"') { + pop @context; + } + # open bracket + elsif ($special =~ /^\$?\(/) { + push @context, ')'; + $unhandled = 1; + } elsif ($special =~ /^\$\{/) { + push @context, '}'; + $unhandled = 1; + } + # close bracket + elsif ($special =~ /^[)}]/ && $special eq $context[$#context]) { + pop @context; + } + # variable substitution + elsif ($special eq '$') { + $unhandled = 1; + } + # not a special character in this context (or a syntax error) + else { + if ($in_value) { + $value .= $special; + } + } + + pos = $end_pos; + } + + $first = 0; + } + + if ($text eq '') { + return (); + } elsif ($unhandled) { + return ($text); + } else { + return ($text, $name, $value); + } +} + +sub shellvars_quote { + my ($value) = @_; + $value =~ s/'/'\''/g; + return "'$value'"; +} + +### GRUB 1 (grub-legacy) config + +sub grub1_parse { + my ($file) = @_; + my @results = (); + my $text = ''; + my $in_auto = 0; + my $in_opts = 0; + + while (<$file>) { + if ($in_opts && /^\# (\w+)=(.*)/) { + push @results, [$text]; + $text = ''; + push @results, [$_, $1, $2]; + } else { + $text .= $_; + if ($_ eq "### BEGIN AUTOMAGIC KERNELS LIST\n") { + $in_auto = 1; + } elsif ($_ eq "### END DEBIAN AUTOMAGIC KERNELS LIST\n") { + $in_auto = 0; + } elsif ($_ eq "## ## Start Default Options ##\n") { + $in_opts = $in_auto; + } elsif ($_ eq "## ## End Default Options ##\n") { + $in_opts = 0; + } + } + } + + if ($text ne '') { + push @results, [$text]; + } + + return @results; +} + +sub grub1_list { + my ($file) = @_; + my %options; + for (grub1_parse($file)) { + my ($text, $name, $value) = @$_; + next unless defined($name); + $options{$name} = $value; + } + + my @bdevs; + if (exists($options{kopt_2_6})) { + push @bdevs, kernel_list($options{kopt_2_6}); + } elsif (exists($options{kopt})) { + push @bdevs, kernel_list($options{kopt}); + } + if (exists($options{xenkopt})) { + push @bdevs, kernel_list($options{xenkopt}); + } + return @bdevs; +} + +sub grub1_update { + my ($old, $new, $map) = @_; + + my %options; + for (grub1_parse($old)) { + my ($text, $name, $value) = @$_; + next unless defined($name); + $options{$name} = $value; + } + + $old->seek(0, 0); + for (grub1_parse($old)) { + my ($text, $name, $value) = @$_; + next unless defined($name); + if ($name eq 'kopt_2_6' || + ($name eq 'kopt' && !exists($options{kopt_2_6})) || + $name eq 'xenkopt') { + if (defined(my $new_value = kernel_update($value))) { + $text = "## $name=$value\n# $name=$new_value\n"; + } + } + $new->print($text); + } +} + +sub grub1_post { + system('update-grub'); +} + +### GRUB 2 config + +sub grub2_list { + my ($file) = @_; + my @bdevs; + + while (1) { + my ($text, $name, $value) = shellvars_next($file); + last unless defined($text); + if (defined($name) && $name =~ /^GRUB_CMDLINE_LINUX(?:_DEFAULT)?$/) { + push @bdevs, kernel_list($value); + } + } + + return @bdevs; +} + +sub grub2_update { + my ($old, $new, $map) = @_; + my @bdevs; + + while (1) { + my ($text, $name, $value) = shellvars_next($old); + last unless defined($text); + if (defined($name) && $name =~ /^GRUB_CMDLINE_LINUX(?:_DEFAULT)?$/ && + defined(my $new_value = kernel_update($value, $map))) { + $text =~ s/^/# /gm; + $text .= sprintf("%s=%s\n", $name, shellvars_quote($new_value)); + } + $new->print($text); + } +} + +sub grub2_post { + system('grub-mkconfig', '-o', '/boot/grub/grub.cfg'); +} + +### LILO + +sub lilo_tokenize { + # Based on cfg_get_token() and next() in cfg.c. + # Line boundaries are *not* significant (except as white space) so + # we tokenize the whole file at once. + + my ($file) = @_; + my @tokens = (); + my $text = ''; + my $token; + my $in_quote = 0; + + while (<$file>) { + # If this is the continuation of a multi-line quote, skip + # leading space and push back the necessary context. + if ($in_quote) { + s/^[ \t]*/"/; + $text .= $&; + } + + pos = 0; + while (/\G \s* (?:\#.*)? + (?: (=) | + " ((?:[^"] | \\[\\"n])*) (" | \\\r?\n) | + ((?:[^\s\#="\\] | \\[^\r\n])+) (\\\r?\n)?)? + /gsx) { + my $cont; + my $new_text = $&; + + if (defined($1)) { + # equals sign + $text = $new_text; + $token = $1; + $cont = 0; + } elsif (defined($2)) { + # quoted text + if (!$in_quote) { + $text = $new_text; + $token = $2; + } else { + $text .= substr($new_text, 1); # remove the quote again; ick + $token .= ' ' . $2; + } + $cont = $3 ne '"'; + } elsif (defined($4)) { + # unquoted word + if (!defined($token)) { + $token = ''; + } + $text .= $new_text; + $token .= $4; + $cont = defined($5); + } else { + $text .= $new_text; + $cont = $new_text eq ''; + } + + if (!$cont) { + if ($text =~ /(?:^|[^\\])\$/) { + # unhandled expansion + $token = undef; + } elsif (defined($token)) { + if ($in_quote) { + $token =~ s/\\(.)/$1 eq 'n' ? "\n" : $1/eg; + } else { + $token =~ s/\\(.)/$1/g; + } + } + push @tokens, [$text, $token]; + $text = ''; + $token = undef; + $in_quote = 0; + } + } + } + + return @tokens; +} + +sub lilo_list { + my ($file) = @_; + my @bdevs = (); + my @tokens = lilo_tokenize($file); + my $i = 0; + my $in_generic = 1; # global or image=/vmlinuz or image=/vmlinuz.old + + while ($i <= $#tokens) { + # Configuration items are either "=" or alone. + if ($#tokens - $i >= 2 && + defined($tokens[$i + 1][1]) && $tokens[$i + 1][1] eq '=') { + my ($name, $value) = ($tokens[$i][1], $tokens[$i + 2][1]); + if (defined($name) && defined($value)) { + if ($name eq 'image') { + $in_generic = ($value =~ m|^/vmlinuz(?:\.old)?$|); + } elsif ($in_generic) { + if ($name =~ /^(?:boot|root)$/) { + push @bdevs, $value; + } elsif ($name =~ /^(?:addappend|append|literal)$/) { + push @bdevs, kernel_list($value); + } + } + } + $i += 3; + } else { + $i += 1; + } + } + + return @bdevs; +} + +sub lilo_update { + my ($old, $new, $map) = @_; + my @tokens = lilo_tokenize($old); + my $i = 0; + my $in_generic = 1; # global or image=/vmlinuz or image=/vmlinuz.old + + while ($i <= $#tokens) { + my $text = $tokens[$i][0]; + + if ($#tokens - $i >= 2 && + defined($tokens[$i + 1][1]) && $tokens[$i + 1][1] eq '=') { + my ($name, $value) = ($tokens[$i][1], $tokens[$i + 2][1]); + my $new_value; + if (defined($name) && defined($value)) { + if ($name eq 'image') { + $in_generic = ($value =~ m|^/vmlinuz(?:\.old)?$|); + } elsif ($in_generic) { + if ($name eq 'boot') { + # 'boot' is used directly by the lilo command, which + # doesn't use libblkid + $new_value = + $map->{$value} && disk_id_to_path($map->{$value}); + } elsif ($name eq 'root') { + # 'root' adds a root parameter to the kernel command + # line + $new_value = $map->{$value}; + } elsif ($name =~ /^(?:addappend|append|literal)$/) { + # These are all destined for the kernel command line + # in some way + $new_value = kernel_update($value, $map); + } + } + } + if (defined($new_value)) { + $new_value =~ s/\\/\\\\/g; + $text = "\n# $name = $value\n$name = \"$new_value\"\n"; + } else { + $text .= $tokens[$i + 1][0] . $tokens[$i + 2][0]; + } + $i += 3; + } else { + $i += 1; + } + + $new->print($text); + } +} + +sub lilo_post { + system('lilo'); +} + +### SILO + +sub silo_post { + system('silo'); +} + +### ELILO + +sub elilo_post { + system('elilo'); +} + +### PALO + +sub palo_next { + my ($file, $expect_opt) = @_; + my $text = <$file>; + + if (!defined($text) || $text eq '') { + return (); + } + + my $arg = $text; + $arg =~ s/^\s*(?:#.*)?//s; + $arg =~ s/\s*$//; + + # I would like to use Getopt::Long but it would make it + # impossible to determine which source text to replace. + if ($expect_opt && $arg =~ /^-(?!-)[?v]*(.)(.+)?$/) { + return ($text, "-$1", $2, defined($2)); + } elsif ($expect_opt && $arg =~ /^(--[^=]+)(?:=(.*))?$/) { + return ($text, $1, $2, defined($2)); + } elsif ($arg ne '') { + return ($text, undef, $arg, 1); + } else { + return ($text, undef, undef, $expect_opt); + } +} + +sub palo_list { + my ($file) = @_; + my $optopt; + my @bdevs; + + while (1) { + my ($text, $optarg, $complete); + if (defined($optopt)) { + ($text, undef, $optarg, $complete) = palo_next($file, 0); + } else { + ($text, $optopt, $optarg, $complete) = palo_next($file, 1); + } + last unless defined($text); + + if ($complete && defined($optopt)) { + if ($optopt eq '-c' || $optopt eq '--commandline') { + # If PALO is not configured to use the generic sym-link, + # ignore it + if ($optarg !~ m|^\d+/vmlinux\b|) { + return (); + } + push @bdevs, kernel_list($optarg); + } elsif ($optopt eq '-I' || $optopt eq '--init-partitioned') { + push @bdevs, $optarg; + } + $optopt = undef; + } + + if (!defined($optopt) && defined($optarg) && $optarg eq '--') { + last; + } + } + + return @bdevs; +} + +sub palo_update { + my ($old, $new, $map) = @_; + my $optopt; + my $allow_opts = 1; + + while (1) { + my ($text, $optarg, $complete); + if (defined($optopt)) { + ($text, undef, $optarg, $complete) = palo_next($old, 0); + } else { + ($text, $optopt, $optarg, $complete) = palo_next($old, $allow_opts); + } + last unless defined($text); + + if (defined($optopt)) { + if ($optopt eq '-c' || $optopt eq '--commandline') { + $text = "# $text"; + if ($complete) { + my $new_cmdline = kernel_update($optarg, $map); + if (!defined($new_cmdline)) { + $new_cmdline = $optarg; + } + $text .= "--commandline=$new_cmdline\n"; + } + } + $optopt = undef; + } + + $new->print($text); + + if (!defined($optopt) && defined($optarg) && $optarg eq '--') { + $allow_opts = 0; + } + } +} + +sub palo_post { + system('palo'); +} + +### delo + +sub delo_next { + # Based on getconfig() in config.c + + my ($file) = @_; + my $text = <$file>; + + if (!defined($text) || $text eq '') { + return (); + } + + local $_ = $text; + s/[ \t]*(?:#.*)?\n//; + s/^[ \t]*//; + + if (/^([a-z]+)=(.*)$/) { + return ($text, $1, $2); + } else { + return ($text); + } +} + +sub delo_sections { + my ($file) = @_; + my @sections; + my $section = {}; + + while (1) { + my ($text, $name, $value) = delo_next($file); + + # If this is EOF or a new section, finish the current section + if (!defined($text) || (defined($name) && $name eq 'label')) { + $section->{is_generic} = + (exists($section->{image}) && + exists($section->{append}) && + $section->{image} =~ m|^/vmlinux(?:\.old)?$|); + push @sections, $section; + $section = {}; + } + + last unless defined($text); + + if (defined($name)) { + if ($name eq 'append') { + $value =~ s/^"([^"]*).*/$1/; + } + $section->{$name} = $value; + } + } + + return @sections; +} + +sub delo_list { + my ($file) = @_; + my ($globals, @entries) = delo_sections($file); + my @bdevs; + + if (exists($globals->{boot})) { + push @bdevs, $globals->{boot}; + } + + for my $entry (@entries) { + if ($entry->{is_generic}) { + push @bdevs, kernel_list($entry->{append}); + } + } + + return @bdevs; +} + +sub delo_update { + my ($old, $new, $map) = @_; + my ($globals, @entries) = delo_sections($old); + my $i = -1; + + $old->seek(0, 0); + + while (1) { + my ($text, $name, $value) = delo_next($old); + last unless defined($text); + + if (defined($name)) { + if ($name eq 'label') { + ++$i; # next entry + } elsif ($name eq 'boot' && $i < 0) { + my $new_value = + $map->{$value} && disk_id_to_path($map->{$value}); + if (defined($new_value)) { + $text = "# $text" . "boot=$new_value\n"; + } + } elsif ($name eq 'append' && + $i >= 0 && $entries[$i]->{is_generic}) { + my $new_cmdline = kernel_update($value, $map); + if (defined($new_cmdline)) { + $text = "# $text" . "append=\"$new_cmdline\"\n"; + } + } + } + + $new->print($text); + } +} + +### extlinux + +sub extlinux_old_path { + for ('/boot/extlinux', '/boot/boot/exlinux', '/extlinux') { + if (-e) { + return "$_/options.cfg"; + } + } + return undef; +} + +sub extlinux_old_list { + my ($file) = @_; + while (<$file>) { + if (/^## ROOT=(.*)/) { + return kernel_list($1); + } + } + return (); +} + +sub extlinux_old_update { + my ($old, $new, $map) = @_; + while (<$old>) { + my $text = $_; + if (/^## ROOT=(.*)/) { + my $new_params = kernel_update($1, $map); + if (defined($new_params)) { + $text = "## $text" . "## ROOT=$new_params\n"; + } + } + $new->print($text); + } +} + +sub extlinux_new_list { + my ($file) = @_; + while (<$file>) { + if (/^# ROOT=(.*)/) { + return kernel_list($1); + } + } + return (); +} + +sub extlinux_new_update { + my ($old, $new, $map) = @_; + while (<$old>) { + my $text = $_; + if (/^# ROOT=(.*)/) { + my $new_params = kernel_update($1, $map); + if (defined($new_params)) { + $text = "## $text" . "# ROOT=$new_params\n"; + } + } + $new->print($text); + } +} + +sub extlinux_post { + system('update-extlinux'); +} + +### aboot + +sub aboot_next { + my ($file) = @_; + my $text = <$file>; + + if (!defined($text) || $text eq '') { + return (); + } + + if ($text =~ /^([0-9]):([^ ]*) (.*)/) { + return ($text, $1, $2, $3); + } else { + return ($text); + } +} + +sub aboot_list { + my ($file) = @_; + my @bdevs; + while (1) { + my ($text, $preset, $kernel, $params) = aboot_next($file); + last unless defined($text); + if (defined($params) && $kernel =~ m|^\d+/vmlinux(?:\.old)?$|) { + push @bdevs, kernel_list($params); + } + } + return @bdevs; +} + +sub aboot_update { + my ($old, $new, $map) = @_; + while (1) { + my ($text, $preset, $kernel, $params) = aboot_next($old); + last unless defined($text); + if (defined($params) && $kernel =~ m|^\d+/vmlinux(?:\.old)?$|) { + my $new_params = kernel_update($params, $map); + if (defined($new_params)) { + $text = "# $text" . "$preset:$kernel $new_params\n"; + } + } + $new->print($text); + } +} + +# udev persistent-cd + +sub udev_next { + my ($file) = @_; + my @results = (); + + # Based on parse_file() and get_key() in udev-rules.c + while (1) { + my $text = <$file>; + last if !defined($text) || $text eq ''; + + if ($text =~ /^\s*(?:#|$)/) { + push @results, [$text]; + } else { + my $end_pos = 0; + while ($text =~ /\G [\s,]* ((?:[^\s=+!:]|[+!:](?!=))+) + \s* ([=+!:]?=) "([^"]*)"/gx) { + push @results, [$&, $1, $2, $3]; + $end_pos = pos($text); + } + push @results, [substr($text, $end_pos)]; + last if $text !~ /\\\n$/; + } + } + + return @results; +} + +sub udev_cd_list { + # doesn't use block device names + return (); +} + +sub udev_cd_update { + my ($old, $new) = @_; # ignore map + my @ide_rules; + my %scsi_rules; + my $i; + + # First pass: list the current symlink rules for IDE and SCSI devices + $i = 0; + while (1) { + my @keys = udev_next($old); + last if $#keys < 0; + + my ($path, $symlink); + for (@keys) { + my ($text, $key, $op, $value) = @$_; + next if !defined($key); + if ($key eq 'ENV{ID_PATH}' && $op eq '==') { + $path = $value; + } elsif ($key eq 'SYMLINK' && $op eq '+=') { + $symlink = $value; + } + } + + if (defined($path) && defined($symlink)) { + if ($path =~ /-ide-\d+:\d+$/) { + $ide_rules[$i] = $symlink; + } elsif ($path =~ /-scsi-\d+:\d+:\d+:\d+$/) { + $scsi_rules{"$path $symlink"} = 1; + } + } + + ++$i; + } + + # Second pass: fill in the missing rules for SCSI devices + $old->seek(0, 0); + $i = 0; + while (1) { + my @keys = udev_next($old); + last if $#keys < 0; + + my $old_text = ''; + my $new_text = ''; + my $need_new; + + for (@keys) { + my ($text, $key, $op, $value) = @$_; + $old_text .= $text; + next unless defined($ide_rules[$i]) && defined($key); + + if ($key eq 'ENV{ID_PATH}' && $op eq '==') { + # libata uses the PATA controller and device numbers + # as SCSI host number and bus id. Channel number and + # LUN are always 0. The parent device path should + # stay the same. + $value =~ s/-ide-(\d+):(\d+)$/-scsi-$1:0:$2:0/; + + my $rule_key = $value . ' ' . $ide_rules[$i]; + if (!exists($scsi_rules{$rule_key})) { + $need_new = 1; + $new_text .= ", $key$op\"$value\""; + } + } else { + $new_text .= $text; + } + } + + $new->print($old_text); + if ($need_new) { + $new->print($new_text . "\n"); + } + + ++$i; + } +} + +# initramfs-tools resume + +sub initramfs_resume_list { + my ($file) = @_; + my @results = (); + + while (1) { + my ($text, $name, $value) = shellvars_next($file); + last unless defined($text); + if (defined($name) && $name eq 'RESUME') { + $results[0] = $value; + } + } + + return @results; +} + +sub initramfs_resume_update { + my ($old, $new, $map) = @_; + + while (1) { + my ($text, $name, $value) = shellvars_next($old); + last unless defined($text); + if (defined($name) && $name eq 'RESUME' && + defined(my $new_value = $map->{$value})) { + $text =~ s/^/# /gm; + $text .= sprintf("%s=%s\n", $name, shellvars_quote($new_value)); + } + $new->print($text); + } +} + +### list of all configuration files and functions + +my @config_files = ({packages => 'mount', + path => '/etc/fstab', + list => \&fstab_list, + update => \&fstab_update}, + {packages => 'grub grub-legacy', + path => '/boot/grub/menu.lst', + list => \&grub1_list, + update => \&grub1_update, + post_update => \&grub1_post}, + {packages => 'grub-common', + path => '/etc/default/grub', + list => \&grub2_list, + update => \&grub2_update, + post_update => \&grub2_post}, + {packages => 'lilo', + path => '/etc/lilo.conf', + list => \&lilo_list, + update => \&lilo_update, + post_update => \&lilo_post}, + {packages => 'silo', + path => '/etc/silo.conf', + list => \&lilo_list, + update => \&lilo_update, + post_update => \&silo_post}, + {packages => 'quik', + path => '/etc/quik.conf', + list => \&lilo_list, + update => \&lilo_update}, + {packages => 'yaboot', + path => '/etc/yaboot.conf', + list => \&lilo_list, + update => \&lilo_update}, + {packages => 'elilo', + path => '/etc/elilo.conf', + list => \&lilo_list, + update => \&lilo_update, + post_update => \&elilo_post}, + {packages => 'palo', + path => '/etc/palo.conf', + list => \&palo_list, + update => \&palo_update, + post_update => \&palo_post}, + {packages => 'delo', + path => '/etc/delo.conf', + list => \&delo_list, + update => \&delo_update}, + {packages => 'arcboot', + path => '/etc/arcboot.conf', + list => \&delo_list, + update => \&delo_update}, + {packages => 'extlinux', + path => extlinux_old_path(), + list => \&extlinux_old_list, + update => \&extlinux_old_update, + post_update => \&extlinux_post}, + {packages => 'extlinux', + path => '/etc/default/extlinux', + list => \&extlinux_new_list, + update => \&extlinux_new_update, + post_update => \&extlinux_post}, + {packages => 'aboot', + path => '/etc/aboot.conf', + list => \&aboot_list, + update => \&aboot_update}, + {packages => 'udev', + path => '/etc/udev/rules.d/70-persistent-cd.rules', + list => \&udev_cd_list, + update => \&udev_cd_update, + always_update => 1}, + {packages => 'initramfs-tools', + path => '/etc/initramfs-tools/conf.d/resume', + list => \&initramfs_resume_list, + update => \&initramfs_resume_update, + # udev will source all files in this directory, + # with few exceptions. Such as including a '^'. + suffix => '^old'}); + +### Filesystem relabelling + +sub ext2_label { + my ($bdev, $label) = @_; + system('e2label', $bdev, $label) == 0 or die "e2label failed: $?"; +} + +sub jfs_label { + my ($bdev, $label) = @_; + system('jfs_tune', '-L', $label, $bdev) == 0 or die "jfs_tune failed: $?"; +} + +sub fat_label { + my ($bdev, $label) = @_; + system('dosfslabel', $bdev, $label) == 0 or die "dosfslabel failed: $?";; +} + +sub ntfs_label { + my ($bdev, $label) = @_; + system('ntfslabel', $bdev, $label) == 0 or die "ntfslabel failed: $?"; +} + +sub reiserfs_label { + my ($bdev, $label) = @_; + system('reiserfstune', '--label', $label, $bdev) + or die "reiserfstune failed: $?"; +} + +# There is no command to relabel swap, and we mustn't run mkswap if +# the partition is already in use. Thankfully the header format is +# pretty simple; it starts with this structure: +# struct swap_header_v1_2 { +# char bootbits[1024]; /* Space for disklabel etc. */ +# unsigned int version; +# unsigned int last_page; +# unsigned int nr_badpages; +# unsigned char uuid[16]; +# char volume_name[16]; +# unsigned int padding[117]; +# unsigned int badpages[1]; +# }; +# and has the signature 'SWAPSPACE2' at the end of the first page. +use constant { SWAP_SIGNATURE => 'SWAPSPACE2', + SWAP_LABEL_OFFSET => 1052, SWAP_LABEL_LEN => 16 }; +sub swap_label { + my ($bdev, $label) = @_; + my $pagesize = POSIX::sysconf(POSIX::_SC_PAGESIZE) or die "$!"; + my ($length, $signature); + + my $fd = POSIX::open($bdev, POSIX::O_RDWR); + defined($fd) or die "$!"; + + # Check the signature + POSIX::lseek($fd, $pagesize - length(SWAP_SIGNATURE), POSIX::SEEK_SET); + $length = POSIX::read($fd, $signature, length(SWAP_SIGNATURE)); + if (!defined($length) || $signature ne SWAP_SIGNATURE) { + POSIX::close($fd); + die "swap signature not found on $bdev"; + } + + # Set the label + $label = pack('Z' . SWAP_LABEL_LEN, $label); + POSIX::lseek($fd, SWAP_LABEL_OFFSET, POSIX::SEEK_SET); + $length = POSIX::write($fd, $label, SWAP_LABEL_LEN); + if (!defined($length) || $length != SWAP_LABEL_LEN) { + my $error = "$!"; + POSIX::close($fd); + die $error; + } + + POSIX::close($fd); +} + +sub ufs_label { + my ($bdev, $label) = @_; + system('tunefs.ufs', '-L', $label, $bdev) or die "tunefs.ufs failed: $?"; +} + +sub xfs_label { + my ($bdev, $label) = @_; + system('xfs_admin', '-L', $label, $bdev) or die "xfs_admin failed: $?"; +} + +my %label_types = (ext2 => { len => 16, relabel => \&ext2_label }, + ext3 => { len => 16, relabel => \&ext2_label }, + ext4 => { len => 16, relabel => \&ext2_label }, + jfs => { len => 16, relabel => \&jfs_label }, + msdos => { len => 11, relabel => \&fat_label }, + ntfs => { len => 128, relabel => \&ntfs_label }, + reiserfs => { len => 16, relabel => \&reiserfs_label }, + swap => { len => SWAP_LABEL_LEN, + relabel => \&swap_label }, + ufs => { len => 32, relabel => \&ufs_label }, + vfat => { len => 11, relabel => \&fat_label }, + xfs => { len => 12, relabel => \&xfs_label }); + +my %bdev_map; +my @matched_configs; +my %id_map; + +sub scan_config_files { + # Find all IDE/SCSI disks mentioned in configurations + for my $config (@config_files) { + # Is the file present? + my $path = $config->{path}; + if (!defined($path)) { + next; + } + my $file = new FileHandle($path, 'r'); + if (!defined($file)) { + if ($! == POSIX::ENOENT) { + next; + } + die $!; + } + + # Are any of the related packages wanted or installed? + my $wanted = 0; + my $installed = 0; + my $packages = $config->{packages}; + for (`dpkg-query 2>/dev/null --showformat '\${status}\\n' -W $packages`) + { + $wanted = 1 if /^install /; + $installed = 1 if / installed\n$/; + } + if (!$wanted && !$installed) { + next; + } + + my @matched_bdevs = (); + + for my $bdev (&{$config->{list}}($file)) { + if ($bdev =~ m{^/dev/(?:[hs]d[a-z]\d*|s(?:cd|r)\d+)$}) { + $bdev_map{$bdev} = {}; + push @matched_bdevs, $bdev; + } + } + + if (@matched_bdevs || $config->{always_update}) { + push @matched_configs, {config => $config, + devices => \@matched_bdevs, + installed => $installed}; + } + } + + my $fstab = new FileHandle('/etc/fstab', 'r'); + while (1) { + my ($text, $bdev, $path, $type) = fstab_next($fstab); + last unless defined($text); + if (defined($type) && exists($bdev_map{$bdev})) { + $bdev_map{$bdev}->{path} = $path; + $bdev_map{$bdev}->{type} = $type; + } + } + $fstab->close(); +} + +sub add_tag { + # Map disks to labels/UUIDs and vice versa. Include all disks in + # the reverse mapping so we can detect ambiguity. + my ($bdev, $name, $value) = @_; + my $id = "$name=$value"; + push @{$id_map{$id}}, $bdev; + if (exists($bdev_map{$bdev})) { + $bdev_map{$bdev}->{$name} = $value; + push @{$bdev_map{$bdev}->{ids}}, $id; + } +} + +sub scan_devices { + for (`blkid -o device`) { + chomp; + my $bdev = $_; + for (`blkid -o udev -s LABEL -s UUID '$bdev'`) { + if (/^ID_FS_(LABEL|UUID)_ENC=(.*)\n$/) { + add_tag($bdev, $1, $2); + } + } + } + + # Discard all device ids that are ambiguous. + for my $bdev (keys(%bdev_map)) { + @{$bdev_map{$bdev}->{ids}} = grep({ $#{$id_map{$_}} == 0 } + @{$bdev_map{$bdev}->{ids}}); + } +} + +sub assign_labels { + my $hostname = (POSIX::uname())[1]; + + # For all devices that have no alternate device ids, suggest labelling + # them based on fstab or just using a generic label. + for my $bdev (keys(%bdev_map)) { + if ($#{$bdev_map{$bdev}->{ids}} >= 0) { + my $id = $bdev_map{$bdev}->{ids}->[0]; + } else { + my $type = $bdev_map{$bdev}->{type}; + + if (!exists($label_types{$type})) { + next; + } + + my $label_len = $label_types{$type}->{len}; + my $label; + use bytes; # string lengths are in bytes + + if (defined($bdev_map{$bdev}->{path})) { + # Convert path/type to label; prepend hostname if possible; + # append numeric suffix if necessary. + + my $base; + if ($bdev_map{$bdev}->{path} =~ m|^/|) { + $base = $bdev_map{$bdev}->{path}; + } else { + $base = $bdev_map{$bdev}->{type}; + } + $base =~ s/[^\w]+/-/g; + $base =~ s/^-//g; + $base =~ s/-$//g; + + my $n = 0; + my $suffix = ''; + do { + $label = "$hostname-$base$suffix"; + if (length($label) > $label_len) { + $label = substr($base, 0, $label_len - length($suffix)) + . $suffix; + } + $n++; + $suffix = "-$n"; + } while (exists($id_map{"LABEL=$label"})); + } else { + my $n = 0; + my $suffix; + do { + $n++; + $suffix = "-$n"; + $label = substr($hostname, 0, $label_len - length($suffix)) + . $suffix; + } while (exists($id_map{"LABEL=$label"})); + } + + add_tag($bdev, 'LABEL', $label); + $bdev_map{$bdev}->{relabel} = 1; + } + } +} + +sub relabel { + for my $bdev (keys(%bdev_map)) { + my $bdev_info = $bdev_map{$bdev}; + if ($bdev_info->{relabel}) { + my $relabel = $label_types{$bdev_info->{type}}->{relabel}; + &{$relabel}($bdev, $bdev_info->{LABEL}); + } + } +} + +sub update_config { + my %map; + for my $bdev (keys(%bdev_map)) { + $map{$bdev} = $bdev_map{$bdev}->{ids}->[0]; + } + + for my $match (@matched_configs) { + # Generate a new config + my $path = $match->{config}->{path}; + my $old = new FileHandle($path, 'r') or die "$!"; + my $new = new FileHandle("$path.new", POSIX::O_WRONLY | POSIX::O_CREAT, + 0600) + or die "$!"; + &{$match->{config}->{update}}($old, $new, \%map); + $old->close(); + $new->close(); + + # New config should have same permissions as the old + my (undef, undef, $mode, undef, $uid, $gid) = stat($path) or die "$!"; + chown($uid, $gid, "$path.new") or die "$!"; + chmod($mode & 07777, "$path.new") or die "$!"; + + # Back up the old config and replace with the new + my $old_path = $path . ($match->{config}->{suffix} || '.old'); + unlink($old_path); + link($path, $old_path) or die "$!"; + rename("$path.new", $path) or die "$!"; + + # If the package is installed, run the post-update function + if ($match->{installed} && $match->{config}->{post_update}) { + &{$match->{config}->{post_update}}(); + } + } +} + +sub transition { + use Debconf::Client::ConfModule ':all'; + + %bdev_map = (); + @matched_configs = (); + %id_map = (); + + scan_config_files(); + + if ($#matched_configs < 0) { + return; + } + + my ($question, $answer, $ret, $seen); + + $question = 'linux-base/disk-id-convert-auto'; + ($ret, $seen) = input('high', $question); + if ($ret && $ret != 30) { + die "Error setting debconf question $question: $seen"; + } + ($ret, $seen) = go(); + if ($ret && $ret != 30) { + die "Error asking debconf question $question: $seen"; + } + ($ret, $answer) = get($question); + die "Error retrieving answer for $question: $answer" if $ret; + + if ($answer eq 'true') { + scan_devices(); + assign_labels(); + + $question = 'linux-base/disk-id-convert-plan'; + ($ret, $seen) = subst($question, 'relabel', + join("\\n", + map({sprintf("%s: %s", $_, $bdev_map{$_}->{LABEL})} + grep({$bdev_map{$_}->{relabel}} + keys(%bdev_map))))); + die "Error setting debconf substitutions in $question: $seen" if $ret; + ($ret, $seen) = subst($question, 'id_map', + join("\\n", + map({sprintf("%s: %s", $_, $bdev_map{$_}->{ids}->[0])} + grep({@{$bdev_map{$_}->{ids}}} + keys(%bdev_map))))); + die "Error setting debconf substitutions in $question: $seen" if $ret; + ($ret, $seen) = subst($question, 'files', + join(', ', + map({$_->{config}->{path}} @matched_configs))); + die "Error setting debconf substitutions in $question: $seen" if $ret; + ($ret, $seen) = input('high', $question); + if ($ret && $ret != 30) { + die "Error setting debconf question $question: $seen"; + } + ($ret, $seen) = go(); + if ($ret && $ret != 30) { + die "Error asking debconf question $question: $seen"; + } + ($ret, $answer) = get($question); + die "Error retrieving answer for $question: $answer" if $ret; + + if ($answer ne 'true') { + # TODO: go back to the auto/manual question or allow editing the plan + } else { + relabel(); + update_config(); + } + } + + my @unconv_files = (); + for my $match (@matched_configs) { + my @unconv_bdevs = grep({!exists($bdev_map{$_}->{ids}) || + @{$bdev_map{$_}->{ids}} == 0} + @{$match->{devices}}); + if (@unconv_bdevs) { + push @unconv_files, sprintf('%s: %s', $match->{config}->{path}, + join(', ',@unconv_bdevs)); + } + } + if (@unconv_files) { + $question = 'linux-base/disk-id-manual'; + ($ret, $seen) = subst($question, 'unconverted', + join("\\n", @unconv_files)); + die "Error setting debconf substitutions in $question: $seen" if $ret; + ($ret, $seen) = input('high', $question); + if ($ret && $ret != 30) { + die "Error setting debconf note $question: $seen"; + } + ($ret, $seen) = go(); + if ($ret && $ret != 30) { + die "Error showing debconf note $question: $seen"; + } + } +} + +package main; + +capb('escape'); + +sub compare_versions { + return $AptPkg::Config::_config->system->versioning->compare(@_); +} + +if ($ARGV[0] eq 'reconfigure' || + compare_versions($ARGV[1], '2.6.32-8a~test') < 0) { + DebianKernel::DiskId::transition(); +} diff --git a/debian/patches/debian/drivers-ata-ata_piix-postpone-pata.patch b/debian/patches/debian/drivers-ata-ata_piix-postpone-pata.patch deleted file mode 100644 index 6851668b5..000000000 --- a/debian/patches/debian/drivers-ata-ata_piix-postpone-pata.patch +++ /dev/null @@ -1,53 +0,0 @@ -diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c -index b952c58..5634cc1 100644 ---- a/drivers/ata/ata_piix.c -+++ b/drivers/ata/ata_piix.c -@@ -164,48 +164,6 @@ static void ich_set_dmamode (struct ata_port *ap, struct ata_device *adev); - static unsigned int in_module_init = 1; - - static const struct pci_device_id piix_pci_tbl[] = { -- /* Intel PIIX3 for the 430HX etc */ -- { 0x8086, 0x7010, PCI_ANY_ID, PCI_ANY_ID, 0, 0, piix_pata_mwdma }, -- /* VMware ICH4 */ -- { 0x8086, 0x7111, 0x15ad, 0x1976, 0, 0, piix_pata_vmw }, -- /* Intel PIIX4 for the 430TX/440BX/MX chipset: UDMA 33 */ -- /* Also PIIX4E (fn3 rev 2) and PIIX4M (fn3 rev 3) */ -- { 0x8086, 0x7111, PCI_ANY_ID, PCI_ANY_ID, 0, 0, piix_pata_33 }, -- /* Intel PIIX4 */ -- { 0x8086, 0x7199, PCI_ANY_ID, PCI_ANY_ID, 0, 0, piix_pata_33 }, -- /* Intel PIIX4 */ -- { 0x8086, 0x7601, PCI_ANY_ID, PCI_ANY_ID, 0, 0, piix_pata_33 }, -- /* Intel PIIX */ -- { 0x8086, 0x84CA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, piix_pata_33 }, -- /* Intel ICH (i810, i815, i840) UDMA 66*/ -- { 0x8086, 0x2411, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_66 }, -- /* Intel ICH0 : UDMA 33*/ -- { 0x8086, 0x2421, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_33 }, -- /* Intel ICH2M */ -- { 0x8086, 0x244A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 }, -- /* Intel ICH2 (i810E2, i845, 850, 860) UDMA 100 */ -- { 0x8086, 0x244B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 }, -- /* Intel ICH3M */ -- { 0x8086, 0x248A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 }, -- /* Intel ICH3 (E7500/1) UDMA 100 */ -- { 0x8086, 0x248B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 }, -- /* Intel ICH4 (i845GV, i845E, i852, i855) UDMA 100 */ -- { 0x8086, 0x24CA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 }, -- { 0x8086, 0x24CB, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 }, -- /* Intel ICH5 */ -- { 0x8086, 0x24DB, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 }, -- /* C-ICH (i810E2) */ -- { 0x8086, 0x245B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 }, -- /* ESB (855GME/875P + 6300ESB) UDMA 100 */ -- { 0x8086, 0x25A2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 }, -- /* ICH6 (and 6) (i915) UDMA 100 */ -- { 0x8086, 0x266F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 }, -- /* ICH7/7-R (i945, i975) UDMA 100*/ -- { 0x8086, 0x27DF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100_nomwdma1 }, -- { 0x8086, 0x269E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100_nomwdma1 }, -- /* ICH8 Mobile PATA Controller */ -- { 0x8086, 0x2850, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 }, -- - /* SATA ports */ - - /* 82801EB (ICH5) */ diff --git a/debian/patches/debian/drivers-ata-pata_sis-postpone-pata.patch b/debian/patches/debian/drivers-ata-pata_sis-postpone-pata.patch deleted file mode 100644 index 4ad71ff53..000000000 --- a/debian/patches/debian/drivers-ata-pata_sis-postpone-pata.patch +++ /dev/null @@ -1,69 +0,0 @@ -diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig -index ae84949..f17c19b 100644 ---- a/drivers/ata/Kconfig -+++ b/drivers/ata/Kconfig -@@ -172,7 +172,7 @@ config SATA_SIL - config SATA_SIS - tristate "SiS 964/965/966/180 SATA support" - depends on PCI -- select PATA_SIS -+ select PATA_SIS_STUB - help - This option enables support for SiS Serial ATA on - SiS 964/965/966/180 and Parallel ATA on SiS 180. -@@ -618,9 +618,13 @@ config PATA_SIL680 - - If unsure, say N. - -+config PATA_SIS_STUB -+ tristate -+ - config PATA_SIS - tristate "SiS PATA support" - depends on PCI -+ select PATA_SIS_STUB - help - This option enables support for SiS PATA controllers - -diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile -index 674965f..c4bce57 100644 ---- a/drivers/ata/Makefile -+++ b/drivers/ata/Makefile -@@ -63,7 +63,7 @@ obj-$(CONFIG_PATA_SIL680) += pata_sil680.o - obj-$(CONFIG_PATA_VIA) += pata_via.o - obj-$(CONFIG_PATA_WINBOND) += pata_sl82c105.o - obj-$(CONFIG_PATA_WINBOND_VLB) += pata_winbond.o --obj-$(CONFIG_PATA_SIS) += pata_sis.o -+obj-$(CONFIG_PATA_SIS_STUB) += pata_sis.o - obj-$(CONFIG_PATA_TRIFLEX) += pata_triflex.o - obj-$(CONFIG_PATA_IXP4XX_CF) += pata_ixp4xx_cf.o - obj-$(CONFIG_PATA_SCC) += pata_scc.o -diff --git a/drivers/ata/pata_sis.c b/drivers/ata/pata_sis.c -index 26345d7..2c3e3ba 100644 ---- a/drivers/ata/pata_sis.c -+++ b/drivers/ata/pata_sis.c -@@ -826,13 +826,16 @@ static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) - } - - static const struct pci_device_id sis_pci_tbl[] = { -+#ifdef CONFIG_PATA_SIS - { PCI_VDEVICE(SI, 0x5513), }, /* SiS 5513 */ - { PCI_VDEVICE(SI, 0x5518), }, /* SiS 5518 */ - { PCI_VDEVICE(SI, 0x1180), }, /* SiS 1180 */ -+#endif - - { } - }; - -+#ifdef CONFIG_PATA_SIS - static struct pci_driver sis_pci_driver = { - .name = DRV_NAME, - .id_table = sis_pci_tbl, -@@ -856,6 +859,7 @@ static void __exit sis_exit(void) - - module_init(sis_init); - module_exit(sis_exit); -+#endif - - MODULE_AUTHOR("Alan Cox"); - MODULE_DESCRIPTION("SCSI low-level driver for SiS ATA"); diff --git a/debian/patches/debian/piix-disable-redundant-devids.patch b/debian/patches/debian/piix-disable-redundant-devids.patch new file mode 100644 index 000000000..434d4a6b7 --- /dev/null +++ b/debian/patches/debian/piix-disable-redundant-devids.patch @@ -0,0 +1,37 @@ +--- a/drivers/ide/piix.c ++++ b/drivers/ide/piix.c +@@ -416,8 +416,14 @@ + + static const struct pci_device_id piix_pci_tbl[] = { + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82371FB_0), 1 }, ++#if !defined(CONFIG_PATA_OLDPIIX) && !defined(CONFIG_PATA_OLDPIIX_MODULE) + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82371FB_1), 1 }, ++#endif ++#if !defined(CONFIG_PATA_MPIIX) && !defined(CONFIG_PATA_MPIIX_MODULE) + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82371MX), 0 }, ++#endif ++ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82801DB_1), 6 }, ++#if !defined(CONFIG_ATA_PIIX) && !defined(CONFIG_ATA_PIIX_MODULE) + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82371SB_1), 1 }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82371AB), 2 }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82801AB_1), 3 }, +@@ -433,15 +439,15 @@ + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82801EB_11), 6 }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82801E_11), 6 }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82801DB_10), 6 }, +-#ifdef CONFIG_BLK_DEV_IDE_SATA +- { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82801EB_1), 6 }, +-#endif + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ESB_2), 6 }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ICH6_19), 6 }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ICH7_21), 6 }, +- { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82801DB_1), 6 }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ESB2_18), 6 }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ICH8_6), 6 }, ++#endif ++#ifdef CONFIG_BLK_DEV_IDE_SATA ++ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82801EB_1), 6 }, ++#endif + { 0, }, + }; + MODULE_DEVICE_TABLE(pci, piix_pci_tbl); diff --git a/debian/patches/series/base b/debian/patches/series/base index 434034b05..207590ec6 100644 --- a/debian/patches/series/base +++ b/debian/patches/series/base @@ -3,8 +3,7 @@ + debian/doc-build-parallel.patch + debian/scripts-kconfig-reportoldconfig.patch -+ debian/drivers-ata-ata_piix-postpone-pata.patch -+ debian/drivers-ata-pata_sis-postpone-pata.patch ++ debian/piix-disable-redundant-devids.patch + features/all/drivers-infiniband-hw-ipath-iba7220-use-request_firmware.patch + features/all/drivers-media-dvb-usb-af9005-request_firmware.patch diff --git a/debian/rules.real b/debian/rules.real index 29534e519..d61b74a85 100644 --- a/debian/rules.real +++ b/debian/rules.real @@ -50,7 +50,7 @@ binary-indep: install-patch binary-indep: install-source binary-indep: install-support binary-indep: install-firmware -#binary-indep: install-linux-base +binary-indep: install-linux-base build: $(STAMPS_DIR)/build_$(ARCH)_$(FEATURESET)_$(FLAVOUR)_$(TYPE) @@ -476,6 +476,7 @@ install-linux-base: dh_testroot dh_prep dh_install -X.svn + dh_installdebconf +$(MAKE_SELF) install-base # vim: filetype=make diff --git a/debian/templates/control.image.type-plain.in b/debian/templates/control.image.type-plain.in index 1dda400bd..852f6591f 100644 --- a/debian/templates/control.image.type-plain.in +++ b/debian/templates/control.image.type-plain.in @@ -1,7 +1,7 @@ Package: linux-image-@upstreamversion@@abiname@@localversion@ Provides: linux-image, linux-image-@major@, linux-modules-@upstreamversion@@abiname@@localversion@ Pre-Depends: debconf | debconf-2.0 -Depends: module-init-tools, ${shlibs:Depends} +Depends: module-init-tools, linux-base (>= @source_upstream@), ${shlibs:Depends} Recommends: firmware-linux-free (>= @source_upstream@) Suggests: linux-doc-@version@ Description: Linux @upstreamversion@ for @class@ diff --git a/debian/templates/control.main.in b/debian/templates/control.main.in index 0ca7ea482..9f50cc393 100644 --- a/debian/templates/control.main.in +++ b/debian/templates/control.main.in @@ -79,7 +79,7 @@ Description: Support files for Linux @upstreamversion@ Package: linux-base Architecture: all -Depends: ${misc:Depends} +Depends: libapt-pkg-perl, ${misc:Depends} Description: Linux image base package This package contains files and support scripts for all Linux images. From a8d61a705835c0b90da9eb2645164a12ebd31c3a Mon Sep 17 00:00:00 2001 From: Maximilian Attems Date: Thu, 25 Feb 2010 11:14:23 +0000 Subject: [PATCH 42/71] changelog add link to kernelnewbies page svn path=/dists/trunk/linux-2.6/; revision=15276 --- debian/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index 61390b0e9..c4a94fc64 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,6 +1,6 @@ linux-2.6 (2.6.33-1~experimental.1) UNRELEASED; urgency=low - * New upstream release. + * New upstream release: http://kernelnewbies.org/Linux_2_6_33 [ maximilian attems] * [topconfig] set BLK_DEV_DRBD, DRM_NOUVEAU, DRM_NOUVEAU_BACKLIGHT, From 6b50694d465ce66138ef417e21494b4602120ee6 Mon Sep 17 00:00:00 2001 From: Maximilian Attems Date: Thu, 25 Feb 2010 14:23:35 +0000 Subject: [PATCH 43/71] prepare to release 2.6.33 to exp svn path=/dists/trunk/linux-2.6/; revision=15278 --- debian/changelog | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/debian/changelog b/debian/changelog index c4a94fc64..3675301ef 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,4 +1,4 @@ -linux-2.6 (2.6.33-1~experimental.1) UNRELEASED; urgency=low +linux-2.6 (2.6.33-1~experimental.1) experimental; urgency=low * New upstream release: http://kernelnewbies.org/Linux_2_6_33 @@ -42,7 +42,7 @@ linux-2.6 (2.6.33-1~experimental.1) UNRELEASED; urgency=low - ata_generic, pata_ns87410, pata_netcell replace ide-pci-generic * Add libata transition script - -- maximilian attems Mon, 15 Feb 2010 23:54:52 +0200 + -- maximilian attems Thu, 25 Feb 2010 15:21:38 +0100 linux-2.6 (2.6.32-9) unstable; urgency=high From 33ce878758f89ada2cbe8ce816b979678d64a596 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Fri, 26 Feb 2010 01:00:41 +0000 Subject: [PATCH 44/71] Add missing debconf templates for linux-base (Closes: #571558) svn path=/dists/trunk/linux-2.6/; revision=15281 --- debian/changelog | 7 +++++++ debian/linux-base.templates | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+) create mode 100644 debian/linux-base.templates diff --git a/debian/changelog b/debian/changelog index 3675301ef..2c2da7a65 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,10 @@ +linux-2.6 (2.6-33-1~experimental.2) UNRELEASED; urgency=low + + [ Ben Hutchings ] + * Add missing debconf templates for linux-base (Closes: #571558) + + -- Ben Hutchings Fri, 26 Feb 2010 00:58:00 +0000 + linux-2.6 (2.6.33-1~experimental.1) experimental; urgency=low * New upstream release: http://kernelnewbies.org/Linux_2_6_33 diff --git a/debian/linux-base.templates b/debian/linux-base.templates new file mode 100644 index 000000000..54bced945 --- /dev/null +++ b/debian/linux-base.templates @@ -0,0 +1,36 @@ +Template: linux-base/disk-id-convert-auto +Type: boolean +Default: true +Description: Update disk device ids in system configuration? + The new Linux kernel version provides different drivers for some + PATA (IDE) controllers. The names of some hard disk, CD-ROM and + tape devices may change. + . + You are recommended to identify disk devices in configuration files + by label or UUID (unique identifier) rather than by device name, + which will work with both old and new kernel versions. Your system + configuration can be updated automatically in most cases. + +Template: linux-base/disk-id-convert-plan +Type: boolean +Default: true +Description: Apply these configuration changes to disk device ids? + These devices will be relabelled: + . + ${relabel} + . + These configuration files will be updated: + . + ${files} + . + The device ids will be changed as follows: + . + ${id_map} + +Template: linux-base/disk-id-manual +Type: note +Description: Please check these configuration files before rebooting + These configuration files still use some device names that may + change when using the new kernel: + . + ${unconverted} From 43cc27eebc06e2631ff5d0275d448a240fdd6388 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Fri, 26 Feb 2010 01:01:48 +0000 Subject: [PATCH 45/71] Include debhelper-generated commands (currently empty) in linux-base postinst svn path=/dists/trunk/linux-2.6/; revision=15282 --- debian/linux-base.postinst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/debian/linux-base.postinst b/debian/linux-base.postinst index f84327208..e78101fcb 100644 --- a/debian/linux-base.postinst +++ b/debian/linux-base.postinst @@ -1468,3 +1468,7 @@ if ($ARGV[0] eq 'reconfigure' || compare_versions($ARGV[1], '2.6.32-8a~test') < 0) { DebianKernel::DiskId::transition(); } + +exec("set -e\nset -- @ARGV\n" . << 'EOF'); +#DEBHELPER# +EOF From 1db6535745c11f1e150084e09a411d5c3b8026a9 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Sat, 27 Feb 2010 01:04:34 +0000 Subject: [PATCH 46/71] Fix version number for current changelog entry svn path=/dists/trunk/linux-2.6/; revision=15283 --- debian/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index 2c2da7a65..d7b426123 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,4 +1,4 @@ -linux-2.6 (2.6-33-1~experimental.2) UNRELEASED; urgency=low +linux-2.6 (2.6.33-1~experimental.2) UNRELEASED; urgency=low [ Ben Hutchings ] * Add missing debconf templates for linux-base (Closes: #571558) From b8f1fe6253914ee7cb93dd18fe5ae3405817f85e Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Sat, 27 Feb 2010 01:27:58 +0000 Subject: [PATCH 47/71] Fix libata transition code for GRUB 1 config (Closes: #571662) svn path=/dists/trunk/linux-2.6/; revision=15284 --- debian/changelog | 1 + debian/linux-base.postinst | 10 +++++----- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/debian/changelog b/debian/changelog index d7b426123..a5689ae85 100644 --- a/debian/changelog +++ b/debian/changelog @@ -2,6 +2,7 @@ linux-2.6 (2.6.33-1~experimental.2) UNRELEASED; urgency=low [ Ben Hutchings ] * Add missing debconf templates for linux-base (Closes: #571558) + * Fix libata transition code for GRUB 1 config (Closes: #571662) -- Ben Hutchings Fri, 26 Feb 2010 00:58:00 +0000 diff --git a/debian/linux-base.postinst b/debian/linux-base.postinst index e78101fcb..c3e0841ea 100644 --- a/debian/linux-base.postinst +++ b/debian/linux-base.postinst @@ -305,11 +305,11 @@ sub grub1_update { $old->seek(0, 0); for (grub1_parse($old)) { my ($text, $name, $value) = @$_; - next unless defined($name); - if ($name eq 'kopt_2_6' || - ($name eq 'kopt' && !exists($options{kopt_2_6})) || - $name eq 'xenkopt') { - if (defined(my $new_value = kernel_update($value))) { + if (defined($name) && + ($name eq 'kopt_2_6' || + ($name eq 'kopt' && !exists($options{kopt_2_6})) || + $name eq 'xenkopt')) { + if (defined(my $new_value = kernel_update($value, $map))) { $text = "## $name=$value\n# $name=$new_value\n"; } } From 3c2a1475b3ef774be1f255c1b43e87c3c5962d63 Mon Sep 17 00:00:00 2001 From: Maximilian Attems Date: Sun, 28 Feb 2010 16:51:21 +0000 Subject: [PATCH 48/71] prepare to release 2.6.33-1~experimental.2 svn path=/dists/trunk/linux-2.6/; revision=15291 --- debian/changelog | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/debian/changelog b/debian/changelog index a5689ae85..e706448dd 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,10 +1,10 @@ -linux-2.6 (2.6.33-1~experimental.2) UNRELEASED; urgency=low +linux-2.6 (2.6.33-1~experimental.2) experimental; urgency=low [ Ben Hutchings ] * Add missing debconf templates for linux-base (Closes: #571558) * Fix libata transition code for GRUB 1 config (Closes: #571662) - -- Ben Hutchings Fri, 26 Feb 2010 00:58:00 +0000 + -- maximilian attems Sun, 28 Feb 2010 17:48:11 +0100 linux-2.6 (2.6.33-1~experimental.1) experimental; urgency=low From ca09963962a7711254e6d2361cb6700b53a09da6 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Sun, 28 Feb 2010 17:02:14 +0000 Subject: [PATCH 49/71] Fix regexp for binNMU versions in modules/rules.include (Closes: #524632) svn path=/dists/trunk/linux-2.6/; revision=15292 --- debian/changelog | 7 +++++++ debian/modules/rules.include | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index e706448dd..1f2daef93 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,10 @@ +linux-2.6 (2.6.33-1~experimental.3) UNRELEASED; urgency=low + + [ Ben Hutchings ] + * Fix regexp for binNMU versions in modules/rules.include (Closes: #524632) + + -- Ben Hutchings Sun, 28 Feb 2010 17:01:33 +0000 + linux-2.6 (2.6.33-1~experimental.2) experimental; urgency=low [ Ben Hutchings ] diff --git a/debian/modules/rules.include b/debian/modules/rules.include index faf7e653c..ac478397c 100644 --- a/debian/modules/rules.include +++ b/debian/modules/rules.include @@ -5,7 +5,7 @@ DEB_BUILD_ARCH := $(shell dpkg-architecture -qDEB_BUILD_ARCH) include $(__MODULES_DIR)rules.defs -__BINNMU := $(shell dpkg-parsechangelog | sed -ne 's,^Version: .*\+b\(.*\)$$,\1,p') +__BINNMU := $(shell dpkg-parsechangelog | sed -rne 's,^Version: .*\+b([0-9]+)$$,\1,p') BUILD_STAMP = $(STAMPS_DIR)/build-base From a3420c5141226033dbac06db9b3645c75cde0ab7 Mon Sep 17 00:00:00 2001 From: Bastian Blank Date: Tue, 2 Mar 2010 12:24:53 +0000 Subject: [PATCH 50/71] debian/config/defines: Fix abiname. svn path=/dists/trunk/linux-2.6/; revision=15305 --- debian/config/defines | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/config/defines b/debian/config/defines index 7381abbc5..dbcd4d7f9 100644 --- a/debian/config/defines +++ b/debian/config/defines @@ -1,5 +1,5 @@ [abi] -abiname: 2 +abiname: trunk [base] arches: From fb3123e6dd44bf381befbc913bf00ded48116b98 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Wed, 3 Mar 2010 00:30:24 +0000 Subject: [PATCH 51/71] linux-base.postinst: Call id_to_path() not disk_id_to_path() svn path=/dists/trunk/linux-2.6/; revision=15307 --- debian/changelog | 2 ++ debian/linux-base.postinst | 6 ++---- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/debian/changelog b/debian/changelog index 1f2daef93..230906522 100644 --- a/debian/changelog +++ b/debian/changelog @@ -2,6 +2,8 @@ linux-2.6 (2.6.33-1~experimental.3) UNRELEASED; urgency=low [ Ben Hutchings ] * Fix regexp for binNMU versions in modules/rules.include (Closes: #524632) + * Fix calls to disk_id_to_path (renamed to id_to_path) in linux-base + (Closes: #572283) -- Ben Hutchings Sun, 28 Feb 2010 17:01:33 +0000 diff --git a/debian/linux-base.postinst b/debian/linux-base.postinst index c3e0841ea..ad0157168 100644 --- a/debian/linux-base.postinst +++ b/debian/linux-base.postinst @@ -490,8 +490,7 @@ sub lilo_update { if ($name eq 'boot') { # 'boot' is used directly by the lilo command, which # doesn't use libblkid - $new_value = - $map->{$value} && disk_id_to_path($map->{$value}); + $new_value = $map->{$value} && id_to_path($map->{$value}); } elsif ($name eq 'root') { # 'root' adds a root parameter to the kernel command # line @@ -724,8 +723,7 @@ sub delo_update { if ($name eq 'label') { ++$i; # next entry } elsif ($name eq 'boot' && $i < 0) { - my $new_value = - $map->{$value} && disk_id_to_path($map->{$value}); + my $new_value = $map->{$value} && id_to_path($map->{$value}); if (defined($new_value)) { $text = "# $text" . "boot=$new_value\n"; } From 3ddbfee3c7ea0000f6f6a0465fa7b1cebe892b8f Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Wed, 3 Mar 2010 01:07:41 +0000 Subject: [PATCH 52/71] Don't show empty list of devices to be relabelled in linux-base svn path=/dists/trunk/linux-2.6/; revision=15308 --- debian/changelog | 1 + debian/linux-base.postinst | 18 +++++++++++------- debian/linux-base.templates | 12 ++++++++++++ 3 files changed, 24 insertions(+), 7 deletions(-) diff --git a/debian/changelog b/debian/changelog index 230906522..9f9aa4950 100644 --- a/debian/changelog +++ b/debian/changelog @@ -4,6 +4,7 @@ linux-2.6 (2.6.33-1~experimental.3) UNRELEASED; urgency=low * Fix regexp for binNMU versions in modules/rules.include (Closes: #524632) * Fix calls to disk_id_to_path (renamed to id_to_path) in linux-base (Closes: #572283) + * Don't show empty list of devices to be relabelled in linux-base -- Ben Hutchings Sun, 28 Feb 2010 17:01:33 +0000 diff --git a/debian/linux-base.postinst b/debian/linux-base.postinst index ad0157168..fc025416f 100644 --- a/debian/linux-base.postinst +++ b/debian/linux-base.postinst @@ -1392,13 +1392,17 @@ sub transition { scan_devices(); assign_labels(); - $question = 'linux-base/disk-id-convert-plan'; - ($ret, $seen) = subst($question, 'relabel', - join("\\n", - map({sprintf("%s: %s", $_, $bdev_map{$_}->{LABEL})} - grep({$bdev_map{$_}->{relabel}} - keys(%bdev_map))))); - die "Error setting debconf substitutions in $question: $seen" if $ret; + if (grep({$bdev_map{$_}->{relabel}} keys(%bdev_map))) { + $question = 'linux-base/disk-id-convert-plan'; + ($ret, $seen) = subst($question, 'relabel', + join("\\n", + map({sprintf("%s: %s", $_, $bdev_map{$_}->{LABEL})} + grep({$bdev_map{$_}->{relabel}} + keys(%bdev_map))))); + die "Error setting debconf substitutions in $question: $seen" if $ret; + } else { + $question = 'linux-base/disk-id-convert-plan-no-relabel'; + } ($ret, $seen) = subst($question, 'id_map', join("\\n", map({sprintf("%s: %s", $_, $bdev_map{$_}->{ids}->[0])} diff --git a/debian/linux-base.templates b/debian/linux-base.templates index 54bced945..3c4a612d9 100644 --- a/debian/linux-base.templates +++ b/debian/linux-base.templates @@ -27,6 +27,18 @@ Description: Apply these configuration changes to disk device ids? . ${id_map} +Template: linux-base/disk-id-convert-plan-no-relabel +Type: boolean +Default: true +Description: Apply these configuration changes to disk device ids? + These configuration files will be updated: + . + ${files} + . + The device ids will be changed as follows: + . + ${id_map} + Template: linux-base/disk-id-manual Type: note Description: Please check these configuration files before rebooting From cf9e18bed4f5fb50f05f9803e0dbee13cfee0853 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Wed, 3 Mar 2010 05:23:48 +0000 Subject: [PATCH 53/71] Use 'linux-base:' as prefix to log lines about it svn path=/dists/trunk/linux-2.6/; revision=15309 --- debian/changelog | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/debian/changelog b/debian/changelog index 9f9aa4950..38d1e3e1a 100644 --- a/debian/changelog +++ b/debian/changelog @@ -2,9 +2,9 @@ linux-2.6 (2.6.33-1~experimental.3) UNRELEASED; urgency=low [ Ben Hutchings ] * Fix regexp for binNMU versions in modules/rules.include (Closes: #524632) - * Fix calls to disk_id_to_path (renamed to id_to_path) in linux-base + * linux-base: Fix calls to disk_id_to_path (renamed to id_to_path) (Closes: #572283) - * Don't show empty list of devices to be relabelled in linux-base + * linux-base: Don't show empty list of devices to be relabelled -- Ben Hutchings Sun, 28 Feb 2010 17:01:33 +0000 From 38c1d3834c9805ec612198d57067e40150adef13 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Wed, 3 Mar 2010 05:32:31 +0000 Subject: [PATCH 54/71] linux-base: Don't update udev CD rules unnecessarily svn path=/dists/trunk/linux-2.6/; revision=15310 --- debian/changelog | 1 + debian/linux-base.postinst | 100 +++++++++++++++++++++++-------------- 2 files changed, 64 insertions(+), 37 deletions(-) diff --git a/debian/changelog b/debian/changelog index 38d1e3e1a..1eb710f78 100644 --- a/debian/changelog +++ b/debian/changelog @@ -5,6 +5,7 @@ linux-2.6 (2.6.33-1~experimental.3) UNRELEASED; urgency=low * linux-base: Fix calls to disk_id_to_path (renamed to id_to_path) (Closes: #572283) * linux-base: Don't show empty list of devices to be relabelled + * linux-base: Don't update udev CD rules unnecessarily -- Ben Hutchings Sun, 28 Feb 2010 17:01:33 +0000 diff --git a/debian/linux-base.postinst b/debian/linux-base.postinst index fc025416f..38bda627f 100644 --- a/debian/linux-base.postinst +++ b/debian/linux-base.postinst @@ -876,21 +876,27 @@ sub udev_next { return @results; } -sub udev_cd_list { - # doesn't use block device names - return (); +# Convert an IDE device path to the corresponding SCSI device path if it's +# handled by a libata driver. +sub udev_ide_to_scsi_path { + # libata uses the PATA controller and device numbers + # as SCSI host number and bus id. Channel number and + # LUN are always 0. The parent device path should + # stay the same. + $_[0] =~ s/-ide-(\d+):(\d+)$/-scsi-$1:0:$2:0/; + return $_[0]; } -sub udev_cd_update { - my ($old, $new) = @_; # ignore map - my @ide_rules; - my %scsi_rules; - my $i; +# Find symlink rules using IDE device paths that aren't matched by rules +# using the SCSI corresponding device path. +sub udev_cd_find_unmatched_ide_rules { + my ($file) = @_; + my %wanted_rule; + my @unmatched; + my $i = 0; - # First pass: list the current symlink rules for IDE and SCSI devices - $i = 0; while (1) { - my @keys = udev_next($old); + my @keys = udev_next($file); last if $#keys < 0; my ($path, $symlink); @@ -906,50 +912,65 @@ sub udev_cd_update { if (defined($path) && defined($symlink)) { if ($path =~ /-ide-\d+:\d+$/) { - $ide_rules[$i] = $symlink; + my $path = udev_ide_to_scsi_path($path); + my $rule_key = $path . ' ' . $symlink; + if (!exists($wanted_rule{$rule_key})) { + $wanted_rule{$rule_key} = $i; + $unmatched[$i] = 1; + } } elsif ($path =~ /-scsi-\d+:\d+:\d+:\d+$/) { - $scsi_rules{"$path $symlink"} = 1; + my $rule_key = $path . ' ' . $symlink; + if (defined(my $j = $wanted_rule{$rule_key})) { + $unmatched[$j] = 0; + } + $wanted_rule{$rule_key} = -1; } } ++$i; } - # Second pass: fill in the missing rules for SCSI devices + return @unmatched; +} + +sub udev_cd_needs_update { + my ($file) = @_; + for (udev_cd_find_unmatched_ide_rules($file)) { + return 1 if $_; + } + return 0; +} + +sub udev_cd_update { + my ($old, $new) = @_; # ignore map + + # Find which rules we will need to copy and edit, then rewind + my @unmatched = udev_cd_find_unmatched_ide_rules($old); $old->seek(0, 0); - $i = 0; + + my $i = 0; while (1) { my @keys = udev_next($old); last if $#keys < 0; my $old_text = ''; my $new_text = ''; - my $need_new; for (@keys) { my ($text, $key, $op, $value) = @$_; $old_text .= $text; - next unless defined($ide_rules[$i]) && defined($key); + next unless defined($unmatched[$i]) && defined($key); if ($key eq 'ENV{ID_PATH}' && $op eq '==') { - # libata uses the PATA controller and device numbers - # as SCSI host number and bus id. Channel number and - # LUN are always 0. The parent device path should - # stay the same. - $value =~ s/-ide-(\d+):(\d+)$/-scsi-$1:0:$2:0/; - - my $rule_key = $value . ' ' . $ide_rules[$i]; - if (!exists($scsi_rules{$rule_key})) { - $need_new = 1; - $new_text .= ", $key$op\"$value\""; - } + my $value = udev_ide_to_scsi_path($value); + $new_text .= ", $key$op\"$value\""; } else { $new_text .= $text; } } $new->print($old_text); - if ($need_new) { + if ($unmatched[$i]) { $new->print($new_text . "\n"); } @@ -1057,9 +1078,8 @@ my @config_files = ({packages => 'mount', update => \&aboot_update}, {packages => 'udev', path => '/etc/udev/rules.d/70-persistent-cd.rules', - list => \&udev_cd_list, - update => \&udev_cd_update, - always_update => 1}, + needs_update => \&udev_cd_needs_update, + update => \&udev_cd_update}, {packages => 'initramfs-tools', path => '/etc/initramfs-tools/conf.d/resume', list => \&initramfs_resume_list, @@ -1198,15 +1218,21 @@ sub scan_config_files { } my @matched_bdevs = (); + my $needs_update; - for my $bdev (&{$config->{list}}($file)) { - if ($bdev =~ m{^/dev/(?:[hs]d[a-z]\d*|s(?:cd|r)\d+)$}) { - $bdev_map{$bdev} = {}; - push @matched_bdevs, $bdev; + if (exists($config->{needs_update})) { + $needs_update = &{$config->{needs_update}}($file); + } else { + for my $bdev (&{$config->{list}}($file)) { + if ($bdev =~ m{^/dev/(?:[hs]d[a-z]\d*|s(?:cd|r)\d+)$}) { + $bdev_map{$bdev} = {}; + push @matched_bdevs, $bdev; + $needs_update = 1; + } } } - if (@matched_bdevs || $config->{always_update}) { + if ($needs_update) { push @matched_configs, {config => $config, devices => \@matched_bdevs, installed => $installed}; From 9c0e8b37305f7d1dd6718aee51cc130f4eab321c Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Wed, 3 Mar 2010 06:05:22 +0000 Subject: [PATCH 55/71] linux-base: Show the device paths to be added to udev CD rules svn path=/dists/trunk/linux-2.6/; revision=15311 --- debian/changelog | 1 + debian/linux-base.postinst | 45 +++++++++++++++++++------------------- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/debian/changelog b/debian/changelog index 1eb710f78..5777e0ccf 100644 --- a/debian/changelog +++ b/debian/changelog @@ -6,6 +6,7 @@ linux-2.6 (2.6.33-1~experimental.3) UNRELEASED; urgency=low (Closes: #572283) * linux-base: Don't show empty list of devices to be relabelled * linux-base: Don't update udev CD rules unnecessarily + * linux-base: Show the device paths to be added to udev CD rules -- Ben Hutchings Sun, 28 Feb 2010 17:01:33 +0000 diff --git a/debian/linux-base.postinst b/debian/linux-base.postinst index 38bda627f..e7db73118 100644 --- a/debian/linux-base.postinst +++ b/debian/linux-base.postinst @@ -876,19 +876,10 @@ sub udev_next { return @results; } -# Convert an IDE device path to the corresponding SCSI device path if it's -# handled by a libata driver. -sub udev_ide_to_scsi_path { - # libata uses the PATA controller and device numbers - # as SCSI host number and bus id. Channel number and - # LUN are always 0. The parent device path should - # stay the same. - $_[0] =~ s/-ide-(\d+):(\d+)$/-scsi-$1:0:$2:0/; - return $_[0]; -} - # Find symlink rules using IDE device paths that aren't matched by rules -# using the SCSI corresponding device path. +# using the corresponding SCSI device path. Return an array containing +# the corresponding path for each rule where this is the case and undef +# for all other rules. sub udev_cd_find_unmatched_ide_rules { my ($file) = @_; my %wanted_rule; @@ -912,16 +903,20 @@ sub udev_cd_find_unmatched_ide_rules { if (defined($path) && defined($symlink)) { if ($path =~ /-ide-\d+:\d+$/) { - my $path = udev_ide_to_scsi_path($path); + # libata uses the PATA controller and device numbers + # as SCSI host number and bus id. Channel number and + # LUN are always 0. The parent device path should + # stay the same. + $path =~ s/-ide-(\d+):(\d+)$/-scsi-$1:0:$2:0/; my $rule_key = $path . ' ' . $symlink; if (!exists($wanted_rule{$rule_key})) { $wanted_rule{$rule_key} = $i; - $unmatched[$i] = 1; + $unmatched[$i] = $path; } } elsif ($path =~ /-scsi-\d+:\d+:\d+:\d+$/) { my $rule_key = $path . ' ' . $symlink; if (defined(my $j = $wanted_rule{$rule_key})) { - $unmatched[$j] = 0; + $unmatched[$j] = undef; } $wanted_rule{$rule_key} = -1; } @@ -935,10 +930,13 @@ sub udev_cd_find_unmatched_ide_rules { sub udev_cd_needs_update { my ($file) = @_; + my %paths; for (udev_cd_find_unmatched_ide_rules($file)) { - return 1 if $_; + if (defined($_)) { + $paths{$_} = 1; + } } - return 0; + return join('\n', map({"+ PATH=$_"} keys(%paths))); } sub udev_cd_update { @@ -962,7 +960,7 @@ sub udev_cd_update { next unless defined($unmatched[$i]) && defined($key); if ($key eq 'ENV{ID_PATH}' && $op eq '==') { - my $value = udev_ide_to_scsi_path($value); + my $value = $unmatched[$i]; $new_text .= ", $key$op\"$value\""; } else { $new_text .= $text; @@ -1218,23 +1216,23 @@ sub scan_config_files { } my @matched_bdevs = (); - my $needs_update; + my $id_map_text; if (exists($config->{needs_update})) { - $needs_update = &{$config->{needs_update}}($file); + $id_map_text = &{$config->{needs_update}}($file); } else { for my $bdev (&{$config->{list}}($file)) { if ($bdev =~ m{^/dev/(?:[hs]d[a-z]\d*|s(?:cd|r)\d+)$}) { $bdev_map{$bdev} = {}; push @matched_bdevs, $bdev; - $needs_update = 1; } } } - if ($needs_update) { + if (@matched_bdevs || $id_map_text) { push @matched_configs, {config => $config, devices => \@matched_bdevs, + id_map_text => $id_map_text, installed => $installed}; } } @@ -1433,7 +1431,8 @@ sub transition { join("\\n", map({sprintf("%s: %s", $_, $bdev_map{$_}->{ids}->[0])} grep({@{$bdev_map{$_}->{ids}}} - keys(%bdev_map))))); + keys(%bdev_map))), + map({$_->{id_map_text}} @matched_configs))); die "Error setting debconf substitutions in $question: $seen" if $ret; ($ret, $seen) = subst($question, 'files', join(', ', From 3020096f4a3d6a97bca24d94e7a025b52bbbea1c Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Thu, 4 Mar 2010 01:10:07 +0000 Subject: [PATCH 56/71] linux-base: Remove unnecessary blocks from assign_labels() svn path=/dists/trunk/linux-2.6/; revision=15313 --- debian/linux-base.postinst | 83 ++++++++++++++++++-------------------- 1 file changed, 39 insertions(+), 44 deletions(-) diff --git a/debian/linux-base.postinst b/debian/linux-base.postinst index e7db73118..63c439b4e 100644 --- a/debian/linux-base.postinst +++ b/debian/linux-base.postinst @@ -1285,58 +1285,53 @@ sub assign_labels { # For all devices that have no alternate device ids, suggest labelling # them based on fstab or just using a generic label. for my $bdev (keys(%bdev_map)) { - if ($#{$bdev_map{$bdev}->{ids}} >= 0) { - my $id = $bdev_map{$bdev}->{ids}->[0]; - } else { - my $type = $bdev_map{$bdev}->{type}; - - if (!exists($label_types{$type})) { - next; - } + next if $#{$bdev_map{$bdev}->{ids}} >= 0; - my $label_len = $label_types{$type}->{len}; - my $label; - use bytes; # string lengths are in bytes + my $type = $bdev_map{$bdev}->{type}; + next unless exists($label_types{$type}); - if (defined($bdev_map{$bdev}->{path})) { - # Convert path/type to label; prepend hostname if possible; - # append numeric suffix if necessary. + my $label_len = $label_types{$type}->{len}; + my $label; + use bytes; # string lengths are in bytes - my $base; - if ($bdev_map{$bdev}->{path} =~ m|^/|) { - $base = $bdev_map{$bdev}->{path}; - } else { - $base = $bdev_map{$bdev}->{type}; - } - $base =~ s/[^\w]+/-/g; - $base =~ s/^-//g; - $base =~ s/-$//g; + if (defined($bdev_map{$bdev}->{path})) { + # Convert path/type to label; prepend hostname if possible; + # append numeric suffix if necessary. - my $n = 0; - my $suffix = ''; - do { - $label = "$hostname-$base$suffix"; - if (length($label) > $label_len) { - $label = substr($base, 0, $label_len - length($suffix)) - . $suffix; - } - $n++; - $suffix = "-$n"; - } while (exists($id_map{"LABEL=$label"})); + my $base; + if ($bdev_map{$bdev}->{path} =~ m|^/|) { + $base = $bdev_map{$bdev}->{path}; } else { - my $n = 0; - my $suffix; - do { - $n++; - $suffix = "-$n"; - $label = substr($hostname, 0, $label_len - length($suffix)) - . $suffix; - } while (exists($id_map{"LABEL=$label"})); + $base = $bdev_map{$bdev}->{type}; } + $base =~ s/[^\w]+/-/g; + $base =~ s/^-//g; + $base =~ s/-$//g; - add_tag($bdev, 'LABEL', $label); - $bdev_map{$bdev}->{relabel} = 1; + my $n = 0; + my $suffix = ''; + do { + $label = "$hostname-$base$suffix"; + if (length($label) > $label_len) { + $label = substr($base, 0, $label_len - length($suffix)) + . $suffix; + } + $n++; + $suffix = "-$n"; + } while (exists($id_map{"LABEL=$label"})); + } else { + my $n = 0; + my $suffix; + do { + $n++; + $suffix = "-$n"; + $label = substr($hostname, 0, $label_len - length($suffix)) + . $suffix; + } while (exists($id_map{"LABEL=$label"})); } + + add_tag($bdev, 'LABEL', $label); + $bdev_map{$bdev}->{relabel} = 1; } } From 0d5c2743cc4ba2ba6f5e2bf20f185e6988f49634 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Thu, 4 Mar 2010 01:26:02 +0000 Subject: [PATCH 57/71] linux-base: Ignore nonexistent devices and properly handle devices of unknown filesystem type (Closes: #572341) svn path=/dists/trunk/linux-2.6/; revision=15314 --- debian/changelog | 2 ++ debian/linux-base.postinst | 5 +++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/debian/changelog b/debian/changelog index 5777e0ccf..ba05bb26d 100644 --- a/debian/changelog +++ b/debian/changelog @@ -7,6 +7,8 @@ linux-2.6 (2.6.33-1~experimental.3) UNRELEASED; urgency=low * linux-base: Don't show empty list of devices to be relabelled * linux-base: Don't update udev CD rules unnecessarily * linux-base: Show the device paths to be added to udev CD rules + * linux-base: Ignore nonexistent devices and properly handle devices + of unknown filesystem type (Closes: #572341) -- Ben Hutchings Sun, 28 Feb 2010 17:01:33 +0000 diff --git a/debian/linux-base.postinst b/debian/linux-base.postinst index 63c439b4e..a64f560ca 100644 --- a/debian/linux-base.postinst +++ b/debian/linux-base.postinst @@ -1222,7 +1222,8 @@ sub scan_config_files { $id_map_text = &{$config->{needs_update}}($file); } else { for my $bdev (&{$config->{list}}($file)) { - if ($bdev =~ m{^/dev/(?:[hs]d[a-z]\d*|s(?:cd|r)\d+)$}) { + if ($bdev =~ m{^/dev/(?:[hs]d[a-z]\d*|s(?:cd|r)\d+)$} && + -b $bdev) { $bdev_map{$bdev} = {}; push @matched_bdevs, $bdev; } @@ -1288,7 +1289,7 @@ sub assign_labels { next if $#{$bdev_map{$bdev}->{ids}} >= 0; my $type = $bdev_map{$bdev}->{type}; - next unless exists($label_types{$type}); + next unless defined($type) && exists($label_types{$type}); my $label_len = $label_types{$type}->{len}; my $label; From 08c835c941fa3984b6a25cdc69faa3549953df8c Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Thu, 4 Mar 2010 23:02:05 +0000 Subject: [PATCH 58/71] Add bug closure (#572445) svn path=/dists/trunk/linux-2.6/; revision=15320 --- debian/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index ba05bb26d..e327f5da9 100644 --- a/debian/changelog +++ b/debian/changelog @@ -8,7 +8,7 @@ linux-2.6 (2.6.33-1~experimental.3) UNRELEASED; urgency=low * linux-base: Don't update udev CD rules unnecessarily * linux-base: Show the device paths to be added to udev CD rules * linux-base: Ignore nonexistent devices and properly handle devices - of unknown filesystem type (Closes: #572341) + of unknown filesystem type (Closes: #572341, #572445) -- Ben Hutchings Sun, 28 Feb 2010 17:01:33 +0000 From 85a33caf874e7cccbea0ab49330bc6ac693e7673 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Fri, 5 Mar 2010 02:02:43 +0000 Subject: [PATCH 59/71] linux-base: Don't accept empty filesystem labels as identifiers (Closes: #572438) svn path=/dists/trunk/linux-2.6/; revision=15324 --- debian/changelog | 2 ++ debian/linux-base.postinst | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index e327f5da9..2cc59fdcb 100644 --- a/debian/changelog +++ b/debian/changelog @@ -9,6 +9,8 @@ linux-2.6 (2.6.33-1~experimental.3) UNRELEASED; urgency=low * linux-base: Show the device paths to be added to udev CD rules * linux-base: Ignore nonexistent devices and properly handle devices of unknown filesystem type (Closes: #572341, #572445) + * linux-base: Don't accept empty filesystem labels as identifiers + (Closes: #572438) -- Ben Hutchings Sun, 28 Feb 2010 17:01:33 +0000 diff --git a/debian/linux-base.postinst b/debian/linux-base.postinst index a64f560ca..c06a45bfa 100644 --- a/debian/linux-base.postinst +++ b/debian/linux-base.postinst @@ -1267,7 +1267,7 @@ sub scan_devices { chomp; my $bdev = $_; for (`blkid -o udev -s LABEL -s UUID '$bdev'`) { - if (/^ID_FS_(LABEL|UUID)_ENC=(.*)\n$/) { + if (/^ID_FS_(LABEL|UUID)_ENC=(.+)\n$/) { add_tag($bdev, $1, $2); } } From a40042f1abe587ad72ebf47d94eb460cc3690457 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Wed, 10 Mar 2010 03:57:49 +0000 Subject: [PATCH 60/71] linux-base: For consistency with fresh installations, use or assign UUIDs rather than labels where both are available (Closes: #572376) svn path=/dists/trunk/linux-2.6/; revision=15347 --- debian/changelog | 2 + debian/linux-base.postinst | 153 +++++++++++++++++++++---------- debian/linux-base.templates | 2 +- debian/templates/control.main.in | 2 +- 4 files changed, 109 insertions(+), 50 deletions(-) diff --git a/debian/changelog b/debian/changelog index 2cc59fdcb..3b66e842d 100644 --- a/debian/changelog +++ b/debian/changelog @@ -11,6 +11,8 @@ linux-2.6 (2.6.33-1~experimental.3) UNRELEASED; urgency=low of unknown filesystem type (Closes: #572341, #572445) * linux-base: Don't accept empty filesystem labels as identifiers (Closes: #572438) + * linux-base: For consistency with fresh installations, use or assign + UUIDs rather than labels where both are available (Closes: #572376) -- Ben Hutchings Sun, 28 Feb 2010 17:01:33 +0000 diff --git a/debian/linux-base.postinst b/debian/linux-base.postinst index c06a45bfa..893daa798 100644 --- a/debian/linux-base.postinst +++ b/debian/linux-base.postinst @@ -22,6 +22,7 @@ use AptPkg::Config; use Debconf::Client::ConfModule ':all'; use FileHandle; use POSIX (); +use UUID; package DebianKernel::DiskId; @@ -1086,33 +1087,46 @@ my @config_files = ({packages => 'mount', # with few exceptions. Such as including a '^'. suffix => '^old'}); -### Filesystem relabelling +### Filesystem labels and UUIDs -sub ext2_label { +sub ext2_set_label { my ($bdev, $label) = @_; - system('e2label', $bdev, $label) == 0 or die "e2label failed: $?"; + system('tune2fs', '-L', $label, $bdev) == 0 or die "tune2fs failed: $?"; +} +sub ext2_set_uuid { + my ($bdev, $uuid) = @_; + system('tune2fs', '-U', $uuid, $bdev) == 0 or die "tune2fs failed: $?"; } -sub jfs_label { +sub jfs_set_label { my ($bdev, $label) = @_; system('jfs_tune', '-L', $label, $bdev) == 0 or die "jfs_tune failed: $?"; } - -sub fat_label { - my ($bdev, $label) = @_; - system('dosfslabel', $bdev, $label) == 0 or die "dosfslabel failed: $?";; +sub jfs_set_uuid { + my ($bdev, $uuid) = @_; + system('jfs_tune', '-U', $uuid, $bdev) == 0 or die "jfs_tune failed: $?"; } -sub ntfs_label { +sub fat_set_label { + my ($bdev, $label) = @_; + system('dosfslabel', $bdev, $label) == 0 or die "dosfslabel failed: $?"; +} + +sub ntfs_set_label { my ($bdev, $label) = @_; system('ntfslabel', $bdev, $label) == 0 or die "ntfslabel failed: $?"; } -sub reiserfs_label { +sub reiserfs_set_label { my ($bdev, $label) = @_; system('reiserfstune', '--label', $label, $bdev) or die "reiserfstune failed: $?"; } +sub reiserfs_set_uuid { + my ($bdev, $uuid) = @_; + system('reiserfstune', '--uuid', $uuid, $bdev) + or die "reiserfstune failed: $?"; +} # There is no command to relabel swap, and we mustn't run mkswap if # the partition is already in use. Thankfully the header format is @@ -1129,9 +1143,10 @@ sub reiserfs_label { # }; # and has the signature 'SWAPSPACE2' at the end of the first page. use constant { SWAP_SIGNATURE => 'SWAPSPACE2', + SWAP_UUID_OFFSET => 1036, SWAP_UUID_LEN => 16, SWAP_LABEL_OFFSET => 1052, SWAP_LABEL_LEN => 16 }; -sub swap_label { - my ($bdev, $label) = @_; +sub _swap_set_field { + my ($bdev, $offset, $value) = @_; my $pagesize = POSIX::sysconf(POSIX::_SC_PAGESIZE) or die "$!"; my ($length, $signature); @@ -1146,11 +1161,10 @@ sub swap_label { die "swap signature not found on $bdev"; } - # Set the label - $label = pack('Z' . SWAP_LABEL_LEN, $label); - POSIX::lseek($fd, SWAP_LABEL_OFFSET, POSIX::SEEK_SET); - $length = POSIX::write($fd, $label, SWAP_LABEL_LEN); - if (!defined($length) || $length != SWAP_LABEL_LEN) { + # Set the field + POSIX::lseek($fd, $offset, POSIX::SEEK_SET); + $length = POSIX::write($fd, $value, length($value)); + if (!defined($length) || $length != length($value)) { my $error = "$!"; POSIX::close($fd); die $error; @@ -1158,29 +1172,54 @@ sub swap_label { POSIX::close($fd); } +sub swap_set_label { + my ($bdev, $label) = @_; + _swap_set_field($bdev, SWAP_LABEL_OFFSET, pack('Z' . SWAP_LABEL_LEN, $label)); +} +sub swap_set_uuid { + my ($bdev, $uuid) = @_; + my $uuid_bin; + if (UUID::parse($uuid, $uuid_bin) != 0 || + length($uuid_bin) != SWAP_UUID_LEN) { + die "internal error: invalid UUID string"; + } + _swap_set_field($bdev, SWAP_UUID_OFFSET, $uuid_bin); +} -sub ufs_label { +sub ufs_set_label { my ($bdev, $label) = @_; system('tunefs.ufs', '-L', $label, $bdev) or die "tunefs.ufs failed: $?"; } -sub xfs_label { +sub xfs_set_label { my ($bdev, $label) = @_; system('xfs_admin', '-L', $label, $bdev) or die "xfs_admin failed: $?"; } +sub xfs_set_uuid { + my ($bdev, $uuid) = @_; + system('xfs_admin', '-U', $uuid, $bdev) or die "xfs_admin failed: $?"; +} -my %label_types = (ext2 => { len => 16, relabel => \&ext2_label }, - ext3 => { len => 16, relabel => \&ext2_label }, - ext4 => { len => 16, relabel => \&ext2_label }, - jfs => { len => 16, relabel => \&jfs_label }, - msdos => { len => 11, relabel => \&fat_label }, - ntfs => { len => 128, relabel => \&ntfs_label }, - reiserfs => { len => 16, relabel => \&reiserfs_label }, - swap => { len => SWAP_LABEL_LEN, - relabel => \&swap_label }, - ufs => { len => 32, relabel => \&ufs_label }, - vfat => { len => 11, relabel => \&fat_label }, - xfs => { len => 12, relabel => \&xfs_label }); +my %filesystem_types = ( + ext2 => { label_len => 16, set_label => \&ext2_set_label, + set_uuid => \&ext2_set_uuid }, + ext3 => { label_len => 16, set_label => \&ext2_set_label, + set_uuid => \&ext2_set_uuid }, + ext4 => { label_len => 16, set_label => \&ext2_set_label, + set_uuid => \&ext2_set_uuid }, + jfs => { label_len => 16, set_label => \&jfs_set_label, + set_uuid => \&jfs_set_uuid }, + msdos => { label_len => 11, set_label => \&fat_set_label }, + ntfs => { label_len => 128, set_label => \&ntfs_set_label }, + reiserfs => { label_len => 16, set_label => \&reiserfs_set_label, + set_uuid => \&reiserfs_set_uuid }, + swap => { label_len => SWAP_LABEL_LEN, set_label => \&swap_set_label, + set_uuid => \&swap_set_uuid }, + ufs => { label_len => 32, set_label => \&ufs_set_label }, + vfat => { label_len => 11, set_label => \&fat_set_label }, + xfs => { label_len => 12, set_label => \&xfs_set_label, + set_uuid => \&xfs_set_uuid } + ); my %bdev_map; my @matched_configs; @@ -1253,13 +1292,16 @@ sub scan_config_files { sub add_tag { # Map disks to labels/UUIDs and vice versa. Include all disks in # the reverse mapping so we can detect ambiguity. - my ($bdev, $name, $value) = @_; + my ($bdev, $name, $value, $new) = @_; my $id = "$name=$value"; push @{$id_map{$id}}, $bdev; if (exists($bdev_map{$bdev})) { $bdev_map{$bdev}->{$name} = $value; push @{$bdev_map{$bdev}->{ids}}, $id; } + if ($new) { + $bdev_map{$bdev}->{new_id} = $id; + } } sub scan_devices { @@ -1280,18 +1322,26 @@ sub scan_devices { } } -sub assign_labels { +sub assign_new_ids { my $hostname = (POSIX::uname())[1]; - # For all devices that have no alternate device ids, suggest labelling - # them based on fstab or just using a generic label. + # For all devices that have no alternate device ids, suggest setting + # UUIDs, labelling them based on fstab or just using a generic label. for my $bdev (keys(%bdev_map)) { next if $#{$bdev_map{$bdev}->{ids}} >= 0; my $type = $bdev_map{$bdev}->{type}; - next unless defined($type) && exists($label_types{$type}); + next unless defined($type) && exists($filesystem_types{$type}); - my $label_len = $label_types{$type}->{len}; + if (defined($filesystem_types{$type}->{set_uuid})) { + my ($uuid_bin, $uuid); + UUID::generate($uuid_bin); + UUID::unparse($uuid_bin, $uuid); + add_tag($bdev, 'UUID', $uuid, 1); + next; + } + + my $label_len = $filesystem_types{$type}->{len}; my $label; use bytes; # string lengths are in bytes @@ -1331,17 +1381,23 @@ sub assign_labels { } while (exists($id_map{"LABEL=$label"})); } - add_tag($bdev, 'LABEL', $label); - $bdev_map{$bdev}->{relabel} = 1; + add_tag($bdev, 'LABEL', $label, 1); } } -sub relabel { +sub set_new_ids { for my $bdev (keys(%bdev_map)) { my $bdev_info = $bdev_map{$bdev}; - if ($bdev_info->{relabel}) { - my $relabel = $label_types{$bdev_info->{type}}->{relabel}; - &{$relabel}($bdev, $bdev_info->{LABEL}); + if ($bdev_info->{new_id}) { + my ($name, $value) = split(/=/, $bdev_info->{new_id}, 2); + my $setter; + if ($name eq 'UUID') { + $setter = $filesystem_types{$bdev_info->{type}}->{set_uuid}; + } elsif ($name eq 'LABEL') { + $setter = $filesystem_types{$bdev_info->{type}}->{set_label}; + } + defined($setter) or die "internal error: invalid new_id type"; + &{$setter}($bdev, $value); } } } @@ -1410,14 +1466,15 @@ sub transition { if ($answer eq 'true') { scan_devices(); - assign_labels(); + assign_new_ids(); - if (grep({$bdev_map{$_}->{relabel}} keys(%bdev_map))) { + if (grep({$bdev_map{$_}->{new_id}} keys(%bdev_map))) { $question = 'linux-base/disk-id-convert-plan'; ($ret, $seen) = subst($question, 'relabel', join("\\n", - map({sprintf("%s: %s", $_, $bdev_map{$_}->{LABEL})} - grep({$bdev_map{$_}->{relabel}} + map({sprintf("%s: %s", + $_, $bdev_map{$_}->{new_id})} + grep({$bdev_map{$_}->{new_id}} keys(%bdev_map))))); die "Error setting debconf substitutions in $question: $seen" if $ret; } else { @@ -1448,7 +1505,7 @@ sub transition { if ($answer ne 'true') { # TODO: go back to the auto/manual question or allow editing the plan } else { - relabel(); + set_new_ids(); update_config(); } } diff --git a/debian/linux-base.templates b/debian/linux-base.templates index 3c4a612d9..98e799f2d 100644 --- a/debian/linux-base.templates +++ b/debian/linux-base.templates @@ -15,7 +15,7 @@ Template: linux-base/disk-id-convert-plan Type: boolean Default: true Description: Apply these configuration changes to disk device ids? - These devices will be relabelled: + These devices will be assigned UUIDs or labels: . ${relabel} . diff --git a/debian/templates/control.main.in b/debian/templates/control.main.in index 9f50cc393..ee290fa13 100644 --- a/debian/templates/control.main.in +++ b/debian/templates/control.main.in @@ -79,7 +79,7 @@ Description: Support files for Linux @upstreamversion@ Package: linux-base Architecture: all -Depends: libapt-pkg-perl, ${misc:Depends} +Depends: libapt-pkg-perl, libuuid-perl, ${misc:Depends} Description: Linux image base package This package contains files and support scripts for all Linux images. From 0885a79b40e07df0d5060936a9a166cb41764e84 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Wed, 10 Mar 2010 04:01:41 +0000 Subject: [PATCH 61/71] Group all libata transition changes as sub-items under one item svn path=/dists/trunk/linux-2.6/; revision=15348 --- debian/changelog | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/debian/changelog b/debian/changelog index 3b66e842d..a47a1b56a 100644 --- a/debian/changelog +++ b/debian/changelog @@ -2,17 +2,16 @@ linux-2.6 (2.6.33-1~experimental.3) UNRELEASED; urgency=low [ Ben Hutchings ] * Fix regexp for binNMU versions in modules/rules.include (Closes: #524632) - * linux-base: Fix calls to disk_id_to_path (renamed to id_to_path) - (Closes: #572283) - * linux-base: Don't show empty list of devices to be relabelled - * linux-base: Don't update udev CD rules unnecessarily - * linux-base: Show the device paths to be added to udev CD rules - * linux-base: Ignore nonexistent devices and properly handle devices - of unknown filesystem type (Closes: #572341, #572445) - * linux-base: Don't accept empty filesystem labels as identifiers - (Closes: #572438) - * linux-base: For consistency with fresh installations, use or assign - UUIDs rather than labels where both are available (Closes: #572376) + * linux-base: Fix bugs and improve libata transition code: + - Fix calls to disk_id_to_path (renamed to id_to_path) (Closes: #572283) + - Don't show empty list of devices to be relabelled + - Don't update udev CD rules unnecessarily + - Show the device paths to be added to udev CD rules + - Ignore nonexistent devices and properly handle devices of unknown + filesystem type (Closes: #572341, #572445) + - Don't accept empty filesystem labels as identifiers (Closes: #572438) + - For consistency with fresh installations, use or assign UUIDs rather + than labels where both are available (Closes: #572376) -- Ben Hutchings Sun, 28 Feb 2010 17:01:33 +0000 From 407faa9cfa7626ff3e4029eaf00e653dbdb7a473 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Thu, 11 Mar 2010 00:54:45 +0000 Subject: [PATCH 62/71] Replace CD/DVD/BD device names with udev-provided persistent aliases svn path=/dists/trunk/linux-2.6/; revision=15349 --- debian/changelog | 1 + debian/linux-base.postinst | 46 ++++++++++++++++++++++++++++---------- 2 files changed, 35 insertions(+), 12 deletions(-) diff --git a/debian/changelog b/debian/changelog index a47a1b56a..e13276930 100644 --- a/debian/changelog +++ b/debian/changelog @@ -12,6 +12,7 @@ linux-2.6 (2.6.33-1~experimental.3) UNRELEASED; urgency=low - Don't accept empty filesystem labels as identifiers (Closes: #572438) - For consistency with fresh installations, use or assign UUIDs rather than labels where both are available (Closes: #572376) + - Replace CD/DVD/BD device names with udev-provided persistent aliases -- Ben Hutchings Sun, 28 Feb 2010 17:01:33 +0000 diff --git a/debian/linux-base.postinst b/debian/linux-base.postinst index 893daa798..9ae900b95 100644 --- a/debian/linux-base.postinst +++ b/debian/linux-base.postinst @@ -877,6 +877,20 @@ sub udev_next { return @results; } +sub udev_parse_symlink_rule { + my ($path, $symlink); + for (@_) { + my ($text, $key, $op, $value) = @$_; + next if !defined($key); + if ($key eq 'ENV{ID_PATH}' && $op eq '==') { + $path = $value; + } elsif ($key eq 'SYMLINK' && $op eq '+=') { + $symlink = $value; + } + } + return ($path, $symlink); +} + # Find symlink rules using IDE device paths that aren't matched by rules # using the corresponding SCSI device path. Return an array containing # the corresponding path for each rule where this is the case and undef @@ -891,17 +905,7 @@ sub udev_cd_find_unmatched_ide_rules { my @keys = udev_next($file); last if $#keys < 0; - my ($path, $symlink); - for (@keys) { - my ($text, $key, $op, $value) = @$_; - next if !defined($key); - if ($key eq 'ENV{ID_PATH}' && $op eq '==') { - $path = $value; - } elsif ($key eq 'SYMLINK' && $op eq '+=') { - $symlink = $value; - } - } - + my ($path, $symlink) = udev_parse_symlink_rule(@keys); if (defined($path) && defined($symlink)) { if ($path =~ /-ide-\d+:\d+$/) { # libata uses the PATA controller and device numbers @@ -1315,11 +1319,29 @@ sub scan_devices { } } - # Discard all device ids that are ambiguous. + # Discard all labels and UUIDs(!) that are ambiguous. for my $bdev (keys(%bdev_map)) { @{$bdev_map{$bdev}->{ids}} = grep({ $#{$id_map{$_}} == 0 } @{$bdev_map{$bdev}->{ids}}); } + + # Add persistent aliases for CD/DVD/BD drives + my $cd_rules = + new FileHandle('/etc/udev/rules.d/70-persistent-cd.rules', 'r'); + while (defined($cd_rules)) { + my @keys = udev_next($cd_rules); + last if $#keys < 0; + + my ($path, $symlink) = udev_parse_symlink_rule(@keys); + if (defined($path) && defined($symlink)) { + $symlink =~ s{^(?!/)}{/dev/}; + my $bdev = readlink($symlink) or next; + $bdev =~ s{^(?!/)}{/dev/}; + if (exists($bdev_map{$bdev})) { + push @{$bdev_map{$bdev}->{ids}}, $symlink; + } + } + } } sub assign_new_ids { From ad583d4ec9a3aae155616556160ff2c5bc42979c Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Thu, 11 Mar 2010 00:56:45 +0000 Subject: [PATCH 63/71] Fix use of undefined value in substitutions svn path=/dists/trunk/linux-2.6/; revision=15350 --- debian/linux-base.postinst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/debian/linux-base.postinst b/debian/linux-base.postinst index 9ae900b95..327b0b1ea 100644 --- a/debian/linux-base.postinst +++ b/debian/linux-base.postinst @@ -1507,7 +1507,8 @@ sub transition { map({sprintf("%s: %s", $_, $bdev_map{$_}->{ids}->[0])} grep({@{$bdev_map{$_}->{ids}}} keys(%bdev_map))), - map({$_->{id_map_text}} @matched_configs))); + grep({defined} + map({$_->{id_map_text}} @matched_configs)))); die "Error setting debconf substitutions in $question: $seen" if $ret; ($ret, $seen) = subst($question, 'files', join(', ', From a87ba5e96aeabcca2d75c99d891a7a11b1f07bb5 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Thu, 11 Mar 2010 00:57:45 +0000 Subject: [PATCH 64/71] Remove TODO comment that will never be implemented svn path=/dists/trunk/linux-2.6/; revision=15351 --- debian/linux-base.postinst | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/debian/linux-base.postinst b/debian/linux-base.postinst index 327b0b1ea..ba35892d7 100644 --- a/debian/linux-base.postinst +++ b/debian/linux-base.postinst @@ -1525,9 +1525,7 @@ sub transition { ($ret, $answer) = get($question); die "Error retrieving answer for $question: $answer" if $ret; - if ($answer ne 'true') { - # TODO: go back to the auto/manual question or allow editing the plan - } else { + if ($answer eq 'true') { set_new_ids(); update_config(); } From c1021b3bb4a709ff21ca70e3bd9a64d8a40c1b6b Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Thu, 11 Mar 2010 03:10:21 +0000 Subject: [PATCH 65/71] Fix update of boot device name for LILO and related loaders svn path=/dists/trunk/linux-2.6/; revision=15352 --- debian/changelog | 1 + debian/linux-base.postinst | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index e13276930..0f388e2bf 100644 --- a/debian/changelog +++ b/debian/changelog @@ -13,6 +13,7 @@ linux-2.6 (2.6.33-1~experimental.3) UNRELEASED; urgency=low - For consistency with fresh installations, use or assign UUIDs rather than labels where both are available (Closes: #572376) - Replace CD/DVD/BD device names with udev-provided persistent aliases + - Fix update of boot device name for LILO and related loaders -- Ben Hutchings Sun, 28 Feb 2010 17:01:33 +0000 diff --git a/debian/linux-base.postinst b/debian/linux-base.postinst index ba35892d7..11a086d56 100644 --- a/debian/linux-base.postinst +++ b/debian/linux-base.postinst @@ -31,7 +31,7 @@ package DebianKernel::DiskId; sub id_to_path { my ($id) = @_; $id =~ m|^/| - or $id =~ s{^(LABEL|UUID)=}{'/dev/disk/by-' . lc($1) . '/'}x + or $id =~ s{^(LABEL|UUID)=}{'/dev/disk/by-' . lc($1) . '/'}e or die "Could not map id $id to path"; return $id; } From ef5cb9f2c20b70b41c14148c1de791f0f03d7b35 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Thu, 11 Mar 2010 03:13:03 +0000 Subject: [PATCH 66/71] Update uswsusp resume device name svn path=/dists/trunk/linux-2.6/; revision=15353 --- debian/changelog | 1 + debian/linux-base.postinst | 59 +++++++++++++++++++++++++++++++++++++- 2 files changed, 59 insertions(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index 0f388e2bf..7deace0a4 100644 --- a/debian/changelog +++ b/debian/changelog @@ -14,6 +14,7 @@ linux-2.6 (2.6.33-1~experimental.3) UNRELEASED; urgency=low than labels where both are available (Closes: #572376) - Replace CD/DVD/BD device names with udev-provided persistent aliases - Fix update of boot device name for LILO and related loaders + - Update uswsusp resume device name -- Ben Hutchings Sun, 28 Feb 2010 17:01:33 +0000 diff --git a/debian/linux-base.postinst b/debian/linux-base.postinst index 11a086d56..bd0d234e1 100644 --- a/debian/linux-base.postinst +++ b/debian/linux-base.postinst @@ -1013,6 +1013,59 @@ sub initramfs_resume_update { } } +# uswsusp resume + +sub uswsusp_next { + # Based on parse_line() in config_parser.c + + my ($file) = @_; + my $text = <$file>; + + if (!defined($text) || $text eq '') { + return (); + } + + local $_ = $text; + s/^\s*(?:#.*)?//; + s/\s*$//; + + if ($text =~ /^([\w ]*\w)[ \t]*[:=][ \t]*(.+)$/) { + return ($text, $1, $2); + } else { + return ($text); + } +} + +sub uswsusp_resume_list { + my ($file) = @_; + my @results = (); + + while (1) { + my ($text, $name, $value) = uswsusp_next($file); + last unless defined($text); + if (defined($name) && $name eq 'resume device') { + $results[0] = $value; + } + } + + return @results; +} + +sub uswsusp_resume_update { + my ($old, $new, $map) = @_; + + while (1) { + my ($text, $name, $value) = uswsusp_next($old); + last unless defined($text); + if (defined($name) && $name eq 'resume device' && + defined(my $new_value = $map->{$value})) { + $text =~ s/^/# /gm; + $text .= sprintf("%s = %s\n", $name, id_to_path($new_value)); + } + $new->print($text); + } +} + ### list of all configuration files and functions my @config_files = ({packages => 'mount', @@ -1089,7 +1142,11 @@ my @config_files = ({packages => 'mount', update => \&initramfs_resume_update, # udev will source all files in this directory, # with few exceptions. Such as including a '^'. - suffix => '^old'}); + suffix => '^old'}, + {packages => 'uswsusp', + path => '/etc/uswsusp.conf', + list => \&uswsusp_resume_list, + update => \&uswsusp_resume_update}); ### Filesystem labels and UUIDs From a8114070f107c918a0e8579d4b2ed7712069b14d Mon Sep 17 00:00:00 2001 From: Maximilian Attems Date: Thu, 11 Mar 2010 04:59:18 +0000 Subject: [PATCH 67/71] prepare to release 2.6.33-1~experimental.3 svn path=/dists/trunk/linux-2.6/; revision=15354 --- debian/changelog | 4 ++-- debian/config/defines | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/debian/changelog b/debian/changelog index 7deace0a4..02424908b 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,4 +1,4 @@ -linux-2.6 (2.6.33-1~experimental.3) UNRELEASED; urgency=low +linux-2.6 (2.6.33-1~experimental.3) experimental; urgency=low [ Ben Hutchings ] * Fix regexp for binNMU versions in modules/rules.include (Closes: #524632) @@ -16,7 +16,7 @@ linux-2.6 (2.6.33-1~experimental.3) UNRELEASED; urgency=low - Fix update of boot device name for LILO and related loaders - Update uswsusp resume device name - -- Ben Hutchings Sun, 28 Feb 2010 17:01:33 +0000 + -- maximilian attems Thu, 11 Mar 2010 05:58:02 +0100 linux-2.6 (2.6.33-1~experimental.2) experimental; urgency=low diff --git a/debian/config/defines b/debian/config/defines index dbcd4d7f9..7381abbc5 100644 --- a/debian/config/defines +++ b/debian/config/defines @@ -1,5 +1,5 @@ [abi] -abiname: trunk +abiname: 2 [base] arches: From 8487903ed96db25bb161ac79cee1542c125952a3 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Sat, 13 Mar 2010 23:27:03 +0000 Subject: [PATCH 68/71] Include aufs2, marked as staging (Closes: #573189) svn path=/dists/trunk/linux-2.6/; revision=15371 --- debian/changelog | 7 + .../features/all/aufs2/aufs2-add.patch | 25476 ++++++++++++++++ .../features/all/aufs2/aufs2-base.patch | 81 + .../features/all/aufs2/aufs2-kbuild.patch | 35 + .../features/all/aufs2/aufs2-standalone.patch | 203 + .../features/all/aufs2/mark-as-staging.patch | 15 + debian/patches/series/base | 8 +- 7 files changed, 25824 insertions(+), 1 deletion(-) create mode 100644 debian/patches/features/all/aufs2/aufs2-add.patch create mode 100644 debian/patches/features/all/aufs2/aufs2-base.patch create mode 100644 debian/patches/features/all/aufs2/aufs2-kbuild.patch create mode 100644 debian/patches/features/all/aufs2/aufs2-standalone.patch create mode 100644 debian/patches/features/all/aufs2/mark-as-staging.patch diff --git a/debian/changelog b/debian/changelog index 02424908b..78c61bcac 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,10 @@ +linux-2.6 (2.6.33-1~experimental.4) UNRELEASED; urgency=low + + [ Ben Hutchings ] + * Include aufs2, marked as staging (Closes: #573189) + + -- Ben Hutchings Sat, 13 Mar 2010 23:06:49 +0000 + linux-2.6 (2.6.33-1~experimental.3) experimental; urgency=low [ Ben Hutchings ] diff --git a/debian/patches/features/all/aufs2/aufs2-add.patch b/debian/patches/features/all/aufs2/aufs2-add.patch new file mode 100644 index 000000000..78b89327d --- /dev/null +++ b/debian/patches/features/all/aufs2/aufs2-add.patch @@ -0,0 +1,25476 @@ +diff --git a/fs/aufs/Kconfig b/fs/aufs/Kconfig +new file mode 100644 +index 0000000..b74c280 +--- /dev/null ++++ b/fs/aufs/Kconfig +@@ -0,0 +1,160 @@ ++config AUFS_FS ++ tristate "Aufs (Advanced multi layered unification filesystem) support" ++ depends on EXPERIMENTAL ++ help ++ Aufs is a stackable unification filesystem such as Unionfs, ++ which unifies several directories and provides a merged single ++ directory. ++ In the early days, aufs was entirely re-designed and ++ re-implemented Unionfs Version 1.x series. Introducing many ++ original ideas, approaches and improvements, it becomes totally ++ different from Unionfs while keeping the basic features. ++ ++if AUFS_FS ++choice ++ prompt "Maximum number of branches" ++ default AUFS_BRANCH_MAX_127 ++ help ++ Specifies the maximum number of branches (or member directories) ++ in a single aufs. The larger value consumes more system ++ resources and has a minor impact to performance. ++config AUFS_BRANCH_MAX_127 ++ bool "127" ++ help ++ Specifies the maximum number of branches (or member directories) ++ in a single aufs. The larger value consumes more system ++ resources and has a minor impact to performance. ++config AUFS_BRANCH_MAX_511 ++ bool "511" ++ help ++ Specifies the maximum number of branches (or member directories) ++ in a single aufs. The larger value consumes more system ++ resources and has a minor impact to performance. ++config AUFS_BRANCH_MAX_1023 ++ bool "1023" ++ help ++ Specifies the maximum number of branches (or member directories) ++ in a single aufs. The larger value consumes more system ++ resources and has a minor impact to performance. ++config AUFS_BRANCH_MAX_32767 ++ bool "32767" ++ help ++ Specifies the maximum number of branches (or member directories) ++ in a single aufs. The larger value consumes more system ++ resources and has a minor impact to performance. ++endchoice ++ ++config AUFS_HINOTIFY ++ bool "Use inotify to detect actions on a branch" ++ depends on INOTIFY ++ help ++ If you want to modify files on branches directly, eg. bypassing aufs, ++ and want aufs to detect the changes of them fully, then enable this ++ option and use 'udba=inotify' mount option. ++ It will have a negative impact to the performance. ++ See detail in aufs.5. ++ ++config AUFS_EXPORT ++ bool "NFS-exportable aufs" ++ depends on (AUFS_FS = y && EXPORTFS = y) || (AUFS_FS = m && EXPORTFS) ++ help ++ If you want to export your mounted aufs via NFS, then enable this ++ option. There are several requirements for this configuration. ++ See detail in aufs.5. ++ ++config AUFS_INO_T_64 ++ bool ++ depends on AUFS_EXPORT ++ depends on 64BIT && !(ALPHA || S390) ++ default y ++ help ++ Automatic configuration for internal use. ++ /* typedef unsigned long/int __kernel_ino_t */ ++ /* alpha and s390x are int */ ++ ++config AUFS_RDU ++ bool "Readdir in userspace" ++ help ++ If you have millions of files under a single aufs directory, and ++ meet the out of memory, then enable this option and set ++ environment variables for your readdir(3). ++ See detail in aufs.5. ++ ++config AUFS_SP_IATTR ++ bool "Respect the attributes (mtime/ctime mainly) of special files" ++ help ++ When you write something to a special file, some attributes of it ++ (mtime/ctime mainly) may be updated. Generally such updates are ++ less important (actually some device drivers and NFS ignore ++ it). But some applications (such like test program) requires ++ such updates. If you need these updates, then enable this ++ configuration which introduces some overhead. ++ Currently this configuration handles FIFO only. ++ ++config AUFS_SHWH ++ bool "Show whiteouts" ++ help ++ If you want to make the whiteouts in aufs visible, then enable ++ this option and specify 'shwh' mount option. Although it may ++ sounds like philosophy or something, but in technically it ++ simply shows the name of whiteout with keeping its behaviour. ++ ++config AUFS_BR_RAMFS ++ bool "Ramfs (initramfs/rootfs) as an aufs branch" ++ help ++ If you want to use ramfs as an aufs branch fs, then enable this ++ option. Generally tmpfs is recommended. ++ Aufs prohibited them to be a branch fs by default, because ++ initramfs becomes unusable after switch_root or something ++ generally. If you sets initramfs as an aufs branch and boot your ++ system by switch_root, you will meet a problem easily since the ++ files in initramfs may be inaccessible. ++ Unless you are going to use ramfs as an aufs branch fs without ++ switch_root or something, leave it N. ++ ++config AUFS_BR_FUSE ++ bool "Fuse fs as an aufs branch" ++ depends on FUSE_FS ++ select AUFS_POLL ++ help ++ If you want to use fuse-based userspace filesystem as an aufs ++ branch fs, then enable this option. ++ It implements the internal poll(2) operation which is ++ implemented by fuse only (curretnly). ++ ++config AUFS_POLL ++ bool ++ help ++ Automatic configuration for internal use. ++ ++config AUFS_BR_HFSPLUS ++ bool "Hfsplus as an aufs branch" ++ depends on HFSPLUS_FS ++ default y ++ help ++ If you want to use hfsplus fs as an aufs branch fs, then enable ++ this option. This option introduces a small overhead at ++ copying-up a file on hfsplus. ++ ++config AUFS_BDEV_LOOP ++ bool ++ depends on BLK_DEV_LOOP ++ default y ++ help ++ Automatic configuration for internal use. ++ Convert =[ym] into =y. ++ ++config AUFS_DEBUG ++ bool "Debug aufs" ++ help ++ Enable this to compile aufs internal debug code. ++ It will have a negative impact to the performance. ++ ++config AUFS_MAGIC_SYSRQ ++ bool ++ depends on AUFS_DEBUG && MAGIC_SYSRQ ++ default y ++ help ++ Automatic configuration for internal use. ++ When aufs supports Magic SysRq, enabled automatically. ++endif +diff --git a/fs/aufs/Makefile b/fs/aufs/Makefile +new file mode 100644 +index 0000000..9b5a4b8 +--- /dev/null ++++ b/fs/aufs/Makefile +@@ -0,0 +1,35 @@ ++ ++include ${src}/magic.mk ++ifeq (${CONFIG_AUFS_FS},m) ++include ${src}/conf.mk ++endif ++-include ${src}/priv_def.mk ++ ++# cf. include/linux/kernel.h ++# enable pr_debug ++ccflags-y += -DDEBUG ++ccflags-y += -D'pr_fmt(fmt)="aufs %s:%d:%s[%d]: " fmt, \ ++ __func__, __LINE__, current->comm, current->pid' ++ ++obj-$(CONFIG_AUFS_FS) += aufs.o ++aufs-y := module.o sbinfo.o super.o branch.o xino.o sysaufs.o opts.o \ ++ wkq.o vfsub.o dcsub.o \ ++ cpup.o whout.o plink.o wbr_policy.o \ ++ dinfo.o dentry.o \ ++ finfo.o file.o f_op.o \ ++ dir.o vdir.o \ ++ iinfo.o inode.o i_op.o i_op_add.o i_op_del.o i_op_ren.o \ ++ ioctl.o ++ ++# all are boolean ++aufs-$(CONFIG_SYSFS) += sysfs.o ++aufs-$(CONFIG_DEBUG_FS) += dbgaufs.o ++aufs-$(CONFIG_AUFS_BDEV_LOOP) += loop.o ++aufs-$(CONFIG_AUFS_HINOTIFY) += hinotify.o ++aufs-$(CONFIG_AUFS_EXPORT) += export.o ++aufs-$(CONFIG_AUFS_POLL) += poll.o ++aufs-$(CONFIG_AUFS_RDU) += rdu.o ++aufs-$(CONFIG_AUFS_SP_IATTR) += f_op_sp.o ++aufs-$(CONFIG_AUFS_BR_HFSPLUS) += hfsplus.o ++aufs-$(CONFIG_AUFS_DEBUG) += debug.o ++aufs-$(CONFIG_AUFS_MAGIC_SYSRQ) += sysrq.o +diff --git a/fs/aufs/aufs.h b/fs/aufs/aufs.h +new file mode 100644 +index 0000000..0dfb6fb +--- /dev/null ++++ b/fs/aufs/aufs.h +@@ -0,0 +1,59 @@ ++/* ++ * Copyright (C) 2005-2010 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* ++ * all header files ++ */ ++ ++#ifndef __AUFS_H__ ++#define __AUFS_H__ ++ ++#ifdef __KERNEL__ ++ ++#define AuStub(type, name, body, ...) \ ++ static inline type name(__VA_ARGS__) { body; } ++ ++#define AuStubVoid(name, ...) \ ++ AuStub(void, name, , __VA_ARGS__) ++#define AuStubInt0(name, ...) \ ++ AuStub(int, name, return 0, __VA_ARGS__) ++ ++#include "debug.h" ++ ++#include "branch.h" ++#include "cpup.h" ++#include "dcsub.h" ++#include "dbgaufs.h" ++#include "dentry.h" ++#include "dir.h" ++#include "file.h" ++#include "fstype.h" ++#include "inode.h" ++#include "loop.h" ++#include "module.h" ++#include "opts.h" ++#include "rwsem.h" ++#include "spl.h" ++#include "super.h" ++#include "sysaufs.h" ++#include "vfsub.h" ++#include "whout.h" ++#include "wkq.h" ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_H__ */ +diff --git a/fs/aufs/branch.c b/fs/aufs/branch.c +new file mode 100644 +index 0000000..2ec2a63 +--- /dev/null ++++ b/fs/aufs/branch.c +@@ -0,0 +1,996 @@ ++/* ++ * Copyright (C) 2005-2010 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* ++ * branch management ++ */ ++ ++#include ++#include ++#include "aufs.h" ++ ++/* ++ * free a single branch ++ */ ++static void au_br_do_free(struct au_branch *br) ++{ ++ int i; ++ struct au_wbr *wbr; ++ ++ if (br->br_xino.xi_file) ++ fput(br->br_xino.xi_file); ++ mutex_destroy(&br->br_xino.xi_nondir_mtx); ++ ++ AuDebugOn(atomic_read(&br->br_count)); ++ ++ wbr = br->br_wbr; ++ if (wbr) { ++ for (i = 0; i < AuBrWh_Last; i++) ++ dput(wbr->wbr_wh[i]); ++ AuDebugOn(atomic_read(&wbr->wbr_wh_running)); ++ AuRwDestroy(&wbr->wbr_wh_rwsem); ++ } ++ ++ /* some filesystems acquire extra lock */ ++ /* lockdep_off(); */ ++ mntput(br->br_mnt); ++ /* lockdep_on(); */ ++ ++ kfree(wbr); ++ kfree(br); ++} ++ ++/* ++ * frees all branches ++ */ ++void au_br_free(struct au_sbinfo *sbinfo) ++{ ++ aufs_bindex_t bmax; ++ struct au_branch **br; ++ ++ AuRwMustWriteLock(&sbinfo->si_rwsem); ++ ++ bmax = sbinfo->si_bend + 1; ++ br = sbinfo->si_branch; ++ while (bmax--) ++ au_br_do_free(*br++); ++} ++ ++/* ++ * find the index of a branch which is specified by @br_id. ++ */ ++int au_br_index(struct super_block *sb, aufs_bindex_t br_id) ++{ ++ aufs_bindex_t bindex, bend; ++ ++ bend = au_sbend(sb); ++ for (bindex = 0; bindex <= bend; bindex++) ++ if (au_sbr_id(sb, bindex) == br_id) ++ return bindex; ++ return -1; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * add a branch ++ */ ++ ++static int test_overlap(struct super_block *sb, struct dentry *h_d1, ++ struct dentry *h_d2) ++{ ++ if (unlikely(h_d1 == h_d2)) ++ return 1; ++ return !!au_test_subdir(h_d1, h_d2) ++ || !!au_test_subdir(h_d2, h_d1) ++ || au_test_loopback_overlap(sb, h_d1, h_d2) ++ || au_test_loopback_overlap(sb, h_d2, h_d1); ++} ++ ++/* ++ * returns a newly allocated branch. @new_nbranch is a number of branches ++ * after adding a branch. ++ */ ++static struct au_branch *au_br_alloc(struct super_block *sb, int new_nbranch, ++ int perm) ++{ ++ struct au_branch *add_branch; ++ struct dentry *root; ++ int err; ++ ++ err = -ENOMEM; ++ root = sb->s_root; ++ add_branch = kmalloc(sizeof(*add_branch), GFP_NOFS); ++ if (unlikely(!add_branch)) ++ goto out; ++ ++ add_branch->br_wbr = NULL; ++ if (au_br_writable(perm)) { ++ /* may be freed separately at changing the branch permission */ ++ add_branch->br_wbr = kmalloc(sizeof(*add_branch->br_wbr), ++ GFP_NOFS); ++ if (unlikely(!add_branch->br_wbr)) ++ goto out_br; ++ } ++ ++ err = au_sbr_realloc(au_sbi(sb), new_nbranch); ++ if (!err) ++ err = au_di_realloc(au_di(root), new_nbranch); ++ if (!err) ++ err = au_ii_realloc(au_ii(root->d_inode), new_nbranch); ++ if (!err) ++ return add_branch; /* success */ ++ ++ kfree(add_branch->br_wbr); ++ ++ out_br: ++ kfree(add_branch); ++ out: ++ return ERR_PTR(err); ++} ++ ++/* ++ * test if the branch permission is legal or not. ++ */ ++static int test_br(struct inode *inode, int brperm, char *path) ++{ ++ int err; ++ ++ err = (au_br_writable(brperm) && IS_RDONLY(inode)); ++ if (!err) ++ goto out; ++ ++ err = -EINVAL; ++ pr_err("write permission for readonly mount or inode, %s\n", path); ++ ++ out: ++ return err; ++} ++ ++/* ++ * returns: ++ * 0: success, the caller will add it ++ * plus: success, it is already unified, the caller should ignore it ++ * minus: error ++ */ ++static int test_add(struct super_block *sb, struct au_opt_add *add, int remount) ++{ ++ int err; ++ aufs_bindex_t bend, bindex; ++ struct dentry *root; ++ struct inode *inode, *h_inode; ++ ++ root = sb->s_root; ++ bend = au_sbend(sb); ++ if (unlikely(bend >= 0 ++ && au_find_dbindex(root, add->path.dentry) >= 0)) { ++ err = 1; ++ if (!remount) { ++ err = -EINVAL; ++ pr_err("%s duplicated\n", add->pathname); ++ } ++ goto out; ++ } ++ ++ err = -ENOSPC; /* -E2BIG; */ ++ if (unlikely(AUFS_BRANCH_MAX <= add->bindex ++ || AUFS_BRANCH_MAX - 1 <= bend)) { ++ pr_err("number of branches exceeded %s\n", add->pathname); ++ goto out; ++ } ++ ++ err = -EDOM; ++ if (unlikely(add->bindex < 0 || bend + 1 < add->bindex)) { ++ pr_err("bad index %d\n", add->bindex); ++ goto out; ++ } ++ ++ inode = add->path.dentry->d_inode; ++ err = -ENOENT; ++ if (unlikely(!inode->i_nlink)) { ++ pr_err("no existence %s\n", add->pathname); ++ goto out; ++ } ++ ++ err = -EINVAL; ++ if (unlikely(inode->i_sb == sb)) { ++ pr_err("%s must be outside\n", add->pathname); ++ goto out; ++ } ++ ++ if (unlikely(au_test_fs_unsuppoted(inode->i_sb))) { ++ pr_err("unsupported filesystem, %s (%s)\n", ++ add->pathname, au_sbtype(inode->i_sb)); ++ goto out; ++ } ++ ++ err = test_br(add->path.dentry->d_inode, add->perm, add->pathname); ++ if (unlikely(err)) ++ goto out; ++ ++ if (bend < 0) ++ return 0; /* success */ ++ ++ err = -EINVAL; ++ for (bindex = 0; bindex <= bend; bindex++) ++ if (unlikely(test_overlap(sb, add->path.dentry, ++ au_h_dptr(root, bindex)))) { ++ pr_err("%s is overlapped\n", add->pathname); ++ goto out; ++ } ++ ++ err = 0; ++ if (au_opt_test(au_mntflags(sb), WARN_PERM)) { ++ h_inode = au_h_dptr(root, 0)->d_inode; ++ if ((h_inode->i_mode & S_IALLUGO) != (inode->i_mode & S_IALLUGO) ++ || h_inode->i_uid != inode->i_uid ++ || h_inode->i_gid != inode->i_gid) ++ pr_warning("uid/gid/perm %s %u/%u/0%o, %u/%u/0%o\n", ++ add->pathname, ++ inode->i_uid, inode->i_gid, ++ (inode->i_mode & S_IALLUGO), ++ h_inode->i_uid, h_inode->i_gid, ++ (h_inode->i_mode & S_IALLUGO)); ++ } ++ ++ out: ++ return err; ++} ++ ++/* ++ * initialize or clean the whiteouts for an adding branch ++ */ ++static int au_br_init_wh(struct super_block *sb, struct au_branch *br, ++ int new_perm, struct dentry *h_root) ++{ ++ int err, old_perm; ++ aufs_bindex_t bindex; ++ struct mutex *h_mtx; ++ struct au_wbr *wbr; ++ struct au_hinode *hdir; ++ ++ wbr = br->br_wbr; ++ old_perm = br->br_perm; ++ br->br_perm = new_perm; ++ hdir = NULL; ++ h_mtx = NULL; ++ bindex = au_br_index(sb, br->br_id); ++ if (0 <= bindex) { ++ hdir = au_hi(sb->s_root->d_inode, bindex); ++ au_hin_imtx_lock_nested(hdir, AuLsc_I_PARENT); ++ } else { ++ h_mtx = &h_root->d_inode->i_mutex; ++ mutex_lock_nested(h_mtx, AuLsc_I_PARENT); ++ } ++ if (!wbr) ++ err = au_wh_init(h_root, br, sb); ++ else { ++ wbr_wh_write_lock(wbr); ++ err = au_wh_init(h_root, br, sb); ++ wbr_wh_write_unlock(wbr); ++ } ++ if (hdir) ++ au_hin_imtx_unlock(hdir); ++ else ++ mutex_unlock(h_mtx); ++ br->br_perm = old_perm; ++ ++ if (!err && wbr && !au_br_writable(new_perm)) { ++ kfree(wbr); ++ br->br_wbr = NULL; ++ } ++ ++ return err; ++} ++ ++static int au_wbr_init(struct au_branch *br, struct super_block *sb, ++ int perm, struct path *path) ++{ ++ int err; ++ struct kstatfs kst; ++ struct au_wbr *wbr; ++ struct dentry *h_dentry; ++ ++ wbr = br->br_wbr; ++ au_rw_init(&wbr->wbr_wh_rwsem); ++ memset(wbr->wbr_wh, 0, sizeof(wbr->wbr_wh)); ++ atomic_set(&wbr->wbr_wh_running, 0); ++ wbr->wbr_bytes = 0; ++ ++ /* ++ * a limit for rmdir/rename a dir ++ * cf. AUFS_MAX_NAMELEN in include/linux/aufs_type.h ++ */ ++ h_dentry = path->dentry; ++ err = vfs_statfs(h_dentry, &kst); ++ if (unlikely(err)) ++ goto out; ++ err = -EINVAL; ++ if (kst.f_namelen >= NAME_MAX) ++ err = au_br_init_wh(sb, br, perm, h_dentry); ++ else ++ pr_err("%.*s(%s), unsupported namelen %ld\n", ++ AuDLNPair(h_dentry), au_sbtype(h_dentry->d_sb), ++ kst.f_namelen); ++ ++ out: ++ return err; ++} ++ ++/* intialize a new branch */ ++static int au_br_init(struct au_branch *br, struct super_block *sb, ++ struct au_opt_add *add) ++{ ++ int err; ++ ++ err = 0; ++ memset(&br->br_xino, 0, sizeof(br->br_xino)); ++ mutex_init(&br->br_xino.xi_nondir_mtx); ++ br->br_perm = add->perm; ++ br->br_mnt = add->path.mnt; /* set first, mntget() later */ ++ atomic_set(&br->br_count, 0); ++ br->br_xino_upper = AUFS_XINO_TRUNC_INIT; ++ atomic_set(&br->br_xino_running, 0); ++ br->br_id = au_new_br_id(sb); ++ ++ if (au_br_writable(add->perm)) { ++ err = au_wbr_init(br, sb, add->perm, &add->path); ++ if (unlikely(err)) ++ goto out; ++ } ++ ++ if (au_opt_test(au_mntflags(sb), XINO)) { ++ err = au_xino_br(sb, br, add->path.dentry->d_inode->i_ino, ++ au_sbr(sb, 0)->br_xino.xi_file, /*do_test*/1); ++ if (unlikely(err)) { ++ AuDebugOn(br->br_xino.xi_file); ++ goto out; ++ } ++ } ++ ++ sysaufs_br_init(br); ++ mntget(add->path.mnt); ++ ++ out: ++ return err; ++} ++ ++static void au_br_do_add_brp(struct au_sbinfo *sbinfo, aufs_bindex_t bindex, ++ struct au_branch *br, aufs_bindex_t bend, ++ aufs_bindex_t amount) ++{ ++ struct au_branch **brp; ++ ++ AuRwMustWriteLock(&sbinfo->si_rwsem); ++ ++ brp = sbinfo->si_branch + bindex; ++ memmove(brp + 1, brp, sizeof(*brp) * amount); ++ *brp = br; ++ sbinfo->si_bend++; ++ if (unlikely(bend < 0)) ++ sbinfo->si_bend = 0; ++} ++ ++static void au_br_do_add_hdp(struct au_dinfo *dinfo, aufs_bindex_t bindex, ++ aufs_bindex_t bend, aufs_bindex_t amount) ++{ ++ struct au_hdentry *hdp; ++ ++ AuRwMustWriteLock(&dinfo->di_rwsem); ++ ++ hdp = dinfo->di_hdentry + bindex; ++ memmove(hdp + 1, hdp, sizeof(*hdp) * amount); ++ au_h_dentry_init(hdp); ++ dinfo->di_bend++; ++ if (unlikely(bend < 0)) ++ dinfo->di_bstart = 0; ++} ++ ++static void au_br_do_add_hip(struct au_iinfo *iinfo, aufs_bindex_t bindex, ++ aufs_bindex_t bend, aufs_bindex_t amount) ++{ ++ struct au_hinode *hip; ++ ++ AuRwMustWriteLock(&iinfo->ii_rwsem); ++ ++ hip = iinfo->ii_hinode + bindex; ++ memmove(hip + 1, hip, sizeof(*hip) * amount); ++ hip->hi_inode = NULL; ++ au_hin_init(hip, NULL); ++ iinfo->ii_bend++; ++ if (unlikely(bend < 0)) ++ iinfo->ii_bstart = 0; ++} ++ ++static void au_br_do_add(struct super_block *sb, struct dentry *h_dentry, ++ struct au_branch *br, aufs_bindex_t bindex) ++{ ++ struct dentry *root; ++ struct inode *root_inode; ++ aufs_bindex_t bend, amount; ++ ++ root = sb->s_root; ++ root_inode = root->d_inode; ++ au_plink_maint_block(sb); ++ bend = au_sbend(sb); ++ amount = bend + 1 - bindex; ++ au_br_do_add_brp(au_sbi(sb), bindex, br, bend, amount); ++ au_br_do_add_hdp(au_di(root), bindex, bend, amount); ++ au_br_do_add_hip(au_ii(root_inode), bindex, bend, amount); ++ au_set_h_dptr(root, bindex, dget(h_dentry)); ++ au_set_h_iptr(root_inode, bindex, au_igrab(h_dentry->d_inode), ++ /*flags*/0); ++} ++ ++int au_br_add(struct super_block *sb, struct au_opt_add *add, int remount) ++{ ++ int err; ++ aufs_bindex_t bend, add_bindex; ++ struct dentry *root, *h_dentry; ++ struct inode *root_inode; ++ struct au_branch *add_branch; ++ ++ root = sb->s_root; ++ root_inode = root->d_inode; ++ IMustLock(root_inode); ++ err = test_add(sb, add, remount); ++ if (unlikely(err < 0)) ++ goto out; ++ if (err) { ++ err = 0; ++ goto out; /* success */ ++ } ++ ++ bend = au_sbend(sb); ++ add_branch = au_br_alloc(sb, bend + 2, add->perm); ++ err = PTR_ERR(add_branch); ++ if (IS_ERR(add_branch)) ++ goto out; ++ ++ err = au_br_init(add_branch, sb, add); ++ if (unlikely(err)) { ++ au_br_do_free(add_branch); ++ goto out; ++ } ++ ++ add_bindex = add->bindex; ++ h_dentry = add->path.dentry; ++ if (!remount) ++ au_br_do_add(sb, h_dentry, add_branch, add_bindex); ++ else { ++ sysaufs_brs_del(sb, add_bindex); ++ au_br_do_add(sb, h_dentry, add_branch, add_bindex); ++ sysaufs_brs_add(sb, add_bindex); ++ } ++ ++ if (!add_bindex) { ++ au_cpup_attr_all(root_inode, /*force*/1); ++ sb->s_maxbytes = h_dentry->d_sb->s_maxbytes; ++ } else ++ au_add_nlink(root_inode, h_dentry->d_inode); ++ ++ /* ++ * this test/set prevents aufs from handling unnecesary inotify events ++ * of xino files, in a case of re-adding a writable branch which was ++ * once detached from aufs. ++ */ ++ if (au_xino_brid(sb) < 0 ++ && au_br_writable(add_branch->br_perm) ++ && !au_test_fs_bad_xino(h_dentry->d_sb) ++ && add_branch->br_xino.xi_file ++ && add_branch->br_xino.xi_file->f_dentry->d_parent == h_dentry) ++ au_xino_brid_set(sb, add_branch->br_id); ++ ++ out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * delete a branch ++ */ ++ ++/* to show the line number, do not make it inlined function */ ++#define AuVerbose(do_info, fmt, ...) do { \ ++ if (do_info) \ ++ pr_info(fmt, ##__VA_ARGS__); \ ++} while (0) ++ ++/* ++ * test if the branch is deletable or not. ++ */ ++static int test_dentry_busy(struct dentry *root, aufs_bindex_t bindex, ++ unsigned int sigen) ++{ ++ int err, i, j, ndentry; ++ aufs_bindex_t bstart, bend; ++ unsigned char verbose; ++ struct au_dcsub_pages dpages; ++ struct au_dpage *dpage; ++ struct dentry *d; ++ struct inode *inode; ++ ++ err = au_dpages_init(&dpages, GFP_NOFS); ++ if (unlikely(err)) ++ goto out; ++ err = au_dcsub_pages(&dpages, root, NULL, NULL); ++ if (unlikely(err)) ++ goto out_dpages; ++ ++ verbose = !!au_opt_test(au_mntflags(root->d_sb), VERBOSE); ++ for (i = 0; !err && i < dpages.ndpage; i++) { ++ dpage = dpages.dpages + i; ++ ndentry = dpage->ndentry; ++ for (j = 0; !err && j < ndentry; j++) { ++ d = dpage->dentries[j]; ++ AuDebugOn(!atomic_read(&d->d_count)); ++ inode = d->d_inode; ++ if (au_digen(d) == sigen && au_iigen(inode) == sigen) ++ di_read_lock_child(d, AuLock_IR); ++ else { ++ di_write_lock_child(d); ++ err = au_reval_dpath(d, sigen); ++ if (!err) ++ di_downgrade_lock(d, AuLock_IR); ++ else { ++ di_write_unlock(d); ++ break; ++ } ++ } ++ ++ bstart = au_dbstart(d); ++ bend = au_dbend(d); ++ if (bstart <= bindex ++ && bindex <= bend ++ && au_h_dptr(d, bindex) ++ && (!S_ISDIR(inode->i_mode) || bstart == bend)) { ++ err = -EBUSY; ++ AuVerbose(verbose, "busy %.*s\n", AuDLNPair(d)); ++ } ++ di_read_unlock(d, AuLock_IR); ++ } ++ } ++ ++ out_dpages: ++ au_dpages_free(&dpages); ++ out: ++ return err; ++} ++ ++static int test_inode_busy(struct super_block *sb, aufs_bindex_t bindex, ++ unsigned int sigen) ++{ ++ int err; ++ struct inode *i; ++ aufs_bindex_t bstart, bend; ++ unsigned char verbose; ++ ++ err = 0; ++ verbose = !!au_opt_test(au_mntflags(sb), VERBOSE); ++ list_for_each_entry(i, &sb->s_inodes, i_sb_list) { ++ AuDebugOn(!atomic_read(&i->i_count)); ++ if (!list_empty(&i->i_dentry)) ++ continue; ++ ++ if (au_iigen(i) == sigen) ++ ii_read_lock_child(i); ++ else { ++ ii_write_lock_child(i); ++ err = au_refresh_hinode_self(i, /*do_attr*/1); ++ if (!err) ++ ii_downgrade_lock(i); ++ else { ++ ii_write_unlock(i); ++ break; ++ } ++ } ++ ++ bstart = au_ibstart(i); ++ bend = au_ibend(i); ++ if (bstart <= bindex ++ && bindex <= bend ++ && au_h_iptr(i, bindex) ++ && (!S_ISDIR(i->i_mode) || bstart == bend)) { ++ err = -EBUSY; ++ AuVerbose(verbose, "busy i%lu\n", i->i_ino); ++ ii_read_unlock(i); ++ break; ++ } ++ ii_read_unlock(i); ++ } ++ ++ return err; ++} ++ ++static int test_children_busy(struct dentry *root, aufs_bindex_t bindex) ++{ ++ int err; ++ unsigned int sigen; ++ ++ sigen = au_sigen(root->d_sb); ++ DiMustNoWaiters(root); ++ IiMustNoWaiters(root->d_inode); ++ di_write_unlock(root); ++ err = test_dentry_busy(root, bindex, sigen); ++ if (!err) ++ err = test_inode_busy(root->d_sb, bindex, sigen); ++ di_write_lock_child(root); /* aufs_write_lock() calls ..._child() */ ++ ++ return err; ++} ++ ++static void au_br_do_del_brp(struct au_sbinfo *sbinfo, ++ const aufs_bindex_t bindex, ++ const aufs_bindex_t bend) ++{ ++ struct au_branch **brp, **p; ++ ++ AuRwMustWriteLock(&sbinfo->si_rwsem); ++ ++ brp = sbinfo->si_branch + bindex; ++ if (bindex < bend) ++ memmove(brp, brp + 1, sizeof(*brp) * (bend - bindex)); ++ sbinfo->si_branch[0 + bend] = NULL; ++ sbinfo->si_bend--; ++ ++ p = krealloc(sbinfo->si_branch, sizeof(*p) * bend, GFP_NOFS); ++ if (p) ++ sbinfo->si_branch = p; ++ /* harmless error */ ++} ++ ++static void au_br_do_del_hdp(struct au_dinfo *dinfo, const aufs_bindex_t bindex, ++ const aufs_bindex_t bend) ++{ ++ struct au_hdentry *hdp, *p; ++ ++ AuRwMustWriteLock(&dinfo->di_rwsem); ++ ++ hdp = dinfo->di_hdentry + bindex; ++ if (bindex < bend) ++ memmove(hdp, hdp + 1, sizeof(*hdp) * (bend - bindex)); ++ dinfo->di_hdentry[0 + bend].hd_dentry = NULL; ++ dinfo->di_bend--; ++ ++ p = krealloc(dinfo->di_hdentry, sizeof(*p) * bend, GFP_NOFS); ++ if (p) ++ dinfo->di_hdentry = p; ++ /* harmless error */ ++} ++ ++static void au_br_do_del_hip(struct au_iinfo *iinfo, const aufs_bindex_t bindex, ++ const aufs_bindex_t bend) ++{ ++ struct au_hinode *hip, *p; ++ ++ AuRwMustWriteLock(&iinfo->ii_rwsem); ++ ++ hip = iinfo->ii_hinode + bindex; ++ if (bindex < bend) ++ memmove(hip, hip + 1, sizeof(*hip) * (bend - bindex)); ++ iinfo->ii_hinode[0 + bend].hi_inode = NULL; ++ au_hin_init(iinfo->ii_hinode + bend, NULL); ++ iinfo->ii_bend--; ++ ++ p = krealloc(iinfo->ii_hinode, sizeof(*p) * bend, GFP_NOFS); ++ if (p) ++ iinfo->ii_hinode = p; ++ /* harmless error */ ++} ++ ++static void au_br_do_del(struct super_block *sb, aufs_bindex_t bindex, ++ struct au_branch *br) ++{ ++ aufs_bindex_t bend; ++ struct au_sbinfo *sbinfo; ++ struct dentry *root; ++ struct inode *inode; ++ ++ SiMustWriteLock(sb); ++ ++ root = sb->s_root; ++ inode = root->d_inode; ++ au_plink_maint_block(sb); ++ sbinfo = au_sbi(sb); ++ bend = sbinfo->si_bend; ++ ++ dput(au_h_dptr(root, bindex)); ++ au_hiput(au_hi(inode, bindex)); ++ au_br_do_free(br); ++ ++ au_br_do_del_brp(sbinfo, bindex, bend); ++ au_br_do_del_hdp(au_di(root), bindex, bend); ++ au_br_do_del_hip(au_ii(inode), bindex, bend); ++} ++ ++int au_br_del(struct super_block *sb, struct au_opt_del *del, int remount) ++{ ++ int err, rerr, i; ++ unsigned int mnt_flags; ++ aufs_bindex_t bindex, bend, br_id; ++ unsigned char do_wh, verbose; ++ struct au_branch *br; ++ struct au_wbr *wbr; ++ ++ err = 0; ++ bindex = au_find_dbindex(sb->s_root, del->h_path.dentry); ++ if (bindex < 0) { ++ if (remount) ++ goto out; /* success */ ++ err = -ENOENT; ++ pr_err("%s no such branch\n", del->pathname); ++ goto out; ++ } ++ AuDbg("bindex b%d\n", bindex); ++ ++ err = -EBUSY; ++ mnt_flags = au_mntflags(sb); ++ verbose = !!au_opt_test(mnt_flags, VERBOSE); ++ bend = au_sbend(sb); ++ if (unlikely(!bend)) { ++ AuVerbose(verbose, "no more branches left\n"); ++ goto out; ++ } ++ br = au_sbr(sb, bindex); ++ i = atomic_read(&br->br_count); ++ if (unlikely(i)) { ++ AuVerbose(verbose, "%d file(s) opened\n", i); ++ goto out; ++ } ++ ++ wbr = br->br_wbr; ++ do_wh = wbr && (wbr->wbr_whbase || wbr->wbr_plink || wbr->wbr_orph); ++ if (do_wh) { ++ /* instead of WbrWhMustWriteLock(wbr) */ ++ SiMustWriteLock(sb); ++ for (i = 0; i < AuBrWh_Last; i++) { ++ dput(wbr->wbr_wh[i]); ++ wbr->wbr_wh[i] = NULL; ++ } ++ } ++ ++ err = test_children_busy(sb->s_root, bindex); ++ if (unlikely(err)) { ++ if (do_wh) ++ goto out_wh; ++ goto out; ++ } ++ ++ err = 0; ++ br_id = br->br_id; ++ if (!remount) ++ au_br_do_del(sb, bindex, br); ++ else { ++ sysaufs_brs_del(sb, bindex); ++ au_br_do_del(sb, bindex, br); ++ sysaufs_brs_add(sb, bindex); ++ } ++ ++ if (!bindex) { ++ au_cpup_attr_all(sb->s_root->d_inode, /*force*/1); ++ sb->s_maxbytes = au_sbr_sb(sb, 0)->s_maxbytes; ++ } else ++ au_sub_nlink(sb->s_root->d_inode, del->h_path.dentry->d_inode); ++ if (au_opt_test(mnt_flags, PLINK)) ++ au_plink_half_refresh(sb, br_id); ++ ++ if (au_xino_brid(sb) == br->br_id) ++ au_xino_brid_set(sb, -1); ++ goto out; /* success */ ++ ++ out_wh: ++ /* revert */ ++ rerr = au_br_init_wh(sb, br, br->br_perm, del->h_path.dentry); ++ if (rerr) ++ pr_warning("failed re-creating base whiteout, %s. (%d)\n", ++ del->pathname, rerr); ++ out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * change a branch permission ++ */ ++ ++static void au_warn_ima(void) ++{ ++#ifdef CONFIG_IMA ++ /* since it doesn't support mark_files_ro() */ ++ pr_warning("RW -> RO makes IMA to produce wrong message"); ++#endif ++} ++ ++static int do_need_sigen_inc(int a, int b) ++{ ++ return au_br_whable(a) && !au_br_whable(b); ++} ++ ++static int need_sigen_inc(int old, int new) ++{ ++ return do_need_sigen_inc(old, new) ++ || do_need_sigen_inc(new, old); ++} ++ ++static int au_br_mod_files_ro(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ int err; ++ unsigned long n, ul, bytes, files; ++ aufs_bindex_t bstart; ++ struct file *file, *hf, **a; ++ const int step_bytes = 1024, /* memory allocation unit */ ++ step_files = step_bytes / sizeof(*a); ++ ++ err = -ENOMEM; ++ n = 0; ++ bytes = step_bytes; ++ files = step_files; ++ a = kmalloc(bytes, GFP_NOFS); ++ if (unlikely(!a)) ++ goto out; ++ ++ /* no need file_list_lock() since sbinfo is locked? defered? */ ++ list_for_each_entry(file, &sb->s_files, f_u.fu_list) { ++ if (special_file(file->f_dentry->d_inode->i_mode)) ++ continue; ++ ++ AuDbg("%.*s\n", AuDLNPair(file->f_dentry)); ++ fi_read_lock(file); ++ if (unlikely(au_test_mmapped(file))) { ++ err = -EBUSY; ++ FiMustNoWaiters(file); ++ fi_read_unlock(file); ++ goto out_free; ++ } ++ ++ bstart = au_fbstart(file); ++ if (!S_ISREG(file->f_dentry->d_inode->i_mode) ++ || !(file->f_mode & FMODE_WRITE) ++ || bstart != bindex) { ++ FiMustNoWaiters(file); ++ fi_read_unlock(file); ++ continue; ++ } ++ ++ hf = au_h_fptr(file, bstart); ++ FiMustNoWaiters(file); ++ fi_read_unlock(file); ++ ++ if (n < files) ++ a[n++] = hf; ++ else { ++ void *p; ++ ++ err = -ENOMEM; ++ bytes += step_bytes; ++ files += step_files; ++ p = krealloc(a, bytes, GFP_NOFS); ++ if (p) { ++ a = p; ++ a[n++] = hf; ++ } else ++ goto out_free; ++ } ++ } ++ ++ err = 0; ++ if (n) ++ au_warn_ima(); ++ for (ul = 0; ul < n; ul++) { ++ /* todo: already flushed? */ ++ /* cf. fs/super.c:mark_files_ro() */ ++ hf = a[ul]; ++ hf->f_mode &= ~FMODE_WRITE; ++ if (!file_check_writeable(hf)) { ++ file_release_write(hf); ++ mnt_drop_write(hf->f_vfsmnt); ++ } ++ } ++ ++ out_free: ++ kfree(a); ++ out: ++ return err; ++} ++ ++int au_br_mod(struct super_block *sb, struct au_opt_mod *mod, int remount, ++ int *do_update) ++{ ++ int err, rerr; ++ aufs_bindex_t bindex; ++ struct path path; ++ struct dentry *root; ++ struct au_branch *br; ++ ++ root = sb->s_root; ++ au_plink_maint_block(sb); ++ bindex = au_find_dbindex(root, mod->h_root); ++ if (bindex < 0) { ++ if (remount) ++ return 0; /* success */ ++ err = -ENOENT; ++ pr_err("%s no such branch\n", mod->path); ++ goto out; ++ } ++ AuDbg("bindex b%d\n", bindex); ++ ++ err = test_br(mod->h_root->d_inode, mod->perm, mod->path); ++ if (unlikely(err)) ++ goto out; ++ ++ br = au_sbr(sb, bindex); ++ if (br->br_perm == mod->perm) ++ return 0; /* success */ ++ ++ if (au_br_writable(br->br_perm)) { ++ /* remove whiteout base */ ++ err = au_br_init_wh(sb, br, mod->perm, mod->h_root); ++ if (unlikely(err)) ++ goto out; ++ ++ if (!au_br_writable(mod->perm)) { ++ /* rw --> ro, file might be mmapped */ ++ DiMustNoWaiters(root); ++ IiMustNoWaiters(root->d_inode); ++ di_write_unlock(root); ++ err = au_br_mod_files_ro(sb, bindex); ++ /* aufs_write_lock() calls ..._child() */ ++ di_write_lock_child(root); ++ ++ if (unlikely(err)) { ++ rerr = -ENOMEM; ++ br->br_wbr = kmalloc(sizeof(*br->br_wbr), ++ GFP_NOFS); ++ if (br->br_wbr) { ++ path.mnt = br->br_mnt; ++ path.dentry = mod->h_root; ++ rerr = au_wbr_init(br, sb, br->br_perm, ++ &path); ++ } ++ if (unlikely(rerr)) { ++ AuIOErr("nested error %d (%d)\n", ++ rerr, err); ++ br->br_perm = mod->perm; ++ } ++ } ++ } ++ } else if (au_br_writable(mod->perm)) { ++ /* ro --> rw */ ++ err = -ENOMEM; ++ br->br_wbr = kmalloc(sizeof(*br->br_wbr), GFP_NOFS); ++ if (br->br_wbr) { ++ path.mnt = br->br_mnt; ++ path.dentry = mod->h_root; ++ err = au_wbr_init(br, sb, mod->perm, &path); ++ if (unlikely(err)) { ++ kfree(br->br_wbr); ++ br->br_wbr = NULL; ++ } ++ } ++ } ++ ++ if (!err) { ++ *do_update |= need_sigen_inc(br->br_perm, mod->perm); ++ br->br_perm = mod->perm; ++ } ++ ++ out: ++ return err; ++} +diff --git a/fs/aufs/branch.h b/fs/aufs/branch.h +new file mode 100644 +index 0000000..5e0e030 +--- /dev/null ++++ b/fs/aufs/branch.h +@@ -0,0 +1,219 @@ ++/* ++ * Copyright (C) 2005-2010 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* ++ * branch filesystems and xino for them ++ */ ++ ++#ifndef __AUFS_BRANCH_H__ ++#define __AUFS_BRANCH_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++#include ++#include "rwsem.h" ++#include "super.h" ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* a xino file */ ++struct au_xino_file { ++ struct file *xi_file; ++ struct mutex xi_nondir_mtx; ++ ++ /* todo: make xino files an array to support huge inode number */ ++ ++#ifdef CONFIG_DEBUG_FS ++ struct dentry *xi_dbgaufs; ++#endif ++}; ++ ++/* members for writable branch only */ ++enum {AuBrWh_BASE, AuBrWh_PLINK, AuBrWh_ORPH, AuBrWh_Last}; ++struct au_wbr { ++ struct au_rwsem wbr_wh_rwsem; ++ struct dentry *wbr_wh[AuBrWh_Last]; ++ atomic_t wbr_wh_running; ++#define wbr_whbase wbr_wh[AuBrWh_BASE] /* whiteout base */ ++#define wbr_plink wbr_wh[AuBrWh_PLINK] /* pseudo-link dir */ ++#define wbr_orph wbr_wh[AuBrWh_ORPH] /* dir for orphans */ ++ ++ /* mfs mode */ ++ unsigned long long wbr_bytes; ++}; ++ ++/* protected by superblock rwsem */ ++struct au_branch { ++ struct au_xino_file br_xino; ++ ++ aufs_bindex_t br_id; ++ ++ int br_perm; ++ struct vfsmount *br_mnt; ++ atomic_t br_count; ++ ++ struct au_wbr *br_wbr; ++ ++ /* xino truncation */ ++ blkcnt_t br_xino_upper; /* watermark in blocks */ ++ atomic_t br_xino_running; ++ ++#ifdef CONFIG_SYSFS ++ /* an entry under sysfs per mount-point */ ++ char br_name[8]; ++ struct attribute br_attr; ++#endif ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* branch permission and attribute */ ++enum { ++ AuBrPerm_RW, /* writable, linkable wh */ ++ AuBrPerm_RO, /* readonly, no wh */ ++ AuBrPerm_RR, /* natively readonly, no wh */ ++ ++ AuBrPerm_RWNoLinkWH, /* un-linkable whiteouts */ ++ ++ AuBrPerm_ROWH, /* whiteout-able */ ++ AuBrPerm_RRWH, /* whiteout-able */ ++ ++ AuBrPerm_Last ++}; ++ ++static inline int au_br_writable(int brperm) ++{ ++ return brperm == AuBrPerm_RW || brperm == AuBrPerm_RWNoLinkWH; ++} ++ ++static inline int au_br_whable(int brperm) ++{ ++ return brperm == AuBrPerm_RW ++ || brperm == AuBrPerm_ROWH ++ || brperm == AuBrPerm_RRWH; ++} ++ ++static inline int au_br_rdonly(struct au_branch *br) ++{ ++ return ((br->br_mnt->mnt_sb->s_flags & MS_RDONLY) ++ || !au_br_writable(br->br_perm)) ++ ? -EROFS : 0; ++} ++ ++static inline int au_br_hinotifyable(int brperm __maybe_unused) ++{ ++#ifdef CONFIG_AUFS_HINOTIFY ++ return brperm != AuBrPerm_RR && brperm != AuBrPerm_RRWH; ++#else ++ return 0; ++#endif ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* branch.c */ ++struct au_sbinfo; ++void au_br_free(struct au_sbinfo *sinfo); ++int au_br_index(struct super_block *sb, aufs_bindex_t br_id); ++struct au_opt_add; ++int au_br_add(struct super_block *sb, struct au_opt_add *add, int remount); ++struct au_opt_del; ++int au_br_del(struct super_block *sb, struct au_opt_del *del, int remount); ++struct au_opt_mod; ++int au_br_mod(struct super_block *sb, struct au_opt_mod *mod, int remount, ++ int *do_update); ++ ++/* xino.c */ ++static const loff_t au_loff_max = LLONG_MAX; ++ ++int au_xib_trunc(struct super_block *sb); ++ssize_t xino_fread(au_readf_t func, struct file *file, void *buf, size_t size, ++ loff_t *pos); ++ssize_t xino_fwrite(au_writef_t func, struct file *file, void *buf, size_t size, ++ loff_t *pos); ++struct file *au_xino_create2(struct file *base_file, struct file *copy_src); ++struct file *au_xino_create(struct super_block *sb, char *fname, int silent); ++ino_t au_xino_new_ino(struct super_block *sb); ++int au_xino_write0(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, ++ ino_t ino); ++int au_xino_write(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, ++ ino_t ino); ++int au_xino_read(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, ++ ino_t *ino); ++int au_xino_br(struct super_block *sb, struct au_branch *br, ino_t hino, ++ struct file *base_file, int do_test); ++int au_xino_trunc(struct super_block *sb, aufs_bindex_t bindex); ++ ++struct au_opt_xino; ++int au_xino_set(struct super_block *sb, struct au_opt_xino *xino, int remount); ++void au_xino_clr(struct super_block *sb); ++struct file *au_xino_def(struct super_block *sb); ++int au_xino_path(struct seq_file *seq, struct file *file); ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* Superblock to branch */ ++static inline ++aufs_bindex_t au_sbr_id(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ return au_sbr(sb, bindex)->br_id; ++} ++ ++static inline ++struct vfsmount *au_sbr_mnt(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ return au_sbr(sb, bindex)->br_mnt; ++} ++ ++static inline ++struct super_block *au_sbr_sb(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ return au_sbr_mnt(sb, bindex)->mnt_sb; ++} ++ ++static inline void au_sbr_put(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ atomic_dec_return(&au_sbr(sb, bindex)->br_count); ++} ++ ++static inline int au_sbr_perm(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ return au_sbr(sb, bindex)->br_perm; ++} ++ ++static inline int au_sbr_whable(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ return au_br_whable(au_sbr_perm(sb, bindex)); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * wbr_wh_read_lock, wbr_wh_write_lock ++ * wbr_wh_read_unlock, wbr_wh_write_unlock, wbr_wh_downgrade_lock ++ */ ++AuSimpleRwsemFuncs(wbr_wh, struct au_wbr *wbr, &wbr->wbr_wh_rwsem); ++ ++#define WbrWhMustNoWaiters(wbr) AuRwMustNoWaiters(&wbr->wbr_wh_rwsem) ++#define WbrWhMustAnyLock(wbr) AuRwMustAnyLock(&wbr->wbr_wh_rwsem) ++#define WbrWhMustWriteLock(wbr) AuRwMustWriteLock(&wbr->wbr_wh_rwsem) ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_BRANCH_H__ */ +diff --git a/fs/aufs/conf.mk b/fs/aufs/conf.mk +new file mode 100644 +index 0000000..13933ee +--- /dev/null ++++ b/fs/aufs/conf.mk +@@ -0,0 +1,33 @@ ++ ++AuConfStr = CONFIG_AUFS_FS=${CONFIG_AUFS_FS} ++ ++define AuConf ++ifdef ${1} ++AuConfStr += ${1}=${${1}} ++endif ++endef ++ ++$(foreach i, BRANCH_MAX_127 BRANCH_MAX_511 BRANCH_MAX_1023 BRANCH_MAX_32767 \ ++ HINOTIFY \ ++ EXPORT INO_T_64 \ ++ RDU \ ++ SP_IATTR \ ++ SHWH \ ++ BR_RAMFS \ ++ BR_FUSE POLL \ ++ BR_HFSPLUS \ ++ BDEV_LOOP \ ++ DEBUG MAGIC_SYSRQ, \ ++ $(eval $(call AuConf,CONFIG_AUFS_${i}))) ++ ++AuConfName = ${obj}/conf.str ++${AuConfName}.tmp: FORCE ++ @echo ${AuConfStr} | tr ' ' '\n' | sed -e 's/^/"/' -e 's/$$/\\n"/' > $@ ++${AuConfName}: ${AuConfName}.tmp ++ @diff -q $< $@ > /dev/null 2>&1 || { \ ++ echo ' GEN ' $@; \ ++ cp -p $< $@; \ ++ } ++FORCE: ++clean-files += ${AuConfName} ${AuConfName}.tmp ++${obj}/sysfs.o: ${AuConfName} +diff --git a/fs/aufs/cpup.c b/fs/aufs/cpup.c +new file mode 100644 +index 0000000..bdfebb8 +--- /dev/null ++++ b/fs/aufs/cpup.c +@@ -0,0 +1,1050 @@ ++/* ++ * Copyright (C) 2005-2010 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* ++ * copy-up functions, see wbr_policy.c for copy-down ++ */ ++ ++#include ++#include ++#include ++#include ++#include "aufs.h" ++ ++void au_cpup_attr_flags(struct inode *dst, struct inode *src) ++{ ++ const unsigned int mask = S_DEAD | S_SWAPFILE | S_PRIVATE ++ | S_NOATIME | S_NOCMTIME; ++ ++ dst->i_flags |= src->i_flags & ~mask; ++ if (au_test_fs_notime(dst->i_sb)) ++ dst->i_flags |= S_NOATIME | S_NOCMTIME; ++} ++ ++void au_cpup_attr_timesizes(struct inode *inode) ++{ ++ struct inode *h_inode; ++ ++ h_inode = au_h_iptr(inode, au_ibstart(inode)); ++ fsstack_copy_attr_times(inode, h_inode); ++ fsstack_copy_inode_size(inode, h_inode); ++} ++ ++void au_cpup_attr_nlink(struct inode *inode, int force) ++{ ++ struct inode *h_inode; ++ struct super_block *sb; ++ aufs_bindex_t bindex, bend; ++ ++ sb = inode->i_sb; ++ bindex = au_ibstart(inode); ++ h_inode = au_h_iptr(inode, bindex); ++ if (!force ++ && !S_ISDIR(h_inode->i_mode) ++ && au_opt_test(au_mntflags(sb), PLINK) ++ && au_plink_test(inode)) ++ return; ++ ++ inode->i_nlink = h_inode->i_nlink; ++ ++ /* ++ * fewer nlink makes find(1) noisy, but larger nlink doesn't. ++ * it may includes whplink directory. ++ */ ++ if (S_ISDIR(h_inode->i_mode)) { ++ bend = au_ibend(inode); ++ for (bindex++; bindex <= bend; bindex++) { ++ h_inode = au_h_iptr(inode, bindex); ++ if (h_inode) ++ au_add_nlink(inode, h_inode); ++ } ++ } ++} ++ ++void au_cpup_attr_changeable(struct inode *inode) ++{ ++ struct inode *h_inode; ++ ++ h_inode = au_h_iptr(inode, au_ibstart(inode)); ++ inode->i_mode = h_inode->i_mode; ++ inode->i_uid = h_inode->i_uid; ++ inode->i_gid = h_inode->i_gid; ++ au_cpup_attr_timesizes(inode); ++ au_cpup_attr_flags(inode, h_inode); ++} ++ ++void au_cpup_igen(struct inode *inode, struct inode *h_inode) ++{ ++ struct au_iinfo *iinfo = au_ii(inode); ++ ++ IiMustWriteLock(inode); ++ ++ iinfo->ii_higen = h_inode->i_generation; ++ iinfo->ii_hsb1 = h_inode->i_sb; ++} ++ ++void au_cpup_attr_all(struct inode *inode, int force) ++{ ++ struct inode *h_inode; ++ ++ h_inode = au_h_iptr(inode, au_ibstart(inode)); ++ au_cpup_attr_changeable(inode); ++ if (inode->i_nlink > 0) ++ au_cpup_attr_nlink(inode, force); ++ inode->i_rdev = h_inode->i_rdev; ++ inode->i_blkbits = h_inode->i_blkbits; ++ au_cpup_igen(inode, h_inode); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* Note: dt_dentry and dt_h_dentry are not dget/dput-ed */ ++ ++/* keep the timestamps of the parent dir when cpup */ ++void au_dtime_store(struct au_dtime *dt, struct dentry *dentry, ++ struct path *h_path) ++{ ++ struct inode *h_inode; ++ ++ dt->dt_dentry = dentry; ++ dt->dt_h_path = *h_path; ++ h_inode = h_path->dentry->d_inode; ++ dt->dt_atime = h_inode->i_atime; ++ dt->dt_mtime = h_inode->i_mtime; ++ /* smp_mb(); */ ++} ++ ++void au_dtime_revert(struct au_dtime *dt) ++{ ++ struct iattr attr; ++ int err; ++ ++ attr.ia_atime = dt->dt_atime; ++ attr.ia_mtime = dt->dt_mtime; ++ attr.ia_valid = ATTR_FORCE | ATTR_MTIME | ATTR_MTIME_SET ++ | ATTR_ATIME | ATTR_ATIME_SET; ++ ++ err = vfsub_notify_change(&dt->dt_h_path, &attr); ++ if (unlikely(err)) ++ pr_warning("restoring timestamps failed(%d). ignored\n", err); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static noinline_for_stack ++int cpup_iattr(struct dentry *dst, aufs_bindex_t bindex, struct dentry *h_src) ++{ ++ int err, sbits; ++ struct iattr ia; ++ struct path h_path; ++ struct inode *h_isrc, *h_idst; ++ ++ h_path.dentry = au_h_dptr(dst, bindex); ++ h_idst = h_path.dentry->d_inode; ++ h_path.mnt = au_sbr_mnt(dst->d_sb, bindex); ++ h_isrc = h_src->d_inode; ++ ia.ia_valid = ATTR_FORCE | ATTR_UID | ATTR_GID ++ | ATTR_ATIME | ATTR_MTIME ++ | ATTR_ATIME_SET | ATTR_MTIME_SET; ++ ia.ia_uid = h_isrc->i_uid; ++ ia.ia_gid = h_isrc->i_gid; ++ ia.ia_atime = h_isrc->i_atime; ++ ia.ia_mtime = h_isrc->i_mtime; ++ if (h_idst->i_mode != h_isrc->i_mode ++ && !S_ISLNK(h_idst->i_mode)) { ++ ia.ia_valid |= ATTR_MODE; ++ ia.ia_mode = h_isrc->i_mode; ++ } ++ sbits = !!(h_isrc->i_mode & (S_ISUID | S_ISGID)); ++ au_cpup_attr_flags(h_idst, h_isrc); ++ err = vfsub_notify_change(&h_path, &ia); ++ ++ /* is this nfs only? */ ++ if (!err && sbits && au_test_nfs(h_path.dentry->d_sb)) { ++ ia.ia_valid = ATTR_FORCE | ATTR_MODE; ++ ia.ia_mode = h_isrc->i_mode; ++ err = vfsub_notify_change(&h_path, &ia); ++ } ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_do_copy_file(struct file *dst, struct file *src, loff_t len, ++ char *buf, unsigned long blksize) ++{ ++ int err; ++ size_t sz, rbytes, wbytes; ++ unsigned char all_zero; ++ char *p, *zp; ++ struct mutex *h_mtx; ++ /* reduce stack usage */ ++ struct iattr *ia; ++ ++ zp = page_address(ZERO_PAGE(0)); ++ if (unlikely(!zp)) ++ return -ENOMEM; /* possible? */ ++ ++ err = 0; ++ all_zero = 0; ++ while (len) { ++ AuDbg("len %lld\n", len); ++ sz = blksize; ++ if (len < blksize) ++ sz = len; ++ ++ rbytes = 0; ++ /* todo: signal_pending? */ ++ while (!rbytes || err == -EAGAIN || err == -EINTR) { ++ rbytes = vfsub_read_k(src, buf, sz, &src->f_pos); ++ err = rbytes; ++ } ++ if (unlikely(err < 0)) ++ break; ++ ++ all_zero = 0; ++ if (len >= rbytes && rbytes == blksize) ++ all_zero = !memcmp(buf, zp, rbytes); ++ if (!all_zero) { ++ wbytes = rbytes; ++ p = buf; ++ while (wbytes) { ++ size_t b; ++ ++ b = vfsub_write_k(dst, p, wbytes, &dst->f_pos); ++ err = b; ++ /* todo: signal_pending? */ ++ if (unlikely(err == -EAGAIN || err == -EINTR)) ++ continue; ++ if (unlikely(err < 0)) ++ break; ++ wbytes -= b; ++ p += b; ++ } ++ } else { ++ loff_t res; ++ ++ AuLabel(hole); ++ res = vfsub_llseek(dst, rbytes, SEEK_CUR); ++ err = res; ++ if (unlikely(res < 0)) ++ break; ++ } ++ len -= rbytes; ++ err = 0; ++ } ++ ++ /* the last block may be a hole */ ++ if (!err && all_zero) { ++ AuLabel(last hole); ++ ++ err = 1; ++ if (au_test_nfs(dst->f_dentry->d_sb)) { ++ /* nfs requires this step to make last hole */ ++ /* is this only nfs? */ ++ do { ++ /* todo: signal_pending? */ ++ err = vfsub_write_k(dst, "\0", 1, &dst->f_pos); ++ } while (err == -EAGAIN || err == -EINTR); ++ if (err == 1) ++ dst->f_pos--; ++ } ++ ++ if (err == 1) { ++ ia = (void *)buf; ++ ia->ia_size = dst->f_pos; ++ ia->ia_valid = ATTR_SIZE | ATTR_FILE; ++ ia->ia_file = dst; ++ h_mtx = &dst->f_dentry->d_inode->i_mutex; ++ mutex_lock_nested(h_mtx, AuLsc_I_CHILD2); ++ err = vfsub_notify_change(&dst->f_path, ia); ++ mutex_unlock(h_mtx); ++ } ++ } ++ ++ return err; ++} ++ ++int au_copy_file(struct file *dst, struct file *src, loff_t len) ++{ ++ int err; ++ unsigned long blksize; ++ unsigned char do_kfree; ++ char *buf; ++ ++ err = -ENOMEM; ++ blksize = dst->f_dentry->d_sb->s_blocksize; ++ if (!blksize || PAGE_SIZE < blksize) ++ blksize = PAGE_SIZE; ++ AuDbg("blksize %lu\n", blksize); ++ do_kfree = (blksize != PAGE_SIZE && blksize >= sizeof(struct iattr *)); ++ if (do_kfree) ++ buf = kmalloc(blksize, GFP_NOFS); ++ else ++ buf = (void *)__get_free_page(GFP_NOFS); ++ if (unlikely(!buf)) ++ goto out; ++ ++ if (len > (1 << 22)) ++ AuDbg("copying a large file %lld\n", (long long)len); ++ ++ src->f_pos = 0; ++ dst->f_pos = 0; ++ err = au_do_copy_file(dst, src, len, buf, blksize); ++ if (do_kfree) ++ kfree(buf); ++ else ++ free_page((unsigned long)buf); ++ ++ out: ++ return err; ++} ++ ++/* ++ * to support a sparse file which is opened with O_APPEND, ++ * we need to close the file. ++ */ ++static int au_cp_regular(struct dentry *dentry, aufs_bindex_t bdst, ++ aufs_bindex_t bsrc, loff_t len) ++{ ++ int err, i; ++ enum { SRC, DST }; ++ struct { ++ aufs_bindex_t bindex; ++ unsigned int flags; ++ struct dentry *dentry; ++ struct file *file; ++ void *label, *label_file; ++ } *f, file[] = { ++ { ++ .bindex = bsrc, ++ .flags = O_RDONLY | O_NOATIME | O_LARGEFILE, ++ .file = NULL, ++ .label = &&out, ++ .label_file = &&out_src ++ }, ++ { ++ .bindex = bdst, ++ .flags = O_WRONLY | O_NOATIME | O_LARGEFILE, ++ .file = NULL, ++ .label = &&out_src, ++ .label_file = &&out_dst ++ } ++ }; ++ struct super_block *sb; ++ ++ /* bsrc branch can be ro/rw. */ ++ sb = dentry->d_sb; ++ f = file; ++ for (i = 0; i < 2; i++, f++) { ++ f->dentry = au_h_dptr(dentry, f->bindex); ++ f->file = au_h_open(dentry, f->bindex, f->flags, /*file*/NULL); ++ err = PTR_ERR(f->file); ++ if (IS_ERR(f->file)) ++ goto *f->label; ++ err = -EINVAL; ++ if (unlikely(!f->file->f_op)) ++ goto *f->label_file; ++ } ++ ++ /* try stopping to update while we copyup */ ++ IMustLock(file[SRC].dentry->d_inode); ++ err = au_copy_file(file[DST].file, file[SRC].file, len); ++ ++ out_dst: ++ fput(file[DST].file); ++ au_sbr_put(sb, file[DST].bindex); ++ out_src: ++ fput(file[SRC].file); ++ au_sbr_put(sb, file[SRC].bindex); ++ out: ++ return err; ++} ++ ++static int au_do_cpup_regular(struct dentry *dentry, aufs_bindex_t bdst, ++ aufs_bindex_t bsrc, loff_t len, ++ struct inode *h_dir, struct path *h_path) ++{ ++ int err, rerr; ++ loff_t l; ++ ++ err = 0; ++ l = i_size_read(au_h_iptr(dentry->d_inode, bsrc)); ++ if (len == -1 || l < len) ++ len = l; ++ if (len) ++ err = au_cp_regular(dentry, bdst, bsrc, len); ++ if (!err) ++ goto out; /* success */ ++ ++ rerr = vfsub_unlink(h_dir, h_path, /*force*/0); ++ if (rerr) { ++ AuIOErr("failed unlinking cpup-ed %.*s(%d, %d)\n", ++ AuDLNPair(h_path->dentry), err, rerr); ++ err = -EIO; ++ } ++ ++ out: ++ return err; ++} ++ ++static int au_do_cpup_symlink(struct path *h_path, struct dentry *h_src, ++ struct inode *h_dir) ++{ ++ int err, symlen; ++ mm_segment_t old_fs; ++ char *sym; ++ ++ err = -ENOSYS; ++ if (unlikely(!h_src->d_inode->i_op->readlink)) ++ goto out; ++ ++ err = -ENOMEM; ++ sym = __getname(); ++ if (unlikely(!sym)) ++ goto out; ++ ++ old_fs = get_fs(); ++ set_fs(KERNEL_DS); ++ symlen = h_src->d_inode->i_op->readlink(h_src, (char __user *)sym, ++ PATH_MAX); ++ err = symlen; ++ set_fs(old_fs); ++ ++ if (symlen > 0) { ++ sym[symlen] = 0; ++ err = vfsub_symlink(h_dir, h_path, sym); ++ } ++ __putname(sym); ++ ++ out: ++ return err; ++} ++ ++/* return with the lower dst inode is locked */ ++static noinline_for_stack ++int cpup_entry(struct dentry *dentry, aufs_bindex_t bdst, ++ aufs_bindex_t bsrc, loff_t len, unsigned int flags, ++ struct dentry *dst_parent) ++{ ++ int err; ++ umode_t mode; ++ unsigned int mnt_flags; ++ unsigned char isdir; ++ const unsigned char do_dt = !!au_ftest_cpup(flags, DTIME); ++ struct au_dtime dt; ++ struct path h_path; ++ struct dentry *h_src, *h_dst, *h_parent; ++ struct inode *h_inode, *h_dir; ++ struct super_block *sb; ++ ++ /* bsrc branch can be ro/rw. */ ++ h_src = au_h_dptr(dentry, bsrc); ++ h_inode = h_src->d_inode; ++ AuDebugOn(h_inode != au_h_iptr(dentry->d_inode, bsrc)); ++ ++ /* try stopping to be referenced while we are creating */ ++ h_dst = au_h_dptr(dentry, bdst); ++ h_parent = h_dst->d_parent; /* dir inode is locked */ ++ h_dir = h_parent->d_inode; ++ IMustLock(h_dir); ++ AuDebugOn(h_parent != h_dst->d_parent); ++ ++ sb = dentry->d_sb; ++ h_path.mnt = au_sbr_mnt(sb, bdst); ++ if (do_dt) { ++ h_path.dentry = h_parent; ++ au_dtime_store(&dt, dst_parent, &h_path); ++ } ++ h_path.dentry = h_dst; ++ ++ isdir = 0; ++ mode = h_inode->i_mode; ++ switch (mode & S_IFMT) { ++ case S_IFREG: ++ /* try stopping to update while we are referencing */ ++ IMustLock(h_inode); ++ err = vfsub_create(h_dir, &h_path, mode | S_IWUSR); ++ if (!err) ++ err = au_do_cpup_regular ++ (dentry, bdst, bsrc, len, ++ au_h_iptr(dst_parent->d_inode, bdst), &h_path); ++ break; ++ case S_IFDIR: ++ isdir = 1; ++ err = vfsub_mkdir(h_dir, &h_path, mode); ++ if (!err) { ++ /* ++ * strange behaviour from the users view, ++ * particularry setattr case ++ */ ++ if (au_ibstart(dst_parent->d_inode) == bdst) ++ au_cpup_attr_nlink(dst_parent->d_inode, ++ /*force*/1); ++ au_cpup_attr_nlink(dentry->d_inode, /*force*/1); ++ } ++ break; ++ case S_IFLNK: ++ err = au_do_cpup_symlink(&h_path, h_src, h_dir); ++ break; ++ case S_IFCHR: ++ case S_IFBLK: ++ AuDebugOn(!capable(CAP_MKNOD)); ++ /*FALLTHROUGH*/ ++ case S_IFIFO: ++ case S_IFSOCK: ++ err = vfsub_mknod(h_dir, &h_path, mode, h_inode->i_rdev); ++ break; ++ default: ++ AuIOErr("Unknown inode type 0%o\n", mode); ++ err = -EIO; ++ } ++ ++ mnt_flags = au_mntflags(sb); ++ if (!au_opt_test(mnt_flags, UDBA_NONE) ++ && !isdir ++ && au_opt_test(mnt_flags, XINO) ++ && h_inode->i_nlink == 1 ++ /* todo: unnecessary? */ ++ /* && dentry->d_inode->i_nlink == 1 */ ++ && bdst < bsrc ++ && !au_ftest_cpup(flags, KEEPLINO)) ++ au_xino_write(sb, bsrc, h_inode->i_ino, /*ino*/0); ++ /* ignore this error */ ++ ++ if (do_dt) ++ au_dtime_revert(&dt); ++ return err; ++} ++ ++/* ++ * copyup the @dentry from @bsrc to @bdst. ++ * the caller must set the both of lower dentries. ++ * @len is for truncating when it is -1 copyup the entire file. ++ * in link/rename cases, @dst_parent may be different from the real one. ++ */ ++static int au_cpup_single(struct dentry *dentry, aufs_bindex_t bdst, ++ aufs_bindex_t bsrc, loff_t len, unsigned int flags, ++ struct dentry *dst_parent) ++{ ++ int err, rerr; ++ aufs_bindex_t old_ibstart; ++ unsigned char isdir, plink; ++ struct au_dtime dt; ++ struct path h_path; ++ struct dentry *h_src, *h_dst, *h_parent; ++ struct inode *dst_inode, *h_dir, *inode; ++ struct super_block *sb; ++ ++ AuDebugOn(bsrc <= bdst); ++ ++ sb = dentry->d_sb; ++ h_path.mnt = au_sbr_mnt(sb, bdst); ++ h_dst = au_h_dptr(dentry, bdst); ++ h_parent = h_dst->d_parent; /* dir inode is locked */ ++ h_dir = h_parent->d_inode; ++ IMustLock(h_dir); ++ ++ h_src = au_h_dptr(dentry, bsrc); ++ inode = dentry->d_inode; ++ ++ if (!dst_parent) ++ dst_parent = dget_parent(dentry); ++ else ++ dget(dst_parent); ++ ++ plink = !!au_opt_test(au_mntflags(sb), PLINK); ++ dst_inode = au_h_iptr(inode, bdst); ++ if (dst_inode) { ++ if (unlikely(!plink)) { ++ err = -EIO; ++ AuIOErr("i%lu exists on a upper branch " ++ "but plink is disabled\n", inode->i_ino); ++ goto out; ++ } ++ ++ if (dst_inode->i_nlink) { ++ const int do_dt = au_ftest_cpup(flags, DTIME); ++ ++ h_src = au_plink_lkup(inode, bdst); ++ err = PTR_ERR(h_src); ++ if (IS_ERR(h_src)) ++ goto out; ++ if (unlikely(!h_src->d_inode)) { ++ err = -EIO; ++ AuIOErr("i%lu exists on a upper branch " ++ "but plink is broken\n", inode->i_ino); ++ dput(h_src); ++ goto out; ++ } ++ ++ if (do_dt) { ++ h_path.dentry = h_parent; ++ au_dtime_store(&dt, dst_parent, &h_path); ++ } ++ h_path.dentry = h_dst; ++ err = vfsub_link(h_src, h_dir, &h_path); ++ if (do_dt) ++ au_dtime_revert(&dt); ++ dput(h_src); ++ goto out; ++ } else ++ /* todo: cpup_wh_file? */ ++ /* udba work */ ++ au_update_brange(inode, 1); ++ } ++ ++ old_ibstart = au_ibstart(inode); ++ err = cpup_entry(dentry, bdst, bsrc, len, flags, dst_parent); ++ if (unlikely(err)) ++ goto out; ++ dst_inode = h_dst->d_inode; ++ mutex_lock_nested(&dst_inode->i_mutex, AuLsc_I_CHILD2); ++ ++ err = cpup_iattr(dentry, bdst, h_src); ++ isdir = S_ISDIR(dst_inode->i_mode); ++ if (!err) { ++ if (bdst < old_ibstart) ++ au_set_ibstart(inode, bdst); ++ au_set_h_iptr(inode, bdst, au_igrab(dst_inode), ++ au_hi_flags(inode, isdir)); ++ mutex_unlock(&dst_inode->i_mutex); ++ if (!isdir ++ && h_src->d_inode->i_nlink > 1 ++ && plink) ++ au_plink_append(inode, bdst, h_dst); ++ goto out; /* success */ ++ } ++ ++ /* revert */ ++ h_path.dentry = h_parent; ++ mutex_unlock(&dst_inode->i_mutex); ++ au_dtime_store(&dt, dst_parent, &h_path); ++ h_path.dentry = h_dst; ++ if (!isdir) ++ rerr = vfsub_unlink(h_dir, &h_path, /*force*/0); ++ else ++ rerr = vfsub_rmdir(h_dir, &h_path); ++ au_dtime_revert(&dt); ++ if (rerr) { ++ AuIOErr("failed removing broken entry(%d, %d)\n", err, rerr); ++ err = -EIO; ++ } ++ ++ out: ++ dput(dst_parent); ++ return err; ++} ++ ++struct au_cpup_single_args { ++ int *errp; ++ struct dentry *dentry; ++ aufs_bindex_t bdst, bsrc; ++ loff_t len; ++ unsigned int flags; ++ struct dentry *dst_parent; ++}; ++ ++static void au_call_cpup_single(void *args) ++{ ++ struct au_cpup_single_args *a = args; ++ *a->errp = au_cpup_single(a->dentry, a->bdst, a->bsrc, a->len, ++ a->flags, a->dst_parent); ++} ++ ++int au_sio_cpup_single(struct dentry *dentry, aufs_bindex_t bdst, ++ aufs_bindex_t bsrc, loff_t len, unsigned int flags, ++ struct dentry *dst_parent) ++{ ++ int err, wkq_err; ++ umode_t mode; ++ struct dentry *h_dentry; ++ ++ h_dentry = au_h_dptr(dentry, bsrc); ++ mode = h_dentry->d_inode->i_mode & S_IFMT; ++ if ((mode != S_IFCHR && mode != S_IFBLK) ++ || capable(CAP_MKNOD)) ++ err = au_cpup_single(dentry, bdst, bsrc, len, flags, ++ dst_parent); ++ else { ++ struct au_cpup_single_args args = { ++ .errp = &err, ++ .dentry = dentry, ++ .bdst = bdst, ++ .bsrc = bsrc, ++ .len = len, ++ .flags = flags, ++ .dst_parent = dst_parent ++ }; ++ wkq_err = au_wkq_wait(au_call_cpup_single, &args); ++ if (unlikely(wkq_err)) ++ err = wkq_err; ++ } ++ ++ return err; ++} ++ ++/* ++ * copyup the @dentry from the first active lower branch to @bdst, ++ * using au_cpup_single(). ++ */ ++static int au_cpup_simple(struct dentry *dentry, aufs_bindex_t bdst, loff_t len, ++ unsigned int flags) ++{ ++ int err; ++ aufs_bindex_t bsrc, bend; ++ ++ bend = au_dbend(dentry); ++ for (bsrc = bdst + 1; bsrc <= bend; bsrc++) ++ if (au_h_dptr(dentry, bsrc)) ++ break; ++ ++ err = au_lkup_neg(dentry, bdst); ++ if (!err) { ++ err = au_cpup_single(dentry, bdst, bsrc, len, flags, NULL); ++ if (!err) ++ return 0; /* success */ ++ ++ /* revert */ ++ au_set_h_dptr(dentry, bdst, NULL); ++ au_set_dbstart(dentry, bsrc); ++ } ++ ++ return err; ++} ++ ++struct au_cpup_simple_args { ++ int *errp; ++ struct dentry *dentry; ++ aufs_bindex_t bdst; ++ loff_t len; ++ unsigned int flags; ++}; ++ ++static void au_call_cpup_simple(void *args) ++{ ++ struct au_cpup_simple_args *a = args; ++ *a->errp = au_cpup_simple(a->dentry, a->bdst, a->len, a->flags); ++} ++ ++int au_sio_cpup_simple(struct dentry *dentry, aufs_bindex_t bdst, loff_t len, ++ unsigned int flags) ++{ ++ int err, wkq_err; ++ unsigned char do_sio; ++ struct dentry *parent; ++ struct inode *h_dir; ++ ++ parent = dget_parent(dentry); ++ h_dir = au_h_iptr(parent->d_inode, bdst); ++ do_sio = !!au_test_h_perm_sio(h_dir, MAY_EXEC | MAY_WRITE); ++ if (!do_sio) { ++ /* ++ * testing CAP_MKNOD is for generic fs, ++ * but CAP_FSETID is for xfs only, currently. ++ */ ++ umode_t mode = dentry->d_inode->i_mode; ++ do_sio = (((mode & (S_IFCHR | S_IFBLK)) ++ && !capable(CAP_MKNOD)) ++ || ((mode & (S_ISUID | S_ISGID)) ++ && !capable(CAP_FSETID))); ++ } ++ if (!do_sio) ++ err = au_cpup_simple(dentry, bdst, len, flags); ++ else { ++ struct au_cpup_simple_args args = { ++ .errp = &err, ++ .dentry = dentry, ++ .bdst = bdst, ++ .len = len, ++ .flags = flags ++ }; ++ wkq_err = au_wkq_wait(au_call_cpup_simple, &args); ++ if (unlikely(wkq_err)) ++ err = wkq_err; ++ } ++ ++ dput(parent); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * copyup the deleted file for writing. ++ */ ++static int au_do_cpup_wh(struct dentry *dentry, aufs_bindex_t bdst, ++ struct dentry *wh_dentry, struct file *file, ++ loff_t len) ++{ ++ int err; ++ aufs_bindex_t bstart; ++ struct au_dinfo *dinfo; ++ struct dentry *h_d_dst, *h_d_start; ++ ++ dinfo = au_di(dentry); ++ AuRwMustWriteLock(&dinfo->di_rwsem); ++ ++ bstart = dinfo->di_bstart; ++ h_d_dst = dinfo->di_hdentry[0 + bdst].hd_dentry; ++ dinfo->di_bstart = bdst; ++ dinfo->di_hdentry[0 + bdst].hd_dentry = wh_dentry; ++ h_d_start = dinfo->di_hdentry[0 + bstart].hd_dentry; ++ if (file) ++ dinfo->di_hdentry[0 + bstart].hd_dentry ++ = au_h_fptr(file, au_fbstart(file))->f_dentry; ++ err = au_cpup_single(dentry, bdst, bstart, len, !AuCpup_DTIME, ++ /*h_parent*/NULL); ++ if (!err && file) { ++ err = au_reopen_nondir(file); ++ dinfo->di_hdentry[0 + bstart].hd_dentry = h_d_start; ++ } ++ dinfo->di_hdentry[0 + bdst].hd_dentry = h_d_dst; ++ dinfo->di_bstart = bstart; ++ ++ return err; ++} ++ ++static int au_cpup_wh(struct dentry *dentry, aufs_bindex_t bdst, loff_t len, ++ struct file *file) ++{ ++ int err; ++ struct au_dtime dt; ++ struct dentry *parent, *h_parent, *wh_dentry; ++ struct au_branch *br; ++ struct path h_path; ++ ++ br = au_sbr(dentry->d_sb, bdst); ++ parent = dget_parent(dentry); ++ h_parent = au_h_dptr(parent, bdst); ++ wh_dentry = au_whtmp_lkup(h_parent, br, &dentry->d_name); ++ err = PTR_ERR(wh_dentry); ++ if (IS_ERR(wh_dentry)) ++ goto out; ++ ++ h_path.dentry = h_parent; ++ h_path.mnt = br->br_mnt; ++ au_dtime_store(&dt, parent, &h_path); ++ err = au_do_cpup_wh(dentry, bdst, wh_dentry, file, len); ++ if (unlikely(err)) ++ goto out_wh; ++ ++ dget(wh_dentry); ++ h_path.dentry = wh_dentry; ++ err = vfsub_unlink(h_parent->d_inode, &h_path, /*force*/0); ++ if (unlikely(err)) { ++ AuIOErr("failed remove copied-up tmp file %.*s(%d)\n", ++ AuDLNPair(wh_dentry), err); ++ err = -EIO; ++ } ++ au_dtime_revert(&dt); ++ au_set_hi_wh(dentry->d_inode, bdst, wh_dentry); ++ ++ out_wh: ++ dput(wh_dentry); ++ out: ++ dput(parent); ++ return err; ++} ++ ++struct au_cpup_wh_args { ++ int *errp; ++ struct dentry *dentry; ++ aufs_bindex_t bdst; ++ loff_t len; ++ struct file *file; ++}; ++ ++static void au_call_cpup_wh(void *args) ++{ ++ struct au_cpup_wh_args *a = args; ++ *a->errp = au_cpup_wh(a->dentry, a->bdst, a->len, a->file); ++} ++ ++int au_sio_cpup_wh(struct dentry *dentry, aufs_bindex_t bdst, loff_t len, ++ struct file *file) ++{ ++ int err, wkq_err; ++ struct dentry *parent, *h_orph, *h_parent, *h_dentry; ++ struct inode *dir, *h_dir, *h_tmpdir, *h_inode; ++ struct au_wbr *wbr; ++ ++ parent = dget_parent(dentry); ++ dir = parent->d_inode; ++ h_orph = NULL; ++ h_parent = NULL; ++ h_dir = au_igrab(au_h_iptr(dir, bdst)); ++ h_tmpdir = h_dir; ++ if (!h_dir->i_nlink) { ++ wbr = au_sbr(dentry->d_sb, bdst)->br_wbr; ++ h_orph = wbr->wbr_orph; ++ ++ h_parent = dget(au_h_dptr(parent, bdst)); ++ au_set_h_dptr(parent, bdst, NULL); ++ au_set_h_dptr(parent, bdst, dget(h_orph)); ++ h_tmpdir = h_orph->d_inode; ++ au_set_h_iptr(dir, bdst, NULL, 0); ++ au_set_h_iptr(dir, bdst, au_igrab(h_tmpdir), /*flags*/0); ++ ++ /* this temporary unlock is safe */ ++ if (file) ++ h_dentry = au_h_fptr(file, au_fbstart(file))->f_dentry; ++ else ++ h_dentry = au_h_dptr(dentry, au_dbstart(dentry)); ++ h_inode = h_dentry->d_inode; ++ IMustLock(h_inode); ++ mutex_unlock(&h_inode->i_mutex); ++ mutex_lock_nested(&h_tmpdir->i_mutex, AuLsc_I_PARENT3); ++ mutex_lock_nested(&h_inode->i_mutex, AuLsc_I_CHILD); ++ /* todo: au_h_open_pre()? */ ++ } ++ ++ if (!au_test_h_perm_sio(h_tmpdir, MAY_EXEC | MAY_WRITE)) ++ err = au_cpup_wh(dentry, bdst, len, file); ++ else { ++ struct au_cpup_wh_args args = { ++ .errp = &err, ++ .dentry = dentry, ++ .bdst = bdst, ++ .len = len, ++ .file = file ++ }; ++ wkq_err = au_wkq_wait(au_call_cpup_wh, &args); ++ if (unlikely(wkq_err)) ++ err = wkq_err; ++ } ++ ++ if (h_orph) { ++ mutex_unlock(&h_tmpdir->i_mutex); ++ /* todo: au_h_open_post()? */ ++ au_set_h_iptr(dir, bdst, NULL, 0); ++ au_set_h_iptr(dir, bdst, au_igrab(h_dir), /*flags*/0); ++ au_set_h_dptr(parent, bdst, NULL); ++ au_set_h_dptr(parent, bdst, h_parent); ++ } ++ iput(h_dir); ++ dput(parent); ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * generic routine for both of copy-up and copy-down. ++ */ ++/* cf. revalidate function in file.c */ ++int au_cp_dirs(struct dentry *dentry, aufs_bindex_t bdst, ++ int (*cp)(struct dentry *dentry, aufs_bindex_t bdst, ++ struct dentry *h_parent, void *arg), ++ void *arg) ++{ ++ int err; ++ struct au_pin pin; ++ struct dentry *d, *parent, *h_parent, *real_parent; ++ ++ err = 0; ++ parent = dget_parent(dentry); ++ if (IS_ROOT(parent)) ++ goto out; ++ ++ au_pin_init(&pin, dentry, bdst, AuLsc_DI_PARENT2, AuLsc_I_PARENT2, ++ au_opt_udba(dentry->d_sb), AuPin_MNT_WRITE); ++ ++ /* do not use au_dpage */ ++ real_parent = parent; ++ while (1) { ++ dput(parent); ++ parent = dget_parent(dentry); ++ h_parent = au_h_dptr(parent, bdst); ++ if (h_parent) ++ goto out; /* success */ ++ ++ /* find top dir which is necessary to cpup */ ++ do { ++ d = parent; ++ dput(parent); ++ parent = dget_parent(d); ++ di_read_lock_parent3(parent, !AuLock_IR); ++ h_parent = au_h_dptr(parent, bdst); ++ di_read_unlock(parent, !AuLock_IR); ++ } while (!h_parent); ++ ++ if (d != real_parent) ++ di_write_lock_child3(d); ++ ++ /* somebody else might create while we were sleeping */ ++ if (!au_h_dptr(d, bdst) || !au_h_dptr(d, bdst)->d_inode) { ++ if (au_h_dptr(d, bdst)) ++ au_update_dbstart(d); ++ ++ au_pin_set_dentry(&pin, d); ++ err = au_do_pin(&pin); ++ if (!err) { ++ err = cp(d, bdst, h_parent, arg); ++ au_unpin(&pin); ++ } ++ } ++ ++ if (d != real_parent) ++ di_write_unlock(d); ++ if (unlikely(err)) ++ break; ++ } ++ ++ out: ++ dput(parent); ++ return err; ++} ++ ++static int au_cpup_dir(struct dentry *dentry, aufs_bindex_t bdst, ++ struct dentry *h_parent __maybe_unused , ++ void *arg __maybe_unused) ++{ ++ return au_sio_cpup_simple(dentry, bdst, -1, AuCpup_DTIME); ++} ++ ++int au_cpup_dirs(struct dentry *dentry, aufs_bindex_t bdst) ++{ ++ return au_cp_dirs(dentry, bdst, au_cpup_dir, NULL); ++} ++ ++int au_test_and_cpup_dirs(struct dentry *dentry, aufs_bindex_t bdst) ++{ ++ int err; ++ struct dentry *parent; ++ struct inode *dir; ++ ++ parent = dget_parent(dentry); ++ dir = parent->d_inode; ++ err = 0; ++ if (au_h_iptr(dir, bdst)) ++ goto out; ++ ++ di_read_unlock(parent, AuLock_IR); ++ di_write_lock_parent(parent); ++ /* someone else might change our inode while we were sleeping */ ++ if (!au_h_iptr(dir, bdst)) ++ err = au_cpup_dirs(dentry, bdst); ++ di_downgrade_lock(parent, AuLock_IR); ++ ++ out: ++ dput(parent); ++ return err; ++} +diff --git a/fs/aufs/cpup.h b/fs/aufs/cpup.h +new file mode 100644 +index 0000000..506350d +--- /dev/null ++++ b/fs/aufs/cpup.h +@@ -0,0 +1,81 @@ ++/* ++ * Copyright (C) 2005-2010 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* ++ * copy-up/down functions ++ */ ++ ++#ifndef __AUFS_CPUP_H__ ++#define __AUFS_CPUP_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++#include ++ ++struct inode; ++struct file; ++ ++void au_cpup_attr_flags(struct inode *dst, struct inode *src); ++void au_cpup_attr_timesizes(struct inode *inode); ++void au_cpup_attr_nlink(struct inode *inode, int force); ++void au_cpup_attr_changeable(struct inode *inode); ++void au_cpup_igen(struct inode *inode, struct inode *h_inode); ++void au_cpup_attr_all(struct inode *inode, int force); ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* cpup flags */ ++#define AuCpup_DTIME 1 /* do dtime_store/revert */ ++#define AuCpup_KEEPLINO (1 << 1) /* do not clear the lower xino, ++ for link(2) */ ++#define au_ftest_cpup(flags, name) ((flags) & AuCpup_##name) ++#define au_fset_cpup(flags, name) { (flags) |= AuCpup_##name; } ++#define au_fclr_cpup(flags, name) { (flags) &= ~AuCpup_##name; } ++ ++int au_copy_file(struct file *dst, struct file *src, loff_t len); ++int au_sio_cpup_single(struct dentry *dentry, aufs_bindex_t bdst, ++ aufs_bindex_t bsrc, loff_t len, unsigned int flags, ++ struct dentry *dst_parent); ++int au_sio_cpup_simple(struct dentry *dentry, aufs_bindex_t bdst, loff_t len, ++ unsigned int flags); ++int au_sio_cpup_wh(struct dentry *dentry, aufs_bindex_t bdst, loff_t len, ++ struct file *file); ++ ++int au_cp_dirs(struct dentry *dentry, aufs_bindex_t bdst, ++ int (*cp)(struct dentry *dentry, aufs_bindex_t bdst, ++ struct dentry *h_parent, void *arg), ++ void *arg); ++int au_cpup_dirs(struct dentry *dentry, aufs_bindex_t bdst); ++int au_test_and_cpup_dirs(struct dentry *dentry, aufs_bindex_t bdst); ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* keep timestamps when copyup */ ++struct au_dtime { ++ struct dentry *dt_dentry; ++ struct path dt_h_path; ++ struct timespec dt_atime, dt_mtime; ++}; ++void au_dtime_store(struct au_dtime *dt, struct dentry *dentry, ++ struct path *h_path); ++void au_dtime_revert(struct au_dtime *dt); ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_CPUP_H__ */ +diff --git a/fs/aufs/dbgaufs.c b/fs/aufs/dbgaufs.c +new file mode 100644 +index 0000000..e69cbd3 +--- /dev/null ++++ b/fs/aufs/dbgaufs.c +@@ -0,0 +1,331 @@ ++/* ++ * Copyright (C) 2005-2010 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* ++ * debugfs interface ++ */ ++ ++#include ++#include "aufs.h" ++ ++#ifndef CONFIG_SYSFS ++#error DEBUG_FS depends upon SYSFS ++#endif ++ ++static struct dentry *dbgaufs; ++static const mode_t dbgaufs_mode = S_IRUSR | S_IRGRP | S_IROTH; ++ ++/* 20 is max digits length of ulong 64 */ ++struct dbgaufs_arg { ++ int n; ++ char a[20 * 4]; ++}; ++ ++/* ++ * common function for all XINO files ++ */ ++static int dbgaufs_xi_release(struct inode *inode __maybe_unused, ++ struct file *file) ++{ ++ kfree(file->private_data); ++ return 0; ++} ++ ++static int dbgaufs_xi_open(struct file *xf, struct file *file, int do_fcnt) ++{ ++ int err; ++ struct kstat st; ++ struct dbgaufs_arg *p; ++ ++ err = -ENOMEM; ++ p = kmalloc(sizeof(*p), GFP_NOFS); ++ if (unlikely(!p)) ++ goto out; ++ ++ err = 0; ++ p->n = 0; ++ file->private_data = p; ++ if (!xf) ++ goto out; ++ ++ err = vfs_getattr(xf->f_vfsmnt, xf->f_dentry, &st); ++ if (!err) { ++ if (do_fcnt) ++ p->n = snprintf ++ (p->a, sizeof(p->a), "%ld, %llux%lu %lld\n", ++ (long)file_count(xf), st.blocks, st.blksize, ++ (long long)st.size); ++ else ++ p->n = snprintf(p->a, sizeof(p->a), "%llux%lu %lld\n", ++ st.blocks, st.blksize, ++ (long long)st.size); ++ AuDebugOn(p->n >= sizeof(p->a)); ++ } else { ++ p->n = snprintf(p->a, sizeof(p->a), "err %d\n", err); ++ err = 0; ++ } ++ ++ out: ++ return err; ++ ++} ++ ++static ssize_t dbgaufs_xi_read(struct file *file, char __user *buf, ++ size_t count, loff_t *ppos) ++{ ++ struct dbgaufs_arg *p; ++ ++ p = file->private_data; ++ return simple_read_from_buffer(buf, count, ppos, p->a, p->n); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int dbgaufs_xib_open(struct inode *inode, struct file *file) ++{ ++ int err; ++ struct au_sbinfo *sbinfo; ++ struct super_block *sb; ++ ++ sbinfo = inode->i_private; ++ sb = sbinfo->si_sb; ++ si_noflush_read_lock(sb); ++ err = dbgaufs_xi_open(sbinfo->si_xib, file, /*do_fcnt*/0); ++ si_read_unlock(sb); ++ return err; ++} ++ ++static const struct file_operations dbgaufs_xib_fop = { ++ .open = dbgaufs_xib_open, ++ .release = dbgaufs_xi_release, ++ .read = dbgaufs_xi_read ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++#define DbgaufsXi_PREFIX "xi" ++ ++static int dbgaufs_xino_open(struct inode *inode, struct file *file) ++{ ++ int err; ++ long l; ++ struct au_sbinfo *sbinfo; ++ struct super_block *sb; ++ struct file *xf; ++ struct qstr *name; ++ ++ err = -ENOENT; ++ xf = NULL; ++ name = &file->f_dentry->d_name; ++ if (unlikely(name->len < sizeof(DbgaufsXi_PREFIX) ++ || memcmp(name->name, DbgaufsXi_PREFIX, ++ sizeof(DbgaufsXi_PREFIX) - 1))) ++ goto out; ++ err = strict_strtol(name->name + sizeof(DbgaufsXi_PREFIX) - 1, 10, &l); ++ if (unlikely(err)) ++ goto out; ++ ++ sbinfo = inode->i_private; ++ sb = sbinfo->si_sb; ++ si_noflush_read_lock(sb); ++ if (l <= au_sbend(sb)) { ++ xf = au_sbr(sb, (aufs_bindex_t)l)->br_xino.xi_file; ++ err = dbgaufs_xi_open(xf, file, /*do_fcnt*/1); ++ } else ++ err = -ENOENT; ++ si_read_unlock(sb); ++ ++ out: ++ return err; ++} ++ ++static const struct file_operations dbgaufs_xino_fop = { ++ .open = dbgaufs_xino_open, ++ .release = dbgaufs_xi_release, ++ .read = dbgaufs_xi_read ++}; ++ ++void dbgaufs_brs_del(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ aufs_bindex_t bend; ++ struct au_branch *br; ++ struct au_xino_file *xi; ++ ++ if (!au_sbi(sb)->si_dbgaufs) ++ return; ++ ++ bend = au_sbend(sb); ++ for (; bindex <= bend; bindex++) { ++ br = au_sbr(sb, bindex); ++ xi = &br->br_xino; ++ if (xi->xi_dbgaufs) { ++ debugfs_remove(xi->xi_dbgaufs); ++ xi->xi_dbgaufs = NULL; ++ } ++ } ++} ++ ++void dbgaufs_brs_add(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ struct au_sbinfo *sbinfo; ++ struct dentry *parent; ++ struct au_branch *br; ++ struct au_xino_file *xi; ++ aufs_bindex_t bend; ++ char name[sizeof(DbgaufsXi_PREFIX) + 5]; /* "xi" bindex NULL */ ++ ++ sbinfo = au_sbi(sb); ++ parent = sbinfo->si_dbgaufs; ++ if (!parent) ++ return; ++ ++ bend = au_sbend(sb); ++ for (; bindex <= bend; bindex++) { ++ snprintf(name, sizeof(name), DbgaufsXi_PREFIX "%d", bindex); ++ br = au_sbr(sb, bindex); ++ xi = &br->br_xino; ++ AuDebugOn(xi->xi_dbgaufs); ++ xi->xi_dbgaufs = debugfs_create_file(name, dbgaufs_mode, parent, ++ sbinfo, &dbgaufs_xino_fop); ++ /* ignore an error */ ++ if (unlikely(!xi->xi_dbgaufs)) ++ AuWarn1("failed %s under debugfs\n", name); ++ } ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++#ifdef CONFIG_AUFS_EXPORT ++static int dbgaufs_xigen_open(struct inode *inode, struct file *file) ++{ ++ int err; ++ struct au_sbinfo *sbinfo; ++ struct super_block *sb; ++ ++ sbinfo = inode->i_private; ++ sb = sbinfo->si_sb; ++ si_noflush_read_lock(sb); ++ err = dbgaufs_xi_open(sbinfo->si_xigen, file, /*do_fcnt*/0); ++ si_read_unlock(sb); ++ return err; ++} ++ ++static const struct file_operations dbgaufs_xigen_fop = { ++ .open = dbgaufs_xigen_open, ++ .release = dbgaufs_xi_release, ++ .read = dbgaufs_xi_read ++}; ++ ++static int dbgaufs_xigen_init(struct au_sbinfo *sbinfo) ++{ ++ int err; ++ ++ /* ++ * This function is a dynamic '__init' fucntion actually, ++ * so the tiny check for si_rwsem is unnecessary. ++ */ ++ /* AuRwMustWriteLock(&sbinfo->si_rwsem); */ ++ ++ err = -EIO; ++ sbinfo->si_dbgaufs_xigen = debugfs_create_file ++ ("xigen", dbgaufs_mode, sbinfo->si_dbgaufs, sbinfo, ++ &dbgaufs_xigen_fop); ++ if (sbinfo->si_dbgaufs_xigen) ++ err = 0; ++ ++ return err; ++} ++#else ++static int dbgaufs_xigen_init(struct au_sbinfo *sbinfo) ++{ ++ return 0; ++} ++#endif /* CONFIG_AUFS_EXPORT */ ++ ++/* ---------------------------------------------------------------------- */ ++ ++void dbgaufs_si_fin(struct au_sbinfo *sbinfo) ++{ ++ /* ++ * This function is a dynamic '__init' fucntion actually, ++ * so the tiny check for si_rwsem is unnecessary. ++ */ ++ /* AuRwMustWriteLock(&sbinfo->si_rwsem); */ ++ ++ debugfs_remove_recursive(sbinfo->si_dbgaufs); ++ sbinfo->si_dbgaufs = NULL; ++ kobject_put(&sbinfo->si_kobj); ++} ++ ++int dbgaufs_si_init(struct au_sbinfo *sbinfo) ++{ ++ int err; ++ char name[SysaufsSiNameLen]; ++ ++ /* ++ * This function is a dynamic '__init' fucntion actually, ++ * so the tiny check for si_rwsem is unnecessary. ++ */ ++ /* AuRwMustWriteLock(&sbinfo->si_rwsem); */ ++ ++ err = -ENOENT; ++ if (!dbgaufs) { ++ AuErr1("/debug/aufs is uninitialized\n"); ++ goto out; ++ } ++ ++ err = -EIO; ++ sysaufs_name(sbinfo, name); ++ sbinfo->si_dbgaufs = debugfs_create_dir(name, dbgaufs); ++ if (unlikely(!sbinfo->si_dbgaufs)) ++ goto out; ++ kobject_get(&sbinfo->si_kobj); ++ ++ sbinfo->si_dbgaufs_xib = debugfs_create_file ++ ("xib", dbgaufs_mode, sbinfo->si_dbgaufs, sbinfo, ++ &dbgaufs_xib_fop); ++ if (unlikely(!sbinfo->si_dbgaufs_xib)) ++ goto out_dir; ++ ++ err = dbgaufs_xigen_init(sbinfo); ++ if (!err) ++ goto out; /* success */ ++ ++ out_dir: ++ dbgaufs_si_fin(sbinfo); ++ out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void dbgaufs_fin(void) ++{ ++ debugfs_remove(dbgaufs); ++} ++ ++int __init dbgaufs_init(void) ++{ ++ int err; ++ ++ err = -EIO; ++ dbgaufs = debugfs_create_dir(AUFS_NAME, NULL); ++ if (dbgaufs) ++ err = 0; ++ return err; ++} +diff --git a/fs/aufs/dbgaufs.h b/fs/aufs/dbgaufs.h +new file mode 100644 +index 0000000..ae41480 +--- /dev/null ++++ b/fs/aufs/dbgaufs.h +@@ -0,0 +1,52 @@ ++/* ++ * Copyright (C) 2005-2010 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* ++ * debugfs interface ++ */ ++ ++#ifndef __DBGAUFS_H__ ++#define __DBGAUFS_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++ ++struct super_block; ++struct au_sbinfo; ++ ++#ifdef CONFIG_DEBUG_FS ++/* dbgaufs.c */ ++void dbgaufs_brs_del(struct super_block *sb, aufs_bindex_t bindex); ++void dbgaufs_brs_add(struct super_block *sb, aufs_bindex_t bindex); ++void dbgaufs_si_fin(struct au_sbinfo *sbinfo); ++int dbgaufs_si_init(struct au_sbinfo *sbinfo); ++void dbgaufs_fin(void); ++int __init dbgaufs_init(void); ++#else ++AuStubVoid(dbgaufs_brs_del, struct super_block *sb, aufs_bindex_t bindex) ++AuStubVoid(dbgaufs_brs_add, struct super_block *sb, aufs_bindex_t bindex) ++AuStubVoid(dbgaufs_si_fin, struct au_sbinfo *sbinfo) ++AuStubInt0(dbgaufs_si_init, struct au_sbinfo *sbinfo) ++AuStubVoid(dbgaufs_fin, void) ++AuStubInt0(__init dbgaufs_init, void) ++#endif /* CONFIG_DEBUG_FS */ ++ ++#endif /* __KERNEL__ */ ++#endif /* __DBGAUFS_H__ */ +diff --git a/fs/aufs/dcsub.c b/fs/aufs/dcsub.c +new file mode 100644 +index 0000000..e7ad06c +--- /dev/null ++++ b/fs/aufs/dcsub.c +@@ -0,0 +1,223 @@ ++/* ++ * Copyright (C) 2005-2010 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* ++ * sub-routines for dentry cache ++ */ ++ ++#include "aufs.h" ++ ++static void au_dpage_free(struct au_dpage *dpage) ++{ ++ int i; ++ struct dentry **p; ++ ++ p = dpage->dentries; ++ for (i = 0; i < dpage->ndentry; i++) ++ dput(*p++); ++ free_page((unsigned long)dpage->dentries); ++} ++ ++int au_dpages_init(struct au_dcsub_pages *dpages, gfp_t gfp) ++{ ++ int err; ++ void *p; ++ ++ err = -ENOMEM; ++ dpages->dpages = kmalloc(sizeof(*dpages->dpages), gfp); ++ if (unlikely(!dpages->dpages)) ++ goto out; ++ ++ p = (void *)__get_free_page(gfp); ++ if (unlikely(!p)) ++ goto out_dpages; ++ ++ dpages->dpages[0].ndentry = 0; ++ dpages->dpages[0].dentries = p; ++ dpages->ndpage = 1; ++ return 0; /* success */ ++ ++ out_dpages: ++ kfree(dpages->dpages); ++ out: ++ return err; ++} ++ ++void au_dpages_free(struct au_dcsub_pages *dpages) ++{ ++ int i; ++ struct au_dpage *p; ++ ++ p = dpages->dpages; ++ for (i = 0; i < dpages->ndpage; i++) ++ au_dpage_free(p++); ++ kfree(dpages->dpages); ++} ++ ++static int au_dpages_append(struct au_dcsub_pages *dpages, ++ struct dentry *dentry, gfp_t gfp) ++{ ++ int err, sz; ++ struct au_dpage *dpage; ++ void *p; ++ ++ dpage = dpages->dpages + dpages->ndpage - 1; ++ sz = PAGE_SIZE / sizeof(dentry); ++ if (unlikely(dpage->ndentry >= sz)) { ++ AuLabel(new dpage); ++ err = -ENOMEM; ++ sz = dpages->ndpage * sizeof(*dpages->dpages); ++ p = au_kzrealloc(dpages->dpages, sz, ++ sz + sizeof(*dpages->dpages), gfp); ++ if (unlikely(!p)) ++ goto out; ++ ++ dpages->dpages = p; ++ dpage = dpages->dpages + dpages->ndpage; ++ p = (void *)__get_free_page(gfp); ++ if (unlikely(!p)) ++ goto out; ++ ++ dpage->ndentry = 0; ++ dpage->dentries = p; ++ dpages->ndpage++; ++ } ++ ++ dpage->dentries[dpage->ndentry++] = dget(dentry); ++ return 0; /* success */ ++ ++ out: ++ return err; ++} ++ ++int au_dcsub_pages(struct au_dcsub_pages *dpages, struct dentry *root, ++ au_dpages_test test, void *arg) ++{ ++ int err; ++ struct dentry *this_parent = root; ++ struct list_head *next; ++ struct super_block *sb = root->d_sb; ++ ++ err = 0; ++ spin_lock(&dcache_lock); ++ repeat: ++ next = this_parent->d_subdirs.next; ++ resume: ++ if (this_parent->d_sb == sb ++ && !IS_ROOT(this_parent) ++ && atomic_read(&this_parent->d_count) ++ && this_parent->d_inode ++ && (!test || test(this_parent, arg))) { ++ err = au_dpages_append(dpages, this_parent, GFP_ATOMIC); ++ if (unlikely(err)) ++ goto out; ++ } ++ ++ while (next != &this_parent->d_subdirs) { ++ struct list_head *tmp = next; ++ struct dentry *dentry = list_entry(tmp, struct dentry, ++ d_u.d_child); ++ next = tmp->next; ++ if (/*d_unhashed(dentry) || */!dentry->d_inode) ++ continue; ++ if (!list_empty(&dentry->d_subdirs)) { ++ this_parent = dentry; ++ goto repeat; ++ } ++ if (dentry->d_sb == sb ++ && atomic_read(&dentry->d_count) ++ && (!test || test(dentry, arg))) { ++ err = au_dpages_append(dpages, dentry, GFP_ATOMIC); ++ if (unlikely(err)) ++ goto out; ++ } ++ } ++ ++ if (this_parent != root) { ++ next = this_parent->d_u.d_child.next; ++ this_parent = this_parent->d_parent; /* dcache_lock is locked */ ++ goto resume; ++ } ++ out: ++ spin_unlock(&dcache_lock); ++ return err; ++} ++ ++int au_dcsub_pages_rev(struct au_dcsub_pages *dpages, struct dentry *dentry, ++ int do_include, au_dpages_test test, void *arg) ++{ ++ int err; ++ ++ err = 0; ++ spin_lock(&dcache_lock); ++ if (do_include && (!test || test(dentry, arg))) { ++ err = au_dpages_append(dpages, dentry, GFP_ATOMIC); ++ if (unlikely(err)) ++ goto out; ++ } ++ while (!IS_ROOT(dentry)) { ++ dentry = dentry->d_parent; /* dcache_lock is locked */ ++ if (!test || test(dentry, arg)) { ++ err = au_dpages_append(dpages, dentry, GFP_ATOMIC); ++ if (unlikely(err)) ++ break; ++ } ++ } ++ ++ out: ++ spin_unlock(&dcache_lock); ++ ++ return err; ++} ++ ++struct dentry *au_test_subdir(struct dentry *d1, struct dentry *d2) ++{ ++ struct dentry *trap, **dentries; ++ int err, i, j; ++ struct au_dcsub_pages dpages; ++ struct au_dpage *dpage; ++ ++ trap = ERR_PTR(-ENOMEM); ++ err = au_dpages_init(&dpages, GFP_NOFS); ++ if (unlikely(err)) ++ goto out; ++ err = au_dcsub_pages_rev(&dpages, d1, /*do_include*/1, NULL, NULL); ++ if (unlikely(err)) ++ goto out_dpages; ++ ++ trap = d1; ++ for (i = 0; !err && i < dpages.ndpage; i++) { ++ dpage = dpages.dpages + i; ++ dentries = dpage->dentries; ++ for (j = 0; !err && j < dpage->ndentry; j++) { ++ struct dentry *d; ++ ++ d = dentries[j]; ++ err = (d == d2); ++ if (!err) ++ trap = d; ++ } ++ } ++ if (!err) ++ trap = NULL; ++ ++ out_dpages: ++ au_dpages_free(&dpages); ++ out: ++ return trap; ++} +diff --git a/fs/aufs/dcsub.h b/fs/aufs/dcsub.h +new file mode 100644 +index 0000000..469d3b4 +--- /dev/null ++++ b/fs/aufs/dcsub.h +@@ -0,0 +1,54 @@ ++/* ++ * Copyright (C) 2005-2010 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* ++ * sub-routines for dentry cache ++ */ ++ ++#ifndef __AUFS_DCSUB_H__ ++#define __AUFS_DCSUB_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++ ++struct dentry; ++ ++struct au_dpage { ++ int ndentry; ++ struct dentry **dentries; ++}; ++ ++struct au_dcsub_pages { ++ int ndpage; ++ struct au_dpage *dpages; ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_dpages_init(struct au_dcsub_pages *dpages, gfp_t gfp); ++void au_dpages_free(struct au_dcsub_pages *dpages); ++typedef int (*au_dpages_test)(struct dentry *dentry, void *arg); ++int au_dcsub_pages(struct au_dcsub_pages *dpages, struct dentry *root, ++ au_dpages_test test, void *arg); ++int au_dcsub_pages_rev(struct au_dcsub_pages *dpages, struct dentry *dentry, ++ int do_include, au_dpages_test test, void *arg); ++struct dentry *au_test_subdir(struct dentry *d1, struct dentry *d2); ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_DCSUB_H__ */ +diff --git a/fs/aufs/debug.c b/fs/aufs/debug.c +new file mode 100644 +index 0000000..87935e9 +--- /dev/null ++++ b/fs/aufs/debug.c +@@ -0,0 +1,432 @@ ++/* ++ * Copyright (C) 2005-2010 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* ++ * debug print functions ++ */ ++ ++#include ++#include ++#include "aufs.h" ++ ++int aufs_debug; ++MODULE_PARM_DESC(debug, "debug print"); ++module_param_named(debug, aufs_debug, int, S_IRUGO | S_IWUSR | S_IWGRP); ++ ++char *au_plevel = KERN_DEBUG; ++#define dpri(fmt, ...) do { \ ++ if (au_debug_test()) \ ++ printk("%s" fmt, au_plevel, ##__VA_ARGS__); \ ++} while (0) ++ ++/* ---------------------------------------------------------------------- */ ++ ++void au_dpri_whlist(struct au_nhash *whlist) ++{ ++ unsigned long ul, n; ++ struct hlist_head *head; ++ struct au_vdir_wh *tpos; ++ struct hlist_node *pos; ++ ++ n = whlist->nh_num; ++ head = whlist->nh_head; ++ for (ul = 0; ul < n; ul++) { ++ hlist_for_each_entry(tpos, pos, head, wh_hash) ++ dpri("b%d, %.*s, %d\n", ++ tpos->wh_bindex, ++ tpos->wh_str.len, tpos->wh_str.name, ++ tpos->wh_str.len); ++ head++; ++ } ++} ++ ++void au_dpri_vdir(struct au_vdir *vdir) ++{ ++ unsigned long ul; ++ union au_vdir_deblk_p p; ++ unsigned char *o; ++ ++ if (!vdir || IS_ERR(vdir)) { ++ dpri("err %ld\n", PTR_ERR(vdir)); ++ return; ++ } ++ ++ dpri("deblk %u, nblk %lu, deblk %p, last{%lu, %p}, ver %lu\n", ++ vdir->vd_deblk_sz, vdir->vd_nblk, vdir->vd_deblk, ++ vdir->vd_last.ul, vdir->vd_last.p.deblk, vdir->vd_version); ++ for (ul = 0; ul < vdir->vd_nblk; ul++) { ++ p.deblk = vdir->vd_deblk[ul]; ++ o = p.deblk; ++ dpri("[%lu]: %p\n", ul, o); ++ } ++} ++ ++static int do_pri_inode(aufs_bindex_t bindex, struct inode *inode, ++ struct dentry *wh) ++{ ++ char *n = NULL; ++ int l = 0; ++ ++ if (!inode || IS_ERR(inode)) { ++ dpri("i%d: err %ld\n", bindex, PTR_ERR(inode)); ++ return -1; ++ } ++ ++ /* the type of i_blocks depends upon CONFIG_LSF */ ++ BUILD_BUG_ON(sizeof(inode->i_blocks) != sizeof(unsigned long) ++ && sizeof(inode->i_blocks) != sizeof(u64)); ++ if (wh) { ++ n = (void *)wh->d_name.name; ++ l = wh->d_name.len; ++ } ++ ++ dpri("i%d: i%lu, %s, cnt %d, nl %u, 0%o, sz %llu, blk %llu," ++ " ct %lld, np %lu, st 0x%lx, f 0x%x, g %x%s%.*s\n", ++ bindex, ++ inode->i_ino, inode->i_sb ? au_sbtype(inode->i_sb) : "??", ++ atomic_read(&inode->i_count), inode->i_nlink, inode->i_mode, ++ i_size_read(inode), (unsigned long long)inode->i_blocks, ++ (long long)timespec_to_ns(&inode->i_ctime) & 0x0ffff, ++ inode->i_mapping ? inode->i_mapping->nrpages : 0, ++ inode->i_state, inode->i_flags, inode->i_generation, ++ l ? ", wh " : "", l, n); ++ return 0; ++} ++ ++void au_dpri_inode(struct inode *inode) ++{ ++ struct au_iinfo *iinfo; ++ aufs_bindex_t bindex; ++ int err; ++ ++ err = do_pri_inode(-1, inode, NULL); ++ if (err || !au_test_aufs(inode->i_sb)) ++ return; ++ ++ iinfo = au_ii(inode); ++ if (!iinfo) ++ return; ++ dpri("i-1: bstart %d, bend %d, gen %d\n", ++ iinfo->ii_bstart, iinfo->ii_bend, au_iigen(inode)); ++ if (iinfo->ii_bstart < 0) ++ return; ++ for (bindex = iinfo->ii_bstart; bindex <= iinfo->ii_bend; bindex++) ++ do_pri_inode(bindex, iinfo->ii_hinode[0 + bindex].hi_inode, ++ iinfo->ii_hinode[0 + bindex].hi_whdentry); ++} ++ ++static int do_pri_dentry(aufs_bindex_t bindex, struct dentry *dentry) ++{ ++ struct dentry *wh = NULL; ++ ++ if (!dentry || IS_ERR(dentry)) { ++ dpri("d%d: err %ld\n", bindex, PTR_ERR(dentry)); ++ return -1; ++ } ++ /* do not call dget_parent() here */ ++ dpri("d%d: %.*s?/%.*s, %s, cnt %d, flags 0x%x\n", ++ bindex, ++ AuDLNPair(dentry->d_parent), AuDLNPair(dentry), ++ dentry->d_sb ? au_sbtype(dentry->d_sb) : "??", ++ atomic_read(&dentry->d_count), dentry->d_flags); ++ if (bindex >= 0 && dentry->d_inode && au_test_aufs(dentry->d_sb)) { ++ struct au_iinfo *iinfo = au_ii(dentry->d_inode); ++ if (iinfo) ++ wh = iinfo->ii_hinode[0 + bindex].hi_whdentry; ++ } ++ do_pri_inode(bindex, dentry->d_inode, wh); ++ return 0; ++} ++ ++void au_dpri_dentry(struct dentry *dentry) ++{ ++ struct au_dinfo *dinfo; ++ aufs_bindex_t bindex; ++ int err; ++ ++ err = do_pri_dentry(-1, dentry); ++ if (err || !au_test_aufs(dentry->d_sb)) ++ return; ++ ++ dinfo = au_di(dentry); ++ if (!dinfo) ++ return; ++ dpri("d-1: bstart %d, bend %d, bwh %d, bdiropq %d, gen %d\n", ++ dinfo->di_bstart, dinfo->di_bend, ++ dinfo->di_bwh, dinfo->di_bdiropq, au_digen(dentry)); ++ if (dinfo->di_bstart < 0) ++ return; ++ for (bindex = dinfo->di_bstart; bindex <= dinfo->di_bend; bindex++) ++ do_pri_dentry(bindex, dinfo->di_hdentry[0 + bindex].hd_dentry); ++} ++ ++static int do_pri_file(aufs_bindex_t bindex, struct file *file) ++{ ++ char a[32]; ++ ++ if (!file || IS_ERR(file)) { ++ dpri("f%d: err %ld\n", bindex, PTR_ERR(file)); ++ return -1; ++ } ++ a[0] = 0; ++ if (bindex < 0 ++ && file->f_dentry ++ && au_test_aufs(file->f_dentry->d_sb) ++ && au_fi(file)) ++ snprintf(a, sizeof(a), ", mmapped %d", ++ !!au_fi(file)->fi_h_vm_ops); ++ dpri("f%d: mode 0x%x, flags 0%o, cnt %ld, pos %llu%s\n", ++ bindex, file->f_mode, file->f_flags, (long)file_count(file), ++ file->f_pos, a); ++ if (file->f_dentry) ++ do_pri_dentry(bindex, file->f_dentry); ++ return 0; ++} ++ ++void au_dpri_file(struct file *file) ++{ ++ struct au_finfo *finfo; ++ aufs_bindex_t bindex; ++ int err; ++ ++ err = do_pri_file(-1, file); ++ if (err || !file->f_dentry || !au_test_aufs(file->f_dentry->d_sb)) ++ return; ++ ++ finfo = au_fi(file); ++ if (!finfo) ++ return; ++ if (finfo->fi_bstart < 0) ++ return; ++ for (bindex = finfo->fi_bstart; bindex <= finfo->fi_bend; bindex++) { ++ struct au_hfile *hf; ++ ++ hf = finfo->fi_hfile + bindex; ++ do_pri_file(bindex, hf ? hf->hf_file : NULL); ++ } ++} ++ ++static int do_pri_br(aufs_bindex_t bindex, struct au_branch *br) ++{ ++ struct vfsmount *mnt; ++ struct super_block *sb; ++ ++ if (!br || IS_ERR(br)) ++ goto out; ++ mnt = br->br_mnt; ++ if (!mnt || IS_ERR(mnt)) ++ goto out; ++ sb = mnt->mnt_sb; ++ if (!sb || IS_ERR(sb)) ++ goto out; ++ ++ dpri("s%d: {perm 0x%x, cnt %d, wbr %p}, " ++ "%s, dev 0x%02x%02x, flags 0x%lx, cnt(BIAS) %d, active %d, " ++ "xino %d\n", ++ bindex, br->br_perm, atomic_read(&br->br_count), br->br_wbr, ++ au_sbtype(sb), MAJOR(sb->s_dev), MINOR(sb->s_dev), ++ sb->s_flags, sb->s_count - S_BIAS, ++ atomic_read(&sb->s_active), !!br->br_xino.xi_file); ++ return 0; ++ ++ out: ++ dpri("s%d: err %ld\n", bindex, PTR_ERR(br)); ++ return -1; ++} ++ ++void au_dpri_sb(struct super_block *sb) ++{ ++ struct au_sbinfo *sbinfo; ++ aufs_bindex_t bindex; ++ int err; ++ /* to reuduce stack size */ ++ struct { ++ struct vfsmount mnt; ++ struct au_branch fake; ++ } *a; ++ ++ /* this function can be called from magic sysrq */ ++ a = kzalloc(sizeof(*a), GFP_ATOMIC); ++ if (unlikely(!a)) { ++ dpri("no memory\n"); ++ return; ++ } ++ ++ a->mnt.mnt_sb = sb; ++ a->fake.br_perm = 0; ++ a->fake.br_mnt = &a->mnt; ++ a->fake.br_xino.xi_file = NULL; ++ atomic_set(&a->fake.br_count, 0); ++ smp_mb(); /* atomic_set */ ++ err = do_pri_br(-1, &a->fake); ++ kfree(a); ++ dpri("dev 0x%x\n", sb->s_dev); ++ if (err || !au_test_aufs(sb)) ++ return; ++ ++ sbinfo = au_sbi(sb); ++ if (!sbinfo) ++ return; ++ dpri("nw %d, gen %u, kobj %d\n", ++ atomic_read(&sbinfo->si_nowait.nw_len), sbinfo->si_generation, ++ atomic_read(&sbinfo->si_kobj.kref.refcount)); ++ for (bindex = 0; bindex <= sbinfo->si_bend; bindex++) ++ do_pri_br(bindex, sbinfo->si_branch[0 + bindex]); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void au_dbg_sleep_jiffy(int jiffy) ++{ ++ while (jiffy) ++ jiffy = schedule_timeout_uninterruptible(jiffy); ++} ++ ++void au_dbg_iattr(struct iattr *ia) ++{ ++#define AuBit(name) if (ia->ia_valid & ATTR_ ## name) \ ++ dpri(#name "\n") ++ AuBit(MODE); ++ AuBit(UID); ++ AuBit(GID); ++ AuBit(SIZE); ++ AuBit(ATIME); ++ AuBit(MTIME); ++ AuBit(CTIME); ++ AuBit(ATIME_SET); ++ AuBit(MTIME_SET); ++ AuBit(FORCE); ++ AuBit(ATTR_FLAG); ++ AuBit(KILL_SUID); ++ AuBit(KILL_SGID); ++ AuBit(FILE); ++ AuBit(KILL_PRIV); ++ AuBit(OPEN); ++ AuBit(TIMES_SET); ++#undef AuBit ++ dpri("ia_file %p\n", ia->ia_file); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void au_dbg_verify_dir_parent(struct dentry *dentry, unsigned int sigen) ++{ ++ struct dentry *parent; ++ ++ parent = dget_parent(dentry); ++ AuDebugOn(!S_ISDIR(dentry->d_inode->i_mode) ++ || IS_ROOT(dentry) ++ || au_digen(parent) != sigen); ++ dput(parent); ++} ++ ++void au_dbg_verify_nondir_parent(struct dentry *dentry, unsigned int sigen) ++{ ++ struct dentry *parent; ++ ++ parent = dget_parent(dentry); ++ AuDebugOn(S_ISDIR(dentry->d_inode->i_mode) ++ || au_digen(parent) != sigen); ++ dput(parent); ++} ++ ++void au_dbg_verify_gen(struct dentry *parent, unsigned int sigen) ++{ ++ int err, i, j; ++ struct au_dcsub_pages dpages; ++ struct au_dpage *dpage; ++ struct dentry **dentries; ++ ++ err = au_dpages_init(&dpages, GFP_NOFS); ++ AuDebugOn(err); ++ err = au_dcsub_pages_rev(&dpages, parent, /*do_include*/1, NULL, NULL); ++ AuDebugOn(err); ++ for (i = dpages.ndpage - 1; !err && i >= 0; i--) { ++ dpage = dpages.dpages + i; ++ dentries = dpage->dentries; ++ for (j = dpage->ndentry - 1; !err && j >= 0; j--) ++ AuDebugOn(au_digen(dentries[j]) != sigen); ++ } ++ au_dpages_free(&dpages); ++} ++ ++void au_dbg_verify_hf(struct au_finfo *finfo) ++{ ++ struct au_hfile *hf; ++ aufs_bindex_t bend, bindex; ++ ++ if (finfo->fi_bstart >= 0) { ++ bend = finfo->fi_bend; ++ for (bindex = finfo->fi_bstart; bindex <= bend; bindex++) { ++ hf = finfo->fi_hfile + bindex; ++ AuDebugOn(hf->hf_file || hf->hf_br); ++ } ++ } ++} ++ ++void au_dbg_verify_kthread(void) ++{ ++ if (au_test_wkq(current)) { ++ au_dbg_blocked(); ++ BUG(); ++ } ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void au_debug_sbinfo_init(struct au_sbinfo *sbinfo __maybe_unused) ++{ ++#ifdef AuForceNoPlink ++ au_opt_clr(sbinfo->si_mntflags, PLINK); ++#endif ++#ifdef AuForceNoXino ++ au_opt_clr(sbinfo->si_mntflags, XINO); ++#endif ++#ifdef AuForceNoRefrof ++ au_opt_clr(sbinfo->si_mntflags, REFROF); ++#endif ++#ifdef AuForceHinotify ++ au_opt_set_udba(sbinfo->si_mntflags, UDBA_HINOTIFY); ++#endif ++#ifdef AuForceRd0 ++ sbinfo->si_rdblk = 0; ++ sbinfo->si_rdhash = 0; ++#endif ++} ++ ++int __init au_debug_init(void) ++{ ++ aufs_bindex_t bindex; ++ struct au_vdir_destr destr; ++ ++ bindex = -1; ++ AuDebugOn(bindex >= 0); ++ ++ destr.len = -1; ++ AuDebugOn(destr.len < NAME_MAX); ++ ++#ifdef CONFIG_4KSTACKS ++ pr_warning("CONFIG_4KSTACKS is defined.\n"); ++#endif ++ ++#ifdef AuForceNoBrs ++ sysaufs_brs = 0; ++#endif ++ ++ return 0; ++} +diff --git a/fs/aufs/debug.h b/fs/aufs/debug.h +new file mode 100644 +index 0000000..dea0ea6 +--- /dev/null ++++ b/fs/aufs/debug.h +@@ -0,0 +1,229 @@ ++/* ++ * Copyright (C) 2005-2010 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* ++ * debug print functions ++ */ ++ ++#ifndef __AUFS_DEBUG_H__ ++#define __AUFS_DEBUG_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++/* #include */ ++#include ++/* #include */ ++#include ++/* #include */ ++/* #include */ ++#include ++#include ++ ++#include ++ ++#ifdef CONFIG_AUFS_DEBUG ++#define AuDebugOn(a) BUG_ON(a) ++ ++/* module parameter */ ++extern int aufs_debug; ++static inline void au_debug(int n) ++{ ++ aufs_debug = n; ++ smp_mb(); ++} ++ ++static inline int au_debug_test(void) ++{ ++ return aufs_debug; ++} ++#else ++#define AuDebugOn(a) do {} while (0) ++AuStubVoid(au_debug, int n) ++AuStubInt0(au_debug_test, void) ++#endif /* CONFIG_AUFS_DEBUG */ ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* debug print */ ++ ++#define AuDbg(fmt, ...) do { \ ++ if (au_debug_test()) \ ++ pr_debug("DEBUG: " fmt, ##__VA_ARGS__); \ ++} while (0) ++#define AuLabel(l) AuDbg(#l "\n") ++#define AuIOErr(fmt, ...) pr_err("I/O Error, " fmt, ##__VA_ARGS__) ++#define AuWarn1(fmt, ...) do { \ ++ static unsigned char _c; \ ++ if (!_c++) \ ++ pr_warning(fmt, ##__VA_ARGS__); \ ++} while (0) ++ ++#define AuErr1(fmt, ...) do { \ ++ static unsigned char _c; \ ++ if (!_c++) \ ++ pr_err(fmt, ##__VA_ARGS__); \ ++} while (0) ++ ++#define AuIOErr1(fmt, ...) do { \ ++ static unsigned char _c; \ ++ if (!_c++) \ ++ AuIOErr(fmt, ##__VA_ARGS__); \ ++} while (0) ++ ++#define AuUnsupportMsg "This operation is not supported." \ ++ " Please report this application to aufs-users ML." ++#define AuUnsupport(fmt, ...) do { \ ++ pr_err(AuUnsupportMsg "\n" fmt, ##__VA_ARGS__); \ ++ dump_stack(); \ ++} while (0) ++ ++#define AuTraceErr(e) do { \ ++ if (unlikely((e) < 0)) \ ++ AuDbg("err %d\n", (int)(e)); \ ++} while (0) ++ ++#define AuTraceErrPtr(p) do { \ ++ if (IS_ERR(p)) \ ++ AuDbg("err %ld\n", PTR_ERR(p)); \ ++} while (0) ++ ++/* dirty macros for debug print, use with "%.*s" and caution */ ++#define AuLNPair(qstr) (qstr)->len, (qstr)->name ++#define AuDLNPair(d) AuLNPair(&(d)->d_name) ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct au_sbinfo; ++struct au_finfo; ++struct dentry; ++#ifdef CONFIG_AUFS_DEBUG ++extern char *au_plevel; ++struct au_nhash; ++void au_dpri_whlist(struct au_nhash *whlist); ++struct au_vdir; ++void au_dpri_vdir(struct au_vdir *vdir); ++struct inode; ++void au_dpri_inode(struct inode *inode); ++void au_dpri_dentry(struct dentry *dentry); ++struct file; ++void au_dpri_file(struct file *filp); ++struct super_block; ++void au_dpri_sb(struct super_block *sb); ++ ++void au_dbg_sleep_jiffy(int jiffy); ++struct iattr; ++void au_dbg_iattr(struct iattr *ia); ++ ++void au_dbg_verify_dir_parent(struct dentry *dentry, unsigned int sigen); ++void au_dbg_verify_nondir_parent(struct dentry *dentry, unsigned int sigen); ++void au_dbg_verify_gen(struct dentry *parent, unsigned int sigen); ++void au_dbg_verify_hf(struct au_finfo *finfo); ++void au_dbg_verify_kthread(void); ++ ++int __init au_debug_init(void); ++void au_debug_sbinfo_init(struct au_sbinfo *sbinfo); ++#define AuDbgWhlist(w) do { \ ++ AuDbg(#w "\n"); \ ++ au_dpri_whlist(w); \ ++} while (0) ++ ++#define AuDbgVdir(v) do { \ ++ AuDbg(#v "\n"); \ ++ au_dpri_vdir(v); \ ++} while (0) ++ ++#define AuDbgInode(i) do { \ ++ AuDbg(#i "\n"); \ ++ au_dpri_inode(i); \ ++} while (0) ++ ++#define AuDbgDentry(d) do { \ ++ AuDbg(#d "\n"); \ ++ au_dpri_dentry(d); \ ++} while (0) ++ ++#define AuDbgFile(f) do { \ ++ AuDbg(#f "\n"); \ ++ au_dpri_file(f); \ ++} while (0) ++ ++#define AuDbgSb(sb) do { \ ++ AuDbg(#sb "\n"); \ ++ au_dpri_sb(sb); \ ++} while (0) ++ ++#define AuDbgSleep(sec) do { \ ++ AuDbg("sleep %d sec\n", sec); \ ++ ssleep(sec); \ ++} while (0) ++ ++#define AuDbgSleepJiffy(jiffy) do { \ ++ AuDbg("sleep %d jiffies\n", jiffy); \ ++ au_dbg_sleep_jiffy(jiffy); \ ++} while (0) ++ ++#define AuDbgIAttr(ia) do { \ ++ AuDbg("ia_valid 0x%x\n", (ia)->ia_valid); \ ++ au_dbg_iattr(ia); \ ++} while (0) ++#else ++AuStubVoid(au_dbg_verify_dir_parent, struct dentry *dentry, unsigned int sigen) ++AuStubVoid(au_dbg_verify_nondir_parent, struct dentry *dentry, ++ unsigned int sigen) ++AuStubVoid(au_dbg_verify_gen, struct dentry *parent, unsigned int sigen) ++AuStubVoid(au_dbg_verify_hf, struct au_finfo *finfo) ++AuStubVoid(au_dbg_verify_kthread, void) ++AuStubInt0(__init au_debug_init, void) ++AuStubVoid(au_debug_sbinfo_init, struct au_sbinfo *sbinfo) ++ ++#define AuDbgWhlist(w) do {} while (0) ++#define AuDbgVdir(v) do {} while (0) ++#define AuDbgInode(i) do {} while (0) ++#define AuDbgDentry(d) do {} while (0) ++#define AuDbgFile(f) do {} while (0) ++#define AuDbgSb(sb) do {} while (0) ++#define AuDbgSleep(sec) do {} while (0) ++#define AuDbgSleepJiffy(jiffy) do {} while (0) ++#define AuDbgIAttr(ia) do {} while (0) ++#endif /* CONFIG_AUFS_DEBUG */ ++ ++/* ---------------------------------------------------------------------- */ ++ ++#ifdef CONFIG_AUFS_MAGIC_SYSRQ ++int __init au_sysrq_init(void); ++void au_sysrq_fin(void); ++ ++#ifdef CONFIG_HW_CONSOLE ++#define au_dbg_blocked() do { \ ++ WARN_ON(1); \ ++ handle_sysrq('w', vc_cons[fg_console].d->vc_tty); \ ++} while (0) ++#else ++AuStubVoid(au_dbg_blocked, void) ++#endif ++ ++#else ++AuStubInt0(__init au_sysrq_init, void) ++AuStubVoid(au_sysrq_fin, void) ++AuStubVoid(au_dbg_blocked, void) ++#endif /* CONFIG_AUFS_MAGIC_SYSRQ */ ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_DEBUG_H__ */ +diff --git a/fs/aufs/dentry.c b/fs/aufs/dentry.c +new file mode 100644 +index 0000000..ba2ef31 +--- /dev/null ++++ b/fs/aufs/dentry.c +@@ -0,0 +1,874 @@ ++/* ++ * Copyright (C) 2005-2010 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* ++ * lookup and dentry operations ++ */ ++ ++#include ++#include "aufs.h" ++ ++static void au_h_nd(struct nameidata *h_nd, struct nameidata *nd) ++{ ++ if (nd) { ++ *h_nd = *nd; ++ ++ /* ++ * gave up supporting LOOKUP_CREATE/OPEN for lower fs, ++ * due to whiteout and branch permission. ++ */ ++ h_nd->flags &= ~(/*LOOKUP_PARENT |*/ LOOKUP_OPEN | LOOKUP_CREATE ++ | LOOKUP_FOLLOW); ++ /* unnecessary? */ ++ h_nd->intent.open.file = NULL; ++ } else ++ memset(h_nd, 0, sizeof(*h_nd)); ++} ++ ++struct au_lkup_one_args { ++ struct dentry **errp; ++ struct qstr *name; ++ struct dentry *h_parent; ++ struct au_branch *br; ++ struct nameidata *nd; ++}; ++ ++struct dentry *au_lkup_one(struct qstr *name, struct dentry *h_parent, ++ struct au_branch *br, struct nameidata *nd) ++{ ++ struct dentry *h_dentry; ++ int err; ++ struct nameidata h_nd; ++ ++ if (au_test_fs_null_nd(h_parent->d_sb)) ++ return vfsub_lookup_one_len(name->name, h_parent, name->len); ++ ++ au_h_nd(&h_nd, nd); ++ h_nd.path.dentry = h_parent; ++ h_nd.path.mnt = br->br_mnt; ++ ++ err = __lookup_one_len(name->name, &h_nd.last, NULL, name->len); ++ h_dentry = ERR_PTR(err); ++ if (!err) { ++ path_get(&h_nd.path); ++ h_dentry = vfsub_lookup_hash(&h_nd); ++ path_put(&h_nd.path); ++ } ++ ++ AuTraceErrPtr(h_dentry); ++ return h_dentry; ++} ++ ++static void au_call_lkup_one(void *args) ++{ ++ struct au_lkup_one_args *a = args; ++ *a->errp = au_lkup_one(a->name, a->h_parent, a->br, a->nd); ++} ++ ++#define AuLkup_ALLOW_NEG 1 ++#define au_ftest_lkup(flags, name) ((flags) & AuLkup_##name) ++#define au_fset_lkup(flags, name) { (flags) |= AuLkup_##name; } ++#define au_fclr_lkup(flags, name) { (flags) &= ~AuLkup_##name; } ++ ++struct au_do_lookup_args { ++ unsigned int flags; ++ mode_t type; ++ struct nameidata *nd; ++}; ++ ++/* ++ * returns positive/negative dentry, NULL or an error. ++ * NULL means whiteout-ed or not-found. ++ */ ++static struct dentry* ++au_do_lookup(struct dentry *h_parent, struct dentry *dentry, ++ aufs_bindex_t bindex, struct qstr *wh_name, ++ struct au_do_lookup_args *args) ++{ ++ struct dentry *h_dentry; ++ struct inode *h_inode, *inode; ++ struct au_branch *br; ++ int wh_found, opq; ++ unsigned char wh_able; ++ const unsigned char allow_neg = !!au_ftest_lkup(args->flags, ALLOW_NEG); ++ ++ wh_found = 0; ++ br = au_sbr(dentry->d_sb, bindex); ++ wh_able = !!au_br_whable(br->br_perm); ++ if (wh_able) ++ wh_found = au_wh_test(h_parent, wh_name, br, /*try_sio*/0); ++ h_dentry = ERR_PTR(wh_found); ++ if (!wh_found) ++ goto real_lookup; ++ if (unlikely(wh_found < 0)) ++ goto out; ++ ++ /* We found a whiteout */ ++ /* au_set_dbend(dentry, bindex); */ ++ au_set_dbwh(dentry, bindex); ++ if (!allow_neg) ++ return NULL; /* success */ ++ ++ real_lookup: ++ h_dentry = au_lkup_one(&dentry->d_name, h_parent, br, args->nd); ++ if (IS_ERR(h_dentry)) ++ goto out; ++ ++ h_inode = h_dentry->d_inode; ++ if (!h_inode) { ++ if (!allow_neg) ++ goto out_neg; ++ } else if (wh_found ++ || (args->type && args->type != (h_inode->i_mode & S_IFMT))) ++ goto out_neg; ++ ++ if (au_dbend(dentry) <= bindex) ++ au_set_dbend(dentry, bindex); ++ if (au_dbstart(dentry) < 0 || bindex < au_dbstart(dentry)) ++ au_set_dbstart(dentry, bindex); ++ au_set_h_dptr(dentry, bindex, h_dentry); ++ ++ inode = dentry->d_inode; ++ if (!h_inode || !S_ISDIR(h_inode->i_mode) || !wh_able ++ || (inode && !S_ISDIR(inode->i_mode))) ++ goto out; /* success */ ++ ++ mutex_lock_nested(&h_inode->i_mutex, AuLsc_I_CHILD); ++ opq = au_diropq_test(h_dentry, br); ++ mutex_unlock(&h_inode->i_mutex); ++ if (opq > 0) ++ au_set_dbdiropq(dentry, bindex); ++ else if (unlikely(opq < 0)) { ++ au_set_h_dptr(dentry, bindex, NULL); ++ h_dentry = ERR_PTR(opq); ++ } ++ goto out; ++ ++ out_neg: ++ dput(h_dentry); ++ h_dentry = NULL; ++ out: ++ return h_dentry; ++} ++ ++static int au_test_shwh(struct super_block *sb, const struct qstr *name) ++{ ++ if (unlikely(!au_opt_test(au_mntflags(sb), SHWH) ++ && !strncmp(name->name, AUFS_WH_PFX, AUFS_WH_PFX_LEN))) ++ return -EPERM; ++ return 0; ++} ++ ++/* ++ * returns the number of lower positive dentries, ++ * otherwise an error. ++ * can be called at unlinking with @type is zero. ++ */ ++int au_lkup_dentry(struct dentry *dentry, aufs_bindex_t bstart, mode_t type, ++ struct nameidata *nd) ++{ ++ int npositive, err; ++ aufs_bindex_t bindex, btail, bdiropq; ++ unsigned char isdir; ++ struct qstr whname; ++ struct au_do_lookup_args args = { ++ .flags = 0, ++ .type = type, ++ .nd = nd ++ }; ++ const struct qstr *name = &dentry->d_name; ++ struct dentry *parent; ++ struct inode *inode; ++ ++ err = au_test_shwh(dentry->d_sb, name); ++ if (unlikely(err)) ++ goto out; ++ ++ err = au_wh_name_alloc(&whname, name); ++ if (unlikely(err)) ++ goto out; ++ ++ inode = dentry->d_inode; ++ isdir = !!(inode && S_ISDIR(inode->i_mode)); ++ if (!type) ++ au_fset_lkup(args.flags, ALLOW_NEG); ++ ++ npositive = 0; ++ parent = dget_parent(dentry); ++ btail = au_dbtaildir(parent); ++ for (bindex = bstart; bindex <= btail; bindex++) { ++ struct dentry *h_parent, *h_dentry; ++ struct inode *h_inode, *h_dir; ++ ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (h_dentry) { ++ if (h_dentry->d_inode) ++ npositive++; ++ if (type != S_IFDIR) ++ break; ++ continue; ++ } ++ h_parent = au_h_dptr(parent, bindex); ++ if (!h_parent) ++ continue; ++ h_dir = h_parent->d_inode; ++ if (!h_dir || !S_ISDIR(h_dir->i_mode)) ++ continue; ++ ++ mutex_lock_nested(&h_dir->i_mutex, AuLsc_I_PARENT); ++ h_dentry = au_do_lookup(h_parent, dentry, bindex, &whname, ++ &args); ++ mutex_unlock(&h_dir->i_mutex); ++ err = PTR_ERR(h_dentry); ++ if (IS_ERR(h_dentry)) ++ goto out_parent; ++ au_fclr_lkup(args.flags, ALLOW_NEG); ++ ++ if (au_dbwh(dentry) >= 0) ++ break; ++ if (!h_dentry) ++ continue; ++ h_inode = h_dentry->d_inode; ++ if (!h_inode) ++ continue; ++ npositive++; ++ if (!args.type) ++ args.type = h_inode->i_mode & S_IFMT; ++ if (args.type != S_IFDIR) ++ break; ++ else if (isdir) { ++ /* the type of lower may be different */ ++ bdiropq = au_dbdiropq(dentry); ++ if (bdiropq >= 0 && bdiropq <= bindex) ++ break; ++ } ++ } ++ ++ if (npositive) { ++ AuLabel(positive); ++ au_update_dbstart(dentry); ++ } ++ err = npositive; ++ if (unlikely(!au_opt_test(au_mntflags(dentry->d_sb), UDBA_NONE) ++ && au_dbstart(dentry) < 0)) ++ /* both of real entry and whiteout found */ ++ err = -EIO; ++ ++ out_parent: ++ dput(parent); ++ kfree(whname.name); ++ out: ++ return err; ++} ++ ++struct dentry *au_sio_lkup_one(struct qstr *name, struct dentry *parent, ++ struct au_branch *br) ++{ ++ struct dentry *dentry; ++ int wkq_err; ++ ++ if (!au_test_h_perm_sio(parent->d_inode, MAY_EXEC)) ++ dentry = au_lkup_one(name, parent, br, /*nd*/NULL); ++ else { ++ struct au_lkup_one_args args = { ++ .errp = &dentry, ++ .name = name, ++ .h_parent = parent, ++ .br = br, ++ .nd = NULL ++ }; ++ ++ wkq_err = au_wkq_wait(au_call_lkup_one, &args); ++ if (unlikely(wkq_err)) ++ dentry = ERR_PTR(wkq_err); ++ } ++ ++ return dentry; ++} ++ ++/* ++ * lookup @dentry on @bindex which should be negative. ++ */ ++int au_lkup_neg(struct dentry *dentry, aufs_bindex_t bindex) ++{ ++ int err; ++ struct dentry *parent, *h_parent, *h_dentry; ++ ++ parent = dget_parent(dentry); ++ h_parent = au_h_dptr(parent, bindex); ++ h_dentry = au_sio_lkup_one(&dentry->d_name, h_parent, ++ au_sbr(dentry->d_sb, bindex)); ++ err = PTR_ERR(h_dentry); ++ if (IS_ERR(h_dentry)) ++ goto out; ++ if (unlikely(h_dentry->d_inode)) { ++ err = -EIO; ++ AuIOErr("b%d %.*s should be negative.\n", ++ bindex, AuDLNPair(h_dentry)); ++ dput(h_dentry); ++ goto out; ++ } ++ ++ err = 0; ++ if (bindex < au_dbstart(dentry)) ++ au_set_dbstart(dentry, bindex); ++ if (au_dbend(dentry) < bindex) ++ au_set_dbend(dentry, bindex); ++ au_set_h_dptr(dentry, bindex, h_dentry); ++ ++ out: ++ dput(parent); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* subset of struct inode */ ++struct au_iattr { ++ unsigned long i_ino; ++ /* unsigned int i_nlink; */ ++ uid_t i_uid; ++ gid_t i_gid; ++ u64 i_version; ++/* ++ loff_t i_size; ++ blkcnt_t i_blocks; ++*/ ++ umode_t i_mode; ++}; ++ ++static void au_iattr_save(struct au_iattr *ia, struct inode *h_inode) ++{ ++ ia->i_ino = h_inode->i_ino; ++ /* ia->i_nlink = h_inode->i_nlink; */ ++ ia->i_uid = h_inode->i_uid; ++ ia->i_gid = h_inode->i_gid; ++ ia->i_version = h_inode->i_version; ++/* ++ ia->i_size = h_inode->i_size; ++ ia->i_blocks = h_inode->i_blocks; ++*/ ++ ia->i_mode = (h_inode->i_mode & S_IFMT); ++} ++ ++static int au_iattr_test(struct au_iattr *ia, struct inode *h_inode) ++{ ++ return ia->i_ino != h_inode->i_ino ++ /* || ia->i_nlink != h_inode->i_nlink */ ++ || ia->i_uid != h_inode->i_uid ++ || ia->i_gid != h_inode->i_gid ++ || ia->i_version != h_inode->i_version ++/* ++ || ia->i_size != h_inode->i_size ++ || ia->i_blocks != h_inode->i_blocks ++*/ ++ || ia->i_mode != (h_inode->i_mode & S_IFMT); ++} ++ ++static int au_h_verify_dentry(struct dentry *h_dentry, struct dentry *h_parent, ++ struct au_branch *br) ++{ ++ int err; ++ struct au_iattr ia; ++ struct inode *h_inode; ++ struct dentry *h_d; ++ struct super_block *h_sb; ++ ++ err = 0; ++ memset(&ia, -1, sizeof(ia)); ++ h_sb = h_dentry->d_sb; ++ h_inode = h_dentry->d_inode; ++ if (h_inode) ++ au_iattr_save(&ia, h_inode); ++ else if (au_test_nfs(h_sb) || au_test_fuse(h_sb)) ++ /* nfs d_revalidate may return 0 for negative dentry */ ++ /* fuse d_revalidate always return 0 for negative dentry */ ++ goto out; ++ ++ /* main purpose is namei.c:cached_lookup() and d_revalidate */ ++ h_d = au_lkup_one(&h_dentry->d_name, h_parent, br, /*nd*/NULL); ++ err = PTR_ERR(h_d); ++ if (IS_ERR(h_d)) ++ goto out; ++ ++ err = 0; ++ if (unlikely(h_d != h_dentry ++ || h_d->d_inode != h_inode ++ || (h_inode && au_iattr_test(&ia, h_inode)))) ++ err = au_busy_or_stale(); ++ dput(h_d); ++ ++ out: ++ AuTraceErr(err); ++ return err; ++} ++ ++int au_h_verify(struct dentry *h_dentry, unsigned int udba, struct inode *h_dir, ++ struct dentry *h_parent, struct au_branch *br) ++{ ++ int err; ++ ++ err = 0; ++ if (udba == AuOpt_UDBA_REVAL) { ++ IMustLock(h_dir); ++ err = (h_dentry->d_parent->d_inode != h_dir); ++ } else if (udba == AuOpt_UDBA_HINOTIFY) ++ err = au_h_verify_dentry(h_dentry, h_parent, br); ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void au_do_refresh_hdentry(struct au_hdentry *p, struct au_dinfo *dinfo, ++ struct dentry *parent) ++{ ++ struct dentry *h_d, *h_dp; ++ struct au_hdentry tmp, *q; ++ struct super_block *sb; ++ aufs_bindex_t new_bindex, bindex, bend, bwh, bdiropq; ++ ++ AuRwMustWriteLock(&dinfo->di_rwsem); ++ ++ bend = dinfo->di_bend; ++ bwh = dinfo->di_bwh; ++ bdiropq = dinfo->di_bdiropq; ++ for (bindex = dinfo->di_bstart; bindex <= bend; bindex++, p++) { ++ h_d = p->hd_dentry; ++ if (!h_d) ++ continue; ++ ++ h_dp = dget_parent(h_d); ++ if (h_dp == au_h_dptr(parent, bindex)) { ++ dput(h_dp); ++ continue; ++ } ++ ++ new_bindex = au_find_dbindex(parent, h_dp); ++ dput(h_dp); ++ if (dinfo->di_bwh == bindex) ++ bwh = new_bindex; ++ if (dinfo->di_bdiropq == bindex) ++ bdiropq = new_bindex; ++ if (new_bindex < 0) { ++ au_hdput(p); ++ p->hd_dentry = NULL; ++ continue; ++ } ++ ++ /* swap two lower dentries, and loop again */ ++ q = dinfo->di_hdentry + new_bindex; ++ tmp = *q; ++ *q = *p; ++ *p = tmp; ++ if (tmp.hd_dentry) { ++ bindex--; ++ p--; ++ } ++ } ++ ++ sb = parent->d_sb; ++ dinfo->di_bwh = -1; ++ if (bwh >= 0 && bwh <= au_sbend(sb) && au_sbr_whable(sb, bwh)) ++ dinfo->di_bwh = bwh; ++ ++ dinfo->di_bdiropq = -1; ++ if (bdiropq >= 0 ++ && bdiropq <= au_sbend(sb) ++ && au_sbr_whable(sb, bdiropq)) ++ dinfo->di_bdiropq = bdiropq; ++ ++ bend = au_dbend(parent); ++ p = dinfo->di_hdentry; ++ for (bindex = 0; bindex <= bend; bindex++, p++) ++ if (p->hd_dentry) { ++ dinfo->di_bstart = bindex; ++ break; ++ } ++ ++ p = dinfo->di_hdentry + bend; ++ for (bindex = bend; bindex >= 0; bindex--, p--) ++ if (p->hd_dentry) { ++ dinfo->di_bend = bindex; ++ break; ++ } ++} ++ ++/* ++ * returns the number of found lower positive dentries, ++ * otherwise an error. ++ */ ++int au_refresh_hdentry(struct dentry *dentry, mode_t type) ++{ ++ int npositive, err; ++ unsigned int sigen; ++ aufs_bindex_t bstart; ++ struct au_dinfo *dinfo; ++ struct super_block *sb; ++ struct dentry *parent; ++ ++ DiMustWriteLock(dentry); ++ ++ sb = dentry->d_sb; ++ AuDebugOn(IS_ROOT(dentry)); ++ sigen = au_sigen(sb); ++ parent = dget_parent(dentry); ++ AuDebugOn(au_digen(parent) != sigen ++ || au_iigen(parent->d_inode) != sigen); ++ ++ dinfo = au_di(dentry); ++ err = au_di_realloc(dinfo, au_sbend(sb) + 1); ++ npositive = err; ++ if (unlikely(err)) ++ goto out; ++ au_do_refresh_hdentry(dinfo->di_hdentry + dinfo->di_bstart, dinfo, ++ parent); ++ ++ npositive = 0; ++ bstart = au_dbstart(parent); ++ if (type != S_IFDIR && dinfo->di_bstart == bstart) ++ goto out_dgen; /* success */ ++ ++ npositive = au_lkup_dentry(dentry, bstart, type, /*nd*/NULL); ++ if (npositive < 0) ++ goto out; ++ if (dinfo->di_bwh >= 0 && dinfo->di_bwh <= dinfo->di_bstart) ++ d_drop(dentry); ++ ++ out_dgen: ++ au_update_digen(dentry); ++ out: ++ dput(parent); ++ AuTraceErr(npositive); ++ return npositive; ++} ++ ++static noinline_for_stack ++int au_do_h_d_reval(struct dentry *h_dentry, struct nameidata *nd, ++ struct dentry *dentry, aufs_bindex_t bindex) ++{ ++ int err, valid; ++ int (*reval)(struct dentry *, struct nameidata *); ++ ++ err = 0; ++ reval = NULL; ++ if (h_dentry->d_op) ++ reval = h_dentry->d_op->d_revalidate; ++ if (!reval) ++ goto out; ++ ++ AuDbg("b%d\n", bindex); ++ if (au_test_fs_null_nd(h_dentry->d_sb)) ++ /* it may return tri-state */ ++ valid = reval(h_dentry, NULL); ++ else { ++ struct nameidata h_nd; ++ int locked; ++ struct dentry *parent; ++ ++ au_h_nd(&h_nd, nd); ++ parent = nd->path.dentry; ++ locked = (nd && nd->path.dentry != dentry); ++ if (locked) ++ di_read_lock_parent(parent, AuLock_IR); ++ BUG_ON(bindex > au_dbend(parent)); ++ h_nd.path.dentry = au_h_dptr(parent, bindex); ++ BUG_ON(!h_nd.path.dentry); ++ h_nd.path.mnt = au_sbr(parent->d_sb, bindex)->br_mnt; ++ path_get(&h_nd.path); ++ valid = reval(h_dentry, &h_nd); ++ path_put(&h_nd.path); ++ if (locked) ++ di_read_unlock(parent, AuLock_IR); ++ } ++ ++ if (unlikely(valid < 0)) ++ err = valid; ++ else if (!valid) ++ err = -EINVAL; ++ ++ out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* todo: remove this */ ++static int h_d_revalidate(struct dentry *dentry, struct inode *inode, ++ struct nameidata *nd, int do_udba) ++{ ++ int err; ++ umode_t mode, h_mode; ++ aufs_bindex_t bindex, btail, bstart, ibs, ibe; ++ unsigned char plus, unhashed, is_root, h_plus; ++ struct inode *h_inode, *h_cached_inode; ++ struct dentry *h_dentry; ++ struct qstr *name, *h_name; ++ ++ err = 0; ++ plus = 0; ++ mode = 0; ++ ibs = -1; ++ ibe = -1; ++ unhashed = !!d_unhashed(dentry); ++ is_root = !!IS_ROOT(dentry); ++ name = &dentry->d_name; ++ ++ /* ++ * Theoretically, REVAL test should be unnecessary in case of INOTIFY. ++ * But inotify doesn't fire some necessary events, ++ * IN_ATTRIB for atime/nlink/pageio ++ * IN_DELETE for NFS dentry ++ * Let's do REVAL test too. ++ */ ++ if (do_udba && inode) { ++ mode = (inode->i_mode & S_IFMT); ++ plus = (inode->i_nlink > 0); ++ ibs = au_ibstart(inode); ++ ibe = au_ibend(inode); ++ } ++ ++ bstart = au_dbstart(dentry); ++ btail = bstart; ++ if (inode && S_ISDIR(inode->i_mode)) ++ btail = au_dbtaildir(dentry); ++ for (bindex = bstart; bindex <= btail; bindex++) { ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (!h_dentry) ++ continue; ++ ++ AuDbg("b%d, %.*s\n", bindex, AuDLNPair(h_dentry)); ++ h_name = &h_dentry->d_name; ++ if (unlikely(do_udba ++ && !is_root ++ && (unhashed != !!d_unhashed(h_dentry) ++ || name->len != h_name->len ++ || memcmp(name->name, h_name->name, name->len)) ++ )) { ++ AuDbg("unhash 0x%x 0x%x, %.*s %.*s\n", ++ unhashed, d_unhashed(h_dentry), ++ AuDLNPair(dentry), AuDLNPair(h_dentry)); ++ goto err; ++ } ++ ++ err = au_do_h_d_reval(h_dentry, nd, dentry, bindex); ++ if (unlikely(err)) ++ /* do not goto err, to keep the errno */ ++ break; ++ ++ /* todo: plink too? */ ++ if (!do_udba) ++ continue; ++ ++ /* UDBA tests */ ++ h_inode = h_dentry->d_inode; ++ if (unlikely(!!inode != !!h_inode)) ++ goto err; ++ ++ h_plus = plus; ++ h_mode = mode; ++ h_cached_inode = h_inode; ++ if (h_inode) { ++ h_mode = (h_inode->i_mode & S_IFMT); ++ h_plus = (h_inode->i_nlink > 0); ++ } ++ if (inode && ibs <= bindex && bindex <= ibe) ++ h_cached_inode = au_h_iptr(inode, bindex); ++ ++ if (unlikely(plus != h_plus ++ || mode != h_mode ++ || h_cached_inode != h_inode)) ++ goto err; ++ continue; ++ ++ err: ++ err = -EINVAL; ++ break; ++ } ++ ++ return err; ++} ++ ++static int simple_reval_dpath(struct dentry *dentry, unsigned int sigen) ++{ ++ int err; ++ struct dentry *parent; ++ struct inode *inode; ++ ++ inode = dentry->d_inode; ++ if (au_digen(dentry) == sigen && au_iigen(inode) == sigen) ++ return 0; ++ ++ parent = dget_parent(dentry); ++ di_read_lock_parent(parent, AuLock_IR); ++ AuDebugOn(au_digen(parent) != sigen ++ || au_iigen(parent->d_inode) != sigen); ++ au_dbg_verify_gen(parent, sigen); ++ ++ /* returns a number of positive dentries */ ++ err = au_refresh_hdentry(dentry, inode->i_mode & S_IFMT); ++ if (err >= 0) ++ err = au_refresh_hinode(inode, dentry); ++ ++ di_read_unlock(parent, AuLock_IR); ++ dput(parent); ++ return err; ++} ++ ++int au_reval_dpath(struct dentry *dentry, unsigned int sigen) ++{ ++ int err; ++ struct dentry *d, *parent; ++ struct inode *inode; ++ ++ if (!au_ftest_si(au_sbi(dentry->d_sb), FAILED_REFRESH_DIRS)) ++ return simple_reval_dpath(dentry, sigen); ++ ++ /* slow loop, keep it simple and stupid */ ++ /* cf: au_cpup_dirs() */ ++ err = 0; ++ parent = NULL; ++ while (au_digen(dentry) != sigen ++ || au_iigen(dentry->d_inode) != sigen) { ++ d = dentry; ++ while (1) { ++ dput(parent); ++ parent = dget_parent(d); ++ if (au_digen(parent) == sigen ++ && au_iigen(parent->d_inode) == sigen) ++ break; ++ d = parent; ++ } ++ ++ inode = d->d_inode; ++ if (d != dentry) ++ di_write_lock_child(d); ++ ++ /* someone might update our dentry while we were sleeping */ ++ if (au_digen(d) != sigen || au_iigen(d->d_inode) != sigen) { ++ di_read_lock_parent(parent, AuLock_IR); ++ /* returns a number of positive dentries */ ++ err = au_refresh_hdentry(d, inode->i_mode & S_IFMT); ++ if (err >= 0) ++ err = au_refresh_hinode(inode, d); ++ di_read_unlock(parent, AuLock_IR); ++ } ++ ++ if (d != dentry) ++ di_write_unlock(d); ++ dput(parent); ++ if (unlikely(err)) ++ break; ++ } ++ ++ return err; ++} ++ ++/* ++ * if valid returns 1, otherwise 0. ++ */ ++static int aufs_d_revalidate(struct dentry *dentry, struct nameidata *nd) ++{ ++ int valid, err; ++ unsigned int sigen; ++ unsigned char do_udba; ++ struct super_block *sb; ++ struct inode *inode; ++ ++ err = -EINVAL; ++ sb = dentry->d_sb; ++ inode = dentry->d_inode; ++ aufs_read_lock(dentry, AuLock_FLUSH | AuLock_DW); ++ sigen = au_sigen(sb); ++ if (au_digen(dentry) != sigen) { ++ AuDebugOn(IS_ROOT(dentry)); ++ if (inode) ++ err = au_reval_dpath(dentry, sigen); ++ if (unlikely(err)) ++ goto out_dgrade; ++ AuDebugOn(au_digen(dentry) != sigen); ++ } ++ if (inode && au_iigen(inode) != sigen) { ++ AuDebugOn(IS_ROOT(dentry)); ++ err = au_refresh_hinode(inode, dentry); ++ if (unlikely(err)) ++ goto out_dgrade; ++ AuDebugOn(au_iigen(inode) != sigen); ++ } ++ di_downgrade_lock(dentry, AuLock_IR); ++ ++ AuDebugOn(au_digen(dentry) != sigen); ++ AuDebugOn(inode && au_iigen(inode) != sigen); ++ err = -EINVAL; ++ do_udba = !au_opt_test(au_mntflags(sb), UDBA_NONE); ++ if (do_udba && inode) { ++ aufs_bindex_t bstart = au_ibstart(inode); ++ ++ if (bstart >= 0 ++ && au_test_higen(inode, au_h_iptr(inode, bstart))) ++ goto out; ++ } ++ ++ err = h_d_revalidate(dentry, inode, nd, do_udba); ++ if (unlikely(!err && do_udba && au_dbstart(dentry) < 0)) ++ /* both of real entry and whiteout found */ ++ err = -EIO; ++ goto out; ++ ++ out_dgrade: ++ di_downgrade_lock(dentry, AuLock_IR); ++ out: ++ aufs_read_unlock(dentry, AuLock_IR); ++ AuTraceErr(err); ++ valid = !err; ++ if (!valid) ++ AuDbg("%.*s invalid\n", AuDLNPair(dentry)); ++ return valid; ++} ++ ++static void aufs_d_release(struct dentry *dentry) ++{ ++ struct au_dinfo *dinfo; ++ aufs_bindex_t bend, bindex; ++ ++ dinfo = dentry->d_fsdata; ++ if (!dinfo) ++ return; ++ ++ /* dentry may not be revalidated */ ++ bindex = dinfo->di_bstart; ++ if (bindex >= 0) { ++ struct au_hdentry *p; ++ ++ bend = dinfo->di_bend; ++ p = dinfo->di_hdentry + bindex; ++ while (bindex++ <= bend) { ++ if (p->hd_dentry) ++ au_hdput(p); ++ p++; ++ } ++ } ++ kfree(dinfo->di_hdentry); ++ AuRwDestroy(&dinfo->di_rwsem); ++ au_cache_free_dinfo(dinfo); ++ au_hin_di_reinit(dentry); ++} ++ ++struct dentry_operations aufs_dop = { ++ .d_revalidate = aufs_d_revalidate, ++ .d_release = aufs_d_release ++}; +diff --git a/fs/aufs/dentry.h b/fs/aufs/dentry.h +new file mode 100644 +index 0000000..42cd70c +--- /dev/null ++++ b/fs/aufs/dentry.h +@@ -0,0 +1,228 @@ ++/* ++ * Copyright (C) 2005-2010 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* ++ * lookup and dentry operations ++ */ ++ ++#ifndef __AUFS_DENTRY_H__ ++#define __AUFS_DENTRY_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++#include "rwsem.h" ++ ++/* make a single member structure for future use */ ++/* todo: remove this structure */ ++struct au_hdentry { ++ struct dentry *hd_dentry; ++}; ++ ++struct au_dinfo { ++ atomic_t di_generation; ++ ++ struct au_rwsem di_rwsem; ++ aufs_bindex_t di_bstart, di_bend, di_bwh, di_bdiropq; ++ struct au_hdentry *di_hdentry; ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* dentry.c */ ++extern struct dentry_operations aufs_dop; ++struct au_branch; ++struct dentry *au_lkup_one(struct qstr *name, struct dentry *h_parent, ++ struct au_branch *br, struct nameidata *nd); ++struct dentry *au_sio_lkup_one(struct qstr *name, struct dentry *parent, ++ struct au_branch *br); ++int au_h_verify(struct dentry *h_dentry, unsigned int udba, struct inode *h_dir, ++ struct dentry *h_parent, struct au_branch *br); ++ ++int au_lkup_dentry(struct dentry *dentry, aufs_bindex_t bstart, mode_t type, ++ struct nameidata *nd); ++int au_lkup_neg(struct dentry *dentry, aufs_bindex_t bindex); ++int au_refresh_hdentry(struct dentry *dentry, mode_t type); ++int au_reval_dpath(struct dentry *dentry, unsigned int sigen); ++ ++/* dinfo.c */ ++int au_alloc_dinfo(struct dentry *dentry); ++int au_di_realloc(struct au_dinfo *dinfo, int nbr); ++ ++void di_read_lock(struct dentry *d, int flags, unsigned int lsc); ++void di_read_unlock(struct dentry *d, int flags); ++void di_downgrade_lock(struct dentry *d, int flags); ++void di_write_lock(struct dentry *d, unsigned int lsc); ++void di_write_unlock(struct dentry *d); ++void di_write_lock2_child(struct dentry *d1, struct dentry *d2, int isdir); ++void di_write_lock2_parent(struct dentry *d1, struct dentry *d2, int isdir); ++void di_write_unlock2(struct dentry *d1, struct dentry *d2); ++ ++struct dentry *au_h_dptr(struct dentry *dentry, aufs_bindex_t bindex); ++aufs_bindex_t au_dbtail(struct dentry *dentry); ++aufs_bindex_t au_dbtaildir(struct dentry *dentry); ++ ++void au_set_h_dptr(struct dentry *dentry, aufs_bindex_t bindex, ++ struct dentry *h_dentry); ++void au_update_digen(struct dentry *dentry); ++void au_update_dbrange(struct dentry *dentry, int do_put_zero); ++void au_update_dbstart(struct dentry *dentry); ++void au_update_dbend(struct dentry *dentry); ++int au_find_dbindex(struct dentry *dentry, struct dentry *h_dentry); ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline struct au_dinfo *au_di(struct dentry *dentry) ++{ ++ return dentry->d_fsdata; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* lock subclass for dinfo */ ++enum { ++ AuLsc_DI_CHILD, /* child first */ ++ AuLsc_DI_CHILD2, /* rename(2), link(2), and cpup at hinotify */ ++ AuLsc_DI_CHILD3, /* copyup dirs */ ++ AuLsc_DI_PARENT, ++ AuLsc_DI_PARENT2, ++ AuLsc_DI_PARENT3 ++}; ++ ++/* ++ * di_read_lock_child, di_write_lock_child, ++ * di_read_lock_child2, di_write_lock_child2, ++ * di_read_lock_child3, di_write_lock_child3, ++ * di_read_lock_parent, di_write_lock_parent, ++ * di_read_lock_parent2, di_write_lock_parent2, ++ * di_read_lock_parent3, di_write_lock_parent3, ++ */ ++#define AuReadLockFunc(name, lsc) \ ++static inline void di_read_lock_##name(struct dentry *d, int flags) \ ++{ di_read_lock(d, flags, AuLsc_DI_##lsc); } ++ ++#define AuWriteLockFunc(name, lsc) \ ++static inline void di_write_lock_##name(struct dentry *d) \ ++{ di_write_lock(d, AuLsc_DI_##lsc); } ++ ++#define AuRWLockFuncs(name, lsc) \ ++ AuReadLockFunc(name, lsc) \ ++ AuWriteLockFunc(name, lsc) ++ ++AuRWLockFuncs(child, CHILD); ++AuRWLockFuncs(child2, CHILD2); ++AuRWLockFuncs(child3, CHILD3); ++AuRWLockFuncs(parent, PARENT); ++AuRWLockFuncs(parent2, PARENT2); ++AuRWLockFuncs(parent3, PARENT3); ++ ++#undef AuReadLockFunc ++#undef AuWriteLockFunc ++#undef AuRWLockFuncs ++ ++#define DiMustNoWaiters(d) AuRwMustNoWaiters(&au_di(d)->di_rwsem) ++#define DiMustAnyLock(d) AuRwMustAnyLock(&au_di(d)->di_rwsem) ++#define DiMustWriteLock(d) AuRwMustWriteLock(&au_di(d)->di_rwsem) ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* todo: memory barrier? */ ++static inline unsigned int au_digen(struct dentry *d) ++{ ++ return atomic_read(&au_di(d)->di_generation); ++} ++ ++static inline void au_h_dentry_init(struct au_hdentry *hdentry) ++{ ++ hdentry->hd_dentry = NULL; ++} ++ ++static inline void au_hdput(struct au_hdentry *hd) ++{ ++ dput(hd->hd_dentry); ++} ++ ++static inline aufs_bindex_t au_dbstart(struct dentry *dentry) ++{ ++ DiMustAnyLock(dentry); ++ return au_di(dentry)->di_bstart; ++} ++ ++static inline aufs_bindex_t au_dbend(struct dentry *dentry) ++{ ++ DiMustAnyLock(dentry); ++ return au_di(dentry)->di_bend; ++} ++ ++static inline aufs_bindex_t au_dbwh(struct dentry *dentry) ++{ ++ DiMustAnyLock(dentry); ++ return au_di(dentry)->di_bwh; ++} ++ ++static inline aufs_bindex_t au_dbdiropq(struct dentry *dentry) ++{ ++ DiMustAnyLock(dentry); ++ return au_di(dentry)->di_bdiropq; ++} ++ ++/* todo: hard/soft set? */ ++static inline void au_set_dbstart(struct dentry *dentry, aufs_bindex_t bindex) ++{ ++ DiMustWriteLock(dentry); ++ au_di(dentry)->di_bstart = bindex; ++} ++ ++static inline void au_set_dbend(struct dentry *dentry, aufs_bindex_t bindex) ++{ ++ DiMustWriteLock(dentry); ++ au_di(dentry)->di_bend = bindex; ++} ++ ++static inline void au_set_dbwh(struct dentry *dentry, aufs_bindex_t bindex) ++{ ++ DiMustWriteLock(dentry); ++ /* dbwh can be outside of bstart - bend range */ ++ au_di(dentry)->di_bwh = bindex; ++} ++ ++static inline void au_set_dbdiropq(struct dentry *dentry, aufs_bindex_t bindex) ++{ ++ DiMustWriteLock(dentry); ++ au_di(dentry)->di_bdiropq = bindex; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++#ifdef CONFIG_AUFS_HINOTIFY ++static inline void au_digen_dec(struct dentry *d) ++{ ++ atomic_dec_return(&au_di(d)->di_generation); ++} ++ ++static inline void au_hin_di_reinit(struct dentry *dentry) ++{ ++ dentry->d_fsdata = NULL; ++} ++#else ++AuStubVoid(au_hin_di_reinit, struct dentry *dentry __maybe_unused) ++#endif /* CONFIG_AUFS_HINOTIFY */ ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_DENTRY_H__ */ +diff --git a/fs/aufs/dinfo.c b/fs/aufs/dinfo.c +new file mode 100644 +index 0000000..dfe4eb8 +--- /dev/null ++++ b/fs/aufs/dinfo.c +@@ -0,0 +1,367 @@ ++/* ++ * Copyright (C) 2005-2010 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* ++ * dentry private data ++ */ ++ ++#include "aufs.h" ++ ++int au_alloc_dinfo(struct dentry *dentry) ++{ ++ struct au_dinfo *dinfo; ++ struct super_block *sb; ++ int nbr; ++ ++ dinfo = au_cache_alloc_dinfo(); ++ if (unlikely(!dinfo)) ++ goto out; ++ ++ sb = dentry->d_sb; ++ nbr = au_sbend(sb) + 1; ++ if (nbr <= 0) ++ nbr = 1; ++ dinfo->di_hdentry = kcalloc(nbr, sizeof(*dinfo->di_hdentry), GFP_NOFS); ++ if (unlikely(!dinfo->di_hdentry)) ++ goto out_dinfo; ++ ++ atomic_set(&dinfo->di_generation, au_sigen(sb)); ++ /* smp_mb(); */ /* atomic_set */ ++ au_rw_init_wlock_nested(&dinfo->di_rwsem, AuLsc_DI_CHILD); ++ dinfo->di_bstart = -1; ++ dinfo->di_bend = -1; ++ dinfo->di_bwh = -1; ++ dinfo->di_bdiropq = -1; ++ ++ dentry->d_fsdata = dinfo; ++ dentry->d_op = &aufs_dop; ++ return 0; /* success */ ++ ++ out_dinfo: ++ au_cache_free_dinfo(dinfo); ++ out: ++ return -ENOMEM; ++} ++ ++int au_di_realloc(struct au_dinfo *dinfo, int nbr) ++{ ++ int err, sz; ++ struct au_hdentry *hdp; ++ ++ AuRwMustWriteLock(&dinfo->di_rwsem); ++ ++ err = -ENOMEM; ++ sz = sizeof(*hdp) * (dinfo->di_bend + 1); ++ if (!sz) ++ sz = sizeof(*hdp); ++ hdp = au_kzrealloc(dinfo->di_hdentry, sz, sizeof(*hdp) * nbr, GFP_NOFS); ++ if (hdp) { ++ dinfo->di_hdentry = hdp; ++ err = 0; ++ } ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void do_ii_write_lock(struct inode *inode, unsigned int lsc) ++{ ++ switch (lsc) { ++ case AuLsc_DI_CHILD: ++ ii_write_lock_child(inode); ++ break; ++ case AuLsc_DI_CHILD2: ++ ii_write_lock_child2(inode); ++ break; ++ case AuLsc_DI_CHILD3: ++ ii_write_lock_child3(inode); ++ break; ++ case AuLsc_DI_PARENT: ++ ii_write_lock_parent(inode); ++ break; ++ case AuLsc_DI_PARENT2: ++ ii_write_lock_parent2(inode); ++ break; ++ case AuLsc_DI_PARENT3: ++ ii_write_lock_parent3(inode); ++ break; ++ default: ++ BUG(); ++ } ++} ++ ++static void do_ii_read_lock(struct inode *inode, unsigned int lsc) ++{ ++ switch (lsc) { ++ case AuLsc_DI_CHILD: ++ ii_read_lock_child(inode); ++ break; ++ case AuLsc_DI_CHILD2: ++ ii_read_lock_child2(inode); ++ break; ++ case AuLsc_DI_CHILD3: ++ ii_read_lock_child3(inode); ++ break; ++ case AuLsc_DI_PARENT: ++ ii_read_lock_parent(inode); ++ break; ++ case AuLsc_DI_PARENT2: ++ ii_read_lock_parent2(inode); ++ break; ++ case AuLsc_DI_PARENT3: ++ ii_read_lock_parent3(inode); ++ break; ++ default: ++ BUG(); ++ } ++} ++ ++void di_read_lock(struct dentry *d, int flags, unsigned int lsc) ++{ ++ au_rw_read_lock_nested(&au_di(d)->di_rwsem, lsc); ++ if (d->d_inode) { ++ if (au_ftest_lock(flags, IW)) ++ do_ii_write_lock(d->d_inode, lsc); ++ else if (au_ftest_lock(flags, IR)) ++ do_ii_read_lock(d->d_inode, lsc); ++ } ++} ++ ++void di_read_unlock(struct dentry *d, int flags) ++{ ++ if (d->d_inode) { ++ if (au_ftest_lock(flags, IW)) ++ ii_write_unlock(d->d_inode); ++ else if (au_ftest_lock(flags, IR)) ++ ii_read_unlock(d->d_inode); ++ } ++ au_rw_read_unlock(&au_di(d)->di_rwsem); ++} ++ ++void di_downgrade_lock(struct dentry *d, int flags) ++{ ++ if (d->d_inode && au_ftest_lock(flags, IR)) ++ ii_downgrade_lock(d->d_inode); ++ au_rw_dgrade_lock(&au_di(d)->di_rwsem); ++} ++ ++void di_write_lock(struct dentry *d, unsigned int lsc) ++{ ++ au_rw_write_lock_nested(&au_di(d)->di_rwsem, lsc); ++ if (d->d_inode) ++ do_ii_write_lock(d->d_inode, lsc); ++} ++ ++void di_write_unlock(struct dentry *d) ++{ ++ if (d->d_inode) ++ ii_write_unlock(d->d_inode); ++ au_rw_write_unlock(&au_di(d)->di_rwsem); ++} ++ ++void di_write_lock2_child(struct dentry *d1, struct dentry *d2, int isdir) ++{ ++ AuDebugOn(d1 == d2 ++ || d1->d_inode == d2->d_inode ++ || d1->d_sb != d2->d_sb); ++ ++ if (isdir && au_test_subdir(d1, d2)) { ++ di_write_lock_child(d1); ++ di_write_lock_child2(d2); ++ } else { ++ /* there should be no races */ ++ di_write_lock_child(d2); ++ di_write_lock_child2(d1); ++ } ++} ++ ++void di_write_lock2_parent(struct dentry *d1, struct dentry *d2, int isdir) ++{ ++ AuDebugOn(d1 == d2 ++ || d1->d_inode == d2->d_inode ++ || d1->d_sb != d2->d_sb); ++ ++ if (isdir && au_test_subdir(d1, d2)) { ++ di_write_lock_parent(d1); ++ di_write_lock_parent2(d2); ++ } else { ++ /* there should be no races */ ++ di_write_lock_parent(d2); ++ di_write_lock_parent2(d1); ++ } ++} ++ ++void di_write_unlock2(struct dentry *d1, struct dentry *d2) ++{ ++ di_write_unlock(d1); ++ if (d1->d_inode == d2->d_inode) ++ au_rw_write_unlock(&au_di(d2)->di_rwsem); ++ else ++ di_write_unlock(d2); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct dentry *au_h_dptr(struct dentry *dentry, aufs_bindex_t bindex) ++{ ++ struct dentry *d; ++ ++ DiMustAnyLock(dentry); ++ ++ if (au_dbstart(dentry) < 0 || bindex < au_dbstart(dentry)) ++ return NULL; ++ AuDebugOn(bindex < 0); ++ d = au_di(dentry)->di_hdentry[0 + bindex].hd_dentry; ++ AuDebugOn(d && (atomic_read(&d->d_count) <= 0)); ++ return d; ++} ++ ++aufs_bindex_t au_dbtail(struct dentry *dentry) ++{ ++ aufs_bindex_t bend, bwh; ++ ++ bend = au_dbend(dentry); ++ if (0 <= bend) { ++ bwh = au_dbwh(dentry); ++ if (!bwh) ++ return bwh; ++ if (0 < bwh && bwh < bend) ++ return bwh - 1; ++ } ++ return bend; ++} ++ ++aufs_bindex_t au_dbtaildir(struct dentry *dentry) ++{ ++ aufs_bindex_t bend, bopq; ++ ++ bend = au_dbtail(dentry); ++ if (0 <= bend) { ++ bopq = au_dbdiropq(dentry); ++ if (0 <= bopq && bopq < bend) ++ bend = bopq; ++ } ++ return bend; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void au_set_h_dptr(struct dentry *dentry, aufs_bindex_t bindex, ++ struct dentry *h_dentry) ++{ ++ struct au_hdentry *hd = au_di(dentry)->di_hdentry + bindex; ++ ++ DiMustWriteLock(dentry); ++ ++ if (hd->hd_dentry) ++ au_hdput(hd); ++ hd->hd_dentry = h_dentry; ++} ++ ++void au_update_digen(struct dentry *dentry) ++{ ++ atomic_set(&au_di(dentry)->di_generation, au_sigen(dentry->d_sb)); ++ /* smp_mb(); */ /* atomic_set */ ++} ++ ++void au_update_dbrange(struct dentry *dentry, int do_put_zero) ++{ ++ struct au_dinfo *dinfo; ++ struct dentry *h_d; ++ ++ DiMustWriteLock(dentry); ++ ++ dinfo = au_di(dentry); ++ if (!dinfo || dinfo->di_bstart < 0) ++ return; ++ ++ if (do_put_zero) { ++ aufs_bindex_t bindex, bend; ++ ++ bend = dinfo->di_bend; ++ for (bindex = dinfo->di_bstart; bindex <= bend; bindex++) { ++ h_d = dinfo->di_hdentry[0 + bindex].hd_dentry; ++ if (h_d && !h_d->d_inode) ++ au_set_h_dptr(dentry, bindex, NULL); ++ } ++ } ++ ++ dinfo->di_bstart = -1; ++ while (++dinfo->di_bstart <= dinfo->di_bend) ++ if (dinfo->di_hdentry[0 + dinfo->di_bstart].hd_dentry) ++ break; ++ if (dinfo->di_bstart > dinfo->di_bend) { ++ dinfo->di_bstart = -1; ++ dinfo->di_bend = -1; ++ return; ++ } ++ ++ dinfo->di_bend++; ++ while (0 <= --dinfo->di_bend) ++ if (dinfo->di_hdentry[0 + dinfo->di_bend].hd_dentry) ++ break; ++ AuDebugOn(dinfo->di_bstart > dinfo->di_bend || dinfo->di_bend < 0); ++} ++ ++void au_update_dbstart(struct dentry *dentry) ++{ ++ aufs_bindex_t bindex, bend; ++ struct dentry *h_dentry; ++ ++ bend = au_dbend(dentry); ++ for (bindex = au_dbstart(dentry); bindex <= bend; bindex++) { ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (!h_dentry) ++ continue; ++ if (h_dentry->d_inode) { ++ au_set_dbstart(dentry, bindex); ++ return; ++ } ++ au_set_h_dptr(dentry, bindex, NULL); ++ } ++} ++ ++void au_update_dbend(struct dentry *dentry) ++{ ++ aufs_bindex_t bindex, bstart; ++ struct dentry *h_dentry; ++ ++ bstart = au_dbstart(dentry); ++ for (bindex = au_dbend(dentry); bindex <= bstart; bindex--) { ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (!h_dentry) ++ continue; ++ if (h_dentry->d_inode) { ++ au_set_dbend(dentry, bindex); ++ return; ++ } ++ au_set_h_dptr(dentry, bindex, NULL); ++ } ++} ++ ++int au_find_dbindex(struct dentry *dentry, struct dentry *h_dentry) ++{ ++ aufs_bindex_t bindex, bend; ++ ++ bend = au_dbend(dentry); ++ for (bindex = au_dbstart(dentry); bindex <= bend; bindex++) ++ if (au_h_dptr(dentry, bindex) == h_dentry) ++ return bindex; ++ return -1; ++} +diff --git a/fs/aufs/dir.c b/fs/aufs/dir.c +new file mode 100644 +index 0000000..aec9452 +--- /dev/null ++++ b/fs/aufs/dir.c +@@ -0,0 +1,579 @@ ++/* ++ * Copyright (C) 2005-2010 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* ++ * directory operations ++ */ ++ ++#include ++#include ++#include "aufs.h" ++ ++void au_add_nlink(struct inode *dir, struct inode *h_dir) ++{ ++ AuDebugOn(!S_ISDIR(dir->i_mode) || !S_ISDIR(h_dir->i_mode)); ++ ++ dir->i_nlink += h_dir->i_nlink - 2; ++ if (h_dir->i_nlink < 2) ++ dir->i_nlink += 2; ++} ++ ++void au_sub_nlink(struct inode *dir, struct inode *h_dir) ++{ ++ AuDebugOn(!S_ISDIR(dir->i_mode) || !S_ISDIR(h_dir->i_mode)); ++ ++ dir->i_nlink -= h_dir->i_nlink - 2; ++ if (h_dir->i_nlink < 2) ++ dir->i_nlink -= 2; ++} ++ ++loff_t au_dir_size(struct file *file, struct dentry *dentry) ++{ ++ loff_t sz; ++ aufs_bindex_t bindex, bend; ++ struct file *h_file; ++ struct dentry *h_dentry; ++ ++ sz = 0; ++ if (file) { ++ AuDebugOn(!file->f_dentry); ++ AuDebugOn(!file->f_dentry->d_inode); ++ AuDebugOn(!S_ISDIR(file->f_dentry->d_inode->i_mode)); ++ ++ bend = au_fbend(file); ++ for (bindex = au_fbstart(file); ++ bindex <= bend && sz < KMALLOC_MAX_SIZE; ++ bindex++) { ++ h_file = au_h_fptr(file, bindex); ++ if (h_file ++ && h_file->f_dentry ++ && h_file->f_dentry->d_inode) ++ sz += i_size_read(h_file->f_dentry->d_inode); ++ } ++ } else { ++ AuDebugOn(!dentry); ++ AuDebugOn(!dentry->d_inode); ++ AuDebugOn(!S_ISDIR(dentry->d_inode->i_mode)); ++ ++ bend = au_dbtaildir(dentry); ++ for (bindex = au_dbstart(dentry); ++ bindex <= bend && sz < KMALLOC_MAX_SIZE; ++ bindex++) { ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (h_dentry && h_dentry->d_inode) ++ sz += i_size_read(h_dentry->d_inode); ++ } ++ } ++ if (sz < KMALLOC_MAX_SIZE) ++ sz = roundup_pow_of_two(sz); ++ if (sz > KMALLOC_MAX_SIZE) ++ sz = KMALLOC_MAX_SIZE; ++ else if (sz < NAME_MAX) { ++ BUILD_BUG_ON(AUFS_RDBLK_DEF < NAME_MAX); ++ sz = AUFS_RDBLK_DEF; ++ } ++ return sz; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int reopen_dir(struct file *file) ++{ ++ int err; ++ unsigned int flags; ++ aufs_bindex_t bindex, btail, bstart; ++ struct dentry *dentry, *h_dentry; ++ struct file *h_file; ++ ++ /* open all lower dirs */ ++ dentry = file->f_dentry; ++ bstart = au_dbstart(dentry); ++ for (bindex = au_fbstart(file); bindex < bstart; bindex++) ++ au_set_h_fptr(file, bindex, NULL); ++ au_set_fbstart(file, bstart); ++ ++ btail = au_dbtaildir(dentry); ++ for (bindex = au_fbend(file); btail < bindex; bindex--) ++ au_set_h_fptr(file, bindex, NULL); ++ au_set_fbend(file, btail); ++ ++ flags = vfsub_file_flags(file); ++ for (bindex = bstart; bindex <= btail; bindex++) { ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (!h_dentry) ++ continue; ++ h_file = au_h_fptr(file, bindex); ++ if (h_file) ++ continue; ++ ++ h_file = au_h_open(dentry, bindex, flags, file); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out; /* close all? */ ++ au_set_h_fptr(file, bindex, h_file); ++ } ++ au_update_figen(file); ++ /* todo: necessary? */ ++ /* file->f_ra = h_file->f_ra; */ ++ err = 0; ++ ++ out: ++ return err; ++} ++ ++static int do_open_dir(struct file *file, int flags) ++{ ++ int err; ++ aufs_bindex_t bindex, btail; ++ struct dentry *dentry, *h_dentry; ++ struct file *h_file; ++ ++ FiMustWriteLock(file); ++ ++ err = 0; ++ dentry = file->f_dentry; ++ au_set_fvdir_cache(file, NULL); ++ file->f_version = dentry->d_inode->i_version; ++ bindex = au_dbstart(dentry); ++ au_set_fbstart(file, bindex); ++ btail = au_dbtaildir(dentry); ++ au_set_fbend(file, btail); ++ for (; !err && bindex <= btail; bindex++) { ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (!h_dentry) ++ continue; ++ ++ h_file = au_h_open(dentry, bindex, flags, file); ++ if (IS_ERR(h_file)) { ++ err = PTR_ERR(h_file); ++ break; ++ } ++ au_set_h_fptr(file, bindex, h_file); ++ } ++ au_update_figen(file); ++ /* todo: necessary? */ ++ /* file->f_ra = h_file->f_ra; */ ++ if (!err) ++ return 0; /* success */ ++ ++ /* close all */ ++ for (bindex = au_fbstart(file); bindex <= btail; bindex++) ++ au_set_h_fptr(file, bindex, NULL); ++ au_set_fbstart(file, -1); ++ au_set_fbend(file, -1); ++ return err; ++} ++ ++static int aufs_open_dir(struct inode *inode __maybe_unused, ++ struct file *file) ++{ ++ return au_do_open(file, do_open_dir); ++} ++ ++static int aufs_release_dir(struct inode *inode __maybe_unused, ++ struct file *file) ++{ ++ struct au_vdir *vdir_cache; ++ struct super_block *sb; ++ ++ sb = file->f_dentry->d_sb; ++ vdir_cache = au_fi(file)->fi_vdir_cache; /* lock-free */ ++ if (vdir_cache) ++ au_vdir_free(vdir_cache); ++ au_plink_maint_leave(file); ++ au_finfo_fin(file); ++ return 0; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_do_fsync_dir_no_file(struct dentry *dentry, int datasync) ++{ ++ int err; ++ aufs_bindex_t bend, bindex; ++ struct inode *inode; ++ struct super_block *sb; ++ ++ err = 0; ++ sb = dentry->d_sb; ++ inode = dentry->d_inode; ++ IMustLock(inode); ++ bend = au_dbend(dentry); ++ for (bindex = au_dbstart(dentry); !err && bindex <= bend; bindex++) { ++ struct path h_path; ++ struct inode *h_inode; ++ ++ if (au_test_ro(sb, bindex, inode)) ++ continue; ++ h_path.dentry = au_h_dptr(dentry, bindex); ++ if (!h_path.dentry) ++ continue; ++ h_inode = h_path.dentry->d_inode; ++ if (!h_inode) ++ continue; ++ ++ /* no mnt_want_write() */ ++ /* cf. fs/nsfd/vfs.c and fs/nfsd/nfs4recover.c */ ++ /* todo: inotiry fired? */ ++ h_path.mnt = au_sbr_mnt(sb, bindex); ++ mutex_lock(&h_inode->i_mutex); ++ err = filemap_fdatawrite(h_inode->i_mapping); ++ AuDebugOn(!h_inode->i_fop); ++ if (!err && h_inode->i_fop->fsync) ++ err = h_inode->i_fop->fsync(NULL, h_path.dentry, ++ datasync); ++ if (!err) ++ err = filemap_fdatawrite(h_inode->i_mapping); ++ if (!err) ++ vfsub_update_h_iattr(&h_path, /*did*/NULL); /*ignore*/ ++ mutex_unlock(&h_inode->i_mutex); ++ } ++ ++ return err; ++} ++ ++static int au_do_fsync_dir(struct file *file, int datasync) ++{ ++ int err; ++ aufs_bindex_t bend, bindex; ++ struct file *h_file; ++ struct super_block *sb; ++ struct inode *inode; ++ struct mutex *h_mtx; ++ ++ err = au_reval_and_lock_fdi(file, reopen_dir, /*wlock*/1); ++ if (unlikely(err)) ++ goto out; ++ ++ sb = file->f_dentry->d_sb; ++ inode = file->f_dentry->d_inode; ++ bend = au_fbend(file); ++ for (bindex = au_fbstart(file); !err && bindex <= bend; bindex++) { ++ h_file = au_h_fptr(file, bindex); ++ if (!h_file || au_test_ro(sb, bindex, inode)) ++ continue; ++ ++ err = vfs_fsync(h_file, h_file->f_dentry, datasync); ++ if (!err) { ++ h_mtx = &h_file->f_dentry->d_inode->i_mutex; ++ mutex_lock(h_mtx); ++ vfsub_update_h_iattr(&h_file->f_path, /*did*/NULL); ++ /*ignore*/ ++ mutex_unlock(h_mtx); ++ } ++ } ++ ++ out: ++ return err; ++} ++ ++/* ++ * @file may be NULL ++ */ ++static int aufs_fsync_dir(struct file *file, struct dentry *dentry, ++ int datasync) ++{ ++ int err; ++ struct super_block *sb; ++ ++ IMustLock(dentry->d_inode); ++ ++ err = 0; ++ sb = dentry->d_sb; ++ si_noflush_read_lock(sb); ++ if (file) ++ err = au_do_fsync_dir(file, datasync); ++ else { ++ di_write_lock_child(dentry); ++ err = au_do_fsync_dir_no_file(dentry, datasync); ++ } ++ au_cpup_attr_timesizes(dentry->d_inode); ++ di_write_unlock(dentry); ++ if (file) ++ fi_write_unlock(file); ++ ++ si_read_unlock(sb); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int aufs_readdir(struct file *file, void *dirent, filldir_t filldir) ++{ ++ int err; ++ struct dentry *dentry; ++ struct inode *inode; ++ struct super_block *sb; ++ ++ dentry = file->f_dentry; ++ inode = dentry->d_inode; ++ IMustLock(inode); ++ ++ sb = dentry->d_sb; ++ si_read_lock(sb, AuLock_FLUSH); ++ err = au_reval_and_lock_fdi(file, reopen_dir, /*wlock*/1); ++ if (unlikely(err)) ++ goto out; ++ err = au_vdir_init(file); ++ di_downgrade_lock(dentry, AuLock_IR); ++ if (unlikely(err)) ++ goto out_unlock; ++ ++ if (!au_test_nfsd(current)) { ++ err = au_vdir_fill_de(file, dirent, filldir); ++ fsstack_copy_attr_atime(inode, ++ au_h_iptr(inode, au_ibstart(inode))); ++ } else { ++ /* ++ * nfsd filldir may call lookup_one_len(), vfs_getattr(), ++ * encode_fh() and others. ++ */ ++ struct inode *h_inode = au_h_iptr(inode, au_ibstart(inode)); ++ ++ di_read_unlock(dentry, AuLock_IR); ++ si_read_unlock(sb); ++ /* lockdep_off(); */ ++ err = au_vdir_fill_de(file, dirent, filldir); ++ /* lockdep_on(); */ ++ fsstack_copy_attr_atime(inode, h_inode); ++ fi_write_unlock(file); ++ ++ AuTraceErr(err); ++ return err; ++ } ++ ++ out_unlock: ++ di_read_unlock(dentry, AuLock_IR); ++ fi_write_unlock(file); ++ out: ++ si_read_unlock(sb); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++#define AuTestEmpty_WHONLY 1 ++#define AuTestEmpty_CALLED (1 << 1) ++#define AuTestEmpty_SHWH (1 << 2) ++#define au_ftest_testempty(flags, name) ((flags) & AuTestEmpty_##name) ++#define au_fset_testempty(flags, name) { (flags) |= AuTestEmpty_##name; } ++#define au_fclr_testempty(flags, name) { (flags) &= ~AuTestEmpty_##name; } ++ ++#ifndef CONFIG_AUFS_SHWH ++#undef AuTestEmpty_SHWH ++#define AuTestEmpty_SHWH 0 ++#endif ++ ++struct test_empty_arg { ++ struct au_nhash *whlist; ++ unsigned int flags; ++ int err; ++ aufs_bindex_t bindex; ++}; ++ ++static int test_empty_cb(void *__arg, const char *__name, int namelen, ++ loff_t offset __maybe_unused, u64 ino, ++ unsigned int d_type) ++{ ++ struct test_empty_arg *arg = __arg; ++ char *name = (void *)__name; ++ ++ arg->err = 0; ++ au_fset_testempty(arg->flags, CALLED); ++ /* smp_mb(); */ ++ if (name[0] == '.' ++ && (namelen == 1 || (name[1] == '.' && namelen == 2))) ++ goto out; /* success */ ++ ++ if (namelen <= AUFS_WH_PFX_LEN ++ || memcmp(name, AUFS_WH_PFX, AUFS_WH_PFX_LEN)) { ++ if (au_ftest_testempty(arg->flags, WHONLY) ++ && !au_nhash_test_known_wh(arg->whlist, name, namelen)) ++ arg->err = -ENOTEMPTY; ++ goto out; ++ } ++ ++ name += AUFS_WH_PFX_LEN; ++ namelen -= AUFS_WH_PFX_LEN; ++ if (!au_nhash_test_known_wh(arg->whlist, name, namelen)) ++ arg->err = au_nhash_append_wh ++ (arg->whlist, name, namelen, ino, d_type, arg->bindex, ++ au_ftest_testempty(arg->flags, SHWH)); ++ ++ out: ++ /* smp_mb(); */ ++ AuTraceErr(arg->err); ++ return arg->err; ++} ++ ++static int do_test_empty(struct dentry *dentry, struct test_empty_arg *arg) ++{ ++ int err; ++ struct file *h_file; ++ ++ h_file = au_h_open(dentry, arg->bindex, ++ O_RDONLY | O_NONBLOCK | O_DIRECTORY | O_LARGEFILE, ++ /*file*/NULL); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out; ++ ++ err = 0; ++ if (!au_opt_test(au_mntflags(dentry->d_sb), UDBA_NONE) ++ && !h_file->f_dentry->d_inode->i_nlink) ++ goto out_put; ++ ++ do { ++ arg->err = 0; ++ au_fclr_testempty(arg->flags, CALLED); ++ /* smp_mb(); */ ++ err = vfsub_readdir(h_file, test_empty_cb, arg); ++ if (err >= 0) ++ err = arg->err; ++ } while (!err && au_ftest_testempty(arg->flags, CALLED)); ++ ++ out_put: ++ fput(h_file); ++ au_sbr_put(dentry->d_sb, arg->bindex); ++ out: ++ return err; ++} ++ ++struct do_test_empty_args { ++ int *errp; ++ struct dentry *dentry; ++ struct test_empty_arg *arg; ++}; ++ ++static void call_do_test_empty(void *args) ++{ ++ struct do_test_empty_args *a = args; ++ *a->errp = do_test_empty(a->dentry, a->arg); ++} ++ ++static int sio_test_empty(struct dentry *dentry, struct test_empty_arg *arg) ++{ ++ int err, wkq_err; ++ struct dentry *h_dentry; ++ struct inode *h_inode; ++ ++ h_dentry = au_h_dptr(dentry, arg->bindex); ++ h_inode = h_dentry->d_inode; ++ mutex_lock_nested(&h_inode->i_mutex, AuLsc_I_CHILD); ++ err = au_test_h_perm_sio(h_inode, MAY_EXEC | MAY_READ); ++ mutex_unlock(&h_inode->i_mutex); ++ if (!err) ++ err = do_test_empty(dentry, arg); ++ else { ++ struct do_test_empty_args args = { ++ .errp = &err, ++ .dentry = dentry, ++ .arg = arg ++ }; ++ unsigned int flags = arg->flags; ++ ++ wkq_err = au_wkq_wait(call_do_test_empty, &args); ++ if (unlikely(wkq_err)) ++ err = wkq_err; ++ arg->flags = flags; ++ } ++ ++ return err; ++} ++ ++int au_test_empty_lower(struct dentry *dentry) ++{ ++ int err; ++ unsigned int rdhash; ++ aufs_bindex_t bindex, bstart, btail; ++ struct au_nhash whlist; ++ struct test_empty_arg arg; ++ ++ SiMustAnyLock(dentry->d_sb); ++ ++ rdhash = au_sbi(dentry->d_sb)->si_rdhash; ++ if (!rdhash) ++ rdhash = au_rdhash_est(au_dir_size(/*file*/NULL, dentry)); ++ err = au_nhash_alloc(&whlist, rdhash, GFP_NOFS); ++ if (unlikely(err)) ++ goto out; ++ ++ arg.flags = 0; ++ arg.whlist = &whlist; ++ bstart = au_dbstart(dentry); ++ if (au_opt_test(au_mntflags(dentry->d_sb), SHWH)) ++ au_fset_testempty(arg.flags, SHWH); ++ arg.bindex = bstart; ++ err = do_test_empty(dentry, &arg); ++ if (unlikely(err)) ++ goto out_whlist; ++ ++ au_fset_testempty(arg.flags, WHONLY); ++ btail = au_dbtaildir(dentry); ++ for (bindex = bstart + 1; !err && bindex <= btail; bindex++) { ++ struct dentry *h_dentry; ++ ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (h_dentry && h_dentry->d_inode) { ++ arg.bindex = bindex; ++ err = do_test_empty(dentry, &arg); ++ } ++ } ++ ++ out_whlist: ++ au_nhash_wh_free(&whlist); ++ out: ++ return err; ++} ++ ++int au_test_empty(struct dentry *dentry, struct au_nhash *whlist) ++{ ++ int err; ++ struct test_empty_arg arg; ++ aufs_bindex_t bindex, btail; ++ ++ err = 0; ++ arg.whlist = whlist; ++ arg.flags = AuTestEmpty_WHONLY; ++ if (au_opt_test(au_mntflags(dentry->d_sb), SHWH)) ++ au_fset_testempty(arg.flags, SHWH); ++ btail = au_dbtaildir(dentry); ++ for (bindex = au_dbstart(dentry); !err && bindex <= btail; bindex++) { ++ struct dentry *h_dentry; ++ ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (h_dentry && h_dentry->d_inode) { ++ arg.bindex = bindex; ++ err = sio_test_empty(dentry, &arg); ++ } ++ } ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++const struct file_operations aufs_dir_fop = { ++ .read = generic_read_dir, ++ .readdir = aufs_readdir, ++ .unlocked_ioctl = aufs_ioctl_dir, ++ .open = aufs_open_dir, ++ .release = aufs_release_dir, ++ .flush = aufs_flush, ++ .fsync = aufs_fsync_dir ++}; +diff --git a/fs/aufs/dir.h b/fs/aufs/dir.h +new file mode 100644 +index 0000000..8ba9c88 +--- /dev/null ++++ b/fs/aufs/dir.h +@@ -0,0 +1,127 @@ ++/* ++ * Copyright (C) 2005-2010 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* ++ * directory operations ++ */ ++ ++#ifndef __AUFS_DIR_H__ ++#define __AUFS_DIR_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* need to be faster and smaller */ ++ ++struct au_nhash { ++ unsigned int nh_num; ++ struct hlist_head *nh_head; ++}; ++ ++struct au_vdir_destr { ++ unsigned char len; ++ unsigned char name[0]; ++} __packed; ++ ++struct au_vdir_dehstr { ++ struct hlist_node hash; ++ struct au_vdir_destr *str; ++}; ++ ++struct au_vdir_de { ++ ino_t de_ino; ++ unsigned char de_type; ++ /* caution: packed */ ++ struct au_vdir_destr de_str; ++} __packed; ++ ++struct au_vdir_wh { ++ struct hlist_node wh_hash; ++#ifdef CONFIG_AUFS_SHWH ++ ino_t wh_ino; ++ aufs_bindex_t wh_bindex; ++ unsigned char wh_type; ++#else ++ aufs_bindex_t wh_bindex; ++#endif ++ /* caution: packed */ ++ struct au_vdir_destr wh_str; ++} __packed; ++ ++union au_vdir_deblk_p { ++ unsigned char *deblk; ++ struct au_vdir_de *de; ++}; ++ ++struct au_vdir { ++ unsigned char **vd_deblk; ++ unsigned long vd_nblk; ++ struct { ++ unsigned long ul; ++ union au_vdir_deblk_p p; ++ } vd_last; ++ ++ unsigned long vd_version; ++ unsigned int vd_deblk_sz; ++ unsigned long vd_jiffy; ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* dir.c */ ++extern const struct file_operations aufs_dir_fop; ++void au_add_nlink(struct inode *dir, struct inode *h_dir); ++void au_sub_nlink(struct inode *dir, struct inode *h_dir); ++loff_t au_dir_size(struct file *file, struct dentry *dentry); ++int au_test_empty_lower(struct dentry *dentry); ++int au_test_empty(struct dentry *dentry, struct au_nhash *whlist); ++ ++/* vdir.c */ ++unsigned int au_rdhash_est(loff_t sz); ++int au_nhash_alloc(struct au_nhash *nhash, unsigned int num_hash, gfp_t gfp); ++void au_nhash_wh_free(struct au_nhash *whlist); ++int au_nhash_test_longer_wh(struct au_nhash *whlist, aufs_bindex_t btgt, ++ int limit); ++int au_nhash_test_known_wh(struct au_nhash *whlist, char *name, int nlen); ++int au_nhash_append_wh(struct au_nhash *whlist, char *name, int nlen, ino_t ino, ++ unsigned int d_type, aufs_bindex_t bindex, ++ unsigned char shwh); ++void au_vdir_free(struct au_vdir *vdir); ++int au_vdir_init(struct file *file); ++int au_vdir_fill_de(struct file *file, void *dirent, filldir_t filldir); ++ ++/* ioctl.c */ ++long aufs_ioctl_dir(struct file *file, unsigned int cmd, unsigned long arg); ++ ++#ifdef CONFIG_AUFS_RDU ++/* rdu.c */ ++long au_rdu_ioctl(struct file *file, unsigned int cmd, unsigned long arg); ++#else ++static inline long au_rdu_ioctl(struct file *file, unsigned int cmd, ++ unsigned long arg) ++{ ++ return -EINVAL; ++} ++#endif ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_DIR_H__ */ +diff --git a/fs/aufs/export.c b/fs/aufs/export.c +new file mode 100644 +index 0000000..1b3a9d9 +--- /dev/null ++++ b/fs/aufs/export.c +@@ -0,0 +1,745 @@ ++/* ++ * Copyright (C) 2005-2010 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* ++ * export via nfs ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "aufs.h" ++ ++union conv { ++#ifdef CONFIG_AUFS_INO_T_64 ++ __u32 a[2]; ++#else ++ __u32 a[1]; ++#endif ++ ino_t ino; ++}; ++ ++static ino_t decode_ino(__u32 *a) ++{ ++ union conv u; ++ ++ BUILD_BUG_ON(sizeof(u.ino) != sizeof(u.a)); ++ u.a[0] = a[0]; ++#ifdef CONFIG_AUFS_INO_T_64 ++ u.a[1] = a[1]; ++#endif ++ return u.ino; ++} ++ ++static void encode_ino(__u32 *a, ino_t ino) ++{ ++ union conv u; ++ ++ u.ino = ino; ++ a[0] = u.a[0]; ++#ifdef CONFIG_AUFS_INO_T_64 ++ a[1] = u.a[1]; ++#endif ++} ++ ++/* NFS file handle */ ++enum { ++ Fh_br_id, ++ Fh_sigen, ++#ifdef CONFIG_AUFS_INO_T_64 ++ /* support 64bit inode number */ ++ Fh_ino1, ++ Fh_ino2, ++ Fh_dir_ino1, ++ Fh_dir_ino2, ++#else ++ Fh_ino1, ++ Fh_dir_ino1, ++#endif ++ Fh_igen, ++ Fh_h_type, ++ Fh_tail, ++ ++ Fh_ino = Fh_ino1, ++ Fh_dir_ino = Fh_dir_ino1 ++}; ++ ++static int au_test_anon(struct dentry *dentry) ++{ ++ return !!(dentry->d_flags & DCACHE_DISCONNECTED); ++} ++ ++/* ---------------------------------------------------------------------- */ ++/* inode generation external table */ ++ ++int au_xigen_inc(struct inode *inode) ++{ ++ int err; ++ loff_t pos; ++ ssize_t sz; ++ __u32 igen; ++ struct super_block *sb; ++ struct au_sbinfo *sbinfo; ++ ++ err = 0; ++ sb = inode->i_sb; ++ sbinfo = au_sbi(sb); ++ /* ++ * temporary workaround for escaping from SiMustAnyLock() in ++ * au_mntflags(), since this function is called from au_iinfo_fin(). ++ */ ++ if (unlikely(!au_opt_test(sbinfo->si_mntflags, XINO))) ++ goto out; ++ ++ pos = inode->i_ino; ++ pos *= sizeof(igen); ++ igen = inode->i_generation + 1; ++ sz = xino_fwrite(sbinfo->si_xwrite, sbinfo->si_xigen, &igen, ++ sizeof(igen), &pos); ++ if (sz == sizeof(igen)) ++ goto out; /* success */ ++ ++ err = sz; ++ if (unlikely(sz >= 0)) { ++ err = -EIO; ++ AuIOErr("xigen error (%zd)\n", sz); ++ } ++ ++ out: ++ return err; ++} ++ ++int au_xigen_new(struct inode *inode) ++{ ++ int err; ++ loff_t pos; ++ ssize_t sz; ++ struct super_block *sb; ++ struct au_sbinfo *sbinfo; ++ struct file *file; ++ ++ err = 0; ++ /* todo: dirty, at mount time */ ++ if (inode->i_ino == AUFS_ROOT_INO) ++ goto out; ++ sb = inode->i_sb; ++ SiMustAnyLock(sb); ++ if (unlikely(!au_opt_test(au_mntflags(sb), XINO))) ++ goto out; ++ ++ err = -EFBIG; ++ pos = inode->i_ino; ++ if (unlikely(au_loff_max / sizeof(inode->i_generation) - 1 < pos)) { ++ AuIOErr1("too large i%lld\n", pos); ++ goto out; ++ } ++ pos *= sizeof(inode->i_generation); ++ ++ err = 0; ++ sbinfo = au_sbi(sb); ++ file = sbinfo->si_xigen; ++ BUG_ON(!file); ++ ++ if (i_size_read(file->f_dentry->d_inode) ++ < pos + sizeof(inode->i_generation)) { ++ inode->i_generation = atomic_inc_return(&sbinfo->si_xigen_next); ++ sz = xino_fwrite(sbinfo->si_xwrite, file, &inode->i_generation, ++ sizeof(inode->i_generation), &pos); ++ } else ++ sz = xino_fread(sbinfo->si_xread, file, &inode->i_generation, ++ sizeof(inode->i_generation), &pos); ++ if (sz == sizeof(inode->i_generation)) ++ goto out; /* success */ ++ ++ err = sz; ++ if (unlikely(sz >= 0)) { ++ err = -EIO; ++ AuIOErr("xigen error (%zd)\n", sz); ++ } ++ ++ out: ++ return err; ++} ++ ++int au_xigen_set(struct super_block *sb, struct file *base) ++{ ++ int err; ++ struct au_sbinfo *sbinfo; ++ struct file *file; ++ ++ SiMustWriteLock(sb); ++ ++ sbinfo = au_sbi(sb); ++ file = au_xino_create2(base, sbinfo->si_xigen); ++ err = PTR_ERR(file); ++ if (IS_ERR(file)) ++ goto out; ++ err = 0; ++ if (sbinfo->si_xigen) ++ fput(sbinfo->si_xigen); ++ sbinfo->si_xigen = file; ++ ++ out: ++ return err; ++} ++ ++void au_xigen_clr(struct super_block *sb) ++{ ++ struct au_sbinfo *sbinfo; ++ ++ SiMustWriteLock(sb); ++ ++ sbinfo = au_sbi(sb); ++ if (sbinfo->si_xigen) { ++ fput(sbinfo->si_xigen); ++ sbinfo->si_xigen = NULL; ++ } ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static struct dentry *decode_by_ino(struct super_block *sb, ino_t ino, ++ ino_t dir_ino) ++{ ++ struct dentry *dentry, *d; ++ struct inode *inode; ++ unsigned int sigen; ++ ++ dentry = NULL; ++ inode = ilookup(sb, ino); ++ if (!inode) ++ goto out; ++ ++ dentry = ERR_PTR(-ESTALE); ++ sigen = au_sigen(sb); ++ if (unlikely(is_bad_inode(inode) ++ || IS_DEADDIR(inode) ++ || sigen != au_iigen(inode))) ++ goto out_iput; ++ ++ dentry = NULL; ++ if (!dir_ino || S_ISDIR(inode->i_mode)) ++ dentry = d_find_alias(inode); ++ else { ++ spin_lock(&dcache_lock); ++ list_for_each_entry(d, &inode->i_dentry, d_alias) ++ if (!au_test_anon(d) ++ && d->d_parent->d_inode->i_ino == dir_ino) { ++ dentry = dget_locked(d); ++ break; ++ } ++ spin_unlock(&dcache_lock); ++ } ++ if (unlikely(dentry && sigen != au_digen(dentry))) { ++ dput(dentry); ++ dentry = ERR_PTR(-ESTALE); ++ } ++ ++ out_iput: ++ iput(inode); ++ out: ++ return dentry; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* todo: dirty? */ ++/* if exportfs_decode_fh() passed vfsmount*, we could be happy */ ++static struct vfsmount *au_mnt_get(struct super_block *sb) ++{ ++ struct mnt_namespace *ns; ++ struct vfsmount *pos, *mnt; ++ ++ spin_lock(&vfsmount_lock); ++ /* no get/put ?? */ ++ AuDebugOn(!current->nsproxy); ++ ns = current->nsproxy->mnt_ns; ++ AuDebugOn(!ns); ++ mnt = NULL; ++ /* the order (reverse) will not be a problem */ ++ list_for_each_entry(pos, &ns->list, mnt_list) ++ if (pos->mnt_sb == sb) { ++ mnt = mntget(pos); ++ break; ++ } ++ spin_unlock(&vfsmount_lock); ++ AuDebugOn(!mnt); ++ ++ return mnt; ++} ++ ++struct au_nfsd_si_lock { ++ const unsigned int sigen; ++ const aufs_bindex_t br_id; ++ unsigned char force_lock; ++}; ++ ++static aufs_bindex_t si_nfsd_read_lock(struct super_block *sb, ++ struct au_nfsd_si_lock *nsi_lock) ++{ ++ aufs_bindex_t bindex; ++ ++ si_read_lock(sb, AuLock_FLUSH); ++ ++ /* branch id may be wrapped around */ ++ bindex = au_br_index(sb, nsi_lock->br_id); ++ if (bindex >= 0 && nsi_lock->sigen + AUFS_BRANCH_MAX > au_sigen(sb)) ++ goto out; /* success */ ++ ++ if (!nsi_lock->force_lock) ++ si_read_unlock(sb); ++ bindex = -1; ++ ++ out: ++ return bindex; ++} ++ ++struct find_name_by_ino { ++ int called, found; ++ ino_t ino; ++ char *name; ++ int namelen; ++}; ++ ++static int ++find_name_by_ino(void *arg, const char *name, int namelen, loff_t offset, ++ u64 ino, unsigned int d_type) ++{ ++ struct find_name_by_ino *a = arg; ++ ++ a->called++; ++ if (a->ino != ino) ++ return 0; ++ ++ memcpy(a->name, name, namelen); ++ a->namelen = namelen; ++ a->found = 1; ++ return 1; ++} ++ ++static struct dentry *au_lkup_by_ino(struct path *path, ino_t ino, ++ struct au_nfsd_si_lock *nsi_lock) ++{ ++ struct dentry *dentry, *parent; ++ struct file *file; ++ struct inode *dir; ++ struct find_name_by_ino arg; ++ int err; ++ ++ parent = path->dentry; ++ if (nsi_lock) ++ si_read_unlock(parent->d_sb); ++ file = vfsub_dentry_open(path, au_dir_roflags); ++ dentry = (void *)file; ++ if (IS_ERR(file)) ++ goto out; ++ ++ dentry = ERR_PTR(-ENOMEM); ++ arg.name = __getname(); ++ if (unlikely(!arg.name)) ++ goto out_file; ++ arg.ino = ino; ++ arg.found = 0; ++ do { ++ arg.called = 0; ++ /* smp_mb(); */ ++ err = vfsub_readdir(file, find_name_by_ino, &arg); ++ } while (!err && !arg.found && arg.called); ++ dentry = ERR_PTR(err); ++ if (unlikely(err)) ++ goto out_name; ++ dentry = ERR_PTR(-ENOENT); ++ if (!arg.found) ++ goto out_name; ++ ++ /* do not call au_lkup_one() */ ++ dir = parent->d_inode; ++ mutex_lock(&dir->i_mutex); ++ dentry = vfsub_lookup_one_len(arg.name, parent, arg.namelen); ++ mutex_unlock(&dir->i_mutex); ++ AuTraceErrPtr(dentry); ++ if (IS_ERR(dentry)) ++ goto out_name; ++ AuDebugOn(au_test_anon(dentry)); ++ if (unlikely(!dentry->d_inode)) { ++ dput(dentry); ++ dentry = ERR_PTR(-ENOENT); ++ } ++ ++ out_name: ++ __putname(arg.name); ++ out_file: ++ fput(file); ++ out: ++ if (unlikely(nsi_lock ++ && si_nfsd_read_lock(parent->d_sb, nsi_lock) < 0)) ++ if (!IS_ERR(dentry)) { ++ dput(dentry); ++ dentry = ERR_PTR(-ESTALE); ++ } ++ AuTraceErrPtr(dentry); ++ return dentry; ++} ++ ++static struct dentry *decode_by_dir_ino(struct super_block *sb, ino_t ino, ++ ino_t dir_ino, ++ struct au_nfsd_si_lock *nsi_lock) ++{ ++ struct dentry *dentry; ++ struct path path; ++ ++ if (dir_ino != AUFS_ROOT_INO) { ++ path.dentry = decode_by_ino(sb, dir_ino, 0); ++ dentry = path.dentry; ++ if (!path.dentry || IS_ERR(path.dentry)) ++ goto out; ++ AuDebugOn(au_test_anon(path.dentry)); ++ } else ++ path.dentry = dget(sb->s_root); ++ ++ path.mnt = au_mnt_get(sb); ++ dentry = au_lkup_by_ino(&path, ino, nsi_lock); ++ path_put(&path); ++ ++ out: ++ AuTraceErrPtr(dentry); ++ return dentry; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int h_acceptable(void *expv, struct dentry *dentry) ++{ ++ return 1; ++} ++ ++static char *au_build_path(struct dentry *h_parent, struct path *h_rootpath, ++ char *buf, int len, struct super_block *sb) ++{ ++ char *p; ++ int n; ++ struct path path; ++ ++ p = d_path(h_rootpath, buf, len); ++ if (IS_ERR(p)) ++ goto out; ++ n = strlen(p); ++ ++ path.mnt = h_rootpath->mnt; ++ path.dentry = h_parent; ++ p = d_path(&path, buf, len); ++ if (IS_ERR(p)) ++ goto out; ++ if (n != 1) ++ p += n; ++ ++ path.mnt = au_mnt_get(sb); ++ path.dentry = sb->s_root; ++ p = d_path(&path, buf, len - strlen(p)); ++ mntput(path.mnt); ++ if (IS_ERR(p)) ++ goto out; ++ if (n != 1) ++ p[strlen(p)] = '/'; ++ ++ out: ++ AuTraceErrPtr(p); ++ return p; ++} ++ ++static ++struct dentry *decode_by_path(struct super_block *sb, aufs_bindex_t bindex, ++ ino_t ino, __u32 *fh, int fh_len, ++ struct au_nfsd_si_lock *nsi_lock) ++{ ++ struct dentry *dentry, *h_parent, *root; ++ struct super_block *h_sb; ++ char *pathname, *p; ++ struct vfsmount *h_mnt; ++ struct au_branch *br; ++ int err; ++ struct path path; ++ ++ br = au_sbr(sb, bindex); ++ /* au_br_get(br); */ ++ h_mnt = br->br_mnt; ++ h_sb = h_mnt->mnt_sb; ++ /* todo: call lower fh_to_dentry()? fh_to_parent()? */ ++ h_parent = exportfs_decode_fh(h_mnt, (void *)(fh + Fh_tail), ++ fh_len - Fh_tail, fh[Fh_h_type], ++ h_acceptable, /*context*/NULL); ++ dentry = h_parent; ++ if (unlikely(!h_parent || IS_ERR(h_parent))) { ++ AuWarn1("%s decode_fh failed, %ld\n", ++ au_sbtype(h_sb), PTR_ERR(h_parent)); ++ goto out; ++ } ++ dentry = NULL; ++ if (unlikely(au_test_anon(h_parent))) { ++ AuWarn1("%s decode_fh returned a disconnected dentry\n", ++ au_sbtype(h_sb)); ++ goto out_h_parent; ++ } ++ ++ dentry = ERR_PTR(-ENOMEM); ++ pathname = (void *)__get_free_page(GFP_NOFS); ++ if (unlikely(!pathname)) ++ goto out_h_parent; ++ ++ root = sb->s_root; ++ path.mnt = h_mnt; ++ di_read_lock_parent(root, !AuLock_IR); ++ path.dentry = au_h_dptr(root, bindex); ++ di_read_unlock(root, !AuLock_IR); ++ p = au_build_path(h_parent, &path, pathname, PAGE_SIZE, sb); ++ dentry = (void *)p; ++ if (IS_ERR(p)) ++ goto out_pathname; ++ ++ si_read_unlock(sb); ++ err = vfsub_kern_path(p, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &path); ++ dentry = ERR_PTR(err); ++ if (unlikely(err)) ++ goto out_relock; ++ ++ dentry = ERR_PTR(-ENOENT); ++ AuDebugOn(au_test_anon(path.dentry)); ++ if (unlikely(!path.dentry->d_inode)) ++ goto out_path; ++ ++ if (ino != path.dentry->d_inode->i_ino) ++ dentry = au_lkup_by_ino(&path, ino, /*nsi_lock*/NULL); ++ else ++ dentry = dget(path.dentry); ++ ++ out_path: ++ path_put(&path); ++ out_relock: ++ if (unlikely(si_nfsd_read_lock(sb, nsi_lock) < 0)) ++ if (!IS_ERR(dentry)) { ++ dput(dentry); ++ dentry = ERR_PTR(-ESTALE); ++ } ++ out_pathname: ++ free_page((unsigned long)pathname); ++ out_h_parent: ++ dput(h_parent); ++ out: ++ /* au_br_put(br); */ ++ AuTraceErrPtr(dentry); ++ return dentry; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static struct dentry * ++aufs_fh_to_dentry(struct super_block *sb, struct fid *fid, int fh_len, ++ int fh_type) ++{ ++ struct dentry *dentry; ++ __u32 *fh = fid->raw; ++ ino_t ino, dir_ino; ++ aufs_bindex_t bindex; ++ struct au_nfsd_si_lock nsi_lock = { ++ .sigen = fh[Fh_sigen], ++ .br_id = fh[Fh_br_id], ++ .force_lock = 0 ++ }; ++ ++ AuDebugOn(fh_len < Fh_tail); ++ ++ dentry = ERR_PTR(-ESTALE); ++ /* branch id may be wrapped around */ ++ bindex = si_nfsd_read_lock(sb, &nsi_lock); ++ if (unlikely(bindex < 0)) ++ goto out; ++ nsi_lock.force_lock = 1; ++ ++ /* is this inode still cached? */ ++ ino = decode_ino(fh + Fh_ino); ++ AuDebugOn(ino == AUFS_ROOT_INO); ++ dir_ino = decode_ino(fh + Fh_dir_ino); ++ dentry = decode_by_ino(sb, ino, dir_ino); ++ if (IS_ERR(dentry)) ++ goto out_unlock; ++ if (dentry) ++ goto accept; ++ ++ /* is the parent dir cached? */ ++ dentry = decode_by_dir_ino(sb, ino, dir_ino, &nsi_lock); ++ if (IS_ERR(dentry)) ++ goto out_unlock; ++ if (dentry) ++ goto accept; ++ ++ /* lookup path */ ++ dentry = decode_by_path(sb, bindex, ino, fh, fh_len, &nsi_lock); ++ if (IS_ERR(dentry)) ++ goto out_unlock; ++ if (unlikely(!dentry)) ++ /* todo?: make it ESTALE */ ++ goto out_unlock; ++ ++ accept: ++ if (dentry->d_inode->i_generation == fh[Fh_igen]) ++ goto out_unlock; /* success */ ++ ++ dput(dentry); ++ dentry = ERR_PTR(-ESTALE); ++ out_unlock: ++ si_read_unlock(sb); ++ out: ++ AuTraceErrPtr(dentry); ++ return dentry; ++} ++ ++#if 0 /* reserved for future use */ ++/* support subtreecheck option */ ++static struct dentry *aufs_fh_to_parent(struct super_block *sb, struct fid *fid, ++ int fh_len, int fh_type) ++{ ++ struct dentry *parent; ++ __u32 *fh = fid->raw; ++ ino_t dir_ino; ++ ++ dir_ino = decode_ino(fh + Fh_dir_ino); ++ parent = decode_by_ino(sb, dir_ino, 0); ++ if (IS_ERR(parent)) ++ goto out; ++ if (!parent) ++ parent = decode_by_path(sb, au_br_index(sb, fh[Fh_br_id]), ++ dir_ino, fh, fh_len); ++ ++ out: ++ AuTraceErrPtr(parent); ++ return parent; ++} ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int aufs_encode_fh(struct dentry *dentry, __u32 *fh, int *max_len, ++ int connectable) ++{ ++ int err; ++ aufs_bindex_t bindex, bend; ++ struct super_block *sb, *h_sb; ++ struct inode *inode; ++ struct dentry *parent, *h_parent; ++ struct au_branch *br; ++ ++ AuDebugOn(au_test_anon(dentry)); ++ ++ parent = NULL; ++ err = -ENOSPC; ++ if (unlikely(*max_len <= Fh_tail)) { ++ AuWarn1("NFSv2 client (max_len %d)?\n", *max_len); ++ goto out; ++ } ++ ++ err = FILEID_ROOT; ++ if (IS_ROOT(dentry)) { ++ AuDebugOn(dentry->d_inode->i_ino != AUFS_ROOT_INO); ++ goto out; ++ } ++ ++ err = -EIO; ++ h_parent = NULL; ++ sb = dentry->d_sb; ++ aufs_read_lock(dentry, AuLock_FLUSH | AuLock_IR); ++ parent = dget_parent(dentry); ++ di_read_lock_parent(parent, !AuLock_IR); ++ inode = dentry->d_inode; ++ AuDebugOn(!inode); ++#ifdef CONFIG_AUFS_DEBUG ++ if (unlikely(!au_opt_test(au_mntflags(sb), XINO))) ++ AuWarn1("NFS-exporting requires xino\n"); ++#endif ++ ++ bend = au_dbtaildir(parent); ++ for (bindex = au_dbstart(parent); bindex <= bend; bindex++) { ++ h_parent = au_h_dptr(parent, bindex); ++ if (h_parent) { ++ dget(h_parent); ++ break; ++ } ++ } ++ if (unlikely(!h_parent)) ++ goto out_unlock; ++ ++ err = -EPERM; ++ br = au_sbr(sb, bindex); ++ h_sb = br->br_mnt->mnt_sb; ++ if (unlikely(!h_sb->s_export_op)) { ++ AuErr1("%s branch is not exportable\n", au_sbtype(h_sb)); ++ goto out_dput; ++ } ++ ++ fh[Fh_br_id] = br->br_id; ++ fh[Fh_sigen] = au_sigen(sb); ++ encode_ino(fh + Fh_ino, inode->i_ino); ++ encode_ino(fh + Fh_dir_ino, parent->d_inode->i_ino); ++ fh[Fh_igen] = inode->i_generation; ++ ++ *max_len -= Fh_tail; ++ fh[Fh_h_type] = exportfs_encode_fh(h_parent, (void *)(fh + Fh_tail), ++ max_len, ++ /*connectable or subtreecheck*/0); ++ err = fh[Fh_h_type]; ++ *max_len += Fh_tail; ++ /* todo: macros? */ ++ if (err != 255) ++ err = 99; ++ else ++ AuWarn1("%s encode_fh failed\n", au_sbtype(h_sb)); ++ ++ out_dput: ++ dput(h_parent); ++ out_unlock: ++ di_read_unlock(parent, !AuLock_IR); ++ dput(parent); ++ aufs_read_unlock(dentry, AuLock_IR); ++ out: ++ if (unlikely(err < 0)) ++ err = 255; ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static struct export_operations aufs_export_op = { ++ .fh_to_dentry = aufs_fh_to_dentry, ++ /* .fh_to_parent = aufs_fh_to_parent, */ ++ .encode_fh = aufs_encode_fh ++}; ++ ++void au_export_init(struct super_block *sb) ++{ ++ struct au_sbinfo *sbinfo; ++ __u32 u; ++ ++ sb->s_export_op = &aufs_export_op; ++ sbinfo = au_sbi(sb); ++ sbinfo->si_xigen = NULL; ++ get_random_bytes(&u, sizeof(u)); ++ BUILD_BUG_ON(sizeof(u) != sizeof(int)); ++ atomic_set(&sbinfo->si_xigen_next, u); ++} +diff --git a/fs/aufs/f_op.c b/fs/aufs/f_op.c +new file mode 100644 +index 0000000..1423c20 +--- /dev/null ++++ b/fs/aufs/f_op.c +@@ -0,0 +1,855 @@ ++/* ++ * Copyright (C) 2005-2010 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* ++ * file and vm operations ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include "aufs.h" ++ ++/* common function to regular file and dir */ ++int aufs_flush(struct file *file, fl_owner_t id) ++{ ++ int err; ++ aufs_bindex_t bindex, bend; ++ struct dentry *dentry; ++ struct file *h_file; ++ ++ dentry = file->f_dentry; ++ si_noflush_read_lock(dentry->d_sb); ++ fi_read_lock(file); ++ di_read_lock_child(dentry, AuLock_IW); ++ ++ err = 0; ++ bend = au_fbend(file); ++ for (bindex = au_fbstart(file); !err && bindex <= bend; bindex++) { ++ h_file = au_h_fptr(file, bindex); ++ if (!h_file || !h_file->f_op || !h_file->f_op->flush) ++ continue; ++ ++ err = h_file->f_op->flush(h_file, id); ++ if (!err) ++ vfsub_update_h_iattr(&h_file->f_path, /*did*/NULL); ++ /*ignore*/ ++ } ++ au_cpup_attr_timesizes(dentry->d_inode); ++ ++ di_read_unlock(dentry, AuLock_IW); ++ fi_read_unlock(file); ++ si_read_unlock(dentry->d_sb); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_do_open_nondir(struct file *file, int flags) ++{ ++ int err; ++ aufs_bindex_t bindex; ++ struct file *h_file; ++ struct dentry *dentry; ++ struct au_finfo *finfo; ++ ++ FiMustWriteLock(file); ++ ++ err = 0; ++ dentry = file->f_dentry; ++ finfo = au_fi(file); ++ finfo->fi_h_vm_ops = NULL; ++ finfo->fi_vm_ops = NULL; ++ bindex = au_dbstart(dentry); ++ h_file = au_h_open(dentry, bindex, flags, file); ++ if (IS_ERR(h_file)) ++ err = PTR_ERR(h_file); ++ else { ++ au_set_fbstart(file, bindex); ++ au_set_fbend(file, bindex); ++ au_set_h_fptr(file, bindex, h_file); ++ au_update_figen(file); ++ /* todo: necessary? */ ++ /* file->f_ra = h_file->f_ra; */ ++ } ++ return err; ++} ++ ++static int aufs_open_nondir(struct inode *inode __maybe_unused, ++ struct file *file) ++{ ++ AuDbg("%.*s, f_ flags 0x%x, f_mode 0x%x\n", ++ AuDLNPair(file->f_dentry), vfsub_file_flags(file), ++ file->f_mode); ++ return au_do_open(file, au_do_open_nondir); ++} ++ ++int aufs_release_nondir(struct inode *inode __maybe_unused, struct file *file) ++{ ++ kfree(au_fi(file)->fi_vm_ops); ++ au_finfo_fin(file); ++ return 0; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static ssize_t aufs_read(struct file *file, char __user *buf, size_t count, ++ loff_t *ppos) ++{ ++ ssize_t err; ++ struct dentry *dentry; ++ struct file *h_file; ++ struct super_block *sb; ++ ++ dentry = file->f_dentry; ++ sb = dentry->d_sb; ++ si_read_lock(sb, AuLock_FLUSH); ++ err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/0); ++ if (unlikely(err)) ++ goto out; ++ ++ h_file = au_h_fptr(file, au_fbstart(file)); ++ err = vfsub_read_u(h_file, buf, count, ppos); ++ /* todo: necessary? */ ++ /* file->f_ra = h_file->f_ra; */ ++ fsstack_copy_attr_atime(dentry->d_inode, h_file->f_dentry->d_inode); ++ ++ di_read_unlock(dentry, AuLock_IR); ++ fi_read_unlock(file); ++ out: ++ si_read_unlock(sb); ++ return err; ++} ++ ++static ssize_t aufs_write(struct file *file, const char __user *ubuf, ++ size_t count, loff_t *ppos) ++{ ++ ssize_t err; ++ aufs_bindex_t bstart; ++ struct au_pin pin; ++ struct dentry *dentry; ++ struct inode *inode; ++ struct super_block *sb; ++ struct file *h_file; ++ char __user *buf = (char __user *)ubuf; ++ ++ dentry = file->f_dentry; ++ sb = dentry->d_sb; ++ inode = dentry->d_inode; ++ mutex_lock(&inode->i_mutex); ++ si_read_lock(sb, AuLock_FLUSH); ++ ++ err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/1); ++ if (unlikely(err)) ++ goto out; ++ ++ err = au_ready_to_write(file, -1, &pin); ++ di_downgrade_lock(dentry, AuLock_IR); ++ if (unlikely(err)) ++ goto out_unlock; ++ ++ bstart = au_fbstart(file); ++ h_file = au_h_fptr(file, bstart); ++ au_unpin(&pin); ++ err = vfsub_write_u(h_file, buf, count, ppos); ++ au_cpup_attr_timesizes(inode); ++ inode->i_mode = h_file->f_dentry->d_inode->i_mode; ++ ++ out_unlock: ++ di_read_unlock(dentry, AuLock_IR); ++ fi_write_unlock(file); ++ out: ++ si_read_unlock(sb); ++ mutex_unlock(&inode->i_mutex); ++ return err; ++} ++ ++static ssize_t au_do_aio(struct file *h_file, int rw, struct kiocb *kio, ++ const struct iovec *iov, unsigned long nv, loff_t pos) ++{ ++ ssize_t err; ++ struct file *file; ++ ++ err = security_file_permission(h_file, rw); ++ if (unlikely(err)) ++ goto out; ++ ++ file = kio->ki_filp; ++ if (!is_sync_kiocb(kio)) { ++ get_file(h_file); ++ fput(file); ++ } ++ kio->ki_filp = h_file; ++ if (rw == MAY_READ) ++ err = h_file->f_op->aio_read(kio, iov, nv, pos); ++ else if (rw == MAY_WRITE) ++ err = h_file->f_op->aio_write(kio, iov, nv, pos); ++ else ++ BUG(); ++ /* do not restore kio->ki_filp */ ++ ++ out: ++ return err; ++} ++ ++static ssize_t aufs_aio_read(struct kiocb *kio, const struct iovec *iov, ++ unsigned long nv, loff_t pos) ++{ ++ ssize_t err; ++ struct file *file, *h_file; ++ struct dentry *dentry; ++ struct super_block *sb; ++ ++ file = kio->ki_filp; ++ dentry = file->f_dentry; ++ sb = dentry->d_sb; ++ si_read_lock(sb, AuLock_FLUSH); ++ err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/0); ++ if (unlikely(err)) ++ goto out; ++ ++ err = -ENOSYS; ++ h_file = au_h_fptr(file, au_fbstart(file)); ++ if (h_file->f_op && h_file->f_op->aio_read) { ++ err = au_do_aio(h_file, MAY_READ, kio, iov, nv, pos); ++ /* todo: necessary? */ ++ /* file->f_ra = h_file->f_ra; */ ++ fsstack_copy_attr_atime(dentry->d_inode, ++ h_file->f_dentry->d_inode); ++ } else ++ /* currently there is no such fs */ ++ WARN_ON_ONCE(h_file->f_op && h_file->f_op->read); ++ ++ di_read_unlock(dentry, AuLock_IR); ++ fi_read_unlock(file); ++ ++ out: ++ si_read_unlock(sb); ++ return err; ++} ++ ++static ssize_t aufs_aio_write(struct kiocb *kio, const struct iovec *iov, ++ unsigned long nv, loff_t pos) ++{ ++ ssize_t err; ++ struct au_pin pin; ++ struct dentry *dentry; ++ struct inode *inode; ++ struct super_block *sb; ++ struct file *file, *h_file; ++ ++ file = kio->ki_filp; ++ dentry = file->f_dentry; ++ sb = dentry->d_sb; ++ inode = dentry->d_inode; ++ mutex_lock(&inode->i_mutex); ++ si_read_lock(sb, AuLock_FLUSH); ++ ++ err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/1); ++ if (unlikely(err)) ++ goto out; ++ ++ err = au_ready_to_write(file, -1, &pin); ++ di_downgrade_lock(dentry, AuLock_IR); ++ if (unlikely(err)) ++ goto out_unlock; ++ ++ err = -ENOSYS; ++ h_file = au_h_fptr(file, au_fbstart(file)); ++ au_unpin(&pin); ++ if (h_file->f_op && h_file->f_op->aio_write) { ++ err = au_do_aio(h_file, MAY_WRITE, kio, iov, nv, pos); ++ au_cpup_attr_timesizes(inode); ++ inode->i_mode = h_file->f_dentry->d_inode->i_mode; ++ } else ++ /* currently there is no such fs */ ++ WARN_ON_ONCE(h_file->f_op && h_file->f_op->write); ++ ++ out_unlock: ++ di_read_unlock(dentry, AuLock_IR); ++ fi_write_unlock(file); ++ out: ++ si_read_unlock(sb); ++ mutex_unlock(&inode->i_mutex); ++ return err; ++} ++ ++static ssize_t aufs_splice_read(struct file *file, loff_t *ppos, ++ struct pipe_inode_info *pipe, size_t len, ++ unsigned int flags) ++{ ++ ssize_t err; ++ struct file *h_file; ++ struct dentry *dentry; ++ struct super_block *sb; ++ ++ dentry = file->f_dentry; ++ sb = dentry->d_sb; ++ si_read_lock(sb, AuLock_FLUSH); ++ err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/0); ++ if (unlikely(err)) ++ goto out; ++ ++ err = -EINVAL; ++ h_file = au_h_fptr(file, au_fbstart(file)); ++ if (au_test_loopback_kthread()) { ++ file->f_mapping = h_file->f_mapping; ++ smp_mb(); /* unnecessary? */ ++ } ++ err = vfsub_splice_to(h_file, ppos, pipe, len, flags); ++ /* todo: necessasry? */ ++ /* file->f_ra = h_file->f_ra; */ ++ fsstack_copy_attr_atime(dentry->d_inode, h_file->f_dentry->d_inode); ++ ++ di_read_unlock(dentry, AuLock_IR); ++ fi_read_unlock(file); ++ ++ out: ++ si_read_unlock(sb); ++ return err; ++} ++ ++static ssize_t ++aufs_splice_write(struct pipe_inode_info *pipe, struct file *file, loff_t *ppos, ++ size_t len, unsigned int flags) ++{ ++ ssize_t err; ++ struct au_pin pin; ++ struct dentry *dentry; ++ struct inode *inode; ++ struct super_block *sb; ++ struct file *h_file; ++ ++ dentry = file->f_dentry; ++ inode = dentry->d_inode; ++ mutex_lock(&inode->i_mutex); ++ sb = dentry->d_sb; ++ si_read_lock(sb, AuLock_FLUSH); ++ ++ err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/1); ++ if (unlikely(err)) ++ goto out; ++ ++ err = au_ready_to_write(file, -1, &pin); ++ di_downgrade_lock(dentry, AuLock_IR); ++ if (unlikely(err)) ++ goto out_unlock; ++ ++ h_file = au_h_fptr(file, au_fbstart(file)); ++ au_unpin(&pin); ++ err = vfsub_splice_from(pipe, h_file, ppos, len, flags); ++ au_cpup_attr_timesizes(inode); ++ inode->i_mode = h_file->f_dentry->d_inode->i_mode; ++ ++ out_unlock: ++ di_read_unlock(dentry, AuLock_IR); ++ fi_write_unlock(file); ++ out: ++ si_read_unlock(sb); ++ mutex_unlock(&inode->i_mutex); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static struct file *au_safe_file(struct vm_area_struct *vma) ++{ ++ struct file *file; ++ ++ file = vma->vm_file; ++ if (file->private_data && au_test_aufs(file->f_dentry->d_sb)) ++ return file; ++ return NULL; ++} ++ ++static void au_reset_file(struct vm_area_struct *vma, struct file *file) ++{ ++ vma->vm_file = file; ++ /* smp_mb(); */ /* flush vm_file */ ++} ++ ++static int aufs_fault(struct vm_area_struct *vma, struct vm_fault *vmf) ++{ ++ int err; ++ static DECLARE_WAIT_QUEUE_HEAD(wq); ++ struct file *file, *h_file; ++ struct au_finfo *finfo; ++ ++ /* todo: non-robr mode, user vm_file as it is? */ ++ wait_event(wq, (file = au_safe_file(vma))); ++ ++ /* do not revalidate, no si lock */ ++ finfo = au_fi(file); ++ h_file = finfo->fi_hfile[0 + finfo->fi_bstart].hf_file; ++ AuDebugOn(!h_file || !finfo->fi_h_vm_ops); ++ ++ mutex_lock(&finfo->fi_vm_mtx); ++ vma->vm_file = h_file; ++ err = finfo->fi_h_vm_ops->fault(vma, vmf); ++ /* todo: necessary? */ ++ /* file->f_ra = h_file->f_ra; */ ++ au_reset_file(vma, file); ++ mutex_unlock(&finfo->fi_vm_mtx); ++#if 0 /* def CONFIG_SMP */ ++ /* wake_up_nr(&wq, online_cpu - 1); */ ++ wake_up_all(&wq); ++#else ++ wake_up(&wq); ++#endif ++ ++ return err; ++} ++ ++static int aufs_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) ++{ ++ int err; ++ static DECLARE_WAIT_QUEUE_HEAD(wq); ++ struct file *file, *h_file; ++ struct au_finfo *finfo; ++ ++ wait_event(wq, (file = au_safe_file(vma))); ++ ++ finfo = au_fi(file); ++ h_file = finfo->fi_hfile[0 + finfo->fi_bstart].hf_file; ++ AuDebugOn(!h_file || !finfo->fi_h_vm_ops); ++ ++ mutex_lock(&finfo->fi_vm_mtx); ++ vma->vm_file = h_file; ++ err = finfo->fi_h_vm_ops->page_mkwrite(vma, vmf); ++ au_reset_file(vma, file); ++ mutex_unlock(&finfo->fi_vm_mtx); ++ wake_up(&wq); ++ ++ return err; ++} ++ ++static void aufs_vm_close(struct vm_area_struct *vma) ++{ ++ static DECLARE_WAIT_QUEUE_HEAD(wq); ++ struct file *file, *h_file; ++ struct au_finfo *finfo; ++ ++ wait_event(wq, (file = au_safe_file(vma))); ++ ++ finfo = au_fi(file); ++ h_file = finfo->fi_hfile[0 + finfo->fi_bstart].hf_file; ++ AuDebugOn(!h_file || !finfo->fi_h_vm_ops); ++ ++ mutex_lock(&finfo->fi_vm_mtx); ++ vma->vm_file = h_file; ++ finfo->fi_h_vm_ops->close(vma); ++ au_reset_file(vma, file); ++ mutex_unlock(&finfo->fi_vm_mtx); ++ wake_up(&wq); ++} ++ ++static struct vm_operations_struct aufs_vm_ops = { ++ /* .close and .page_mkwrite are not set by default */ ++ .fault = aufs_fault, ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* cf. linux/include/linux/mman.h: calc_vm_prot_bits() */ ++#define AuConv_VM_PROT(f, b) _calc_vm_trans(f, VM_##b, PROT_##b) ++ ++static unsigned long au_arch_prot_conv(unsigned long flags) ++{ ++ /* currently ppc64 only */ ++#ifdef CONFIG_PPC64 ++ /* cf. linux/arch/powerpc/include/asm/mman.h */ ++ AuDebugOn(arch_calc_vm_prot_bits(-1) != VM_SAO); ++ return AuConv_VM_PROT(flags, SAO); ++#else ++ AuDebugOn(arch_calc_vm_prot_bits(-1)); ++ return 0; ++#endif ++} ++ ++static unsigned long au_prot_conv(unsigned long flags) ++{ ++ return AuConv_VM_PROT(flags, READ) ++ | AuConv_VM_PROT(flags, WRITE) ++ | AuConv_VM_PROT(flags, EXEC) ++ | au_arch_prot_conv(flags); ++} ++ ++/* cf. linux/include/linux/mman.h: calc_vm_flag_bits() */ ++#define AuConv_VM_MAP(f, b) _calc_vm_trans(f, VM_##b, MAP_##b) ++ ++static unsigned long au_flag_conv(unsigned long flags) ++{ ++ return AuConv_VM_MAP(flags, GROWSDOWN) ++ | AuConv_VM_MAP(flags, DENYWRITE) ++ | AuConv_VM_MAP(flags, EXECUTABLE) ++ | AuConv_VM_MAP(flags, LOCKED); ++} ++ ++static struct vm_operations_struct *au_vm_ops(struct file *h_file, ++ struct vm_area_struct *vma) ++{ ++ struct vm_operations_struct *vm_ops; ++ unsigned long prot; ++ int err; ++ ++ vm_ops = ERR_PTR(-ENODEV); ++ if (!h_file->f_op || !h_file->f_op->mmap) ++ goto out; ++ ++ prot = au_prot_conv(vma->vm_flags); ++ err = security_file_mmap(h_file, /*reqprot*/prot, prot, ++ au_flag_conv(vma->vm_flags), vma->vm_start, 0); ++ vm_ops = ERR_PTR(err); ++ if (unlikely(err)) ++ goto out; ++ ++ err = h_file->f_op->mmap(h_file, vma); ++ vm_ops = ERR_PTR(err); ++ if (unlikely(err)) ++ goto out; ++ ++ /* oops, it became 'const' */ ++ vm_ops = (struct vm_operations_struct *)vma->vm_ops; ++ err = do_munmap(current->mm, vma->vm_start, ++ vma->vm_end - vma->vm_start); ++ if (unlikely(err)) { ++ AuIOErr("failed internal unmapping %.*s, %d\n", ++ AuDLNPair(h_file->f_dentry), err); ++ vm_ops = ERR_PTR(-EIO); ++ } ++ ++ out: ++ return vm_ops; ++} ++ ++static int au_custom_vm_ops(struct au_finfo *finfo, struct vm_area_struct *vma) ++{ ++ int err; ++ struct vm_operations_struct *h_ops; ++ ++ AuRwMustAnyLock(&finfo->fi_rwsem); ++ ++ err = 0; ++ h_ops = finfo->fi_h_vm_ops; ++ AuDebugOn(!h_ops); ++ if ((!h_ops->page_mkwrite && !h_ops->close) ++ || finfo->fi_vm_ops) ++ goto out; ++ ++ err = -ENOMEM; ++ finfo->fi_vm_ops = kmemdup(&aufs_vm_ops, sizeof(aufs_vm_ops), GFP_NOFS); ++ if (unlikely(!finfo->fi_vm_ops)) ++ goto out; ++ ++ err = 0; ++ if (h_ops->page_mkwrite) ++ finfo->fi_vm_ops->page_mkwrite = aufs_page_mkwrite; ++ if (h_ops->close) ++ finfo->fi_vm_ops->close = aufs_vm_close; ++ ++ vma->vm_ops = finfo->fi_vm_ops; ++ ++ out: ++ return err; ++} ++ ++static int aufs_mmap(struct file *file, struct vm_area_struct *vma) ++{ ++ int err; ++ unsigned char wlock, mmapped; ++ struct dentry *dentry; ++ struct super_block *sb; ++ struct file *h_file; ++ struct vm_operations_struct *vm_ops; ++ ++ dentry = file->f_dentry; ++ wlock = !!(file->f_mode & FMODE_WRITE) && (vma->vm_flags & VM_SHARED); ++ sb = dentry->d_sb; ++ si_read_lock(sb, AuLock_FLUSH); ++ err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/1); ++ if (unlikely(err)) ++ goto out; ++ ++ mmapped = !!au_test_mmapped(file); ++ if (wlock) { ++ struct au_pin pin; ++ ++ err = au_ready_to_write(file, -1, &pin); ++ di_downgrade_lock(dentry, AuLock_IR); ++ if (unlikely(err)) ++ goto out_unlock; ++ au_unpin(&pin); ++ } else ++ di_downgrade_lock(dentry, AuLock_IR); ++ ++ h_file = au_h_fptr(file, au_fbstart(file)); ++ if (!mmapped && au_test_fs_bad_mapping(h_file->f_dentry->d_sb)) { ++ /* ++ * by this assignment, f_mapping will differs from aufs inode ++ * i_mapping. ++ * if someone else mixes the use of f_dentry->d_inode and ++ * f_mapping->host, then a problem may arise. ++ */ ++ file->f_mapping = h_file->f_mapping; ++ } ++ ++ vm_ops = NULL; ++ if (!mmapped) { ++ vm_ops = au_vm_ops(h_file, vma); ++ err = PTR_ERR(vm_ops); ++ if (IS_ERR(vm_ops)) ++ goto out_unlock; ++ } ++ ++ /* ++ * unnecessary to handle MAP_DENYWRITE and deny_write_access()? ++ * currently MAP_DENYWRITE from userspace is ignored, but elf loader ++ * sets it. when FMODE_EXEC is set (by open_exec() or sys_uselib()), ++ * both of the aufs file and the lower file is deny_write_access()-ed. ++ * finally I hope we can skip handlling MAP_DENYWRITE here. ++ */ ++ err = generic_file_mmap(file, vma); ++ if (unlikely(err)) ++ goto out_unlock; ++ ++ vma->vm_ops = &aufs_vm_ops; ++ if (!mmapped) { ++ struct au_finfo *finfo = au_fi(file); ++ ++ finfo->fi_h_vm_ops = vm_ops; ++ mutex_init(&finfo->fi_vm_mtx); ++ } ++ ++ err = au_custom_vm_ops(au_fi(file), vma); ++ if (unlikely(err)) ++ goto out_unlock; ++ ++ vfsub_file_accessed(h_file); ++ fsstack_copy_attr_atime(dentry->d_inode, h_file->f_dentry->d_inode); ++ ++ out_unlock: ++ di_read_unlock(dentry, AuLock_IR); ++ fi_write_unlock(file); ++ out: ++ si_read_unlock(sb); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int aufs_fsync_nondir(struct file *file, struct dentry *dentry, ++ int datasync) ++{ ++ int err; ++ struct au_pin pin; ++ struct inode *inode; ++ struct file *h_file; ++ struct super_block *sb; ++ ++ inode = dentry->d_inode; ++ IMustLock(file->f_mapping->host); ++ if (inode != file->f_mapping->host) { ++ mutex_unlock(&file->f_mapping->host->i_mutex); ++ mutex_lock(&inode->i_mutex); ++ } ++ IMustLock(inode); ++ ++ sb = dentry->d_sb; ++ si_read_lock(sb, AuLock_FLUSH); ++ ++ err = 0; /* -EBADF; */ /* posix? */ ++ if (unlikely(!(file->f_mode & FMODE_WRITE))) ++ goto out; ++ err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/1); ++ if (unlikely(err)) ++ goto out; ++ ++ err = au_ready_to_write(file, -1, &pin); ++ di_downgrade_lock(dentry, AuLock_IR); ++ if (unlikely(err)) ++ goto out_unlock; ++ au_unpin(&pin); ++ ++ err = -EINVAL; ++ h_file = au_h_fptr(file, au_fbstart(file)); ++ if (h_file->f_op && h_file->f_op->fsync) { ++ struct dentry *h_d; ++ struct mutex *h_mtx; ++ ++ /* ++ * no filemap_fdatawrite() since aufs file has no its own ++ * mapping, but dir. ++ */ ++ h_d = h_file->f_dentry; ++ h_mtx = &h_d->d_inode->i_mutex; ++ mutex_lock_nested(h_mtx, AuLsc_I_CHILD); ++ err = h_file->f_op->fsync(h_file, h_d, datasync); ++ if (!err) ++ vfsub_update_h_iattr(&h_file->f_path, /*did*/NULL); ++ /*ignore*/ ++ au_cpup_attr_timesizes(inode); ++ mutex_unlock(h_mtx); ++ } ++ ++ out_unlock: ++ di_read_unlock(dentry, AuLock_IR); ++ fi_write_unlock(file); ++ out: ++ si_read_unlock(sb); ++ if (inode != file->f_mapping->host) { ++ mutex_unlock(&inode->i_mutex); ++ mutex_lock(&file->f_mapping->host->i_mutex); ++ } ++ return err; ++} ++ ++/* no one supports this operation, currently */ ++#if 0 ++static int aufs_aio_fsync_nondir(struct kiocb *kio, int datasync) ++{ ++ int err; ++ struct au_pin pin; ++ struct dentry *dentry; ++ struct inode *inode; ++ struct file *file, *h_file; ++ struct super_block *sb; ++ ++ file = kio->ki_filp; ++ dentry = file->f_dentry; ++ inode = dentry->d_inode; ++ mutex_lock(&inode->i_mutex); ++ ++ sb = dentry->d_sb; ++ si_read_lock(sb, AuLock_FLUSH); ++ ++ err = 0; /* -EBADF; */ /* posix? */ ++ if (unlikely(!(file->f_mode & FMODE_WRITE))) ++ goto out; ++ err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/1); ++ if (unlikely(err)) ++ goto out; ++ ++ err = au_ready_to_write(file, -1, &pin); ++ di_downgrade_lock(dentry, AuLock_IR); ++ if (unlikely(err)) ++ goto out_unlock; ++ au_unpin(&pin); ++ ++ err = -ENOSYS; ++ h_file = au_h_fptr(file, au_fbstart(file)); ++ if (h_file->f_op && h_file->f_op->aio_fsync) { ++ struct dentry *h_d; ++ struct mutex *h_mtx; ++ ++ h_d = h_file->f_dentry; ++ h_mtx = &h_d->d_inode->i_mutex; ++ if (!is_sync_kiocb(kio)) { ++ get_file(h_file); ++ fput(file); ++ } ++ kio->ki_filp = h_file; ++ err = h_file->f_op->aio_fsync(kio, datasync); ++ mutex_lock_nested(h_mtx, AuLsc_I_CHILD); ++ if (!err) ++ vfsub_update_h_iattr(&h_file->f_path, /*did*/NULL); ++ /*ignore*/ ++ au_cpup_attr_timesizes(inode); ++ mutex_unlock(h_mtx); ++ } ++ ++ out_unlock: ++ di_read_unlock(dentry, AuLock_IR); ++ fi_write_unlock(file); ++ out: ++ si_read_unlock(sb); ++ mutex_unlock(&inode->i_mutex); ++ return err; ++} ++#endif ++ ++static int aufs_fasync(int fd, struct file *file, int flag) ++{ ++ int err; ++ struct file *h_file; ++ struct dentry *dentry; ++ struct super_block *sb; ++ ++ dentry = file->f_dentry; ++ sb = dentry->d_sb; ++ si_read_lock(sb, AuLock_FLUSH); ++ err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/0); ++ if (unlikely(err)) ++ goto out; ++ ++ h_file = au_h_fptr(file, au_fbstart(file)); ++ if (h_file->f_op && h_file->f_op->fasync) ++ err = h_file->f_op->fasync(fd, h_file, flag); ++ ++ di_read_unlock(dentry, AuLock_IR); ++ fi_read_unlock(file); ++ ++ out: ++ si_read_unlock(sb); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* no one supports this operation, currently */ ++#if 0 ++static ssize_t aufs_sendpage(struct file *file, struct page *page, int offset, ++ size_t len, loff_t *pos , int more) ++{ ++} ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++const struct file_operations aufs_file_fop = { ++ /* ++ * while generic_file_llseek/_unlocked() don't use BKL, ++ * don't use it since it operates file->f_mapping->host. ++ * in aufs, it may be a real file and may confuse users by UDBA. ++ */ ++ /* .llseek = generic_file_llseek, */ ++ ++ .read = aufs_read, ++ .write = aufs_write, ++ .aio_read = aufs_aio_read, ++ .aio_write = aufs_aio_write, ++#ifdef CONFIG_AUFS_POLL ++ .poll = aufs_poll, ++#endif ++ .unlocked_ioctl = aufs_ioctl_nondir, ++ .mmap = aufs_mmap, ++ .open = aufs_open_nondir, ++ .flush = aufs_flush, ++ .release = aufs_release_nondir, ++ .fsync = aufs_fsync_nondir, ++ /* .aio_fsync = aufs_aio_fsync_nondir, */ ++ .fasync = aufs_fasync, ++ /* .sendpage = aufs_sendpage, */ ++ .splice_write = aufs_splice_write, ++ .splice_read = aufs_splice_read, ++#if 0 ++ .aio_splice_write = aufs_aio_splice_write, ++ .aio_splice_read = aufs_aio_splice_read ++#endif ++}; +diff --git a/fs/aufs/f_op_sp.c b/fs/aufs/f_op_sp.c +new file mode 100644 +index 0000000..f4a4124 +--- /dev/null ++++ b/fs/aufs/f_op_sp.c +@@ -0,0 +1,290 @@ ++/* ++ * Copyright (C) 2005-2010 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* ++ * file operations for special files. ++ * while they exist in aufs virtually, ++ * their file I/O is handled out of aufs. ++ */ ++ ++#include ++#include "aufs.h" ++ ++static ssize_t aufs_aio_read_sp(struct kiocb *kio, const struct iovec *iov, ++ unsigned long nv, loff_t pos) ++{ ++ ssize_t err; ++ aufs_bindex_t bstart; ++ unsigned char wbr; ++ struct file *file, *h_file; ++ struct super_block *sb; ++ ++ file = kio->ki_filp; ++ sb = file->f_dentry->d_sb; ++ si_read_lock(sb, AuLock_FLUSH); ++ fi_read_lock(file); ++ bstart = au_fbstart(file); ++ h_file = au_h_fptr(file, bstart); ++ fi_read_unlock(file); ++ wbr = !!au_br_writable(au_sbr(sb, bstart)->br_perm); ++ si_read_unlock(sb); ++ ++ /* do not change the file in kio */ ++ AuDebugOn(!h_file->f_op || !h_file->f_op->aio_read); ++ err = h_file->f_op->aio_read(kio, iov, nv, pos); ++ if (err > 0 && wbr) ++ file_accessed(h_file); ++ ++ return err; ++} ++ ++static ssize_t aufs_aio_write_sp(struct kiocb *kio, const struct iovec *iov, ++ unsigned long nv, loff_t pos) ++{ ++ ssize_t err; ++ aufs_bindex_t bstart; ++ unsigned char wbr; ++ struct super_block *sb; ++ struct file *file, *h_file; ++ ++ file = kio->ki_filp; ++ sb = file->f_dentry->d_sb; ++ si_read_lock(sb, AuLock_FLUSH); ++ fi_read_lock(file); ++ bstart = au_fbstart(file); ++ h_file = au_h_fptr(file, bstart); ++ fi_read_unlock(file); ++ wbr = !!au_br_writable(au_sbr(sb, bstart)->br_perm); ++ si_read_unlock(sb); ++ ++ /* do not change the file in kio */ ++ AuDebugOn(!h_file->f_op || !h_file->f_op->aio_write); ++ err = h_file->f_op->aio_write(kio, iov, nv, pos); ++ if (err > 0 && wbr) ++ file_update_time(h_file); ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int aufs_release_sp(struct inode *inode, struct file *file) ++{ ++ int err; ++ struct file *h_file; ++ ++ fi_read_lock(file); ++ h_file = au_h_fptr(file, au_fbstart(file)); ++ fi_read_unlock(file); ++ /* close this fifo in aufs */ ++ err = h_file->f_op->release(inode, file); /* ignore */ ++ aufs_release_nondir(inode, file); /* ignore */ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* currently, support only FIFO */ ++enum {AuSp_FIFO, AuSp_FIFO_R, AuSp_FIFO_W, AuSp_FIFO_RW, ++ /* AuSp_SOCK, AuSp_CHR, AuSp_BLK, */ ++ AuSp_Last}; ++static int aufs_open_sp(struct inode *inode, struct file *file); ++static struct au_sp_fop { ++ int done; ++ struct file_operations fop; /* not 'const' */ ++ spinlock_t spin; ++} au_sp_fop[AuSp_Last] = { ++ [AuSp_FIFO] = { ++ .fop = { ++ .open = aufs_open_sp ++ } ++ } ++}; ++ ++static void au_init_fop_sp(struct file *file) ++{ ++ struct au_sp_fop *p; ++ int i; ++ struct file *h_file; ++ ++ p = au_sp_fop; ++ if (unlikely(!p->done)) { ++ /* initialize first time only */ ++ static DEFINE_SPINLOCK(spin); ++ ++ spin_lock(&spin); ++ if (!p->done) { ++ BUILD_BUG_ON(sizeof(au_sp_fop)/sizeof(*au_sp_fop) ++ != AuSp_Last); ++ for (i = 0; i < AuSp_Last; i++) ++ spin_lock_init(&p[i].spin); ++ p->done = 1; ++ } ++ spin_unlock(&spin); ++ } ++ ++ switch (file->f_mode & (FMODE_READ | FMODE_WRITE)) { ++ case FMODE_READ: ++ i = AuSp_FIFO_R; ++ break; ++ case FMODE_WRITE: ++ i = AuSp_FIFO_W; ++ break; ++ case FMODE_READ | FMODE_WRITE: ++ i = AuSp_FIFO_RW; ++ break; ++ default: ++ BUG(); ++ } ++ ++ p += i; ++ if (unlikely(!p->done)) { ++ /* initialize first time only */ ++ h_file = au_h_fptr(file, au_fbstart(file)); ++ spin_lock(&p->spin); ++ if (!p->done) { ++ p->fop = *h_file->f_op; ++ if (p->fop.aio_read) ++ p->fop.aio_read = aufs_aio_read_sp; ++ if (p->fop.aio_write) ++ p->fop.aio_write = aufs_aio_write_sp; ++ p->fop.release = aufs_release_sp; ++ p->done = 1; ++ } ++ spin_unlock(&p->spin); ++ } ++ file->f_op = &p->fop; ++} ++ ++static int au_cpup_sp(struct dentry *dentry) ++{ ++ int err; ++ aufs_bindex_t bcpup; ++ struct au_pin pin; ++ struct au_wr_dir_args wr_dir_args = { ++ .force_btgt = -1, ++ .flags = 0 ++ }; ++ ++ AuDbg("%.*s\n", AuDLNPair(dentry)); ++ ++ di_read_unlock(dentry, AuLock_IR); ++ di_write_lock_child(dentry); ++ err = au_wr_dir(dentry, /*src_dentry*/NULL, &wr_dir_args); ++ if (unlikely(err < 0)) ++ goto out; ++ bcpup = err; ++ err = 0; ++ if (bcpup == au_dbstart(dentry)) ++ goto out; /* success */ ++ ++ err = au_pin(&pin, dentry, bcpup, au_opt_udba(dentry->d_sb), ++ AuPin_MNT_WRITE); ++ if (!err) { ++ err = au_sio_cpup_simple(dentry, bcpup, -1, AuCpup_DTIME); ++ au_unpin(&pin); ++ } ++ ++ out: ++ di_downgrade_lock(dentry, AuLock_IR); ++ return err; ++} ++ ++static int au_do_open_sp(struct file *file, int flags) ++{ ++ int err; ++ struct dentry *dentry; ++ struct super_block *sb; ++ struct file *h_file; ++ struct inode *h_inode; ++ ++ dentry = file->f_dentry; ++ AuDbg("%.*s\n", AuDLNPair(dentry)); ++ ++ /* ++ * try copying-up. ++ * operate on the ro branch is not an error. ++ */ ++ au_cpup_sp(dentry); /* ignore */ ++ ++ /* prepare h_file */ ++ err = au_do_open_nondir(file, vfsub_file_flags(file)); ++ if (unlikely(err)) ++ goto out; ++ ++ sb = dentry->d_sb; ++ h_file = au_h_fptr(file, au_fbstart(file)); ++ h_inode = h_file->f_dentry->d_inode; ++ di_read_unlock(dentry, AuLock_IR); ++ fi_write_unlock(file); ++ si_read_unlock(sb); ++ /* open this fifo in aufs */ ++ err = h_inode->i_fop->open(file->f_dentry->d_inode, file); ++ si_noflush_read_lock(sb); ++ fi_write_lock(file); ++ di_read_lock_child(dentry, AuLock_IR); ++ if (!err) ++ au_init_fop_sp(file); ++ else ++ au_finfo_fin(file); ++ ++ out: ++ return err; ++} ++ ++static int aufs_open_sp(struct inode *inode, struct file *file) ++{ ++ return au_do_open(file, au_do_open_sp); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void au_init_special_fop(struct inode *inode, umode_t mode, dev_t rdev) ++{ ++ init_special_inode(inode, mode, rdev); ++ ++ switch (mode & S_IFMT) { ++ case S_IFIFO: ++ inode->i_fop = &au_sp_fop[AuSp_FIFO].fop; ++ /*FALLTHROUGH*/ ++ case S_IFCHR: ++ case S_IFBLK: ++ case S_IFSOCK: ++ break; ++ default: ++ AuDebugOn(1); ++ } ++} ++ ++int au_special_file(umode_t mode) ++{ ++ int ret; ++ ++ ret = 0; ++ switch (mode & S_IFMT) { ++ case S_IFIFO: ++#if 0 ++ case S_IFCHR: ++ case S_IFBLK: ++ case S_IFSOCK: ++#endif ++ ret = 1; ++ } ++ ++ return ret; ++} +diff --git a/fs/aufs/file.c b/fs/aufs/file.c +new file mode 100644 +index 0000000..0ee8e29 +--- /dev/null ++++ b/fs/aufs/file.c +@@ -0,0 +1,606 @@ ++/* ++ * Copyright (C) 2005-2010 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* ++ * handling file/dir, and address_space operation ++ */ ++ ++#include ++#include ++#include ++#include ++#include "aufs.h" ++ ++/* drop flags for writing */ ++unsigned int au_file_roflags(unsigned int flags) ++{ ++ flags &= ~(O_WRONLY | O_RDWR | O_APPEND | O_CREAT | O_TRUNC); ++ flags |= O_RDONLY | O_NOATIME; ++ return flags; ++} ++ ++/* common functions to regular file and dir */ ++struct file *au_h_open(struct dentry *dentry, aufs_bindex_t bindex, int flags, ++ struct file *file) ++{ ++ struct file *h_file; ++ struct dentry *h_dentry; ++ struct inode *h_inode; ++ struct super_block *sb; ++ struct au_branch *br; ++ struct path h_path; ++ int err, exec_flag; ++ ++ /* a race condition can happen between open and unlink/rmdir */ ++ h_file = ERR_PTR(-ENOENT); ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (au_test_nfsd(current) && !h_dentry) ++ goto out; ++ h_inode = h_dentry->d_inode; ++ if (au_test_nfsd(current) && !h_inode) ++ goto out; ++ if (unlikely((!d_unhashed(dentry) && d_unhashed(h_dentry)) ++ || !h_inode)) ++ goto out; ++ ++ sb = dentry->d_sb; ++ br = au_sbr(sb, bindex); ++ h_file = ERR_PTR(-EACCES); ++ exec_flag = flags & vfsub_fmode_to_uint(FMODE_EXEC); ++ if (exec_flag && (br->br_mnt->mnt_flags & MNT_NOEXEC)) ++ goto out; ++ ++ /* drop flags for writing */ ++ if (au_test_ro(sb, bindex, dentry->d_inode)) ++ flags = au_file_roflags(flags); ++ flags &= ~O_CREAT; ++ atomic_inc(&br->br_count); ++ h_path.dentry = h_dentry; ++ h_path.mnt = br->br_mnt; ++ if (!au_special_file(h_inode->i_mode)) ++ h_file = vfsub_dentry_open(&h_path, flags); ++ else { ++ /* this block depends upon the configuration */ ++ di_read_unlock(dentry, AuLock_IR); ++ fi_write_unlock(file); ++ si_read_unlock(sb); ++ h_file = vfsub_dentry_open(&h_path, flags); ++ si_noflush_read_lock(sb); ++ fi_write_lock(file); ++ di_read_lock_child(dentry, AuLock_IR); ++ } ++ if (IS_ERR(h_file)) ++ goto out_br; ++ ++ if (exec_flag) { ++ err = deny_write_access(h_file); ++ if (unlikely(err)) { ++ fput(h_file); ++ h_file = ERR_PTR(err); ++ goto out_br; ++ } ++ } ++ fsnotify_open(h_dentry); ++ goto out; /* success */ ++ ++ out_br: ++ atomic_dec(&br->br_count); ++ out: ++ return h_file; ++} ++ ++int au_do_open(struct file *file, int (*open)(struct file *file, int flags)) ++{ ++ int err; ++ struct dentry *dentry; ++ struct super_block *sb; ++ ++ dentry = file->f_dentry; ++ sb = dentry->d_sb; ++ si_read_lock(sb, AuLock_FLUSH); ++ err = au_finfo_init(file); ++ if (unlikely(err)) ++ goto out; ++ ++ di_read_lock_child(dentry, AuLock_IR); ++ err = open(file, vfsub_file_flags(file)); ++ di_read_unlock(dentry, AuLock_IR); ++ ++ fi_write_unlock(file); ++ if (unlikely(err)) ++ au_finfo_fin(file); ++ out: ++ si_read_unlock(sb); ++ return err; ++} ++ ++int au_reopen_nondir(struct file *file) ++{ ++ int err; ++ aufs_bindex_t bstart, bindex, bend; ++ struct dentry *dentry; ++ struct file *h_file, *h_file_tmp; ++ ++ dentry = file->f_dentry; ++ AuDebugOn(au_special_file(dentry->d_inode->i_mode)); ++ bstart = au_dbstart(dentry); ++ h_file_tmp = NULL; ++ if (au_fbstart(file) == bstart) { ++ h_file = au_h_fptr(file, bstart); ++ if (file->f_mode == h_file->f_mode) ++ return 0; /* success */ ++ h_file_tmp = h_file; ++ get_file(h_file_tmp); ++ au_set_h_fptr(file, bstart, NULL); ++ } ++ AuDebugOn(au_fbstart(file) < bstart ++ || au_fi(file)->fi_hfile[0 + bstart].hf_file); ++ ++ h_file = au_h_open(dentry, bstart, vfsub_file_flags(file) & ~O_TRUNC, ++ file); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out; /* todo: close all? */ ++ ++ err = 0; ++ au_set_fbstart(file, bstart); ++ au_set_h_fptr(file, bstart, h_file); ++ au_update_figen(file); ++ /* todo: necessary? */ ++ /* file->f_ra = h_file->f_ra; */ ++ ++ /* close lower files */ ++ bend = au_fbend(file); ++ for (bindex = bstart + 1; bindex <= bend; bindex++) ++ au_set_h_fptr(file, bindex, NULL); ++ au_set_fbend(file, bstart); ++ ++ out: ++ if (h_file_tmp) ++ fput(h_file_tmp); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_reopen_wh(struct file *file, aufs_bindex_t btgt, ++ struct dentry *hi_wh) ++{ ++ int err; ++ aufs_bindex_t bstart; ++ struct au_dinfo *dinfo; ++ struct dentry *h_dentry; ++ ++ dinfo = au_di(file->f_dentry); ++ AuRwMustWriteLock(&dinfo->di_rwsem); ++ ++ bstart = dinfo->di_bstart; ++ dinfo->di_bstart = btgt; ++ h_dentry = dinfo->di_hdentry[0 + btgt].hd_dentry; ++ dinfo->di_hdentry[0 + btgt].hd_dentry = hi_wh; ++ err = au_reopen_nondir(file); ++ dinfo->di_hdentry[0 + btgt].hd_dentry = h_dentry; ++ dinfo->di_bstart = bstart; ++ ++ return err; ++} ++ ++static int au_ready_to_write_wh(struct file *file, loff_t len, ++ aufs_bindex_t bcpup) ++{ ++ int err; ++ struct inode *inode; ++ struct dentry *dentry, *hi_wh; ++ ++ dentry = file->f_dentry; ++ au_update_dbstart(dentry); ++ inode = dentry->d_inode; ++ hi_wh = au_hi_wh(inode, bcpup); ++ if (!hi_wh) ++ err = au_sio_cpup_wh(dentry, bcpup, len, file); ++ else ++ /* already copied-up after unlink */ ++ err = au_reopen_wh(file, bcpup, hi_wh); ++ ++ if (!err ++ && inode->i_nlink > 1 ++ && au_opt_test(au_mntflags(dentry->d_sb), PLINK)) ++ au_plink_append(inode, bcpup, au_h_dptr(dentry, bcpup)); ++ ++ return err; ++} ++ ++/* ++ * prepare the @file for writing. ++ */ ++int au_ready_to_write(struct file *file, loff_t len, struct au_pin *pin) ++{ ++ int err; ++ aufs_bindex_t bstart, bcpup; ++ struct dentry *dentry, *parent, *h_dentry; ++ struct inode *h_inode, *inode; ++ struct super_block *sb; ++ struct file *h_file; ++ ++ dentry = file->f_dentry; ++ sb = dentry->d_sb; ++ inode = dentry->d_inode; ++ AuDebugOn(au_special_file(inode->i_mode)); ++ bstart = au_fbstart(file); ++ err = au_test_ro(sb, bstart, inode); ++ if (!err && (au_h_fptr(file, bstart)->f_mode & FMODE_WRITE)) { ++ err = au_pin(pin, dentry, bstart, AuOpt_UDBA_NONE, /*flags*/0); ++ goto out; ++ } ++ ++ /* need to cpup */ ++ parent = dget_parent(dentry); ++ di_write_lock_parent(parent); ++ err = AuWbrCopyup(au_sbi(sb), dentry); ++ bcpup = err; ++ if (unlikely(err < 0)) ++ goto out_dgrade; ++ err = 0; ++ ++ if (!au_h_dptr(parent, bcpup)) { ++ err = au_cpup_dirs(dentry, bcpup); ++ if (unlikely(err)) ++ goto out_dgrade; ++ } ++ ++ err = au_pin(pin, dentry, bcpup, AuOpt_UDBA_NONE, ++ AuPin_DI_LOCKED | AuPin_MNT_WRITE); ++ if (unlikely(err)) ++ goto out_dgrade; ++ ++ h_dentry = au_h_fptr(file, bstart)->f_dentry; ++ h_inode = h_dentry->d_inode; ++ mutex_lock_nested(&h_inode->i_mutex, AuLsc_I_CHILD); ++ h_file = au_h_open_pre(dentry, bstart); ++ if (IS_ERR(h_file)) { ++ err = PTR_ERR(h_file); ++ h_file = NULL; ++ } else if (d_unhashed(dentry) /* || d_unhashed(h_dentry) */ ++ /* || !h_inode->i_nlink */) { ++ err = au_ready_to_write_wh(file, len, bcpup); ++ di_downgrade_lock(parent, AuLock_IR); ++ } else { ++ di_downgrade_lock(parent, AuLock_IR); ++ if (!au_h_dptr(dentry, bcpup)) ++ err = au_sio_cpup_simple(dentry, bcpup, len, ++ AuCpup_DTIME); ++ if (!err) ++ err = au_reopen_nondir(file); ++ } ++ mutex_unlock(&h_inode->i_mutex); ++ au_h_open_post(dentry, bstart, h_file); ++ ++ if (!err) { ++ au_pin_set_parent_lflag(pin, /*lflag*/0); ++ goto out_dput; /* success */ ++ } ++ au_unpin(pin); ++ goto out_unlock; ++ ++ out_dgrade: ++ di_downgrade_lock(parent, AuLock_IR); ++ out_unlock: ++ di_read_unlock(parent, AuLock_IR); ++ out_dput: ++ dput(parent); ++ out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_file_refresh_by_inode(struct file *file, int *need_reopen) ++{ ++ int err; ++ aufs_bindex_t bstart; ++ struct au_pin pin; ++ struct au_finfo *finfo; ++ struct dentry *dentry, *parent, *hi_wh; ++ struct inode *inode; ++ struct super_block *sb; ++ ++ FiMustWriteLock(file); ++ ++ err = 0; ++ finfo = au_fi(file); ++ dentry = file->f_dentry; ++ sb = dentry->d_sb; ++ inode = dentry->d_inode; ++ bstart = au_ibstart(inode); ++ if (bstart == finfo->fi_bstart) ++ goto out; ++ ++ parent = dget_parent(dentry); ++ if (au_test_ro(sb, bstart, inode)) { ++ di_read_lock_parent(parent, !AuLock_IR); ++ err = AuWbrCopyup(au_sbi(sb), dentry); ++ bstart = err; ++ di_read_unlock(parent, !AuLock_IR); ++ if (unlikely(err < 0)) ++ goto out_parent; ++ err = 0; ++ } ++ ++ di_read_lock_parent(parent, AuLock_IR); ++ hi_wh = au_hi_wh(inode, bstart); ++ if (au_opt_test(au_mntflags(sb), PLINK) ++ && au_plink_test(inode) ++ && !d_unhashed(dentry)) { ++ err = au_test_and_cpup_dirs(dentry, bstart); ++ if (unlikely(err)) ++ goto out_unlock; ++ ++ /* always superio. */ ++ err = au_pin(&pin, dentry, bstart, AuOpt_UDBA_NONE, ++ AuPin_DI_LOCKED | AuPin_MNT_WRITE); ++ if (!err) ++ err = au_sio_cpup_simple(dentry, bstart, -1, ++ AuCpup_DTIME); ++ au_unpin(&pin); ++ } else if (hi_wh) { ++ /* already copied-up after unlink */ ++ err = au_reopen_wh(file, bstart, hi_wh); ++ *need_reopen = 0; ++ } ++ ++ out_unlock: ++ di_read_unlock(parent, AuLock_IR); ++ out_parent: ++ dput(parent); ++ out: ++ return err; ++} ++ ++static void au_do_refresh_file(struct file *file) ++{ ++ aufs_bindex_t bindex, bend, new_bindex, brid; ++ struct au_hfile *p, tmp, *q; ++ struct au_finfo *finfo; ++ struct super_block *sb; ++ ++ FiMustWriteLock(file); ++ ++ sb = file->f_dentry->d_sb; ++ finfo = au_fi(file); ++ p = finfo->fi_hfile + finfo->fi_bstart; ++ brid = p->hf_br->br_id; ++ bend = finfo->fi_bend; ++ for (bindex = finfo->fi_bstart; bindex <= bend; bindex++, p++) { ++ if (!p->hf_file) ++ continue; ++ ++ new_bindex = au_br_index(sb, p->hf_br->br_id); ++ if (new_bindex == bindex) ++ continue; ++ if (new_bindex < 0) { ++ au_set_h_fptr(file, bindex, NULL); ++ continue; ++ } ++ ++ /* swap two lower inode, and loop again */ ++ q = finfo->fi_hfile + new_bindex; ++ tmp = *q; ++ *q = *p; ++ *p = tmp; ++ if (tmp.hf_file) { ++ bindex--; ++ p--; ++ } ++ } ++ ++ p = finfo->fi_hfile; ++ if (!au_test_mmapped(file) && !d_unhashed(file->f_dentry)) { ++ bend = au_sbend(sb); ++ for (finfo->fi_bstart = 0; finfo->fi_bstart <= bend; ++ finfo->fi_bstart++, p++) ++ if (p->hf_file) { ++ if (p->hf_file->f_dentry ++ && p->hf_file->f_dentry->d_inode) ++ break; ++ else ++ au_hfput(p, file); ++ } ++ } else { ++ bend = au_br_index(sb, brid); ++ for (finfo->fi_bstart = 0; finfo->fi_bstart < bend; ++ finfo->fi_bstart++, p++) ++ if (p->hf_file) ++ au_hfput(p, file); ++ bend = au_sbend(sb); ++ } ++ ++ p = finfo->fi_hfile + bend; ++ for (finfo->fi_bend = bend; finfo->fi_bend >= finfo->fi_bstart; ++ finfo->fi_bend--, p--) ++ if (p->hf_file) { ++ if (p->hf_file->f_dentry ++ && p->hf_file->f_dentry->d_inode) ++ break; ++ else ++ au_hfput(p, file); ++ } ++ AuDebugOn(finfo->fi_bend < finfo->fi_bstart); ++} ++ ++/* ++ * after branch manipulating, refresh the file. ++ */ ++static int refresh_file(struct file *file, int (*reopen)(struct file *file)) ++{ ++ int err, need_reopen; ++ struct dentry *dentry; ++ aufs_bindex_t bend, bindex; ++ ++ dentry = file->f_dentry; ++ err = au_fi_realloc(au_fi(file), au_sbend(dentry->d_sb) + 1); ++ if (unlikely(err)) ++ goto out; ++ au_do_refresh_file(file); ++ ++ err = 0; ++ need_reopen = 1; ++ if (!au_test_mmapped(file)) ++ err = au_file_refresh_by_inode(file, &need_reopen); ++ if (!err && need_reopen && !d_unhashed(dentry)) ++ err = reopen(file); ++ if (!err) { ++ au_update_figen(file); ++ return 0; /* success */ ++ } ++ ++ /* error, close all lower files */ ++ bend = au_fbend(file); ++ for (bindex = au_fbstart(file); bindex <= bend; bindex++) ++ au_set_h_fptr(file, bindex, NULL); ++ ++ out: ++ return err; ++} ++ ++/* common function to regular file and dir */ ++int au_reval_and_lock_fdi(struct file *file, int (*reopen)(struct file *file), ++ int wlock) ++{ ++ int err; ++ unsigned int sigen, figen; ++ aufs_bindex_t bstart; ++ unsigned char pseudo_link; ++ struct dentry *dentry; ++ struct inode *inode; ++ ++ err = 0; ++ dentry = file->f_dentry; ++ inode = dentry->d_inode; ++ AuDebugOn(au_special_file(inode->i_mode)); ++ sigen = au_sigen(dentry->d_sb); ++ fi_write_lock(file); ++ figen = au_figen(file); ++ di_write_lock_child(dentry); ++ bstart = au_dbstart(dentry); ++ pseudo_link = (bstart != au_ibstart(inode)); ++ if (sigen == figen && !pseudo_link && au_fbstart(file) == bstart) { ++ if (!wlock) { ++ di_downgrade_lock(dentry, AuLock_IR); ++ fi_downgrade_lock(file); ++ } ++ goto out; /* success */ ++ } ++ ++ AuDbg("sigen %d, figen %d\n", sigen, figen); ++ if (sigen != au_digen(dentry) ++ || sigen != au_iigen(inode)) { ++ err = au_reval_dpath(dentry, sigen); ++ if (unlikely(err < 0)) ++ goto out; ++ AuDebugOn(au_digen(dentry) != sigen ++ || au_iigen(inode) != sigen); ++ } ++ ++ err = refresh_file(file, reopen); ++ if (!err) { ++ if (!wlock) { ++ di_downgrade_lock(dentry, AuLock_IR); ++ fi_downgrade_lock(file); ++ } ++ } else { ++ di_write_unlock(dentry); ++ fi_write_unlock(file); ++ } ++ ++ out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* cf. aufs_nopage() */ ++/* for madvise(2) */ ++static int aufs_readpage(struct file *file __maybe_unused, struct page *page) ++{ ++ unlock_page(page); ++ return 0; ++} ++ ++/* they will never be called. */ ++#ifdef CONFIG_AUFS_DEBUG ++static int aufs_write_begin(struct file *file, struct address_space *mapping, ++ loff_t pos, unsigned len, unsigned flags, ++ struct page **pagep, void **fsdata) ++{ AuUnsupport(); return 0; } ++static int aufs_write_end(struct file *file, struct address_space *mapping, ++ loff_t pos, unsigned len, unsigned copied, ++ struct page *page, void *fsdata) ++{ AuUnsupport(); return 0; } ++static int aufs_writepage(struct page *page, struct writeback_control *wbc) ++{ AuUnsupport(); return 0; } ++static void aufs_sync_page(struct page *page) ++{ AuUnsupport(); } ++ ++static int aufs_set_page_dirty(struct page *page) ++{ AuUnsupport(); return 0; } ++static void aufs_invalidatepage(struct page *page, unsigned long offset) ++{ AuUnsupport(); } ++static int aufs_releasepage(struct page *page, gfp_t gfp) ++{ AuUnsupport(); return 0; } ++static ssize_t aufs_direct_IO(int rw, struct kiocb *iocb, ++ const struct iovec *iov, loff_t offset, ++ unsigned long nr_segs) ++{ AuUnsupport(); return 0; } ++static int aufs_get_xip_mem(struct address_space *mapping, pgoff_t pgoff, ++ int create, void **kmem, unsigned long *pfn) ++{ AuUnsupport(); return 0; } ++static int aufs_migratepage(struct address_space *mapping, struct page *newpage, ++ struct page *page) ++{ AuUnsupport(); return 0; } ++static int aufs_launder_page(struct page *page) ++{ AuUnsupport(); return 0; } ++static int aufs_is_partially_uptodate(struct page *page, ++ read_descriptor_t *desc, ++ unsigned long from) ++{ AuUnsupport(); return 0; } ++static int aufs_error_remove_page(struct address_space *mapping, ++ struct page *page) ++{ AuUnsupport(); return 0; } ++#endif /* CONFIG_AUFS_DEBUG */ ++ ++struct address_space_operations aufs_aop = { ++ .readpage = aufs_readpage, ++#ifdef CONFIG_AUFS_DEBUG ++ .writepage = aufs_writepage, ++ .sync_page = aufs_sync_page, ++ /* no writepages, because of writepage */ ++ .set_page_dirty = aufs_set_page_dirty, ++ /* no readpages, because of readpage */ ++ .write_begin = aufs_write_begin, ++ .write_end = aufs_write_end, ++ /* no bmap, no block device */ ++ .invalidatepage = aufs_invalidatepage, ++ .releasepage = aufs_releasepage, ++ .direct_IO = aufs_direct_IO, /* todo */ ++ .get_xip_mem = aufs_get_xip_mem, /* todo */ ++ .migratepage = aufs_migratepage, ++ .launder_page = aufs_launder_page, ++ .is_partially_uptodate = aufs_is_partially_uptodate, ++ .error_remove_page = aufs_error_remove_page ++#endif /* CONFIG_AUFS_DEBUG */ ++}; +diff --git a/fs/aufs/file.h b/fs/aufs/file.h +new file mode 100644 +index 0000000..a5affe0 +--- /dev/null ++++ b/fs/aufs/file.h +@@ -0,0 +1,208 @@ ++/* ++ * Copyright (C) 2005-2010 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* ++ * file operations ++ */ ++ ++#ifndef __AUFS_FILE_H__ ++#define __AUFS_FILE_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++#include ++#include "rwsem.h" ++ ++struct au_branch; ++struct au_hfile { ++ struct file *hf_file; ++ struct au_branch *hf_br; ++}; ++ ++struct au_vdir; ++struct au_finfo { ++ atomic_t fi_generation; ++ ++ struct au_rwsem fi_rwsem; ++ struct au_hfile *fi_hfile; ++ aufs_bindex_t fi_bstart, fi_bend; ++ ++ union { ++ /* non-dir only */ ++ struct { ++ struct vm_operations_struct *fi_h_vm_ops; ++ struct vm_operations_struct *fi_vm_ops; ++ struct mutex fi_vm_mtx; ++ }; ++ ++ /* dir only */ ++ struct { ++ struct au_vdir *fi_vdir_cache; ++ }; ++ }; ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* file.c */ ++extern struct address_space_operations aufs_aop; ++unsigned int au_file_roflags(unsigned int flags); ++struct file *au_h_open(struct dentry *dentry, aufs_bindex_t bindex, int flags, ++ struct file *file); ++int au_do_open(struct file *file, int (*open)(struct file *file, int flags)); ++int au_reopen_nondir(struct file *file); ++struct au_pin; ++int au_ready_to_write(struct file *file, loff_t len, struct au_pin *pin); ++int au_reval_and_lock_fdi(struct file *file, int (*reopen)(struct file *file), ++ int wlock); ++ ++/* poll.c */ ++#ifdef CONFIG_AUFS_POLL ++unsigned int aufs_poll(struct file *file, poll_table *wait); ++#endif ++ ++#ifdef CONFIG_AUFS_BR_HFSPLUS ++/* hfsplus.c */ ++struct file *au_h_open_pre(struct dentry *dentry, aufs_bindex_t bindex); ++void au_h_open_post(struct dentry *dentry, aufs_bindex_t bindex, ++ struct file *h_file); ++#else ++static inline ++struct file *au_h_open_pre(struct dentry *dentry, aufs_bindex_t bindex) ++{ ++ return NULL; ++} ++ ++AuStubVoid(au_h_open_post, struct dentry *dentry, aufs_bindex_t bindex, ++ struct file *h_file); ++#endif ++ ++/* f_op.c */ ++extern const struct file_operations aufs_file_fop; ++int aufs_flush(struct file *file, fl_owner_t id); ++int au_do_open_nondir(struct file *file, int flags); ++int aufs_release_nondir(struct inode *inode __maybe_unused, struct file *file); ++ ++#ifdef CONFIG_AUFS_SP_IATTR ++/* f_op_sp.c */ ++int au_special_file(umode_t mode); ++void au_init_special_fop(struct inode *inode, umode_t mode, dev_t rdev); ++#else ++AuStubInt0(au_special_file, umode_t mode) ++static inline void au_init_special_fop(struct inode *inode, umode_t mode, ++ dev_t rdev) ++{ ++ init_special_inode(inode, mode, rdev); ++} ++#endif ++ ++/* finfo.c */ ++void au_hfput(struct au_hfile *hf, struct file *file); ++void au_set_h_fptr(struct file *file, aufs_bindex_t bindex, ++ struct file *h_file); ++ ++void au_update_figen(struct file *file); ++ ++void au_finfo_fin(struct file *file); ++int au_finfo_init(struct file *file); ++int au_fi_realloc(struct au_finfo *finfo, int nbr); ++ ++/* ioctl.c */ ++long aufs_ioctl_nondir(struct file *file, unsigned int cmd, unsigned long arg); ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline struct au_finfo *au_fi(struct file *file) ++{ ++ return file->private_data; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * fi_read_lock, fi_write_lock, ++ * fi_read_unlock, fi_write_unlock, fi_downgrade_lock ++ */ ++AuSimpleRwsemFuncs(fi, struct file *f, &au_fi(f)->fi_rwsem); ++ ++#define FiMustNoWaiters(f) AuRwMustNoWaiters(&au_fi(f)->fi_rwsem) ++#define FiMustAnyLock(f) AuRwMustAnyLock(&au_fi(f)->fi_rwsem) ++#define FiMustWriteLock(f) AuRwMustWriteLock(&au_fi(f)->fi_rwsem) ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* todo: hard/soft set? */ ++static inline aufs_bindex_t au_fbstart(struct file *file) ++{ ++ FiMustAnyLock(file); ++ return au_fi(file)->fi_bstart; ++} ++ ++static inline aufs_bindex_t au_fbend(struct file *file) ++{ ++ FiMustAnyLock(file); ++ return au_fi(file)->fi_bend; ++} ++ ++static inline struct au_vdir *au_fvdir_cache(struct file *file) ++{ ++ FiMustAnyLock(file); ++ return au_fi(file)->fi_vdir_cache; ++} ++ ++static inline void au_set_fbstart(struct file *file, aufs_bindex_t bindex) ++{ ++ FiMustWriteLock(file); ++ au_fi(file)->fi_bstart = bindex; ++} ++ ++static inline void au_set_fbend(struct file *file, aufs_bindex_t bindex) ++{ ++ FiMustWriteLock(file); ++ au_fi(file)->fi_bend = bindex; ++} ++ ++static inline void au_set_fvdir_cache(struct file *file, ++ struct au_vdir *vdir_cache) ++{ ++ FiMustWriteLock(file); ++ au_fi(file)->fi_vdir_cache = vdir_cache; ++} ++ ++static inline struct file *au_h_fptr(struct file *file, aufs_bindex_t bindex) ++{ ++ FiMustAnyLock(file); ++ return au_fi(file)->fi_hfile[0 + bindex].hf_file; ++} ++ ++/* todo: memory barrier? */ ++static inline unsigned int au_figen(struct file *f) ++{ ++ return atomic_read(&au_fi(f)->fi_generation); ++} ++ ++static inline int au_test_mmapped(struct file *f) ++{ ++ FiMustAnyLock(f); ++ return !!(au_fi(f)->fi_h_vm_ops); ++} ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_FILE_H__ */ +diff --git a/fs/aufs/finfo.c b/fs/aufs/finfo.c +new file mode 100644 +index 0000000..b15b32b +--- /dev/null ++++ b/fs/aufs/finfo.c +@@ -0,0 +1,129 @@ ++/* ++ * Copyright (C) 2005-2010 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* ++ * file private data ++ */ ++ ++#include ++#include "aufs.h" ++ ++void au_hfput(struct au_hfile *hf, struct file *file) ++{ ++ /* todo: direct access f_flags */ ++ if (vfsub_file_flags(file) & vfsub_fmode_to_uint(FMODE_EXEC)) ++ allow_write_access(hf->hf_file); ++ fput(hf->hf_file); ++ hf->hf_file = NULL; ++ atomic_dec_return(&hf->hf_br->br_count); ++ hf->hf_br = NULL; ++} ++ ++void au_set_h_fptr(struct file *file, aufs_bindex_t bindex, struct file *val) ++{ ++ struct au_finfo *finfo = au_fi(file); ++ struct au_hfile *hf; ++ ++ hf = finfo->fi_hfile + bindex; ++ if (hf->hf_file) ++ au_hfput(hf, file); ++ if (val) { ++ FiMustWriteLock(file); ++ hf->hf_file = val; ++ hf->hf_br = au_sbr(file->f_dentry->d_sb, bindex); ++ } ++} ++ ++void au_update_figen(struct file *file) ++{ ++ atomic_set(&au_fi(file)->fi_generation, au_digen(file->f_dentry)); ++ /* smp_mb(); */ /* atomic_set */ ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void au_finfo_fin(struct file *file) ++{ ++ struct au_finfo *finfo; ++ aufs_bindex_t bindex, bend; ++ ++ finfo = au_fi(file); ++ bindex = finfo->fi_bstart; ++ if (bindex >= 0) { ++ /* ++ * calls fput() instead of filp_close(), ++ * since no dnotify or lock for the lower file. ++ */ ++ bend = finfo->fi_bend; ++ for (; bindex <= bend; bindex++) ++ au_set_h_fptr(file, bindex, NULL); ++ } ++ ++ au_dbg_verify_hf(finfo); ++ kfree(finfo->fi_hfile); ++ AuRwDestroy(&finfo->fi_rwsem); ++ au_cache_free_finfo(finfo); ++} ++ ++int au_finfo_init(struct file *file) ++{ ++ struct au_finfo *finfo; ++ struct dentry *dentry; ++ ++ dentry = file->f_dentry; ++ finfo = au_cache_alloc_finfo(); ++ if (unlikely(!finfo)) ++ goto out; ++ ++ finfo->fi_hfile = kcalloc(au_sbend(dentry->d_sb) + 1, ++ sizeof(*finfo->fi_hfile), GFP_NOFS); ++ if (unlikely(!finfo->fi_hfile)) ++ goto out_finfo; ++ ++ au_rw_init_wlock(&finfo->fi_rwsem); ++ finfo->fi_bstart = -1; ++ finfo->fi_bend = -1; ++ atomic_set(&finfo->fi_generation, au_digen(dentry)); ++ /* smp_mb(); */ /* atomic_set */ ++ ++ file->private_data = finfo; ++ return 0; /* success */ ++ ++ out_finfo: ++ au_cache_free_finfo(finfo); ++ out: ++ return -ENOMEM; ++} ++ ++int au_fi_realloc(struct au_finfo *finfo, int nbr) ++{ ++ int err, sz; ++ struct au_hfile *hfp; ++ ++ err = -ENOMEM; ++ sz = sizeof(*hfp) * (finfo->fi_bend + 1); ++ if (!sz) ++ sz = sizeof(*hfp); ++ hfp = au_kzrealloc(finfo->fi_hfile, sz, sizeof(*hfp) * nbr, GFP_NOFS); ++ if (hfp) { ++ finfo->fi_hfile = hfp; ++ err = 0; ++ } ++ ++ return err; ++} +diff --git a/fs/aufs/fstype.h b/fs/aufs/fstype.h +new file mode 100644 +index 0000000..270f2a4 +--- /dev/null ++++ b/fs/aufs/fstype.h +@@ -0,0 +1,497 @@ ++/* ++ * Copyright (C) 2005-2010 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* ++ * judging filesystem type ++ */ ++ ++#ifndef __AUFS_FSTYPE_H__ ++#define __AUFS_FSTYPE_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++#include ++#include ++ ++static inline int au_test_aufs(struct super_block *sb) ++{ ++ return sb->s_magic == AUFS_SUPER_MAGIC; ++} ++ ++static inline const char *au_sbtype(struct super_block *sb) ++{ ++ return sb->s_type->name; ++} ++ ++static inline int au_test_iso9660(struct super_block *sb __maybe_unused) ++{ ++#if defined(CONFIG_ROMFS_FS) || defined(CONFIG_ROMFS_FS_MODULE) ++ return sb->s_magic == ROMFS_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_romfs(struct super_block *sb __maybe_unused) ++{ ++#if defined(CONFIG_ISO9660_FS) || defined(CONFIG_ISO9660_FS_MODULE) ++ return sb->s_magic == ISOFS_SUPER_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_cramfs(struct super_block *sb __maybe_unused) ++{ ++#if defined(CONFIG_CRAMFS) || defined(CONFIG_CRAMFS_MODULE) ++ return sb->s_magic == CRAMFS_MAGIC; ++#endif ++ return 0; ++} ++ ++static inline int au_test_nfs(struct super_block *sb __maybe_unused) ++{ ++#if defined(CONFIG_NFS_FS) || defined(CONFIG_NFS_FS_MODULE) ++ return sb->s_magic == NFS_SUPER_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_fuse(struct super_block *sb __maybe_unused) ++{ ++#if defined(CONFIG_FUSE_FS) || defined(CONFIG_FUSE_FS_MODULE) ++ return sb->s_magic == FUSE_SUPER_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_xfs(struct super_block *sb __maybe_unused) ++{ ++#if defined(CONFIG_XFS_FS) || defined(CONFIG_XFS_FS_MODULE) ++ return sb->s_magic == XFS_SB_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_tmpfs(struct super_block *sb __maybe_unused) ++{ ++#ifdef CONFIG_TMPFS ++ return sb->s_magic == TMPFS_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_ecryptfs(struct super_block *sb __maybe_unused) ++{ ++#if defined(CONFIG_ECRYPT_FS) || defined(CONFIG_ECRYPT_FS_MODULE) ++ return !strcmp(au_sbtype(sb), "ecryptfs"); ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_smbfs(struct super_block *sb __maybe_unused) ++{ ++#if defined(CONFIG_SMB_FS) || defined(CONFIG_SMB_FS_MODULE) ++ return sb->s_magic == SMB_SUPER_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_ocfs2(struct super_block *sb __maybe_unused) ++{ ++#if defined(CONFIG_OCFS2_FS) || defined(CONFIG_OCFS2_FS_MODULE) ++ return sb->s_magic == OCFS2_SUPER_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_ocfs2_dlmfs(struct super_block *sb __maybe_unused) ++{ ++#if defined(CONFIG_OCFS2_FS_O2CB) || defined(CONFIG_OCFS2_FS_O2CB_MODULE) ++ return sb->s_magic == DLMFS_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_coda(struct super_block *sb __maybe_unused) ++{ ++#if defined(CONFIG_CODA_FS) || defined(CONFIG_CODA_FS_MODULE) ++ return sb->s_magic == CODA_SUPER_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_v9fs(struct super_block *sb __maybe_unused) ++{ ++#if defined(CONFIG_9P_FS) || defined(CONFIG_9P_FS_MODULE) ++ return sb->s_magic == V9FS_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_ext4(struct super_block *sb __maybe_unused) ++{ ++#if defined(CONFIG_EXT4DEV_FS) || defined(CONFIG_EXT4DEV_FS_MODULE) ++ return sb->s_magic == EXT4_SUPER_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_sysv(struct super_block *sb __maybe_unused) ++{ ++#if defined(CONFIG_SYSV_FS) || defined(CONFIG_SYSV_FS_MODULE) ++ return !strcmp(au_sbtype(sb), "sysv"); ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_ramfs(struct super_block *sb) ++{ ++ return sb->s_magic == RAMFS_MAGIC; ++} ++ ++static inline int au_test_ubifs(struct super_block *sb __maybe_unused) ++{ ++#if defined(CONFIG_UBIFS_FS) || defined(CONFIG_UBIFS_FS_MODULE) ++ return sb->s_magic == UBIFS_SUPER_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_procfs(struct super_block *sb __maybe_unused) ++{ ++#ifdef CONFIG_PROC_FS ++ return sb->s_magic == PROC_SUPER_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_sysfs(struct super_block *sb __maybe_unused) ++{ ++#ifdef CONFIG_SYSFS ++ return sb->s_magic == SYSFS_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_configfs(struct super_block *sb __maybe_unused) ++{ ++#if defined(CONFIG_CONFIGFS_FS) || defined(CONFIG_CONFIGFS_FS_MODULE) ++ return sb->s_magic == CONFIGFS_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_minix(struct super_block *sb __maybe_unused) ++{ ++#if defined(CONFIG_MINIX_FS) || defined(CONFIG_MINIX_FS_MODULE) ++ return sb->s_magic == MINIX3_SUPER_MAGIC ++ || sb->s_magic == MINIX2_SUPER_MAGIC ++ || sb->s_magic == MINIX2_SUPER_MAGIC2 ++ || sb->s_magic == MINIX_SUPER_MAGIC ++ || sb->s_magic == MINIX_SUPER_MAGIC2; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_cifs(struct super_block *sb __maybe_unused) ++{ ++#if defined(CONFIG_CIFS_FS) || defined(CONFIGCIFS_FS_MODULE) ++ return sb->s_magic == CIFS_MAGIC_NUMBER; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_fat(struct super_block *sb __maybe_unused) ++{ ++#if defined(CONFIG_FAT_FS) || defined(CONFIG_FAT_FS_MODULE) ++ return sb->s_magic == MSDOS_SUPER_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_msdos(struct super_block *sb) ++{ ++ return au_test_fat(sb); ++} ++ ++static inline int au_test_vfat(struct super_block *sb) ++{ ++ return au_test_fat(sb); ++} ++ ++static inline int au_test_securityfs(struct super_block *sb __maybe_unused) ++{ ++#ifdef CONFIG_SECURITYFS ++ return sb->s_magic == SECURITYFS_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_squashfs(struct super_block *sb __maybe_unused) ++{ ++#if defined(CONFIG_SQUASHFS) || defined(CONFIG_SQUASHFS_MODULE) ++ return sb->s_magic == SQUASHFS_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_btrfs(struct super_block *sb __maybe_unused) ++{ ++#if defined(CONFIG_BTRFS_FS) || defined(CONFIG_BTRFS_FS_MODULE) ++ return sb->s_magic == BTRFS_SUPER_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_xenfs(struct super_block *sb __maybe_unused) ++{ ++#if defined(CONFIG_XENFS) || defined(CONFIG_XENFS_MODULE) ++ return sb->s_magic == XENFS_SUPER_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_debugfs(struct super_block *sb __maybe_unused) ++{ ++#ifdef CONFIG_DEBUG_FS ++ return sb->s_magic == DEBUGFS_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_nilfs(struct super_block *sb __maybe_unused) ++{ ++#if defined(CONFIG_NILFS) || defined(CONFIG_NILFS_MODULE) ++ return sb->s_magic == NILFS_SUPER_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_hfsplus(struct super_block *sb __maybe_unused) ++{ ++#if defined(CONFIG_HFSPLUS_FS) || defined(CONFIG_HFSPLUS_FS_MODULE) ++ return sb->s_magic == HFSPLUS_SUPER_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++/* ---------------------------------------------------------------------- */ ++/* ++ * they can't be an aufs branch. ++ */ ++static inline int au_test_fs_unsuppoted(struct super_block *sb) ++{ ++ return ++#ifndef CONFIG_AUFS_BR_RAMFS ++ au_test_ramfs(sb) || ++#endif ++ au_test_procfs(sb) ++ || au_test_sysfs(sb) ++ || au_test_configfs(sb) ++ || au_test_debugfs(sb) ++ || au_test_securityfs(sb) ++ || au_test_xenfs(sb) ++ || au_test_ecryptfs(sb) ++ /* || !strcmp(au_sbtype(sb), "unionfs") */ ++ || au_test_aufs(sb); /* will be supported in next version */ ++} ++ ++/* ++ * If the filesystem supports NFS-export, then it has to support NULL as ++ * a nameidata parameter for ->create(), ->lookup() and ->d_revalidate(). ++ * We can apply this principle when we handle a lower filesystem. ++ */ ++static inline int au_test_fs_null_nd(struct super_block *sb) ++{ ++ return !!sb->s_export_op; ++} ++ ++static inline int au_test_fs_remote(struct super_block *sb) ++{ ++ return !au_test_tmpfs(sb) ++#ifdef CONFIG_AUFS_BR_RAMFS ++ && !au_test_ramfs(sb) ++#endif ++ && !(sb->s_type->fs_flags & FS_REQUIRES_DEV); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * Note: these functions (below) are created after reading ->getattr() in all ++ * filesystems under linux/fs. it means we have to do so in every update... ++ */ ++ ++/* ++ * some filesystems require getattr to refresh the inode attributes before ++ * referencing. ++ * in most cases, we can rely on the inode attribute in NFS (or every remote fs) ++ * and leave the work for d_revalidate() ++ */ ++static inline int au_test_fs_refresh_iattr(struct super_block *sb) ++{ ++ return au_test_nfs(sb) ++ || au_test_fuse(sb) ++ /* || au_test_smbfs(sb) */ /* untested */ ++ /* || au_test_ocfs2(sb) */ /* untested */ ++ /* || au_test_btrfs(sb) */ /* untested */ ++ /* || au_test_coda(sb) */ /* untested */ ++ /* || au_test_v9fs(sb) */ /* untested */ ++ ; ++} ++ ++/* ++ * filesystems which don't maintain i_size or i_blocks. ++ */ ++static inline int au_test_fs_bad_iattr_size(struct super_block *sb) ++{ ++ return au_test_xfs(sb) ++ || au_test_btrfs(sb) ++ || au_test_ubifs(sb) ++ || au_test_hfsplus(sb) /* maintained, but incorrect */ ++ /* || au_test_ext4(sb) */ /* untested */ ++ /* || au_test_ocfs2(sb) */ /* untested */ ++ /* || au_test_ocfs2_dlmfs(sb) */ /* untested */ ++ /* || au_test_sysv(sb) */ /* untested */ ++ /* || au_test_minix(sb) */ /* untested */ ++ ; ++} ++ ++/* ++ * filesystems which don't store the correct value in some of their inode ++ * attributes. ++ */ ++static inline int au_test_fs_bad_iattr(struct super_block *sb) ++{ ++ return au_test_fs_bad_iattr_size(sb) ++ /* || au_test_cifs(sb) */ /* untested */ ++ || au_test_fat(sb) ++ || au_test_msdos(sb) ++ || au_test_vfat(sb); ++} ++ ++/* they don't check i_nlink in link(2) */ ++static inline int au_test_fs_no_limit_nlink(struct super_block *sb) ++{ ++ return au_test_tmpfs(sb) ++#ifdef CONFIG_AUFS_BR_RAMFS ++ || au_test_ramfs(sb) ++#endif ++ || au_test_ubifs(sb) ++ || au_test_btrfs(sb) ++ || au_test_hfsplus(sb); ++} ++ ++/* ++ * filesystems which sets S_NOATIME and S_NOCMTIME. ++ */ ++static inline int au_test_fs_notime(struct super_block *sb) ++{ ++ return au_test_nfs(sb) ++ || au_test_fuse(sb) ++ || au_test_ubifs(sb) ++ /* || au_test_cifs(sb) */ /* untested */ ++ ; ++} ++ ++/* ++ * filesystems which requires replacing i_mapping. ++ */ ++static inline int au_test_fs_bad_mapping(struct super_block *sb) ++{ ++ return au_test_fuse(sb) ++ || au_test_ubifs(sb); ++} ++ ++/* temporary support for i#1 in cramfs */ ++static inline int au_test_fs_unique_ino(struct inode *inode) ++{ ++ if (au_test_cramfs(inode->i_sb)) ++ return inode->i_ino != 1; ++ return 1; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * the filesystem where the xino files placed must support i/o after unlink and ++ * maintain i_size and i_blocks. ++ */ ++static inline int au_test_fs_bad_xino(struct super_block *sb) ++{ ++ return au_test_fs_remote(sb) ++ || au_test_fs_bad_iattr_size(sb) ++#ifdef CONFIG_AUFS_BR_RAMFS ++ || !(au_test_ramfs(sb) || au_test_fs_null_nd(sb)) ++#else ++ || !au_test_fs_null_nd(sb) /* to keep xino code simple */ ++#endif ++ /* don't want unnecessary work for xino */ ++ || au_test_aufs(sb) ++ || au_test_ecryptfs(sb) ++ || au_test_nilfs(sb); ++} ++ ++static inline int au_test_fs_trunc_xino(struct super_block *sb) ++{ ++ return au_test_tmpfs(sb) ++ || au_test_ramfs(sb); ++} ++ ++/* ++ * test if the @sb is real-readonly. ++ */ ++static inline int au_test_fs_rr(struct super_block *sb) ++{ ++ return au_test_squashfs(sb) ++ || au_test_iso9660(sb) ++ || au_test_cramfs(sb) ++ || au_test_romfs(sb); ++} ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_FSTYPE_H__ */ +diff --git a/fs/aufs/hfsplus.c b/fs/aufs/hfsplus.c +new file mode 100644 +index 0000000..3bb997c +--- /dev/null ++++ b/fs/aufs/hfsplus.c +@@ -0,0 +1,58 @@ ++/* ++ * Copyright (C) 2010 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* ++ * special support for filesystems which aqucires an inode mutex ++ * at final closing a file, eg, hfsplus. ++ * ++ * This trick is very simple and stupid, just to open the file before really ++ * neceeary open to tell hfsplus that this is not the final closing. ++ * The caller should call au_h_open_pre() after acquiring the inode mutex, ++ * and au_h_open_post() after releasing it. ++ */ ++ ++#include ++#include "aufs.h" ++ ++struct file *au_h_open_pre(struct dentry *dentry, aufs_bindex_t bindex) ++{ ++ struct file *h_file; ++ struct dentry *h_dentry; ++ ++ h_dentry = au_h_dptr(dentry, bindex); ++ AuDebugOn(!h_dentry); ++ AuDebugOn(!h_dentry->d_inode); ++ IMustLock(h_dentry->d_inode); ++ ++ h_file = NULL; ++ if (au_test_hfsplus(h_dentry->d_sb) ++ && S_ISREG(h_dentry->d_inode->i_mode)) ++ h_file = au_h_open(dentry, bindex, ++ O_RDONLY | O_NOATIME | O_LARGEFILE, ++ /*file*/NULL); ++ return h_file; ++} ++ ++void au_h_open_post(struct dentry *dentry, aufs_bindex_t bindex, ++ struct file *h_file) ++{ ++ if (h_file) { ++ fput(h_file); ++ au_sbr_put(dentry->d_sb, bindex); ++ } ++} +diff --git a/fs/aufs/hinotify.c b/fs/aufs/hinotify.c +new file mode 100644 +index 0000000..f3f1fda +--- /dev/null ++++ b/fs/aufs/hinotify.c +@@ -0,0 +1,749 @@ ++/* ++ * Copyright (C) 2005-2010 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* ++ * inotify for the lower directories ++ */ ++ ++#include "aufs.h" ++ ++static const __u32 AuHinMask = (IN_MOVE | IN_DELETE | IN_CREATE); ++static struct inotify_handle *au_hin_handle; ++ ++AuCacheFuncs(hinotify, HINOTIFY); ++ ++int au_hin_alloc(struct au_hinode *hinode, struct inode *inode, ++ struct inode *h_inode) ++{ ++ int err; ++ struct au_hinotify *hin; ++ s32 wd; ++ ++ err = -ENOMEM; ++ hin = au_cache_alloc_hinotify(); ++ if (hin) { ++ AuDebugOn(hinode->hi_notify); ++ hinode->hi_notify = hin; ++ hin->hin_aufs_inode = inode; ++ ++ inotify_init_watch(&hin->hin_watch); ++ wd = inotify_add_watch(au_hin_handle, &hin->hin_watch, h_inode, ++ AuHinMask); ++ if (wd >= 0) ++ return 0; /* success */ ++ ++ err = wd; ++ put_inotify_watch(&hin->hin_watch); ++ au_cache_free_hinotify(hin); ++ hinode->hi_notify = NULL; ++ } ++ ++ return err; ++} ++ ++void au_hin_free(struct au_hinode *hinode) ++{ ++ int err; ++ struct au_hinotify *hin; ++ ++ hin = hinode->hi_notify; ++ if (hin) { ++ err = 0; ++ if (atomic_read(&hin->hin_watch.count)) ++ err = inotify_rm_watch(au_hin_handle, &hin->hin_watch); ++ if (unlikely(err)) ++ /* it means the watch is already removed */ ++ pr_warning("failed inotify_rm_watch() %d\n", err); ++ au_cache_free_hinotify(hin); ++ hinode->hi_notify = NULL; ++ } ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void au_hin_ctl(struct au_hinode *hinode, int do_set) ++{ ++ struct inode *h_inode; ++ struct inotify_watch *watch; ++ ++ if (!hinode->hi_notify) ++ return; ++ ++ h_inode = hinode->hi_inode; ++ IMustLock(h_inode); ++ ++ /* todo: try inotify_find_update_watch()? */ ++ watch = &hinode->hi_notify->hin_watch; ++ mutex_lock(&h_inode->inotify_mutex); ++ /* mutex_lock(&watch->ih->mutex); */ ++ if (do_set) { ++ AuDebugOn(watch->mask & AuHinMask); ++ watch->mask |= AuHinMask; ++ } else { ++ AuDebugOn(!(watch->mask & AuHinMask)); ++ watch->mask &= ~AuHinMask; ++ } ++ /* mutex_unlock(&watch->ih->mutex); */ ++ mutex_unlock(&h_inode->inotify_mutex); ++} ++ ++void au_reset_hinotify(struct inode *inode, unsigned int flags) ++{ ++ aufs_bindex_t bindex, bend; ++ struct inode *hi; ++ struct dentry *iwhdentry; ++ ++ bend = au_ibend(inode); ++ for (bindex = au_ibstart(inode); bindex <= bend; bindex++) { ++ hi = au_h_iptr(inode, bindex); ++ if (!hi) ++ continue; ++ ++ /* mutex_lock_nested(&hi->i_mutex, AuLsc_I_CHILD); */ ++ iwhdentry = au_hi_wh(inode, bindex); ++ if (iwhdentry) ++ dget(iwhdentry); ++ au_igrab(hi); ++ au_set_h_iptr(inode, bindex, NULL, 0); ++ au_set_h_iptr(inode, bindex, au_igrab(hi), ++ flags & ~AuHi_XINO); ++ iput(hi); ++ dput(iwhdentry); ++ /* mutex_unlock(&hi->i_mutex); */ ++ } ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int hin_xino(struct inode *inode, struct inode *h_inode) ++{ ++ int err; ++ aufs_bindex_t bindex, bend, bfound, bstart; ++ struct inode *h_i; ++ ++ err = 0; ++ if (unlikely(inode->i_ino == AUFS_ROOT_INO)) { ++ pr_warning("branch root dir was changed\n"); ++ goto out; ++ } ++ ++ bfound = -1; ++ bend = au_ibend(inode); ++ bstart = au_ibstart(inode); ++#if 0 /* reserved for future use */ ++ if (bindex == bend) { ++ /* keep this ino in rename case */ ++ goto out; ++ } ++#endif ++ for (bindex = bstart; bindex <= bend; bindex++) ++ if (au_h_iptr(inode, bindex) == h_inode) { ++ bfound = bindex; ++ break; ++ } ++ if (bfound < 0) ++ goto out; ++ ++ for (bindex = bstart; bindex <= bend; bindex++) { ++ h_i = au_h_iptr(inode, bindex); ++ if (!h_i) ++ continue; ++ ++ err = au_xino_write(inode->i_sb, bindex, h_i->i_ino, /*ino*/0); ++ /* ignore this error */ ++ /* bad action? */ ++ } ++ ++ /* children inode number will be broken */ ++ ++ out: ++ AuTraceErr(err); ++ return err; ++} ++ ++static int hin_gen_tree(struct dentry *dentry) ++{ ++ int err, i, j, ndentry; ++ struct au_dcsub_pages dpages; ++ struct au_dpage *dpage; ++ struct dentry **dentries; ++ ++ err = au_dpages_init(&dpages, GFP_NOFS); ++ if (unlikely(err)) ++ goto out; ++ err = au_dcsub_pages(&dpages, dentry, NULL, NULL); ++ if (unlikely(err)) ++ goto out_dpages; ++ ++ for (i = 0; i < dpages.ndpage; i++) { ++ dpage = dpages.dpages + i; ++ dentries = dpage->dentries; ++ ndentry = dpage->ndentry; ++ for (j = 0; j < ndentry; j++) { ++ struct dentry *d; ++ ++ d = dentries[j]; ++ if (IS_ROOT(d)) ++ continue; ++ ++ d_drop(d); ++ au_digen_dec(d); ++ if (d->d_inode) ++ /* todo: reset children xino? ++ cached children only? */ ++ au_iigen_dec(d->d_inode); ++ } ++ } ++ ++ out_dpages: ++ au_dpages_free(&dpages); ++ ++ /* discard children */ ++ dentry_unhash(dentry); ++ dput(dentry); ++ out: ++ return err; ++} ++ ++/* ++ * return 0 if processed. ++ */ ++static int hin_gen_by_inode(char *name, unsigned int nlen, struct inode *inode, ++ const unsigned int isdir) ++{ ++ int err; ++ struct dentry *d; ++ struct qstr *dname; ++ ++ err = 1; ++ if (unlikely(inode->i_ino == AUFS_ROOT_INO)) { ++ pr_warning("branch root dir was changed\n"); ++ err = 0; ++ goto out; ++ } ++ ++ if (!isdir) { ++ AuDebugOn(!name); ++ au_iigen_dec(inode); ++ spin_lock(&dcache_lock); ++ list_for_each_entry(d, &inode->i_dentry, d_alias) { ++ dname = &d->d_name; ++ if (dname->len != nlen ++ && memcmp(dname->name, name, nlen)) ++ continue; ++ err = 0; ++ spin_lock(&d->d_lock); ++ __d_drop(d); ++ au_digen_dec(d); ++ spin_unlock(&d->d_lock); ++ break; ++ } ++ spin_unlock(&dcache_lock); ++ } else { ++ au_fset_si(au_sbi(inode->i_sb), FAILED_REFRESH_DIRS); ++ d = d_find_alias(inode); ++ if (!d) { ++ au_iigen_dec(inode); ++ goto out; ++ } ++ ++ dname = &d->d_name; ++ if (dname->len == nlen && !memcmp(dname->name, name, nlen)) ++ err = hin_gen_tree(d); ++ dput(d); ++ } ++ ++ out: ++ AuTraceErr(err); ++ return err; ++} ++ ++static int hin_gen_by_name(struct dentry *dentry, const unsigned int isdir) ++{ ++ int err; ++ struct inode *inode; ++ ++ inode = dentry->d_inode; ++ if (IS_ROOT(dentry) ++ /* || (inode && inode->i_ino == AUFS_ROOT_INO) */ ++ ) { ++ pr_warning("branch root dir was changed\n"); ++ return 0; ++ } ++ ++ err = 0; ++ if (!isdir) { ++ d_drop(dentry); ++ au_digen_dec(dentry); ++ if (inode) ++ au_iigen_dec(inode); ++ } else { ++ au_fset_si(au_sbi(dentry->d_sb), FAILED_REFRESH_DIRS); ++ if (inode) ++ err = hin_gen_tree(dentry); ++ } ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* hinotify job flags */ ++#define AuHinJob_XINO0 1 ++#define AuHinJob_GEN (1 << 1) ++#define AuHinJob_DIRENT (1 << 2) ++#define AuHinJob_ISDIR (1 << 3) ++#define AuHinJob_TRYXINO0 (1 << 4) ++#define AuHinJob_MNTPNT (1 << 5) ++#define au_ftest_hinjob(flags, name) ((flags) & AuHinJob_##name) ++#define au_fset_hinjob(flags, name) { (flags) |= AuHinJob_##name; } ++#define au_fclr_hinjob(flags, name) { (flags) &= ~AuHinJob_##name; } ++ ++struct hin_job_args { ++ unsigned int flags; ++ struct inode *inode, *h_inode, *dir, *h_dir; ++ struct dentry *dentry; ++ char *h_name; ++ int h_nlen; ++}; ++ ++static int hin_job(struct hin_job_args *a) ++{ ++ const unsigned int isdir = au_ftest_hinjob(a->flags, ISDIR); ++ ++ /* reset xino */ ++ if (au_ftest_hinjob(a->flags, XINO0) && a->inode) ++ hin_xino(a->inode, a->h_inode); /* ignore this error */ ++ ++ if (au_ftest_hinjob(a->flags, TRYXINO0) ++ && a->inode ++ && a->h_inode) { ++ mutex_lock_nested(&a->h_inode->i_mutex, AuLsc_I_CHILD); ++ if (!a->h_inode->i_nlink) ++ hin_xino(a->inode, a->h_inode); /* ignore this error */ ++ mutex_unlock(&a->h_inode->i_mutex); ++ } ++ ++ /* make the generation obsolete */ ++ if (au_ftest_hinjob(a->flags, GEN)) { ++ int err = -1; ++ if (a->inode) ++ err = hin_gen_by_inode(a->h_name, a->h_nlen, a->inode, ++ isdir); ++ if (err && a->dentry) ++ hin_gen_by_name(a->dentry, isdir); ++ /* ignore this error */ ++ } ++ ++ /* make dir entries obsolete */ ++ if (au_ftest_hinjob(a->flags, DIRENT) && a->inode) { ++ struct au_vdir *vdir; ++ ++ vdir = au_ivdir(a->inode); ++ if (vdir) ++ vdir->vd_jiffy = 0; ++ /* IMustLock(a->inode); */ ++ /* a->inode->i_version++; */ ++ } ++ ++ /* can do nothing but warn */ ++ if (au_ftest_hinjob(a->flags, MNTPNT) ++ && a->dentry ++ && d_mountpoint(a->dentry)) ++ pr_warning("mount-point %.*s is removed or renamed\n", ++ AuDLNPair(a->dentry)); ++ ++ return 0; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static char *in_name(u32 mask) ++{ ++#ifdef CONFIG_AUFS_DEBUG ++#define test_ret(flag) if (mask & flag) \ ++ return #flag; ++ test_ret(IN_ACCESS); ++ test_ret(IN_MODIFY); ++ test_ret(IN_ATTRIB); ++ test_ret(IN_CLOSE_WRITE); ++ test_ret(IN_CLOSE_NOWRITE); ++ test_ret(IN_OPEN); ++ test_ret(IN_MOVED_FROM); ++ test_ret(IN_MOVED_TO); ++ test_ret(IN_CREATE); ++ test_ret(IN_DELETE); ++ test_ret(IN_DELETE_SELF); ++ test_ret(IN_MOVE_SELF); ++ test_ret(IN_UNMOUNT); ++ test_ret(IN_Q_OVERFLOW); ++ test_ret(IN_IGNORED); ++ return ""; ++#undef test_ret ++#else ++ return "??"; ++#endif ++} ++ ++static struct dentry *lookup_wlock_by_name(char *name, unsigned int nlen, ++ struct inode *dir) ++{ ++ struct dentry *dentry, *d, *parent; ++ struct qstr *dname; ++ ++ parent = d_find_alias(dir); ++ if (!parent) ++ return NULL; ++ ++ dentry = NULL; ++ spin_lock(&dcache_lock); ++ list_for_each_entry(d, &parent->d_subdirs, d_u.d_child) { ++ /* AuDbg("%.*s\n", AuDLNPair(d)); */ ++ dname = &d->d_name; ++ if (dname->len != nlen || memcmp(dname->name, name, nlen)) ++ continue; ++ if (!atomic_read(&d->d_count) || !d->d_fsdata) { ++ spin_lock(&d->d_lock); ++ __d_drop(d); ++ spin_unlock(&d->d_lock); ++ continue; ++ } ++ ++ dentry = dget(d); ++ break; ++ } ++ spin_unlock(&dcache_lock); ++ dput(parent); ++ ++ if (dentry) ++ di_write_lock_child(dentry); ++ ++ return dentry; ++} ++ ++static struct inode *lookup_wlock_by_ino(struct super_block *sb, ++ aufs_bindex_t bindex, ino_t h_ino) ++{ ++ struct inode *inode; ++ ino_t ino; ++ int err; ++ ++ inode = NULL; ++ err = au_xino_read(sb, bindex, h_ino, &ino); ++ if (!err && ino) ++ inode = ilookup(sb, ino); ++ if (!inode) ++ goto out; ++ ++ if (unlikely(inode->i_ino == AUFS_ROOT_INO)) { ++ pr_warning("wrong root branch\n"); ++ iput(inode); ++ inode = NULL; ++ goto out; ++ } ++ ++ ii_write_lock_child(inode); ++ ++ out: ++ return inode; ++} ++ ++enum { CHILD, PARENT }; ++struct postproc_args { ++ struct inode *h_dir, *dir, *h_child_inode; ++ u32 mask; ++ unsigned int flags[2]; ++ unsigned int h_child_nlen; ++ char h_child_name[]; ++}; ++ ++static void postproc(void *_args) ++{ ++ struct postproc_args *a = _args; ++ struct super_block *sb; ++ aufs_bindex_t bindex, bend, bfound; ++ unsigned char xino, try_iput; ++ int err; ++ struct inode *inode; ++ ino_t h_ino; ++ struct hin_job_args args; ++ struct dentry *dentry; ++ struct au_sbinfo *sbinfo; ++ ++ AuDebugOn(!_args); ++ AuDebugOn(!a->h_dir); ++ AuDebugOn(!a->dir); ++ AuDebugOn(!a->mask); ++ AuDbg("mask 0x%x %s, i%lu, hi%lu, hci%lu\n", ++ a->mask, in_name(a->mask), a->dir->i_ino, a->h_dir->i_ino, ++ a->h_child_inode ? a->h_child_inode->i_ino : 0); ++ ++ inode = NULL; ++ dentry = NULL; ++ /* ++ * do not lock a->dir->i_mutex here ++ * because of d_revalidate() may cause a deadlock. ++ */ ++ sb = a->dir->i_sb; ++ AuDebugOn(!sb); ++ sbinfo = au_sbi(sb); ++ AuDebugOn(!sbinfo); ++ /* big aufs lock */ ++ si_noflush_write_lock(sb); ++ ++ ii_read_lock_parent(a->dir); ++ bfound = -1; ++ bend = au_ibend(a->dir); ++ for (bindex = au_ibstart(a->dir); bindex <= bend; bindex++) ++ if (au_h_iptr(a->dir, bindex) == a->h_dir) { ++ bfound = bindex; ++ break; ++ } ++ ii_read_unlock(a->dir); ++ if (unlikely(bfound < 0)) ++ goto out; ++ ++ xino = !!au_opt_test(au_mntflags(sb), XINO); ++ h_ino = 0; ++ if (a->h_child_inode) ++ h_ino = a->h_child_inode->i_ino; ++ ++ if (a->h_child_nlen ++ && (au_ftest_hinjob(a->flags[CHILD], GEN) ++ || au_ftest_hinjob(a->flags[CHILD], MNTPNT))) ++ dentry = lookup_wlock_by_name(a->h_child_name, a->h_child_nlen, ++ a->dir); ++ try_iput = 0; ++ if (dentry) ++ inode = dentry->d_inode; ++ if (xino && !inode && h_ino ++ && (au_ftest_hinjob(a->flags[CHILD], XINO0) ++ || au_ftest_hinjob(a->flags[CHILD], TRYXINO0) ++ || au_ftest_hinjob(a->flags[CHILD], GEN))) { ++ inode = lookup_wlock_by_ino(sb, bfound, h_ino); ++ try_iput = 1; ++ } ++ ++ args.flags = a->flags[CHILD]; ++ args.dentry = dentry; ++ args.inode = inode; ++ args.h_inode = a->h_child_inode; ++ args.dir = a->dir; ++ args.h_dir = a->h_dir; ++ args.h_name = a->h_child_name; ++ args.h_nlen = a->h_child_nlen; ++ err = hin_job(&args); ++ if (dentry) { ++ if (dentry->d_fsdata) ++ di_write_unlock(dentry); ++ dput(dentry); ++ } ++ if (inode && try_iput) { ++ ii_write_unlock(inode); ++ iput(inode); ++ } ++ ++ ii_write_lock_parent(a->dir); ++ args.flags = a->flags[PARENT]; ++ args.dentry = NULL; ++ args.inode = a->dir; ++ args.h_inode = a->h_dir; ++ args.dir = NULL; ++ args.h_dir = NULL; ++ args.h_name = NULL; ++ args.h_nlen = 0; ++ err = hin_job(&args); ++ ii_write_unlock(a->dir); ++ ++ out: ++ au_nwt_done(&sbinfo->si_nowait); ++ si_write_unlock(sb); ++ ++ iput(a->h_child_inode); ++ iput(a->h_dir); ++ iput(a->dir); ++ kfree(a); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void aufs_inotify(struct inotify_watch *watch, u32 wd __maybe_unused, ++ u32 mask, u32 cookie __maybe_unused, ++ const char *h_child_name, struct inode *h_child_inode) ++{ ++ struct au_hinotify *hinotify; ++ struct postproc_args *args; ++ int len, wkq_err; ++ unsigned char isdir, isroot, wh; ++ char *p; ++ struct inode *dir; ++ unsigned int flags[2]; ++ ++ /* if IN_UNMOUNT happens, there must be another bug */ ++ AuDebugOn(mask & IN_UNMOUNT); ++ if (mask & (IN_IGNORED | IN_UNMOUNT)) { ++ put_inotify_watch(watch); ++ return; ++ } ++#ifdef AuDbgHinotify ++ au_debug(1); ++ if (1 || !h_child_name || strcmp(h_child_name, AUFS_XINO_FNAME)) { ++ AuDbg("i%lu, wd %d, mask 0x%x %s, cookie 0x%x, hcname %s," ++ " hi%lu\n", ++ watch->inode->i_ino, wd, mask, in_name(mask), cookie, ++ h_child_name ? h_child_name : "", ++ h_child_inode ? h_child_inode->i_ino : 0); ++ WARN_ON(1); ++ } ++ au_debug(0); ++#endif ++ ++ hinotify = container_of(watch, struct au_hinotify, hin_watch); ++ AuDebugOn(!hinotify || !hinotify->hin_aufs_inode); ++ dir = igrab(hinotify->hin_aufs_inode); ++ if (!dir) ++ return; ++ ++ isroot = (dir->i_ino == AUFS_ROOT_INO); ++ len = 0; ++ wh = 0; ++ if (h_child_name) { ++ len = strlen(h_child_name); ++ if (!memcmp(h_child_name, AUFS_WH_PFX, AUFS_WH_PFX_LEN)) { ++ h_child_name += AUFS_WH_PFX_LEN; ++ len -= AUFS_WH_PFX_LEN; ++ wh = 1; ++ } ++ } ++ ++ isdir = 0; ++ if (h_child_inode) ++ isdir = !!S_ISDIR(h_child_inode->i_mode); ++ flags[PARENT] = AuHinJob_ISDIR; ++ flags[CHILD] = 0; ++ if (isdir) ++ flags[CHILD] = AuHinJob_ISDIR; ++ au_fset_hinjob(flags[PARENT], DIRENT); ++ au_fset_hinjob(flags[CHILD], GEN); ++ switch (mask & IN_ALL_EVENTS) { ++ case IN_MOVED_FROM: ++ case IN_MOVED_TO: ++ au_fset_hinjob(flags[CHILD], XINO0); ++ au_fset_hinjob(flags[CHILD], MNTPNT); ++ /*FALLTHROUGH*/ ++ case IN_CREATE: ++ AuDebugOn(!h_child_name || !h_child_inode); ++ break; ++ ++ case IN_DELETE: ++ /* ++ * aufs never be able to get this child inode. ++ * revalidation should be in d_revalidate() ++ * by checking i_nlink, i_generation or d_unhashed(). ++ */ ++ AuDebugOn(!h_child_name); ++ au_fset_hinjob(flags[CHILD], TRYXINO0); ++ au_fset_hinjob(flags[CHILD], MNTPNT); ++ break; ++ ++ default: ++ AuDebugOn(1); ++ } ++ ++ if (wh) ++ h_child_inode = NULL; ++ ++ /* iput() and kfree() will be called in postproc() */ ++ /* ++ * inotify_mutex is already acquired and kmalloc/prune_icache may lock ++ * iprune_mutex. strange. ++ */ ++ /* lockdep_off(); */ ++ args = kmalloc(sizeof(*args) + len + 1, GFP_NOFS); ++ /* lockdep_on(); */ ++ if (unlikely(!args)) { ++ AuErr1("no memory\n"); ++ iput(dir); ++ return; ++ } ++ args->flags[PARENT] = flags[PARENT]; ++ args->flags[CHILD] = flags[CHILD]; ++ args->mask = mask; ++ args->dir = dir; ++ args->h_dir = igrab(watch->inode); ++ if (h_child_inode) ++ h_child_inode = igrab(h_child_inode); /* can be NULL */ ++ args->h_child_inode = h_child_inode; ++ args->h_child_nlen = len; ++ if (len) { ++ p = (void *)args; ++ p += sizeof(*args); ++ memcpy(p, h_child_name, len + 1); ++ } ++ ++ /* lockdep_off(); */ ++ wkq_err = au_wkq_nowait(postproc, args, dir->i_sb); ++ /* lockdep_on(); */ ++ if (unlikely(wkq_err)) ++ pr_err("wkq %d\n", wkq_err); ++} ++ ++static void aufs_inotify_destroy(struct inotify_watch *watch __maybe_unused) ++{ ++ return; ++} ++ ++static struct inotify_operations aufs_inotify_ops = { ++ .handle_event = aufs_inotify, ++ .destroy_watch = aufs_inotify_destroy ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void au_hin_destroy_cache(void) ++{ ++ kmem_cache_destroy(au_cachep[AuCache_HINOTIFY]); ++ au_cachep[AuCache_HINOTIFY] = NULL; ++} ++ ++int __init au_hinotify_init(void) ++{ ++ int err; ++ ++ err = -ENOMEM; ++ au_cachep[AuCache_HINOTIFY] = AuCache(au_hinotify); ++ if (au_cachep[AuCache_HINOTIFY]) { ++ err = 0; ++ au_hin_handle = inotify_init(&aufs_inotify_ops); ++ if (IS_ERR(au_hin_handle)) { ++ err = PTR_ERR(au_hin_handle); ++ au_hin_destroy_cache(); ++ } ++ } ++ AuTraceErr(err); ++ return err; ++} ++ ++void au_hinotify_fin(void) ++{ ++ inotify_destroy(au_hin_handle); ++ /* cf. au_cache_fin() */ ++ if (au_cachep[AuCache_HINOTIFY]) ++ au_hin_destroy_cache(); ++} +diff --git a/fs/aufs/i_op.c b/fs/aufs/i_op.c +new file mode 100644 +index 0000000..dfacf50 +--- /dev/null ++++ b/fs/aufs/i_op.c +@@ -0,0 +1,907 @@ ++/* ++ * Copyright (C) 2005-2010 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* ++ * inode operations (except add/del/rename) ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "aufs.h" ++ ++static int h_permission(struct inode *h_inode, int mask, ++ struct vfsmount *h_mnt, int brperm) ++{ ++ int err; ++ const unsigned char write_mask = !!(mask & (MAY_WRITE | MAY_APPEND)); ++ ++ err = -EACCES; ++ if ((write_mask && IS_IMMUTABLE(h_inode)) ++ || ((mask & MAY_EXEC) ++ && S_ISREG(h_inode->i_mode) ++ && ((h_mnt->mnt_flags & MNT_NOEXEC) ++ || !(h_inode->i_mode & S_IXUGO)))) ++ goto out; ++ ++ /* ++ * - skip the lower fs test in the case of write to ro branch. ++ * - nfs dir permission write check is optimized, but a policy for ++ * link/rename requires a real check. ++ */ ++ if ((write_mask && !au_br_writable(brperm)) ++ || (au_test_nfs(h_inode->i_sb) && S_ISDIR(h_inode->i_mode) ++ && write_mask && !(mask & MAY_READ)) ++ || !h_inode->i_op->permission) { ++ /* AuLabel(generic_permission); */ ++ err = generic_permission(h_inode, mask, NULL); ++ } else { ++ /* AuLabel(h_inode->permission); */ ++ err = h_inode->i_op->permission(h_inode, mask); ++ AuTraceErr(err); ++ } ++ ++ if (!err) ++ err = devcgroup_inode_permission(h_inode, mask); ++ if (!err) { ++ mask &= (MAY_READ | MAY_WRITE | MAY_EXEC | MAY_APPEND); ++ err = security_inode_permission(h_inode, mask); ++ } ++ ++#if 0 ++ if (!err) { ++ /* todo: do we need to call ima_path_check()? */ ++ struct path h_path = { ++ .dentry = ++ .mnt = h_mnt ++ }; ++ err = ima_path_check(&h_path, ++ mask & (MAY_READ | MAY_WRITE | MAY_EXEC), ++ IMA_COUNT_LEAVE); ++ } ++#endif ++ ++ out: ++ return err; ++} ++ ++static int aufs_permission(struct inode *inode, int mask) ++{ ++ int err; ++ aufs_bindex_t bindex, bend; ++ const unsigned char isdir = !!S_ISDIR(inode->i_mode), ++ write_mask = !!(mask & (MAY_WRITE | MAY_APPEND)); ++ struct inode *h_inode; ++ struct super_block *sb; ++ struct au_branch *br; ++ ++ sb = inode->i_sb; ++ si_read_lock(sb, AuLock_FLUSH); ++ ii_read_lock_child(inode); ++ ++ if (!isdir || write_mask) { ++ err = au_busy_or_stale(); ++ h_inode = au_h_iptr(inode, au_ibstart(inode)); ++ if (unlikely(!h_inode ++ || (h_inode->i_mode & S_IFMT) ++ != (inode->i_mode & S_IFMT))) ++ goto out; ++ ++ err = 0; ++ bindex = au_ibstart(inode); ++ br = au_sbr(sb, bindex); ++ err = h_permission(h_inode, mask, br->br_mnt, br->br_perm); ++ if (write_mask ++ && !err ++ && !special_file(h_inode->i_mode)) { ++ /* test whether the upper writable branch exists */ ++ err = -EROFS; ++ for (; bindex >= 0; bindex--) ++ if (!au_br_rdonly(au_sbr(sb, bindex))) { ++ err = 0; ++ break; ++ } ++ } ++ goto out; ++ } ++ ++ /* non-write to dir */ ++ err = 0; ++ bend = au_ibend(inode); ++ for (bindex = au_ibstart(inode); !err && bindex <= bend; bindex++) { ++ h_inode = au_h_iptr(inode, bindex); ++ if (h_inode) { ++ err = au_busy_or_stale(); ++ if (unlikely(!S_ISDIR(h_inode->i_mode))) ++ break; ++ ++ br = au_sbr(sb, bindex); ++ err = h_permission(h_inode, mask, br->br_mnt, ++ br->br_perm); ++ } ++ } ++ ++ out: ++ ii_read_unlock(inode); ++ si_read_unlock(sb); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static struct dentry *aufs_lookup(struct inode *dir, struct dentry *dentry, ++ struct nameidata *nd) ++{ ++ struct dentry *ret, *parent; ++ struct inode *inode, *h_inode; ++ struct mutex *mtx; ++ struct super_block *sb; ++ int err, npositive; ++ aufs_bindex_t bstart; ++ ++ IMustLock(dir); ++ ++ sb = dir->i_sb; ++ si_read_lock(sb, AuLock_FLUSH); ++ ret = ERR_PTR(-ENAMETOOLONG); ++ if (unlikely(dentry->d_name.len > AUFS_MAX_NAMELEN)) ++ goto out; ++ err = au_alloc_dinfo(dentry); ++ ret = ERR_PTR(err); ++ if (unlikely(err)) ++ goto out; ++ ++ parent = dentry->d_parent; /* dir inode is locked */ ++ di_read_lock_parent(parent, AuLock_IR); ++ npositive = au_lkup_dentry(dentry, au_dbstart(parent), /*type*/0, nd); ++ di_read_unlock(parent, AuLock_IR); ++ err = npositive; ++ ret = ERR_PTR(err); ++ if (unlikely(err < 0)) ++ goto out_unlock; ++ ++ inode = NULL; ++ if (npositive) { ++ bstart = au_dbstart(dentry); ++ h_inode = au_h_dptr(dentry, bstart)->d_inode; ++ if (!S_ISDIR(h_inode->i_mode)) { ++ /* ++ * stop 'race'-ing between hardlinks under different ++ * parents. ++ */ ++ mtx = &au_sbr(sb, bstart)->br_xino.xi_nondir_mtx; ++ mutex_lock(mtx); ++ inode = au_new_inode(dentry, /*must_new*/0); ++ mutex_unlock(mtx); ++ } else ++ inode = au_new_inode(dentry, /*must_new*/0); ++ ret = (void *)inode; ++ } ++ if (IS_ERR(inode)) ++ goto out_unlock; ++ ++ ret = d_splice_alias(inode, dentry); ++ if (unlikely(IS_ERR(ret) && inode)) ++ ii_write_unlock(inode); ++ ++ out_unlock: ++ di_write_unlock(dentry); ++ out: ++ si_read_unlock(sb); ++ return ret; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_wr_dir_cpup(struct dentry *dentry, struct dentry *parent, ++ const unsigned char add_entry, aufs_bindex_t bcpup, ++ aufs_bindex_t bstart) ++{ ++ int err; ++ struct dentry *h_parent; ++ struct inode *h_dir; ++ ++ if (add_entry) { ++ au_update_dbstart(dentry); ++ IMustLock(parent->d_inode); ++ } else ++ di_write_lock_parent(parent); ++ ++ err = 0; ++ if (!au_h_dptr(parent, bcpup)) { ++ if (bstart < bcpup) ++ err = au_cpdown_dirs(dentry, bcpup); ++ else ++ err = au_cpup_dirs(dentry, bcpup); ++ } ++ if (!err && add_entry) { ++ h_parent = au_h_dptr(parent, bcpup); ++ h_dir = h_parent->d_inode; ++ mutex_lock_nested(&h_dir->i_mutex, AuLsc_I_PARENT); ++ err = au_lkup_neg(dentry, bcpup); ++ /* todo: no unlock here */ ++ mutex_unlock(&h_dir->i_mutex); ++ if (bstart < bcpup && au_dbstart(dentry) < 0) { ++ au_set_dbstart(dentry, 0); ++ au_update_dbrange(dentry, /*do_put_zero*/0); ++ } ++ } ++ ++ if (!add_entry) ++ di_write_unlock(parent); ++ if (!err) ++ err = bcpup; /* success */ ++ ++ return err; ++} ++ ++/* ++ * decide the branch and the parent dir where we will create a new entry. ++ * returns new bindex or an error. ++ * copyup the parent dir if needed. ++ */ ++int au_wr_dir(struct dentry *dentry, struct dentry *src_dentry, ++ struct au_wr_dir_args *args) ++{ ++ int err; ++ aufs_bindex_t bcpup, bstart, src_bstart; ++ const unsigned char add_entry = !!au_ftest_wrdir(args->flags, ++ ADD_ENTRY); ++ struct super_block *sb; ++ struct dentry *parent; ++ struct au_sbinfo *sbinfo; ++ ++ sb = dentry->d_sb; ++ sbinfo = au_sbi(sb); ++ parent = dget_parent(dentry); ++ bstart = au_dbstart(dentry); ++ bcpup = bstart; ++ if (args->force_btgt < 0) { ++ if (src_dentry) { ++ src_bstart = au_dbstart(src_dentry); ++ if (src_bstart < bstart) ++ bcpup = src_bstart; ++ } else if (add_entry) { ++ err = AuWbrCreate(sbinfo, dentry, ++ au_ftest_wrdir(args->flags, ISDIR)); ++ bcpup = err; ++ } ++ ++ if (bcpup < 0 || au_test_ro(sb, bcpup, dentry->d_inode)) { ++ if (add_entry) ++ err = AuWbrCopyup(sbinfo, dentry); ++ else { ++ if (!IS_ROOT(dentry)) { ++ di_read_lock_parent(parent, !AuLock_IR); ++ err = AuWbrCopyup(sbinfo, dentry); ++ di_read_unlock(parent, !AuLock_IR); ++ } else ++ err = AuWbrCopyup(sbinfo, dentry); ++ } ++ bcpup = err; ++ if (unlikely(err < 0)) ++ goto out; ++ } ++ } else { ++ bcpup = args->force_btgt; ++ AuDebugOn(au_test_ro(sb, bcpup, dentry->d_inode)); ++ } ++ AuDbg("bstart %d, bcpup %d\n", bstart, bcpup); ++ if (bstart < bcpup) ++ au_update_dbrange(dentry, /*do_put_zero*/1); ++ ++ err = bcpup; ++ if (bcpup == bstart) ++ goto out; /* success */ ++ ++ /* copyup the new parent into the branch we process */ ++ err = au_wr_dir_cpup(dentry, parent, add_entry, bcpup, bstart); ++ ++ out: ++ dput(parent); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct dentry *au_pinned_h_parent(struct au_pin *pin) ++{ ++ if (pin && pin->parent) ++ return au_h_dptr(pin->parent, pin->bindex); ++ return NULL; ++} ++ ++void au_unpin(struct au_pin *p) ++{ ++ if (au_ftest_pin(p->flags, MNT_WRITE)) ++ mnt_drop_write(p->h_mnt); ++ if (!p->hdir) ++ return; ++ ++ au_hin_imtx_unlock(p->hdir); ++ if (!au_ftest_pin(p->flags, DI_LOCKED)) ++ di_read_unlock(p->parent, AuLock_IR); ++ iput(p->hdir->hi_inode); ++ dput(p->parent); ++ p->parent = NULL; ++ p->hdir = NULL; ++ p->h_mnt = NULL; ++} ++ ++int au_do_pin(struct au_pin *p) ++{ ++ int err; ++ struct super_block *sb; ++ struct dentry *h_dentry, *h_parent; ++ struct au_branch *br; ++ struct inode *h_dir; ++ ++ err = 0; ++ sb = p->dentry->d_sb; ++ br = au_sbr(sb, p->bindex); ++ if (IS_ROOT(p->dentry)) { ++ if (au_ftest_pin(p->flags, MNT_WRITE)) { ++ p->h_mnt = br->br_mnt; ++ err = mnt_want_write(p->h_mnt); ++ if (unlikely(err)) { ++ au_fclr_pin(p->flags, MNT_WRITE); ++ goto out_err; ++ } ++ } ++ goto out; ++ } ++ ++ h_dentry = NULL; ++ if (p->bindex <= au_dbend(p->dentry)) ++ h_dentry = au_h_dptr(p->dentry, p->bindex); ++ ++ p->parent = dget_parent(p->dentry); ++ if (!au_ftest_pin(p->flags, DI_LOCKED)) ++ di_read_lock(p->parent, AuLock_IR, p->lsc_di); ++ ++ h_dir = NULL; ++ h_parent = au_h_dptr(p->parent, p->bindex); ++ p->hdir = au_hi(p->parent->d_inode, p->bindex); ++ if (p->hdir) ++ h_dir = p->hdir->hi_inode; ++ ++ /* udba case */ ++ if (unlikely(!p->hdir || !h_dir)) { ++ if (!au_ftest_pin(p->flags, DI_LOCKED)) ++ di_read_unlock(p->parent, AuLock_IR); ++ dput(p->parent); ++ p->parent = NULL; ++ goto out_err; ++ } ++ ++ au_igrab(h_dir); ++ au_hin_imtx_lock_nested(p->hdir, p->lsc_hi); ++ ++ if (unlikely(p->hdir->hi_inode != h_parent->d_inode)) { ++ err = -EBUSY; ++ goto out_unpin; ++ } ++ if (h_dentry) { ++ err = au_h_verify(h_dentry, p->udba, h_dir, h_parent, br); ++ if (unlikely(err)) { ++ au_fclr_pin(p->flags, MNT_WRITE); ++ goto out_unpin; ++ } ++ } ++ ++ if (au_ftest_pin(p->flags, MNT_WRITE)) { ++ p->h_mnt = br->br_mnt; ++ err = mnt_want_write(p->h_mnt); ++ if (unlikely(err)) { ++ au_fclr_pin(p->flags, MNT_WRITE); ++ goto out_unpin; ++ } ++ } ++ goto out; /* success */ ++ ++ out_unpin: ++ au_unpin(p); ++ out_err: ++ pr_err("err %d\n", err); ++ err = au_busy_or_stale(); ++ out: ++ return err; ++} ++ ++void au_pin_init(struct au_pin *p, struct dentry *dentry, ++ aufs_bindex_t bindex, int lsc_di, int lsc_hi, ++ unsigned int udba, unsigned char flags) ++{ ++ p->dentry = dentry; ++ p->udba = udba; ++ p->lsc_di = lsc_di; ++ p->lsc_hi = lsc_hi; ++ p->flags = flags; ++ p->bindex = bindex; ++ ++ p->parent = NULL; ++ p->hdir = NULL; ++ p->h_mnt = NULL; ++} ++ ++int au_pin(struct au_pin *pin, struct dentry *dentry, aufs_bindex_t bindex, ++ unsigned int udba, unsigned char flags) ++{ ++ au_pin_init(pin, dentry, bindex, AuLsc_DI_PARENT, AuLsc_I_PARENT2, ++ udba, flags); ++ return au_do_pin(pin); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++#define AuIcpup_DID_CPUP 1 ++#define au_ftest_icpup(flags, name) ((flags) & AuIcpup_##name) ++#define au_fset_icpup(flags, name) { (flags) |= AuIcpup_##name; } ++#define au_fclr_icpup(flags, name) { (flags) &= ~AuIcpup_##name; } ++ ++struct au_icpup_args { ++ unsigned char flags; ++ unsigned char pin_flags; ++ aufs_bindex_t btgt; ++ struct au_pin pin; ++ struct path h_path; ++ struct inode *h_inode; ++}; ++ ++static int au_lock_and_icpup(struct dentry *dentry, struct iattr *ia, ++ struct au_icpup_args *a) ++{ ++ int err; ++ unsigned int udba; ++ loff_t sz; ++ aufs_bindex_t bstart; ++ struct dentry *hi_wh, *parent; ++ struct inode *inode; ++ struct file *h_file; ++ struct au_wr_dir_args wr_dir_args = { ++ .force_btgt = -1, ++ .flags = 0 ++ }; ++ ++ di_write_lock_child(dentry); ++ bstart = au_dbstart(dentry); ++ inode = dentry->d_inode; ++ if (S_ISDIR(inode->i_mode)) ++ au_fset_wrdir(wr_dir_args.flags, ISDIR); ++ /* plink or hi_wh() case */ ++ if (bstart != au_ibstart(inode)) ++ wr_dir_args.force_btgt = au_ibstart(inode); ++ err = au_wr_dir(dentry, /*src_dentry*/NULL, &wr_dir_args); ++ if (unlikely(err < 0)) ++ goto out_dentry; ++ a->btgt = err; ++ if (err != bstart) ++ au_fset_icpup(a->flags, DID_CPUP); ++ ++ err = 0; ++ a->pin_flags = AuPin_MNT_WRITE; ++ parent = NULL; ++ if (!IS_ROOT(dentry)) { ++ au_fset_pin(a->pin_flags, DI_LOCKED); ++ parent = dget_parent(dentry); ++ di_write_lock_parent(parent); ++ } ++ ++ udba = au_opt_udba(dentry->d_sb); ++ if (d_unhashed(dentry) || (ia->ia_valid & ATTR_FILE)) ++ udba = AuOpt_UDBA_NONE; ++ err = au_pin(&a->pin, dentry, a->btgt, udba, a->pin_flags); ++ if (unlikely(err)) { ++ if (parent) { ++ di_write_unlock(parent); ++ dput(parent); ++ } ++ goto out_dentry; ++ } ++ a->h_path.dentry = au_h_dptr(dentry, bstart); ++ a->h_inode = a->h_path.dentry->d_inode; ++ mutex_lock_nested(&a->h_inode->i_mutex, AuLsc_I_CHILD); ++ sz = -1; ++ if ((ia->ia_valid & ATTR_SIZE) && ia->ia_size < i_size_read(a->h_inode)) ++ sz = ia->ia_size; ++ ++ h_file = NULL; ++ hi_wh = NULL; ++ if (au_ftest_icpup(a->flags, DID_CPUP) && d_unhashed(dentry)) { ++ hi_wh = au_hi_wh(inode, a->btgt); ++ if (!hi_wh) { ++ err = au_sio_cpup_wh(dentry, a->btgt, sz, /*file*/NULL); ++ if (unlikely(err)) ++ goto out_unlock; ++ hi_wh = au_hi_wh(inode, a->btgt); ++ /* todo: revalidate hi_wh? */ ++ } ++ } ++ ++ if (parent) { ++ au_pin_set_parent_lflag(&a->pin, /*lflag*/0); ++ di_downgrade_lock(parent, AuLock_IR); ++ dput(parent); ++ } ++ if (!au_ftest_icpup(a->flags, DID_CPUP)) ++ goto out; /* success */ ++ ++ if (!d_unhashed(dentry)) { ++ h_file = au_h_open_pre(dentry, bstart); ++ if (IS_ERR(h_file)) { ++ err = PTR_ERR(h_file); ++ h_file = NULL; ++ } else ++ err = au_sio_cpup_simple(dentry, a->btgt, sz, ++ AuCpup_DTIME); ++ if (!err) ++ a->h_path.dentry = au_h_dptr(dentry, a->btgt); ++ } else if (!hi_wh) ++ a->h_path.dentry = au_h_dptr(dentry, a->btgt); ++ else ++ a->h_path.dentry = hi_wh; /* do not dget here */ ++ ++ out_unlock: ++ mutex_unlock(&a->h_inode->i_mutex); ++ au_h_open_post(dentry, bstart, h_file); ++ a->h_inode = a->h_path.dentry->d_inode; ++ if (!err) { ++ mutex_lock_nested(&a->h_inode->i_mutex, AuLsc_I_CHILD); ++ goto out; /* success */ ++ } ++ ++ au_unpin(&a->pin); ++ ++ out_dentry: ++ di_write_unlock(dentry); ++ out: ++ return err; ++} ++ ++static int aufs_setattr(struct dentry *dentry, struct iattr *ia) ++{ ++ int err; ++ struct inode *inode; ++ struct super_block *sb; ++ struct file *file; ++ struct au_icpup_args *a; ++ ++ err = -ENOMEM; ++ a = kzalloc(sizeof(*a), GFP_NOFS); ++ if (unlikely(!a)) ++ goto out; ++ ++ inode = dentry->d_inode; ++ IMustLock(inode); ++ sb = dentry->d_sb; ++ si_read_lock(sb, AuLock_FLUSH); ++ ++ file = NULL; ++ if (ia->ia_valid & ATTR_FILE) { ++ /* currently ftruncate(2) only */ ++ file = ia->ia_file; ++ fi_write_lock(file); ++ ia->ia_file = au_h_fptr(file, au_fbstart(file)); ++ } ++ ++ if (ia->ia_valid & (ATTR_KILL_SUID | ATTR_KILL_SGID)) ++ ia->ia_valid &= ~ATTR_MODE; ++ ++ err = au_lock_and_icpup(dentry, ia, a); ++ if (unlikely(err < 0)) ++ goto out_si; ++ if (au_ftest_icpup(a->flags, DID_CPUP)) { ++ ia->ia_file = NULL; ++ ia->ia_valid &= ~ATTR_FILE; ++ } ++ ++ a->h_path.mnt = au_sbr_mnt(sb, a->btgt); ++ if ((ia->ia_valid & (ATTR_MODE | ATTR_CTIME)) ++ == (ATTR_MODE | ATTR_CTIME)) { ++ err = security_path_chmod(a->h_path.dentry, a->h_path.mnt, ++ ia->ia_mode); ++ if (unlikely(err)) ++ goto out_unlock; ++ } else if ((ia->ia_valid & (ATTR_UID | ATTR_GID)) ++ && (ia->ia_valid & ATTR_CTIME)) { ++ err = security_path_chown(&a->h_path, ia->ia_uid, ia->ia_gid); ++ if (unlikely(err)) ++ goto out_unlock; ++ } ++ ++ if (ia->ia_valid & ATTR_SIZE) { ++ struct file *f; ++ ++ if (ia->ia_size < i_size_read(inode)) { ++ /* unmap only */ ++ err = vmtruncate(inode, ia->ia_size); ++ if (unlikely(err)) ++ goto out_unlock; ++ } ++ ++ f = NULL; ++ if (ia->ia_valid & ATTR_FILE) ++ f = ia->ia_file; ++ mutex_unlock(&a->h_inode->i_mutex); ++ err = vfsub_trunc(&a->h_path, ia->ia_size, ia->ia_valid, f); ++ mutex_lock_nested(&a->h_inode->i_mutex, AuLsc_I_CHILD); ++ } else ++ err = vfsub_notify_change(&a->h_path, ia); ++ if (!err) ++ au_cpup_attr_changeable(inode); ++ ++ out_unlock: ++ mutex_unlock(&a->h_inode->i_mutex); ++ au_unpin(&a->pin); ++ di_write_unlock(dentry); ++ out_si: ++ if (file) { ++ fi_write_unlock(file); ++ ia->ia_file = file; ++ ia->ia_valid |= ATTR_FILE; ++ } ++ si_read_unlock(sb); ++ kfree(a); ++ out: ++ return err; ++} ++ ++static int au_getattr_lock_reval(struct dentry *dentry, unsigned int sigen) ++{ ++ int err; ++ struct inode *inode; ++ struct dentry *parent; ++ ++ err = 0; ++ inode = dentry->d_inode; ++ di_write_lock_child(dentry); ++ if (au_digen(dentry) != sigen || au_iigen(inode) != sigen) { ++ parent = dget_parent(dentry); ++ di_read_lock_parent(parent, AuLock_IR); ++ /* returns a number of positive dentries */ ++ err = au_refresh_hdentry(dentry, inode->i_mode & S_IFMT); ++ if (err >= 0) ++ err = au_refresh_hinode(inode, dentry); ++ di_read_unlock(parent, AuLock_IR); ++ dput(parent); ++ } ++ di_downgrade_lock(dentry, AuLock_IR); ++ if (unlikely(err)) ++ di_read_unlock(dentry, AuLock_IR); ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++static void au_refresh_iattr(struct inode *inode, struct kstat *st, ++ unsigned int nlink) ++{ ++ inode->i_mode = st->mode; ++ inode->i_uid = st->uid; ++ inode->i_gid = st->gid; ++ inode->i_atime = st->atime; ++ inode->i_mtime = st->mtime; ++ inode->i_ctime = st->ctime; ++ ++ au_cpup_attr_nlink(inode, /*force*/0); ++ if (S_ISDIR(inode->i_mode)) { ++ inode->i_nlink -= nlink; ++ inode->i_nlink += st->nlink; ++ } ++ ++ spin_lock(&inode->i_lock); ++ inode->i_blocks = st->blocks; ++ i_size_write(inode, st->size); ++ spin_unlock(&inode->i_lock); ++} ++ ++static int aufs_getattr(struct vfsmount *mnt __maybe_unused, ++ struct dentry *dentry, struct kstat *st) ++{ ++ int err; ++ unsigned int mnt_flags; ++ aufs_bindex_t bindex; ++ unsigned char udba_none, positive; ++ struct super_block *sb, *h_sb; ++ struct inode *inode; ++ struct vfsmount *h_mnt; ++ struct dentry *h_dentry; ++ ++ err = 0; ++ sb = dentry->d_sb; ++ inode = dentry->d_inode; ++ si_read_lock(sb, AuLock_FLUSH); ++ mnt_flags = au_mntflags(sb); ++ udba_none = !!au_opt_test(mnt_flags, UDBA_NONE); ++ ++ /* support fstat(2) */ ++ if (!d_unhashed(dentry) && !udba_none) { ++ unsigned int sigen = au_sigen(sb); ++ if (au_digen(dentry) == sigen && au_iigen(inode) == sigen) ++ di_read_lock_child(dentry, AuLock_IR); ++ else { ++ AuDebugOn(IS_ROOT(dentry)); ++ err = au_getattr_lock_reval(dentry, sigen); ++ if (unlikely(err)) ++ goto out; ++ } ++ } else ++ di_read_lock_child(dentry, AuLock_IR); ++ ++ bindex = au_ibstart(inode); ++ h_mnt = au_sbr_mnt(sb, bindex); ++ h_sb = h_mnt->mnt_sb; ++ if (!au_test_fs_bad_iattr(h_sb) && udba_none) ++ goto out_fill; /* success */ ++ ++ h_dentry = NULL; ++ if (au_dbstart(dentry) == bindex) ++ h_dentry = dget(au_h_dptr(dentry, bindex)); ++ else if (au_opt_test(mnt_flags, PLINK) && au_plink_test(inode)) { ++ h_dentry = au_plink_lkup(inode, bindex); ++ if (IS_ERR(h_dentry)) ++ goto out_fill; /* pretending success */ ++ } ++ /* illegally overlapped or something */ ++ if (unlikely(!h_dentry)) ++ goto out_fill; /* pretending success */ ++ ++ positive = !!h_dentry->d_inode; ++ if (positive) ++ err = vfs_getattr(h_mnt, h_dentry, st); ++ dput(h_dentry); ++ if (!err) { ++ if (positive) ++ au_refresh_iattr(inode, st, h_dentry->d_inode->i_nlink); ++ goto out_fill; /* success */ ++ } ++ goto out_unlock; ++ ++ out_fill: ++ generic_fillattr(inode, st); ++ out_unlock: ++ di_read_unlock(dentry, AuLock_IR); ++ out: ++ si_read_unlock(sb); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int h_readlink(struct dentry *dentry, int bindex, char __user *buf, ++ int bufsiz) ++{ ++ int err; ++ struct super_block *sb; ++ struct dentry *h_dentry; ++ ++ err = -EINVAL; ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (unlikely(!h_dentry->d_inode->i_op->readlink)) ++ goto out; ++ ++ err = security_inode_readlink(h_dentry); ++ if (unlikely(err)) ++ goto out; ++ ++ sb = dentry->d_sb; ++ if (!au_test_ro(sb, bindex, dentry->d_inode)) { ++ vfsub_touch_atime(au_sbr_mnt(sb, bindex), h_dentry); ++ fsstack_copy_attr_atime(dentry->d_inode, h_dentry->d_inode); ++ } ++ err = h_dentry->d_inode->i_op->readlink(h_dentry, buf, bufsiz); ++ ++ out: ++ return err; ++} ++ ++static int aufs_readlink(struct dentry *dentry, char __user *buf, int bufsiz) ++{ ++ int err; ++ ++ aufs_read_lock(dentry, AuLock_IR); ++ err = h_readlink(dentry, au_dbstart(dentry), buf, bufsiz); ++ aufs_read_unlock(dentry, AuLock_IR); ++ ++ return err; ++} ++ ++static void *aufs_follow_link(struct dentry *dentry, struct nameidata *nd) ++{ ++ int err; ++ char *buf; ++ mm_segment_t old_fs; ++ ++ err = -ENOMEM; ++ buf = __getname(); ++ if (unlikely(!buf)) ++ goto out; ++ ++ aufs_read_lock(dentry, AuLock_IR); ++ old_fs = get_fs(); ++ set_fs(KERNEL_DS); ++ err = h_readlink(dentry, au_dbstart(dentry), (char __user *)buf, ++ PATH_MAX); ++ set_fs(old_fs); ++ aufs_read_unlock(dentry, AuLock_IR); ++ ++ if (err >= 0) { ++ buf[err] = 0; ++ /* will be freed by put_link */ ++ nd_set_link(nd, buf); ++ return NULL; /* success */ ++ } ++ __putname(buf); ++ ++ out: ++ path_put(&nd->path); ++ AuTraceErr(err); ++ return ERR_PTR(err); ++} ++ ++static void aufs_put_link(struct dentry *dentry __maybe_unused, ++ struct nameidata *nd, void *cookie __maybe_unused) ++{ ++ __putname(nd_get_link(nd)); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void aufs_truncate_range(struct inode *inode __maybe_unused, ++ loff_t start __maybe_unused, ++ loff_t end __maybe_unused) ++{ ++ AuUnsupport(); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct inode_operations aufs_symlink_iop = { ++ .permission = aufs_permission, ++ .setattr = aufs_setattr, ++ .getattr = aufs_getattr, ++ .readlink = aufs_readlink, ++ .follow_link = aufs_follow_link, ++ .put_link = aufs_put_link ++}; ++ ++struct inode_operations aufs_dir_iop = { ++ .create = aufs_create, ++ .lookup = aufs_lookup, ++ .link = aufs_link, ++ .unlink = aufs_unlink, ++ .symlink = aufs_symlink, ++ .mkdir = aufs_mkdir, ++ .rmdir = aufs_rmdir, ++ .mknod = aufs_mknod, ++ .rename = aufs_rename, ++ ++ .permission = aufs_permission, ++ .setattr = aufs_setattr, ++ .getattr = aufs_getattr ++}; ++ ++struct inode_operations aufs_iop = { ++ .permission = aufs_permission, ++ .setattr = aufs_setattr, ++ .getattr = aufs_getattr, ++ .truncate_range = aufs_truncate_range ++}; +diff --git a/fs/aufs/i_op_add.c b/fs/aufs/i_op_add.c +new file mode 100644 +index 0000000..015492f +--- /dev/null ++++ b/fs/aufs/i_op_add.c +@@ -0,0 +1,672 @@ ++/* ++ * Copyright (C) 2005-2010 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* ++ * inode operations (add entry) ++ */ ++ ++#include "aufs.h" ++ ++/* ++ * final procedure of adding a new entry, except link(2). ++ * remove whiteout, instantiate, copyup the parent dir's times and size ++ * and update version. ++ * if it failed, re-create the removed whiteout. ++ */ ++static int epilog(struct inode *dir, aufs_bindex_t bindex, ++ struct dentry *wh_dentry, struct dentry *dentry) ++{ ++ int err, rerr; ++ aufs_bindex_t bwh; ++ struct path h_path; ++ struct inode *inode, *h_dir; ++ struct dentry *wh; ++ ++ bwh = -1; ++ if (wh_dentry) { ++ h_dir = wh_dentry->d_parent->d_inode; /* dir inode is locked */ ++ IMustLock(h_dir); ++ AuDebugOn(au_h_iptr(dir, bindex) != h_dir); ++ bwh = au_dbwh(dentry); ++ h_path.dentry = wh_dentry; ++ h_path.mnt = au_sbr_mnt(dir->i_sb, bindex); ++ err = au_wh_unlink_dentry(au_h_iptr(dir, bindex), &h_path, ++ dentry); ++ if (unlikely(err)) ++ goto out; ++ } ++ ++ inode = au_new_inode(dentry, /*must_new*/1); ++ if (!IS_ERR(inode)) { ++ d_instantiate(dentry, inode); ++ dir = dentry->d_parent->d_inode; /* dir inode is locked */ ++ IMustLock(dir); ++ if (au_ibstart(dir) == au_dbstart(dentry)) ++ au_cpup_attr_timesizes(dir); ++ dir->i_version++; ++ return 0; /* success */ ++ } ++ ++ err = PTR_ERR(inode); ++ if (!wh_dentry) ++ goto out; ++ ++ /* revert */ ++ /* dir inode is locked */ ++ wh = au_wh_create(dentry, bwh, wh_dentry->d_parent); ++ rerr = PTR_ERR(wh); ++ if (IS_ERR(wh)) { ++ AuIOErr("%.*s reverting whiteout failed(%d, %d)\n", ++ AuDLNPair(dentry), err, rerr); ++ err = -EIO; ++ } else ++ dput(wh); ++ ++ out: ++ return err; ++} ++ ++/* ++ * simple tests for the adding inode operations. ++ * following the checks in vfs, plus the parent-child relationship. ++ */ ++int au_may_add(struct dentry *dentry, aufs_bindex_t bindex, ++ struct dentry *h_parent, int isdir) ++{ ++ int err; ++ umode_t h_mode; ++ struct dentry *h_dentry; ++ struct inode *h_inode; ++ ++ err = -ENAMETOOLONG; ++ if (unlikely(dentry->d_name.len > AUFS_MAX_NAMELEN)) ++ goto out; ++ ++ h_dentry = au_h_dptr(dentry, bindex); ++ h_inode = h_dentry->d_inode; ++ if (!dentry->d_inode) { ++ err = -EEXIST; ++ if (unlikely(h_inode)) ++ goto out; ++ } else { ++ /* rename(2) case */ ++ err = -EIO; ++ if (unlikely(!h_inode || !h_inode->i_nlink)) ++ goto out; ++ ++ h_mode = h_inode->i_mode; ++ if (!isdir) { ++ err = -EISDIR; ++ if (unlikely(S_ISDIR(h_mode))) ++ goto out; ++ } else if (unlikely(!S_ISDIR(h_mode))) { ++ err = -ENOTDIR; ++ goto out; ++ } ++ } ++ ++ err = 0; ++ /* expected parent dir is locked */ ++ if (unlikely(h_parent != h_dentry->d_parent)) ++ err = -EIO; ++ ++ out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ++ * initial procedure of adding a new entry. ++ * prepare writable branch and the parent dir, lock it, ++ * and lookup whiteout for the new entry. ++ */ ++static struct dentry* ++lock_hdir_lkup_wh(struct dentry *dentry, struct au_dtime *dt, ++ struct dentry *src_dentry, struct au_pin *pin, ++ struct au_wr_dir_args *wr_dir_args) ++{ ++ struct dentry *wh_dentry, *h_parent; ++ struct super_block *sb; ++ struct au_branch *br; ++ int err; ++ unsigned int udba; ++ aufs_bindex_t bcpup; ++ ++ AuDbg("%.*s\n", AuDLNPair(dentry)); ++ ++ err = au_wr_dir(dentry, src_dentry, wr_dir_args); ++ bcpup = err; ++ wh_dentry = ERR_PTR(err); ++ if (unlikely(err < 0)) ++ goto out; ++ ++ sb = dentry->d_sb; ++ udba = au_opt_udba(sb); ++ err = au_pin(pin, dentry, bcpup, udba, ++ AuPin_DI_LOCKED | AuPin_MNT_WRITE); ++ wh_dentry = ERR_PTR(err); ++ if (unlikely(err)) ++ goto out; ++ ++ h_parent = au_pinned_h_parent(pin); ++ if (udba != AuOpt_UDBA_NONE ++ && au_dbstart(dentry) == bcpup) ++ err = au_may_add(dentry, bcpup, h_parent, ++ au_ftest_wrdir(wr_dir_args->flags, ISDIR)); ++ else if (unlikely(dentry->d_name.len > AUFS_MAX_NAMELEN)) ++ err = -ENAMETOOLONG; ++ wh_dentry = ERR_PTR(err); ++ if (unlikely(err)) ++ goto out_unpin; ++ ++ br = au_sbr(sb, bcpup); ++ if (dt) { ++ struct path tmp = { ++ .dentry = h_parent, ++ .mnt = br->br_mnt ++ }; ++ au_dtime_store(dt, au_pinned_parent(pin), &tmp); ++ } ++ ++ wh_dentry = NULL; ++ if (bcpup != au_dbwh(dentry)) ++ goto out; /* success */ ++ ++ wh_dentry = au_wh_lkup(h_parent, &dentry->d_name, br); ++ ++ out_unpin: ++ if (IS_ERR(wh_dentry)) ++ au_unpin(pin); ++ out: ++ return wh_dentry; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++enum { Mknod, Symlink, Creat }; ++struct simple_arg { ++ int type; ++ union { ++ struct { ++ int mode; ++ struct nameidata *nd; ++ } c; ++ struct { ++ const char *symname; ++ } s; ++ struct { ++ int mode; ++ dev_t dev; ++ } m; ++ } u; ++}; ++ ++static int add_simple(struct inode *dir, struct dentry *dentry, ++ struct simple_arg *arg) ++{ ++ int err; ++ aufs_bindex_t bstart; ++ unsigned char created; ++ struct au_dtime dt; ++ struct au_pin pin; ++ struct path h_path; ++ struct dentry *wh_dentry, *parent; ++ struct inode *h_dir; ++ struct au_wr_dir_args wr_dir_args = { ++ .force_btgt = -1, ++ .flags = AuWrDir_ADD_ENTRY ++ }; ++ ++ AuDbg("%.*s\n", AuDLNPair(dentry)); ++ IMustLock(dir); ++ ++ parent = dentry->d_parent; /* dir inode is locked */ ++ aufs_read_lock(dentry, AuLock_DW); ++ di_write_lock_parent(parent); ++ wh_dentry = lock_hdir_lkup_wh(dentry, &dt, /*src_dentry*/NULL, &pin, ++ &wr_dir_args); ++ err = PTR_ERR(wh_dentry); ++ if (IS_ERR(wh_dentry)) ++ goto out; ++ ++ bstart = au_dbstart(dentry); ++ h_path.dentry = au_h_dptr(dentry, bstart); ++ h_path.mnt = au_sbr_mnt(dentry->d_sb, bstart); ++ h_dir = au_pinned_h_dir(&pin); ++ switch (arg->type) { ++ case Creat: ++ err = vfsub_create(h_dir, &h_path, arg->u.c.mode); ++ break; ++ case Symlink: ++ err = vfsub_symlink(h_dir, &h_path, arg->u.s.symname); ++ break; ++ case Mknod: ++ err = vfsub_mknod(h_dir, &h_path, arg->u.m.mode, arg->u.m.dev); ++ break; ++ default: ++ BUG(); ++ } ++ created = !err; ++ if (!err) ++ err = epilog(dir, bstart, wh_dentry, dentry); ++ ++ /* revert */ ++ if (unlikely(created && err && h_path.dentry->d_inode)) { ++ int rerr; ++ rerr = vfsub_unlink(h_dir, &h_path, /*force*/0); ++ if (rerr) { ++ AuIOErr("%.*s revert failure(%d, %d)\n", ++ AuDLNPair(dentry), err, rerr); ++ err = -EIO; ++ } ++ au_dtime_revert(&dt); ++ d_drop(dentry); ++ } ++ ++ au_unpin(&pin); ++ dput(wh_dentry); ++ ++ out: ++ if (unlikely(err)) { ++ au_update_dbstart(dentry); ++ d_drop(dentry); ++ } ++ di_write_unlock(parent); ++ aufs_read_unlock(dentry, AuLock_DW); ++ return err; ++} ++ ++int aufs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev) ++{ ++ struct simple_arg arg = { ++ .type = Mknod, ++ .u.m = { ++ .mode = mode, ++ .dev = dev ++ } ++ }; ++ return add_simple(dir, dentry, &arg); ++} ++ ++int aufs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) ++{ ++ struct simple_arg arg = { ++ .type = Symlink, ++ .u.s.symname = symname ++ }; ++ return add_simple(dir, dentry, &arg); ++} ++ ++int aufs_create(struct inode *dir, struct dentry *dentry, int mode, ++ struct nameidata *nd) ++{ ++ struct simple_arg arg = { ++ .type = Creat, ++ .u.c = { ++ .mode = mode, ++ .nd = nd ++ } ++ }; ++ return add_simple(dir, dentry, &arg); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct au_link_args { ++ aufs_bindex_t bdst, bsrc; ++ struct au_pin pin; ++ struct path h_path; ++ struct dentry *src_parent, *parent; ++}; ++ ++static int au_cpup_before_link(struct dentry *src_dentry, ++ struct au_link_args *a) ++{ ++ int err; ++ struct dentry *h_src_dentry; ++ struct mutex *h_mtx; ++ struct file *h_file; ++ ++ di_read_lock_parent(a->src_parent, AuLock_IR); ++ err = au_test_and_cpup_dirs(src_dentry, a->bdst); ++ if (unlikely(err)) ++ goto out; ++ ++ h_src_dentry = au_h_dptr(src_dentry, a->bsrc); ++ h_mtx = &h_src_dentry->d_inode->i_mutex; ++ err = au_pin(&a->pin, src_dentry, a->bdst, ++ au_opt_udba(src_dentry->d_sb), ++ AuPin_DI_LOCKED | AuPin_MNT_WRITE); ++ if (unlikely(err)) ++ goto out; ++ mutex_lock_nested(h_mtx, AuLsc_I_CHILD); ++ h_file = au_h_open_pre(src_dentry, a->bsrc); ++ if (IS_ERR(h_file)) { ++ err = PTR_ERR(h_file); ++ h_file = NULL; ++ } else ++ err = au_sio_cpup_simple(src_dentry, a->bdst, a->bsrc, ++ AuCpup_DTIME /* | AuCpup_KEEPLINO */); ++ mutex_unlock(h_mtx); ++ au_h_open_post(src_dentry, a->bsrc, h_file); ++ au_unpin(&a->pin); ++ ++ out: ++ di_read_unlock(a->src_parent, AuLock_IR); ++ return err; ++} ++ ++static int au_cpup_or_link(struct dentry *src_dentry, struct au_link_args *a) ++{ ++ int err; ++ unsigned char plink; ++ struct inode *h_inode, *inode; ++ struct dentry *h_src_dentry; ++ struct super_block *sb; ++ struct file *h_file; ++ ++ plink = 0; ++ h_inode = NULL; ++ sb = src_dentry->d_sb; ++ inode = src_dentry->d_inode; ++ if (au_ibstart(inode) <= a->bdst) ++ h_inode = au_h_iptr(inode, a->bdst); ++ if (!h_inode || !h_inode->i_nlink) { ++ /* copyup src_dentry as the name of dentry. */ ++ au_set_dbstart(src_dentry, a->bdst); ++ au_set_h_dptr(src_dentry, a->bdst, dget(a->h_path.dentry)); ++ h_inode = au_h_dptr(src_dentry, a->bsrc)->d_inode; ++ mutex_lock_nested(&h_inode->i_mutex, AuLsc_I_CHILD); ++ h_file = au_h_open_pre(src_dentry, a->bsrc); ++ if (IS_ERR(h_file)) { ++ err = PTR_ERR(h_file); ++ h_file = NULL; ++ } else ++ err = au_sio_cpup_single(src_dentry, a->bdst, a->bsrc, ++ -1, AuCpup_KEEPLINO, ++ a->parent); ++ mutex_unlock(&h_inode->i_mutex); ++ au_h_open_post(src_dentry, a->bsrc, h_file); ++ au_set_h_dptr(src_dentry, a->bdst, NULL); ++ au_set_dbstart(src_dentry, a->bsrc); ++ } else { ++ /* the inode of src_dentry already exists on a.bdst branch */ ++ h_src_dentry = d_find_alias(h_inode); ++ if (!h_src_dentry && au_plink_test(inode)) { ++ plink = 1; ++ h_src_dentry = au_plink_lkup(inode, a->bdst); ++ err = PTR_ERR(h_src_dentry); ++ if (IS_ERR(h_src_dentry)) ++ goto out; ++ ++ if (unlikely(!h_src_dentry->d_inode)) { ++ dput(h_src_dentry); ++ h_src_dentry = NULL; ++ } ++ ++ } ++ if (h_src_dentry) { ++ err = vfsub_link(h_src_dentry, au_pinned_h_dir(&a->pin), ++ &a->h_path); ++ dput(h_src_dentry); ++ } else { ++ AuIOErr("no dentry found for hi%lu on b%d\n", ++ h_inode->i_ino, a->bdst); ++ err = -EIO; ++ } ++ } ++ ++ if (!err && !plink) ++ au_plink_append(inode, a->bdst, a->h_path.dentry); ++ ++out: ++ return err; ++} ++ ++int aufs_link(struct dentry *src_dentry, struct inode *dir, ++ struct dentry *dentry) ++{ ++ int err, rerr; ++ struct au_dtime dt; ++ struct au_link_args *a; ++ struct dentry *wh_dentry, *h_src_dentry; ++ struct inode *inode; ++ struct super_block *sb; ++ struct au_wr_dir_args wr_dir_args = { ++ /* .force_btgt = -1, */ ++ .flags = AuWrDir_ADD_ENTRY ++ }; ++ ++ IMustLock(dir); ++ inode = src_dentry->d_inode; ++ IMustLock(inode); ++ ++ err = -ENOENT; ++ if (unlikely(!inode->i_nlink)) ++ goto out; ++ ++ err = -ENOMEM; ++ a = kzalloc(sizeof(*a), GFP_NOFS); ++ if (unlikely(!a)) ++ goto out; ++ ++ a->parent = dentry->d_parent; /* dir inode is locked */ ++ aufs_read_and_write_lock2(dentry, src_dentry, /*AuLock_FLUSH*/0); ++ a->src_parent = dget_parent(src_dentry); ++ wr_dir_args.force_btgt = au_dbstart(src_dentry); ++ ++ di_write_lock_parent(a->parent); ++ wr_dir_args.force_btgt = au_wbr(dentry, wr_dir_args.force_btgt); ++ wh_dentry = lock_hdir_lkup_wh(dentry, &dt, src_dentry, &a->pin, ++ &wr_dir_args); ++ err = PTR_ERR(wh_dentry); ++ if (IS_ERR(wh_dentry)) ++ goto out_unlock; ++ ++ err = 0; ++ sb = dentry->d_sb; ++ a->bdst = au_dbstart(dentry); ++ a->h_path.dentry = au_h_dptr(dentry, a->bdst); ++ a->h_path.mnt = au_sbr_mnt(sb, a->bdst); ++ a->bsrc = au_dbstart(src_dentry); ++ if (au_opt_test(au_mntflags(sb), PLINK)) { ++ if (a->bdst < a->bsrc ++ /* && h_src_dentry->d_sb != a->h_path.dentry->d_sb */) ++ err = au_cpup_or_link(src_dentry, a); ++ else { ++ h_src_dentry = au_h_dptr(src_dentry, a->bdst); ++ err = vfsub_link(h_src_dentry, au_pinned_h_dir(&a->pin), ++ &a->h_path); ++ } ++ } else { ++ /* ++ * copyup src_dentry to the branch we process, ++ * and then link(2) to it. ++ */ ++ if (a->bdst < a->bsrc ++ /* && h_src_dentry->d_sb != a->h_path.dentry->d_sb */) { ++ au_unpin(&a->pin); ++ di_write_unlock(a->parent); ++ err = au_cpup_before_link(src_dentry, a); ++ di_write_lock_parent(a->parent); ++ if (!err) ++ err = au_pin(&a->pin, dentry, a->bdst, ++ au_opt_udba(sb), ++ AuPin_DI_LOCKED | AuPin_MNT_WRITE); ++ if (unlikely(err)) ++ goto out_wh; ++ } ++ if (!err) { ++ h_src_dentry = au_h_dptr(src_dentry, a->bdst); ++ err = -ENOENT; ++ if (h_src_dentry && h_src_dentry->d_inode) ++ err = vfsub_link(h_src_dentry, ++ au_pinned_h_dir(&a->pin), ++ &a->h_path); ++ } ++ } ++ if (unlikely(err)) ++ goto out_unpin; ++ ++ if (wh_dentry) { ++ a->h_path.dentry = wh_dentry; ++ err = au_wh_unlink_dentry(au_pinned_h_dir(&a->pin), &a->h_path, ++ dentry); ++ if (unlikely(err)) ++ goto out_revert; ++ } ++ ++ dir->i_version++; ++ if (au_ibstart(dir) == au_dbstart(dentry)) ++ au_cpup_attr_timesizes(dir); ++ inc_nlink(inode); ++ inode->i_ctime = dir->i_ctime; ++ if (!d_unhashed(a->h_path.dentry)) ++ d_instantiate(dentry, au_igrab(inode)); ++ else ++ /* some filesystem calls d_drop() */ ++ d_drop(dentry); ++ goto out_unpin; /* success */ ++ ++ out_revert: ++ rerr = vfsub_unlink(au_pinned_h_dir(&a->pin), &a->h_path, /*force*/0); ++ if (!rerr) ++ goto out_dt; ++ AuIOErr("%.*s reverting failed(%d, %d)\n", ++ AuDLNPair(dentry), err, rerr); ++ err = -EIO; ++ out_dt: ++ d_drop(dentry); ++ au_dtime_revert(&dt); ++ out_unpin: ++ au_unpin(&a->pin); ++ out_wh: ++ dput(wh_dentry); ++ out_unlock: ++ if (unlikely(err)) { ++ au_update_dbstart(dentry); ++ d_drop(dentry); ++ } ++ di_write_unlock(a->parent); ++ dput(a->src_parent); ++ aufs_read_and_write_unlock2(dentry, src_dentry); ++ kfree(a); ++ out: ++ return err; ++} ++ ++int aufs_mkdir(struct inode *dir, struct dentry *dentry, int mode) ++{ ++ int err, rerr; ++ aufs_bindex_t bindex; ++ unsigned char diropq; ++ struct path h_path; ++ struct dentry *wh_dentry, *parent, *opq_dentry; ++ struct mutex *h_mtx; ++ struct super_block *sb; ++ struct { ++ struct au_pin pin; ++ struct au_dtime dt; ++ } *a; /* reduce the stack usage */ ++ struct au_wr_dir_args wr_dir_args = { ++ .force_btgt = -1, ++ .flags = AuWrDir_ADD_ENTRY | AuWrDir_ISDIR ++ }; ++ ++ IMustLock(dir); ++ ++ err = -ENOMEM; ++ a = kmalloc(sizeof(*a), GFP_NOFS); ++ if (unlikely(!a)) ++ goto out; ++ ++ aufs_read_lock(dentry, AuLock_DW); ++ parent = dentry->d_parent; /* dir inode is locked */ ++ di_write_lock_parent(parent); ++ wh_dentry = lock_hdir_lkup_wh(dentry, &a->dt, /*src_dentry*/NULL, ++ &a->pin, &wr_dir_args); ++ err = PTR_ERR(wh_dentry); ++ if (IS_ERR(wh_dentry)) ++ goto out_free; ++ ++ sb = dentry->d_sb; ++ bindex = au_dbstart(dentry); ++ h_path.dentry = au_h_dptr(dentry, bindex); ++ h_path.mnt = au_sbr_mnt(sb, bindex); ++ err = vfsub_mkdir(au_pinned_h_dir(&a->pin), &h_path, mode); ++ if (unlikely(err)) ++ goto out_unlock; ++ ++ /* make the dir opaque */ ++ diropq = 0; ++ h_mtx = &h_path.dentry->d_inode->i_mutex; ++ if (wh_dentry ++ || au_opt_test(au_mntflags(sb), ALWAYS_DIROPQ)) { ++ mutex_lock_nested(h_mtx, AuLsc_I_CHILD); ++ opq_dentry = au_diropq_create(dentry, bindex); ++ mutex_unlock(h_mtx); ++ err = PTR_ERR(opq_dentry); ++ if (IS_ERR(opq_dentry)) ++ goto out_dir; ++ dput(opq_dentry); ++ diropq = 1; ++ } ++ ++ err = epilog(dir, bindex, wh_dentry, dentry); ++ if (!err) { ++ inc_nlink(dir); ++ goto out_unlock; /* success */ ++ } ++ ++ /* revert */ ++ if (diropq) { ++ AuLabel(revert opq); ++ mutex_lock_nested(h_mtx, AuLsc_I_CHILD); ++ rerr = au_diropq_remove(dentry, bindex); ++ mutex_unlock(h_mtx); ++ if (rerr) { ++ AuIOErr("%.*s reverting diropq failed(%d, %d)\n", ++ AuDLNPair(dentry), err, rerr); ++ err = -EIO; ++ } ++ } ++ ++ out_dir: ++ AuLabel(revert dir); ++ rerr = vfsub_rmdir(au_pinned_h_dir(&a->pin), &h_path); ++ if (rerr) { ++ AuIOErr("%.*s reverting dir failed(%d, %d)\n", ++ AuDLNPair(dentry), err, rerr); ++ err = -EIO; ++ } ++ d_drop(dentry); ++ au_dtime_revert(&a->dt); ++ out_unlock: ++ au_unpin(&a->pin); ++ dput(wh_dentry); ++ out_free: ++ if (unlikely(err)) { ++ au_update_dbstart(dentry); ++ d_drop(dentry); ++ } ++ di_write_unlock(parent); ++ aufs_read_unlock(dentry, AuLock_DW); ++ kfree(a); ++ out: ++ return err; ++} +diff --git a/fs/aufs/i_op_del.c b/fs/aufs/i_op_del.c +new file mode 100644 +index 0000000..684aec1 +--- /dev/null ++++ b/fs/aufs/i_op_del.c +@@ -0,0 +1,472 @@ ++/* ++ * Copyright (C) 2005-2010 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* ++ * inode operations (del entry) ++ */ ++ ++#include "aufs.h" ++ ++/* ++ * decide if a new whiteout for @dentry is necessary or not. ++ * when it is necessary, prepare the parent dir for the upper branch whose ++ * branch index is @bcpup for creation. the actual creation of the whiteout will ++ * be done by caller. ++ * return value: ++ * 0: wh is unnecessary ++ * plus: wh is necessary ++ * minus: error ++ */ ++int au_wr_dir_need_wh(struct dentry *dentry, int isdir, aufs_bindex_t *bcpup) ++{ ++ int need_wh, err; ++ aufs_bindex_t bstart; ++ struct super_block *sb; ++ ++ sb = dentry->d_sb; ++ bstart = au_dbstart(dentry); ++ if (*bcpup < 0) { ++ *bcpup = bstart; ++ if (au_test_ro(sb, bstart, dentry->d_inode)) { ++ err = AuWbrCopyup(au_sbi(sb), dentry); ++ *bcpup = err; ++ if (unlikely(err < 0)) ++ goto out; ++ } ++ } else ++ AuDebugOn(bstart < *bcpup ++ || au_test_ro(sb, *bcpup, dentry->d_inode)); ++ AuDbg("bcpup %d, bstart %d\n", *bcpup, bstart); ++ ++ if (*bcpup != bstart) { ++ err = au_cpup_dirs(dentry, *bcpup); ++ if (unlikely(err)) ++ goto out; ++ need_wh = 1; ++ } else { ++ aufs_bindex_t old_bend, new_bend, bdiropq = -1; ++ ++ old_bend = au_dbend(dentry); ++ if (isdir) { ++ bdiropq = au_dbdiropq(dentry); ++ au_set_dbdiropq(dentry, -1); ++ } ++ need_wh = au_lkup_dentry(dentry, bstart + 1, /*type*/0, ++ /*nd*/NULL); ++ err = need_wh; ++ if (isdir) ++ au_set_dbdiropq(dentry, bdiropq); ++ if (unlikely(err < 0)) ++ goto out; ++ new_bend = au_dbend(dentry); ++ if (!need_wh && old_bend != new_bend) { ++ au_set_h_dptr(dentry, new_bend, NULL); ++ au_set_dbend(dentry, old_bend); ++ } ++ } ++ AuDbg("need_wh %d\n", need_wh); ++ err = need_wh; ++ ++ out: ++ return err; ++} ++ ++/* ++ * simple tests for the del-entry operations. ++ * following the checks in vfs, plus the parent-child relationship. ++ */ ++int au_may_del(struct dentry *dentry, aufs_bindex_t bindex, ++ struct dentry *h_parent, int isdir) ++{ ++ int err; ++ umode_t h_mode; ++ struct dentry *h_dentry, *h_latest; ++ struct inode *h_inode; ++ ++ h_dentry = au_h_dptr(dentry, bindex); ++ h_inode = h_dentry->d_inode; ++ if (dentry->d_inode) { ++ err = -ENOENT; ++ if (unlikely(!h_inode || !h_inode->i_nlink)) ++ goto out; ++ ++ h_mode = h_inode->i_mode; ++ if (!isdir) { ++ err = -EISDIR; ++ if (unlikely(S_ISDIR(h_mode))) ++ goto out; ++ } else if (unlikely(!S_ISDIR(h_mode))) { ++ err = -ENOTDIR; ++ goto out; ++ } ++ } else { ++ /* rename(2) case */ ++ err = -EIO; ++ if (unlikely(h_inode)) ++ goto out; ++ } ++ ++ err = -ENOENT; ++ /* expected parent dir is locked */ ++ if (unlikely(h_parent != h_dentry->d_parent)) ++ goto out; ++ err = 0; ++ ++ /* ++ * rmdir a dir may break the consistency on some filesystem. ++ * let's try heavy test. ++ */ ++ err = -EACCES; ++ if (unlikely(au_test_h_perm(h_parent->d_inode, MAY_EXEC | MAY_WRITE))) ++ goto out; ++ ++ h_latest = au_sio_lkup_one(&dentry->d_name, h_parent, ++ au_sbr(dentry->d_sb, bindex)); ++ err = -EIO; ++ if (IS_ERR(h_latest)) ++ goto out; ++ if (h_latest == h_dentry) ++ err = 0; ++ dput(h_latest); ++ ++ out: ++ return err; ++} ++ ++/* ++ * decide the branch where we operate for @dentry. the branch index will be set ++ * @rbcpup. after diciding it, 'pin' it and store the timestamps of the parent ++ * dir for reverting. ++ * when a new whiteout is necessary, create it. ++ */ ++static struct dentry* ++lock_hdir_create_wh(struct dentry *dentry, int isdir, aufs_bindex_t *rbcpup, ++ struct au_dtime *dt, struct au_pin *pin) ++{ ++ struct dentry *wh_dentry; ++ struct super_block *sb; ++ struct path h_path; ++ int err, need_wh; ++ unsigned int udba; ++ aufs_bindex_t bcpup; ++ ++ need_wh = au_wr_dir_need_wh(dentry, isdir, rbcpup); ++ wh_dentry = ERR_PTR(need_wh); ++ if (unlikely(need_wh < 0)) ++ goto out; ++ ++ sb = dentry->d_sb; ++ udba = au_opt_udba(sb); ++ bcpup = *rbcpup; ++ err = au_pin(pin, dentry, bcpup, udba, ++ AuPin_DI_LOCKED | AuPin_MNT_WRITE); ++ wh_dentry = ERR_PTR(err); ++ if (unlikely(err)) ++ goto out; ++ ++ h_path.dentry = au_pinned_h_parent(pin); ++ if (udba != AuOpt_UDBA_NONE ++ && au_dbstart(dentry) == bcpup) { ++ err = au_may_del(dentry, bcpup, h_path.dentry, isdir); ++ wh_dentry = ERR_PTR(err); ++ if (unlikely(err)) ++ goto out_unpin; ++ } ++ ++ h_path.mnt = au_sbr_mnt(sb, bcpup); ++ au_dtime_store(dt, au_pinned_parent(pin), &h_path); ++ wh_dentry = NULL; ++ if (!need_wh) ++ goto out; /* success, no need to create whiteout */ ++ ++ wh_dentry = au_wh_create(dentry, bcpup, h_path.dentry); ++ if (IS_ERR(wh_dentry)) ++ goto out_unpin; ++ ++ /* returns with the parent is locked and wh_dentry is dget-ed */ ++ goto out; /* success */ ++ ++ out_unpin: ++ au_unpin(pin); ++ out: ++ return wh_dentry; ++} ++ ++/* ++ * when removing a dir, rename it to a unique temporary whiteout-ed name first ++ * in order to be revertible and save time for removing many child whiteouts ++ * under the dir. ++ * returns 1 when there are too many child whiteout and caller should remove ++ * them asynchronously. returns 0 when the number of children is enough small to ++ * remove now or the branch fs is a remote fs. ++ * otherwise return an error. ++ */ ++static int renwh_and_rmdir(struct dentry *dentry, aufs_bindex_t bindex, ++ struct au_nhash *whlist, struct inode *dir) ++{ ++ int rmdir_later, err, dirwh; ++ struct dentry *h_dentry; ++ struct super_block *sb; ++ ++ sb = dentry->d_sb; ++ SiMustAnyLock(sb); ++ h_dentry = au_h_dptr(dentry, bindex); ++ err = au_whtmp_ren(h_dentry, au_sbr(sb, bindex)); ++ if (unlikely(err)) ++ goto out; ++ ++ /* stop monitoring */ ++ au_hin_free(au_hi(dentry->d_inode, bindex)); ++ ++ if (!au_test_fs_remote(h_dentry->d_sb)) { ++ dirwh = au_sbi(sb)->si_dirwh; ++ rmdir_later = (dirwh <= 1); ++ if (!rmdir_later) ++ rmdir_later = au_nhash_test_longer_wh(whlist, bindex, ++ dirwh); ++ if (rmdir_later) ++ return rmdir_later; ++ } ++ ++ err = au_whtmp_rmdir(dir, bindex, h_dentry, whlist); ++ if (unlikely(err)) { ++ AuIOErr("rmdir %.*s, b%d failed, %d. ignored\n", ++ AuDLNPair(h_dentry), bindex, err); ++ err = 0; ++ } ++ ++ out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ++ * final procedure for deleting a entry. ++ * maintain dentry and iattr. ++ */ ++static void epilog(struct inode *dir, struct dentry *dentry, ++ aufs_bindex_t bindex) ++{ ++ struct inode *inode; ++ ++ inode = dentry->d_inode; ++ d_drop(dentry); ++ inode->i_ctime = dir->i_ctime; ++ ++ if (atomic_read(&dentry->d_count) == 1) { ++ au_set_h_dptr(dentry, au_dbstart(dentry), NULL); ++ au_update_dbstart(dentry); ++ } ++ if (au_ibstart(dir) == bindex) ++ au_cpup_attr_timesizes(dir); ++ dir->i_version++; ++} ++ ++/* ++ * when an error happened, remove the created whiteout and revert everything. ++ */ ++static int do_revert(int err, struct inode *dir, aufs_bindex_t bwh, ++ struct dentry *wh_dentry, struct dentry *dentry, ++ struct au_dtime *dt) ++{ ++ int rerr; ++ struct path h_path = { ++ .dentry = wh_dentry, ++ .mnt = au_sbr_mnt(dir->i_sb, bwh) ++ }; ++ ++ rerr = au_wh_unlink_dentry(au_h_iptr(dir, bwh), &h_path, dentry); ++ if (!rerr) { ++ au_set_dbwh(dentry, bwh); ++ au_dtime_revert(dt); ++ return 0; ++ } ++ ++ AuIOErr("%.*s reverting whiteout failed(%d, %d)\n", ++ AuDLNPair(dentry), err, rerr); ++ return -EIO; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int aufs_unlink(struct inode *dir, struct dentry *dentry) ++{ ++ int err; ++ aufs_bindex_t bwh, bindex, bstart; ++ struct au_dtime dt; ++ struct au_pin pin; ++ struct path h_path; ++ struct inode *inode, *h_dir; ++ struct dentry *parent, *wh_dentry; ++ ++ IMustLock(dir); ++ inode = dentry->d_inode; ++ if (unlikely(!inode)) ++ return -ENOENT; /* possible? */ ++ IMustLock(inode); ++ ++ aufs_read_lock(dentry, AuLock_DW); ++ parent = dentry->d_parent; /* dir inode is locked */ ++ di_write_lock_parent(parent); ++ ++ bstart = au_dbstart(dentry); ++ bwh = au_dbwh(dentry); ++ bindex = -1; ++ wh_dentry = lock_hdir_create_wh(dentry, /*isdir*/0, &bindex, &dt, &pin); ++ err = PTR_ERR(wh_dentry); ++ if (IS_ERR(wh_dentry)) ++ goto out; ++ ++ h_path.mnt = au_sbr_mnt(dentry->d_sb, bstart); ++ h_path.dentry = au_h_dptr(dentry, bstart); ++ dget(h_path.dentry); ++ if (bindex == bstart) { ++ h_dir = au_pinned_h_dir(&pin); ++ err = vfsub_unlink(h_dir, &h_path, /*force*/0); ++ } else { ++ /* dir inode is locked */ ++ h_dir = wh_dentry->d_parent->d_inode; ++ IMustLock(h_dir); ++ err = 0; ++ } ++ ++ if (!err) { ++ drop_nlink(inode); ++ epilog(dir, dentry, bindex); ++ ++ /* update target timestamps */ ++ if (bindex == bstart) { ++ vfsub_update_h_iattr(&h_path, /*did*/NULL); /*ignore*/ ++ inode->i_ctime = h_path.dentry->d_inode->i_ctime; ++ } else ++ /* todo: this timestamp may be reverted later */ ++ inode->i_ctime = h_dir->i_ctime; ++ goto out_unlock; /* success */ ++ } ++ ++ /* revert */ ++ if (wh_dentry) { ++ int rerr; ++ ++ rerr = do_revert(err, dir, bwh, wh_dentry, dentry, &dt); ++ if (rerr) ++ err = rerr; ++ } ++ ++ out_unlock: ++ au_unpin(&pin); ++ dput(wh_dentry); ++ dput(h_path.dentry); ++ out: ++ di_write_unlock(parent); ++ aufs_read_unlock(dentry, AuLock_DW); ++ return err; ++} ++ ++int aufs_rmdir(struct inode *dir, struct dentry *dentry) ++{ ++ int err, rmdir_later; ++ aufs_bindex_t bwh, bindex, bstart; ++ struct au_dtime dt; ++ struct au_pin pin; ++ struct inode *inode; ++ struct dentry *parent, *wh_dentry, *h_dentry; ++ struct au_whtmp_rmdir *args; ++ ++ IMustLock(dir); ++ inode = dentry->d_inode; ++ err = -ENOENT; /* possible? */ ++ if (unlikely(!inode)) ++ goto out; ++ IMustLock(inode); ++ ++ aufs_read_lock(dentry, AuLock_DW | AuLock_FLUSH); ++ err = -ENOMEM; ++ args = au_whtmp_rmdir_alloc(dir->i_sb, GFP_NOFS); ++ if (unlikely(!args)) ++ goto out_unlock; ++ ++ parent = dentry->d_parent; /* dir inode is locked */ ++ di_write_lock_parent(parent); ++ err = au_test_empty(dentry, &args->whlist); ++ if (unlikely(err)) ++ goto out_args; ++ ++ bstart = au_dbstart(dentry); ++ bwh = au_dbwh(dentry); ++ bindex = -1; ++ wh_dentry = lock_hdir_create_wh(dentry, /*isdir*/1, &bindex, &dt, &pin); ++ err = PTR_ERR(wh_dentry); ++ if (IS_ERR(wh_dentry)) ++ goto out_args; ++ ++ h_dentry = au_h_dptr(dentry, bstart); ++ dget(h_dentry); ++ rmdir_later = 0; ++ if (bindex == bstart) { ++ err = renwh_and_rmdir(dentry, bstart, &args->whlist, dir); ++ if (err > 0) { ++ rmdir_later = err; ++ err = 0; ++ } ++ } else { ++ /* stop monitoring */ ++ au_hin_free(au_hi(inode, bstart)); ++ ++ /* dir inode is locked */ ++ IMustLock(wh_dentry->d_parent->d_inode); ++ err = 0; ++ } ++ ++ if (!err) { ++ clear_nlink(inode); ++ au_set_dbdiropq(dentry, -1); ++ epilog(dir, dentry, bindex); ++ ++ if (rmdir_later) { ++ au_whtmp_kick_rmdir(dir, bstart, h_dentry, args); ++ args = NULL; ++ } ++ ++ goto out_unpin; /* success */ ++ } ++ ++ /* revert */ ++ AuLabel(revert); ++ if (wh_dentry) { ++ int rerr; ++ ++ rerr = do_revert(err, dir, bwh, wh_dentry, dentry, &dt); ++ if (rerr) ++ err = rerr; ++ } ++ ++ out_unpin: ++ au_unpin(&pin); ++ dput(wh_dentry); ++ dput(h_dentry); ++ out_args: ++ di_write_unlock(parent); ++ if (args) ++ au_whtmp_rmdir_free(args); ++ out_unlock: ++ aufs_read_unlock(dentry, AuLock_DW); ++ out: ++ AuTraceErr(err); ++ return err; ++} +diff --git a/fs/aufs/i_op_ren.c b/fs/aufs/i_op_ren.c +new file mode 100644 +index 0000000..9bf0e50 +--- /dev/null ++++ b/fs/aufs/i_op_ren.c +@@ -0,0 +1,978 @@ ++/* ++ * Copyright (C) 2005-2010 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* ++ * inode operation (rename entry) ++ * todo: this is crazy monster ++ */ ++ ++#include "aufs.h" ++ ++enum { AuSRC, AuDST, AuSrcDst }; ++enum { AuPARENT, AuCHILD, AuParentChild }; ++ ++#define AuRen_ISDIR 1 ++#define AuRen_ISSAMEDIR (1 << 1) ++#define AuRen_WHSRC (1 << 2) ++#define AuRen_WHDST (1 << 3) ++#define AuRen_MNT_WRITE (1 << 4) ++#define AuRen_DT_DSTDIR (1 << 5) ++#define AuRen_DIROPQ (1 << 6) ++#define AuRen_CPUP (1 << 7) ++#define au_ftest_ren(flags, name) ((flags) & AuRen_##name) ++#define au_fset_ren(flags, name) { (flags) |= AuRen_##name; } ++#define au_fclr_ren(flags, name) { (flags) &= ~AuRen_##name; } ++ ++struct au_ren_args { ++ struct { ++ struct dentry *dentry, *h_dentry, *parent, *h_parent, ++ *wh_dentry; ++ struct inode *dir, *inode; ++ struct au_hinode *hdir; ++ struct au_dtime dt[AuParentChild]; ++ aufs_bindex_t bstart; ++ } sd[AuSrcDst]; ++ ++#define src_dentry sd[AuSRC].dentry ++#define src_dir sd[AuSRC].dir ++#define src_inode sd[AuSRC].inode ++#define src_h_dentry sd[AuSRC].h_dentry ++#define src_parent sd[AuSRC].parent ++#define src_h_parent sd[AuSRC].h_parent ++#define src_wh_dentry sd[AuSRC].wh_dentry ++#define src_hdir sd[AuSRC].hdir ++#define src_h_dir sd[AuSRC].hdir->hi_inode ++#define src_dt sd[AuSRC].dt ++#define src_bstart sd[AuSRC].bstart ++ ++#define dst_dentry sd[AuDST].dentry ++#define dst_dir sd[AuDST].dir ++#define dst_inode sd[AuDST].inode ++#define dst_h_dentry sd[AuDST].h_dentry ++#define dst_parent sd[AuDST].parent ++#define dst_h_parent sd[AuDST].h_parent ++#define dst_wh_dentry sd[AuDST].wh_dentry ++#define dst_hdir sd[AuDST].hdir ++#define dst_h_dir sd[AuDST].hdir->hi_inode ++#define dst_dt sd[AuDST].dt ++#define dst_bstart sd[AuDST].bstart ++ ++ struct dentry *h_trap; ++ struct au_branch *br; ++ struct au_hinode *src_hinode; ++ struct path h_path; ++ struct au_nhash whlist; ++ aufs_bindex_t btgt; ++ ++ unsigned int flags; ++ ++ struct au_whtmp_rmdir *thargs; ++ struct dentry *h_dst; ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * functions for reverting. ++ * when an error happened in a single rename systemcall, we should revert ++ * everything as if nothing happend. ++ * we don't need to revert the copied-up/down the parent dir since they are ++ * harmless. ++ */ ++ ++#define RevertFailure(fmt, ...) do { \ ++ AuIOErr("revert failure: " fmt " (%d, %d)\n", \ ++ ##__VA_ARGS__, err, rerr); \ ++ err = -EIO; \ ++} while (0) ++ ++static void au_ren_rev_diropq(int err, struct au_ren_args *a) ++{ ++ int rerr; ++ ++ au_hin_imtx_lock_nested(a->src_hinode, AuLsc_I_CHILD); ++ rerr = au_diropq_remove(a->src_dentry, a->btgt); ++ au_hin_imtx_unlock(a->src_hinode); ++ if (rerr) ++ RevertFailure("remove diropq %.*s", AuDLNPair(a->src_dentry)); ++} ++ ++static void au_ren_rev_rename(int err, struct au_ren_args *a) ++{ ++ int rerr; ++ ++ a->h_path.dentry = au_lkup_one(&a->src_dentry->d_name, a->src_h_parent, ++ a->br, /*nd*/NULL); ++ rerr = PTR_ERR(a->h_path.dentry); ++ if (IS_ERR(a->h_path.dentry)) { ++ RevertFailure("au_lkup_one %.*s", AuDLNPair(a->src_dentry)); ++ return; ++ } ++ ++ rerr = vfsub_rename(a->dst_h_dir, ++ au_h_dptr(a->src_dentry, a->btgt), ++ a->src_h_dir, &a->h_path); ++ d_drop(a->h_path.dentry); ++ dput(a->h_path.dentry); ++ /* au_set_h_dptr(a->src_dentry, a->btgt, NULL); */ ++ if (rerr) ++ RevertFailure("rename %.*s", AuDLNPair(a->src_dentry)); ++} ++ ++static void au_ren_rev_cpup(int err, struct au_ren_args *a) ++{ ++ int rerr; ++ ++ a->h_path.dentry = a->dst_h_dentry; ++ rerr = vfsub_unlink(a->dst_h_dir, &a->h_path, /*force*/0); ++ au_set_h_dptr(a->src_dentry, a->btgt, NULL); ++ au_set_dbstart(a->src_dentry, a->src_bstart); ++ if (rerr) ++ RevertFailure("unlink %.*s", AuDLNPair(a->dst_h_dentry)); ++} ++ ++static void au_ren_rev_whtmp(int err, struct au_ren_args *a) ++{ ++ int rerr; ++ ++ a->h_path.dentry = au_lkup_one(&a->dst_dentry->d_name, a->dst_h_parent, ++ a->br, /*nd*/NULL); ++ rerr = PTR_ERR(a->h_path.dentry); ++ if (IS_ERR(a->h_path.dentry)) { ++ RevertFailure("lookup %.*s", AuDLNPair(a->dst_dentry)); ++ return; ++ } ++ if (a->h_path.dentry->d_inode) { ++ d_drop(a->h_path.dentry); ++ dput(a->h_path.dentry); ++ return; ++ } ++ ++ rerr = vfsub_rename(a->dst_h_dir, a->h_dst, a->dst_h_dir, &a->h_path); ++ d_drop(a->h_path.dentry); ++ dput(a->h_path.dentry); ++ if (!rerr) { ++ au_set_h_dptr(a->dst_dentry, a->btgt, NULL); ++ au_set_h_dptr(a->dst_dentry, a->btgt, dget(a->h_dst)); ++ } else ++ RevertFailure("rename %.*s", AuDLNPair(a->h_dst)); ++} ++ ++static void au_ren_rev_whsrc(int err, struct au_ren_args *a) ++{ ++ int rerr; ++ ++ a->h_path.dentry = a->src_wh_dentry; ++ rerr = au_wh_unlink_dentry(a->src_h_dir, &a->h_path, a->src_dentry); ++ if (rerr) ++ RevertFailure("unlink %.*s", AuDLNPair(a->src_wh_dentry)); ++} ++ ++static void au_ren_rev_drop(struct au_ren_args *a) ++{ ++ struct dentry *d, *h_d; ++ int i; ++ aufs_bindex_t bend, bindex; ++ ++ for (i = 0; i < AuSrcDst; i++) { ++ d = a->sd[i].dentry; ++ d_drop(d); ++ bend = au_dbend(d); ++ for (bindex = au_dbstart(d); bindex <= bend; bindex++) { ++ h_d = au_h_dptr(d, bindex); ++ if (h_d) ++ d_drop(h_d); ++ } ++ } ++ ++ au_update_dbstart(a->dst_dentry); ++ if (a->thargs) ++ d_drop(a->h_dst); ++} ++#undef RevertFailure ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * when we have to copyup the renaming entry, do it with the rename-target name ++ * in order to minimize the cost (the later actual rename is unnecessary). ++ * otherwise rename it on the target branch. ++ */ ++static int au_ren_or_cpup(struct au_ren_args *a) ++{ ++ int err; ++ struct dentry *d; ++ ++ d = a->src_dentry; ++ if (au_dbstart(d) == a->btgt) { ++ a->h_path.dentry = a->dst_h_dentry; ++ if (au_ftest_ren(a->flags, DIROPQ) ++ && au_dbdiropq(d) == a->btgt) ++ au_fclr_ren(a->flags, DIROPQ); ++ AuDebugOn(au_dbstart(d) != a->btgt); ++ err = vfsub_rename(a->src_h_dir, au_h_dptr(d, a->btgt), ++ a->dst_h_dir, &a->h_path); ++ } else { ++ struct mutex *h_mtx = &a->src_h_dentry->d_inode->i_mutex; ++ struct file *h_file; ++ ++ au_fset_ren(a->flags, CPUP); ++ mutex_lock_nested(h_mtx, AuLsc_I_CHILD); ++ au_set_dbstart(d, a->btgt); ++ au_set_h_dptr(d, a->btgt, dget(a->dst_h_dentry)); ++ h_file = au_h_open_pre(d, a->src_bstart); ++ if (IS_ERR(h_file)) { ++ err = PTR_ERR(h_file); ++ h_file = NULL; ++ } else ++ err = au_sio_cpup_single(d, a->btgt, a->src_bstart, -1, ++ !AuCpup_DTIME, a->dst_parent); ++ mutex_unlock(h_mtx); ++ au_h_open_post(d, a->src_bstart, h_file); ++ if (!err) { ++ d = a->dst_dentry; ++ au_set_h_dptr(d, a->btgt, NULL); ++ au_update_dbstart(d); ++ } else { ++ au_set_h_dptr(d, a->btgt, NULL); ++ au_set_dbstart(d, a->src_bstart); ++ } ++ } ++ ++ return err; ++} ++ ++/* cf. aufs_rmdir() */ ++static int au_ren_del_whtmp(struct au_ren_args *a) ++{ ++ int err; ++ struct inode *dir; ++ ++ dir = a->dst_dir; ++ SiMustAnyLock(dir->i_sb); ++ if (!au_nhash_test_longer_wh(&a->whlist, a->btgt, ++ au_sbi(dir->i_sb)->si_dirwh) ++ || au_test_fs_remote(a->h_dst->d_sb)) { ++ err = au_whtmp_rmdir(dir, a->btgt, a->h_dst, &a->whlist); ++ if (unlikely(err)) ++ pr_warning("failed removing whtmp dir %.*s (%d), " ++ "ignored.\n", AuDLNPair(a->h_dst), err); ++ } else { ++ au_nhash_wh_free(&a->thargs->whlist); ++ a->thargs->whlist = a->whlist; ++ a->whlist.nh_num = 0; ++ au_whtmp_kick_rmdir(dir, a->btgt, a->h_dst, a->thargs); ++ dput(a->h_dst); ++ a->thargs = NULL; ++ } ++ ++ return 0; ++} ++ ++/* make it 'opaque' dir. */ ++static int au_ren_diropq(struct au_ren_args *a) ++{ ++ int err; ++ struct dentry *diropq; ++ ++ err = 0; ++ a->src_hinode = au_hi(a->src_inode, a->btgt); ++ au_hin_imtx_lock_nested(a->src_hinode, AuLsc_I_CHILD); ++ diropq = au_diropq_create(a->src_dentry, a->btgt); ++ au_hin_imtx_unlock(a->src_hinode); ++ if (IS_ERR(diropq)) ++ err = PTR_ERR(diropq); ++ dput(diropq); ++ ++ return err; ++} ++ ++static int do_rename(struct au_ren_args *a) ++{ ++ int err; ++ struct dentry *d, *h_d; ++ ++ /* prepare workqueue args for asynchronous rmdir */ ++ h_d = a->dst_h_dentry; ++ if (au_ftest_ren(a->flags, ISDIR) && h_d->d_inode) { ++ err = -ENOMEM; ++ a->thargs = au_whtmp_rmdir_alloc(a->src_dentry->d_sb, GFP_NOFS); ++ if (unlikely(!a->thargs)) ++ goto out; ++ a->h_dst = dget(h_d); ++ } ++ ++ /* create whiteout for src_dentry */ ++ if (au_ftest_ren(a->flags, WHSRC)) { ++ a->src_wh_dentry ++ = au_wh_create(a->src_dentry, a->btgt, a->src_h_parent); ++ err = PTR_ERR(a->src_wh_dentry); ++ if (IS_ERR(a->src_wh_dentry)) ++ goto out_thargs; ++ } ++ ++ /* lookup whiteout for dentry */ ++ if (au_ftest_ren(a->flags, WHDST)) { ++ h_d = au_wh_lkup(a->dst_h_parent, &a->dst_dentry->d_name, ++ a->br); ++ err = PTR_ERR(h_d); ++ if (IS_ERR(h_d)) ++ goto out_whsrc; ++ if (!h_d->d_inode) ++ dput(h_d); ++ else ++ a->dst_wh_dentry = h_d; ++ } ++ ++ /* rename dentry to tmpwh */ ++ if (a->thargs) { ++ err = au_whtmp_ren(a->dst_h_dentry, a->br); ++ if (unlikely(err)) ++ goto out_whdst; ++ ++ d = a->dst_dentry; ++ au_set_h_dptr(d, a->btgt, NULL); ++ err = au_lkup_neg(d, a->btgt); ++ if (unlikely(err)) ++ goto out_whtmp; ++ a->dst_h_dentry = au_h_dptr(d, a->btgt); ++ } ++ ++ /* cpup src */ ++ if (a->dst_h_dentry->d_inode && a->src_bstart != a->btgt) { ++ struct mutex *h_mtx = &a->src_h_dentry->d_inode->i_mutex; ++ struct file *h_file; ++ ++ mutex_lock_nested(h_mtx, AuLsc_I_CHILD); ++ AuDebugOn(au_dbstart(a->src_dentry) != a->src_bstart); ++ h_file = au_h_open_pre(a->src_dentry, a->src_bstart); ++ if (IS_ERR(h_file)) { ++ err = PTR_ERR(h_file); ++ h_file = NULL; ++ } else ++ err = au_sio_cpup_simple(a->src_dentry, a->btgt, -1, ++ !AuCpup_DTIME); ++ mutex_unlock(h_mtx); ++ au_h_open_post(a->src_dentry, a->src_bstart, h_file); ++ if (unlikely(err)) ++ goto out_whtmp; ++ } ++ ++ /* rename by vfs_rename or cpup */ ++ d = a->dst_dentry; ++ if (au_ftest_ren(a->flags, ISDIR) ++ && (a->dst_wh_dentry ++ || au_dbdiropq(d) == a->btgt ++ /* hide the lower to keep xino */ ++ || a->btgt < au_dbend(d) ++ || au_opt_test(au_mntflags(d->d_sb), ALWAYS_DIROPQ))) ++ au_fset_ren(a->flags, DIROPQ); ++ err = au_ren_or_cpup(a); ++ if (unlikely(err)) ++ /* leave the copied-up one */ ++ goto out_whtmp; ++ ++ /* make dir opaque */ ++ if (au_ftest_ren(a->flags, DIROPQ)) { ++ err = au_ren_diropq(a); ++ if (unlikely(err)) ++ goto out_rename; ++ } ++ ++ /* update target timestamps */ ++ AuDebugOn(au_dbstart(a->src_dentry) != a->btgt); ++ a->h_path.dentry = au_h_dptr(a->src_dentry, a->btgt); ++ vfsub_update_h_iattr(&a->h_path, /*did*/NULL); /*ignore*/ ++ a->src_inode->i_ctime = a->h_path.dentry->d_inode->i_ctime; ++ ++ /* remove whiteout for dentry */ ++ if (a->dst_wh_dentry) { ++ a->h_path.dentry = a->dst_wh_dentry; ++ err = au_wh_unlink_dentry(a->dst_h_dir, &a->h_path, ++ a->dst_dentry); ++ if (unlikely(err)) ++ goto out_diropq; ++ } ++ ++ /* remove whtmp */ ++ if (a->thargs) ++ au_ren_del_whtmp(a); /* ignore this error */ ++ ++ err = 0; ++ goto out_success; ++ ++ out_diropq: ++ if (au_ftest_ren(a->flags, DIROPQ)) ++ au_ren_rev_diropq(err, a); ++ out_rename: ++ if (!au_ftest_ren(a->flags, CPUP)) ++ au_ren_rev_rename(err, a); ++ else ++ au_ren_rev_cpup(err, a); ++ out_whtmp: ++ if (a->thargs) ++ au_ren_rev_whtmp(err, a); ++ out_whdst: ++ dput(a->dst_wh_dentry); ++ a->dst_wh_dentry = NULL; ++ out_whsrc: ++ if (a->src_wh_dentry) ++ au_ren_rev_whsrc(err, a); ++ au_ren_rev_drop(a); ++ out_success: ++ dput(a->src_wh_dentry); ++ dput(a->dst_wh_dentry); ++ out_thargs: ++ if (a->thargs) { ++ dput(a->h_dst); ++ au_whtmp_rmdir_free(a->thargs); ++ a->thargs = NULL; ++ } ++ out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * test if @dentry dir can be rename destination or not. ++ * success means, it is a logically empty dir. ++ */ ++static int may_rename_dstdir(struct dentry *dentry, struct au_nhash *whlist) ++{ ++ return au_test_empty(dentry, whlist); ++} ++ ++/* ++ * test if @dentry dir can be rename source or not. ++ * if it can, return 0 and @children is filled. ++ * success means, ++ * - it is a logically empty dir. ++ * - or, it exists on writable branch and has no children including whiteouts ++ * on the lower branch. ++ */ ++static int may_rename_srcdir(struct dentry *dentry, aufs_bindex_t btgt) ++{ ++ int err; ++ unsigned int rdhash; ++ aufs_bindex_t bstart; ++ ++ bstart = au_dbstart(dentry); ++ if (bstart != btgt) { ++ struct au_nhash whlist; ++ ++ SiMustAnyLock(dentry->d_sb); ++ rdhash = au_sbi(dentry->d_sb)->si_rdhash; ++ if (!rdhash) ++ rdhash = au_rdhash_est(au_dir_size(/*file*/NULL, ++ dentry)); ++ err = au_nhash_alloc(&whlist, rdhash, GFP_NOFS); ++ if (unlikely(err)) ++ goto out; ++ err = au_test_empty(dentry, &whlist); ++ au_nhash_wh_free(&whlist); ++ goto out; ++ } ++ ++ if (bstart == au_dbtaildir(dentry)) ++ return 0; /* success */ ++ ++ err = au_test_empty_lower(dentry); ++ ++ out: ++ if (err == -ENOTEMPTY) { ++ AuWarn1("renaming dir who has child(ren) on multiple branches," ++ " is not supported\n"); ++ err = -EXDEV; ++ } ++ return err; ++} ++ ++/* side effect: sets whlist and h_dentry */ ++static int au_ren_may_dir(struct au_ren_args *a) ++{ ++ int err; ++ unsigned int rdhash; ++ struct dentry *d; ++ ++ d = a->dst_dentry; ++ SiMustAnyLock(d->d_sb); ++ ++ err = 0; ++ if (au_ftest_ren(a->flags, ISDIR) && a->dst_inode) { ++ rdhash = au_sbi(d->d_sb)->si_rdhash; ++ if (!rdhash) ++ rdhash = au_rdhash_est(au_dir_size(/*file*/NULL, d)); ++ err = au_nhash_alloc(&a->whlist, rdhash, GFP_NOFS); ++ if (unlikely(err)) ++ goto out; ++ ++ au_set_dbstart(d, a->dst_bstart); ++ err = may_rename_dstdir(d, &a->whlist); ++ au_set_dbstart(d, a->btgt); ++ } ++ a->dst_h_dentry = au_h_dptr(d, au_dbstart(d)); ++ if (unlikely(err)) ++ goto out; ++ ++ d = a->src_dentry; ++ a->src_h_dentry = au_h_dptr(d, au_dbstart(d)); ++ if (au_ftest_ren(a->flags, ISDIR)) { ++ err = may_rename_srcdir(d, a->btgt); ++ if (unlikely(err)) { ++ au_nhash_wh_free(&a->whlist); ++ a->whlist.nh_num = 0; ++ } ++ } ++ out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * simple tests for rename. ++ * following the checks in vfs, plus the parent-child relationship. ++ */ ++static int au_may_ren(struct au_ren_args *a) ++{ ++ int err, isdir; ++ struct inode *h_inode; ++ ++ if (a->src_bstart == a->btgt) { ++ err = au_may_del(a->src_dentry, a->btgt, a->src_h_parent, ++ au_ftest_ren(a->flags, ISDIR)); ++ if (unlikely(err)) ++ goto out; ++ err = -EINVAL; ++ if (unlikely(a->src_h_dentry == a->h_trap)) ++ goto out; ++ } ++ ++ err = 0; ++ if (a->dst_bstart != a->btgt) ++ goto out; ++ ++ err = -EIO; ++ h_inode = a->dst_h_dentry->d_inode; ++ isdir = !!au_ftest_ren(a->flags, ISDIR); ++ if (!a->dst_dentry->d_inode) { ++ if (unlikely(h_inode)) ++ goto out; ++ err = au_may_add(a->dst_dentry, a->btgt, a->dst_h_parent, ++ isdir); ++ } else { ++ if (unlikely(!h_inode || !h_inode->i_nlink)) ++ goto out; ++ err = au_may_del(a->dst_dentry, a->btgt, a->dst_h_parent, ++ isdir); ++ if (unlikely(err)) ++ goto out; ++ err = -ENOTEMPTY; ++ if (unlikely(a->dst_h_dentry == a->h_trap)) ++ goto out; ++ err = 0; ++ } ++ ++ out: ++ if (unlikely(err == -ENOENT || err == -EEXIST)) ++ err = -EIO; ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * locking order ++ * (VFS) ++ * - src_dir and dir by lock_rename() ++ * - inode if exitsts ++ * (aufs) ++ * - lock all ++ * + src_dentry and dentry by aufs_read_and_write_lock2() which calls, ++ * + si_read_lock ++ * + di_write_lock2_child() ++ * + di_write_lock_child() ++ * + ii_write_lock_child() ++ * + di_write_lock_child2() ++ * + ii_write_lock_child2() ++ * + src_parent and parent ++ * + di_write_lock_parent() ++ * + ii_write_lock_parent() ++ * + di_write_lock_parent2() ++ * + ii_write_lock_parent2() ++ * + lower src_dir and dir by vfsub_lock_rename() ++ * + verify the every relationships between child and parent. if any ++ * of them failed, unlock all and return -EBUSY. ++ */ ++static void au_ren_unlock(struct au_ren_args *a) ++{ ++ struct super_block *sb; ++ ++ sb = a->dst_dentry->d_sb; ++ if (au_ftest_ren(a->flags, MNT_WRITE)) ++ mnt_drop_write(a->br->br_mnt); ++ vfsub_unlock_rename(a->src_h_parent, a->src_hdir, ++ a->dst_h_parent, a->dst_hdir); ++} ++ ++static int au_ren_lock(struct au_ren_args *a) ++{ ++ int err; ++ unsigned int udba; ++ ++ err = 0; ++ a->src_h_parent = au_h_dptr(a->src_parent, a->btgt); ++ a->src_hdir = au_hi(a->src_dir, a->btgt); ++ a->dst_h_parent = au_h_dptr(a->dst_parent, a->btgt); ++ a->dst_hdir = au_hi(a->dst_dir, a->btgt); ++ a->h_trap = vfsub_lock_rename(a->src_h_parent, a->src_hdir, ++ a->dst_h_parent, a->dst_hdir); ++ udba = au_opt_udba(a->src_dentry->d_sb); ++ if (unlikely(a->src_hdir->hi_inode != a->src_h_parent->d_inode ++ || a->dst_hdir->hi_inode != a->dst_h_parent->d_inode)) ++ err = au_busy_or_stale(); ++ if (!err && au_dbstart(a->src_dentry) == a->btgt) ++ err = au_h_verify(a->src_h_dentry, udba, ++ a->src_h_parent->d_inode, a->src_h_parent, ++ a->br); ++ if (!err && au_dbstart(a->dst_dentry) == a->btgt) ++ err = au_h_verify(a->dst_h_dentry, udba, ++ a->dst_h_parent->d_inode, a->dst_h_parent, ++ a->br); ++ if (!err) { ++ err = mnt_want_write(a->br->br_mnt); ++ if (unlikely(err)) ++ goto out_unlock; ++ au_fset_ren(a->flags, MNT_WRITE); ++ goto out; /* success */ ++ } ++ ++ err = au_busy_or_stale(); ++ ++ out_unlock: ++ au_ren_unlock(a); ++ out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void au_ren_refresh_dir(struct au_ren_args *a) ++{ ++ struct inode *dir; ++ ++ dir = a->dst_dir; ++ dir->i_version++; ++ if (au_ftest_ren(a->flags, ISDIR)) { ++ /* is this updating defined in POSIX? */ ++ au_cpup_attr_timesizes(a->src_inode); ++ au_cpup_attr_nlink(dir, /*force*/1); ++ if (a->dst_inode) { ++ clear_nlink(a->dst_inode); ++ au_cpup_attr_timesizes(a->dst_inode); ++ } ++ } ++ if (au_ibstart(dir) == a->btgt) ++ au_cpup_attr_timesizes(dir); ++ ++ if (au_ftest_ren(a->flags, ISSAMEDIR)) ++ return; ++ ++ dir = a->src_dir; ++ dir->i_version++; ++ if (au_ftest_ren(a->flags, ISDIR)) ++ au_cpup_attr_nlink(dir, /*force*/1); ++ if (au_ibstart(dir) == a->btgt) ++ au_cpup_attr_timesizes(dir); ++} ++ ++static void au_ren_refresh(struct au_ren_args *a) ++{ ++ aufs_bindex_t bend, bindex; ++ struct dentry *d, *h_d; ++ struct inode *i, *h_i; ++ struct super_block *sb; ++ ++ d = a->src_dentry; ++ au_set_dbwh(d, -1); ++ bend = au_dbend(d); ++ for (bindex = a->btgt + 1; bindex <= bend; bindex++) { ++ h_d = au_h_dptr(d, bindex); ++ if (h_d) ++ au_set_h_dptr(d, bindex, NULL); ++ } ++ au_set_dbend(d, a->btgt); ++ ++ sb = d->d_sb; ++ i = a->src_inode; ++ if (au_opt_test(au_mntflags(sb), PLINK) && au_plink_test(i)) ++ return; /* success */ ++ ++ bend = au_ibend(i); ++ for (bindex = a->btgt + 1; bindex <= bend; bindex++) { ++ h_i = au_h_iptr(i, bindex); ++ if (h_i) { ++ au_xino_write(sb, bindex, h_i->i_ino, /*ino*/0); ++ /* ignore this error */ ++ au_set_h_iptr(i, bindex, NULL, 0); ++ } ++ } ++ au_set_ibend(i, a->btgt); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* mainly for link(2) and rename(2) */ ++int au_wbr(struct dentry *dentry, aufs_bindex_t btgt) ++{ ++ aufs_bindex_t bdiropq, bwh; ++ struct dentry *parent; ++ struct au_branch *br; ++ ++ parent = dentry->d_parent; ++ IMustLock(parent->d_inode); /* dir is locked */ ++ ++ bdiropq = au_dbdiropq(parent); ++ bwh = au_dbwh(dentry); ++ br = au_sbr(dentry->d_sb, btgt); ++ if (au_br_rdonly(br) ++ || (0 <= bdiropq && bdiropq < btgt) ++ || (0 <= bwh && bwh < btgt)) ++ btgt = -1; ++ ++ AuDbg("btgt %d\n", btgt); ++ return btgt; ++} ++ ++/* sets src_bstart, dst_bstart and btgt */ ++static int au_ren_wbr(struct au_ren_args *a) ++{ ++ int err; ++ struct au_wr_dir_args wr_dir_args = { ++ /* .force_btgt = -1, */ ++ .flags = AuWrDir_ADD_ENTRY ++ }; ++ ++ a->src_bstart = au_dbstart(a->src_dentry); ++ a->dst_bstart = au_dbstart(a->dst_dentry); ++ if (au_ftest_ren(a->flags, ISDIR)) ++ au_fset_wrdir(wr_dir_args.flags, ISDIR); ++ wr_dir_args.force_btgt = a->src_bstart; ++ if (a->dst_inode && a->dst_bstart < a->src_bstart) ++ wr_dir_args.force_btgt = a->dst_bstart; ++ wr_dir_args.force_btgt = au_wbr(a->dst_dentry, wr_dir_args.force_btgt); ++ err = au_wr_dir(a->dst_dentry, a->src_dentry, &wr_dir_args); ++ a->btgt = err; ++ ++ return err; ++} ++ ++static void au_ren_dt(struct au_ren_args *a) ++{ ++ a->h_path.dentry = a->src_h_parent; ++ au_dtime_store(a->src_dt + AuPARENT, a->src_parent, &a->h_path); ++ if (!au_ftest_ren(a->flags, ISSAMEDIR)) { ++ a->h_path.dentry = a->dst_h_parent; ++ au_dtime_store(a->dst_dt + AuPARENT, a->dst_parent, &a->h_path); ++ } ++ ++ au_fclr_ren(a->flags, DT_DSTDIR); ++ if (!au_ftest_ren(a->flags, ISDIR)) ++ return; ++ ++ a->h_path.dentry = a->src_h_dentry; ++ au_dtime_store(a->src_dt + AuCHILD, a->src_dentry, &a->h_path); ++ if (a->dst_h_dentry->d_inode) { ++ au_fset_ren(a->flags, DT_DSTDIR); ++ a->h_path.dentry = a->dst_h_dentry; ++ au_dtime_store(a->dst_dt + AuCHILD, a->dst_dentry, &a->h_path); ++ } ++} ++ ++static void au_ren_rev_dt(int err, struct au_ren_args *a) ++{ ++ struct dentry *h_d; ++ struct mutex *h_mtx; ++ ++ au_dtime_revert(a->src_dt + AuPARENT); ++ if (!au_ftest_ren(a->flags, ISSAMEDIR)) ++ au_dtime_revert(a->dst_dt + AuPARENT); ++ ++ if (au_ftest_ren(a->flags, ISDIR) && err != -EIO) { ++ h_d = a->src_dt[AuCHILD].dt_h_path.dentry; ++ h_mtx = &h_d->d_inode->i_mutex; ++ mutex_lock_nested(h_mtx, AuLsc_I_CHILD); ++ au_dtime_revert(a->src_dt + AuCHILD); ++ mutex_unlock(h_mtx); ++ ++ if (au_ftest_ren(a->flags, DT_DSTDIR)) { ++ h_d = a->dst_dt[AuCHILD].dt_h_path.dentry; ++ h_mtx = &h_d->d_inode->i_mutex; ++ mutex_lock_nested(h_mtx, AuLsc_I_CHILD); ++ au_dtime_revert(a->dst_dt + AuCHILD); ++ mutex_unlock(h_mtx); ++ } ++ } ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int aufs_rename(struct inode *_src_dir, struct dentry *_src_dentry, ++ struct inode *_dst_dir, struct dentry *_dst_dentry) ++{ ++ int err; ++ /* reduce stack space */ ++ struct au_ren_args *a; ++ ++ AuDbg("%.*s, %.*s\n", AuDLNPair(_src_dentry), AuDLNPair(_dst_dentry)); ++ IMustLock(_src_dir); ++ IMustLock(_dst_dir); ++ ++ err = -ENOMEM; ++ BUILD_BUG_ON(sizeof(*a) > PAGE_SIZE); ++ a = kzalloc(sizeof(*a), GFP_NOFS); ++ if (unlikely(!a)) ++ goto out; ++ ++ a->src_dir = _src_dir; ++ a->src_dentry = _src_dentry; ++ a->src_inode = a->src_dentry->d_inode; ++ a->src_parent = a->src_dentry->d_parent; /* dir inode is locked */ ++ a->dst_dir = _dst_dir; ++ a->dst_dentry = _dst_dentry; ++ a->dst_inode = a->dst_dentry->d_inode; ++ a->dst_parent = a->dst_dentry->d_parent; /* dir inode is locked */ ++ if (a->dst_inode) { ++ IMustLock(a->dst_inode); ++ au_igrab(a->dst_inode); ++ } ++ ++ err = -ENOTDIR; ++ if (S_ISDIR(a->src_inode->i_mode)) { ++ au_fset_ren(a->flags, ISDIR); ++ if (unlikely(a->dst_inode && !S_ISDIR(a->dst_inode->i_mode))) ++ goto out_free; ++ aufs_read_and_write_lock2(a->dst_dentry, a->src_dentry, ++ AuLock_DIR | AuLock_FLUSH); ++ } else ++ aufs_read_and_write_lock2(a->dst_dentry, a->src_dentry, ++ AuLock_FLUSH); ++ ++ au_fset_ren(a->flags, ISSAMEDIR); /* temporary */ ++ di_write_lock_parent(a->dst_parent); ++ ++ /* which branch we process */ ++ err = au_ren_wbr(a); ++ if (unlikely(err < 0)) ++ goto out_unlock; ++ a->br = au_sbr(a->dst_dentry->d_sb, a->btgt); ++ a->h_path.mnt = a->br->br_mnt; ++ ++ /* are they available to be renamed */ ++ err = au_ren_may_dir(a); ++ if (unlikely(err)) ++ goto out_children; ++ ++ /* prepare the writable parent dir on the same branch */ ++ if (a->dst_bstart == a->btgt) { ++ au_fset_ren(a->flags, WHDST); ++ } else { ++ err = au_cpup_dirs(a->dst_dentry, a->btgt); ++ if (unlikely(err)) ++ goto out_children; ++ } ++ ++ if (a->src_dir != a->dst_dir) { ++ /* ++ * this temporary unlock is safe, ++ * because both dir->i_mutex are locked. ++ */ ++ di_write_unlock(a->dst_parent); ++ di_write_lock_parent(a->src_parent); ++ err = au_wr_dir_need_wh(a->src_dentry, ++ au_ftest_ren(a->flags, ISDIR), ++ &a->btgt); ++ di_write_unlock(a->src_parent); ++ di_write_lock2_parent(a->src_parent, a->dst_parent, /*isdir*/1); ++ au_fclr_ren(a->flags, ISSAMEDIR); ++ } else ++ err = au_wr_dir_need_wh(a->src_dentry, ++ au_ftest_ren(a->flags, ISDIR), ++ &a->btgt); ++ if (unlikely(err < 0)) ++ goto out_children; ++ if (err) ++ au_fset_ren(a->flags, WHSRC); ++ ++ /* lock them all */ ++ err = au_ren_lock(a); ++ if (unlikely(err)) ++ goto out_children; ++ ++ if (!au_opt_test(au_mntflags(a->dst_dir->i_sb), UDBA_NONE)) ++ err = au_may_ren(a); ++ else if (unlikely(a->dst_dentry->d_name.len > AUFS_MAX_NAMELEN)) ++ err = -ENAMETOOLONG; ++ if (unlikely(err)) ++ goto out_hdir; ++ ++ /* store timestamps to be revertible */ ++ au_ren_dt(a); ++ ++ /* here we go */ ++ err = do_rename(a); ++ if (unlikely(err)) ++ goto out_dt; ++ ++ /* update dir attributes */ ++ au_ren_refresh_dir(a); ++ ++ /* dput/iput all lower dentries */ ++ au_ren_refresh(a); ++ ++ goto out_hdir; /* success */ ++ ++ out_dt: ++ au_ren_rev_dt(err, a); ++ out_hdir: ++ au_ren_unlock(a); ++ out_children: ++ au_nhash_wh_free(&a->whlist); ++ out_unlock: ++ if (unlikely(err && au_ftest_ren(a->flags, ISDIR))) { ++ au_update_dbstart(a->dst_dentry); ++ d_drop(a->dst_dentry); ++ } ++ if (!err) ++ d_move(a->src_dentry, a->dst_dentry); ++ if (au_ftest_ren(a->flags, ISSAMEDIR)) ++ di_write_unlock(a->dst_parent); ++ else ++ di_write_unlock2(a->src_parent, a->dst_parent); ++ aufs_read_and_write_unlock2(a->dst_dentry, a->src_dentry); ++ out_free: ++ iput(a->dst_inode); ++ if (a->thargs) ++ au_whtmp_rmdir_free(a->thargs); ++ kfree(a); ++ out: ++ AuTraceErr(err); ++ return err; ++} +diff --git a/fs/aufs/iinfo.c b/fs/aufs/iinfo.c +new file mode 100644 +index 0000000..5a61d8c +--- /dev/null ++++ b/fs/aufs/iinfo.c +@@ -0,0 +1,283 @@ ++/* ++ * Copyright (C) 2005-2010 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* ++ * inode private data ++ */ ++ ++#include "aufs.h" ++ ++struct inode *au_h_iptr(struct inode *inode, aufs_bindex_t bindex) ++{ ++ struct inode *h_inode; ++ ++ IiMustAnyLock(inode); ++ ++ h_inode = au_ii(inode)->ii_hinode[0 + bindex].hi_inode; ++ AuDebugOn(h_inode && atomic_read(&h_inode->i_count) <= 0); ++ return h_inode; ++} ++ ++/* todo: hard/soft set? */ ++void au_set_ibstart(struct inode *inode, aufs_bindex_t bindex) ++{ ++ struct au_iinfo *iinfo = au_ii(inode); ++ struct inode *h_inode; ++ ++ IiMustWriteLock(inode); ++ ++ iinfo->ii_bstart = bindex; ++ h_inode = iinfo->ii_hinode[bindex + 0].hi_inode; ++ if (h_inode) ++ au_cpup_igen(inode, h_inode); ++} ++ ++void au_hiput(struct au_hinode *hinode) ++{ ++ au_hin_free(hinode); ++ dput(hinode->hi_whdentry); ++ iput(hinode->hi_inode); ++} ++ ++unsigned int au_hi_flags(struct inode *inode, int isdir) ++{ ++ unsigned int flags; ++ const unsigned int mnt_flags = au_mntflags(inode->i_sb); ++ ++ flags = 0; ++ if (au_opt_test(mnt_flags, XINO)) ++ au_fset_hi(flags, XINO); ++ if (isdir && au_opt_test(mnt_flags, UDBA_HINOTIFY)) ++ au_fset_hi(flags, HINOTIFY); ++ return flags; ++} ++ ++void au_set_h_iptr(struct inode *inode, aufs_bindex_t bindex, ++ struct inode *h_inode, unsigned int flags) ++{ ++ struct au_hinode *hinode; ++ struct inode *hi; ++ struct au_iinfo *iinfo = au_ii(inode); ++ ++ IiMustWriteLock(inode); ++ ++ hinode = iinfo->ii_hinode + bindex; ++ hi = hinode->hi_inode; ++ AuDebugOn(h_inode && atomic_read(&h_inode->i_count) <= 0); ++ AuDebugOn(h_inode && hi); ++ ++ if (hi) ++ au_hiput(hinode); ++ hinode->hi_inode = h_inode; ++ if (h_inode) { ++ int err; ++ struct super_block *sb = inode->i_sb; ++ struct au_branch *br; ++ ++ if (bindex == iinfo->ii_bstart) ++ au_cpup_igen(inode, h_inode); ++ br = au_sbr(sb, bindex); ++ hinode->hi_id = br->br_id; ++ if (au_ftest_hi(flags, XINO)) { ++ err = au_xino_write(sb, bindex, h_inode->i_ino, ++ inode->i_ino); ++ if (unlikely(err)) ++ AuIOErr1("failed au_xino_write() %d\n", err); ++ } ++ ++ if (au_ftest_hi(flags, HINOTIFY) ++ && au_br_hinotifyable(br->br_perm)) { ++ err = au_hin_alloc(hinode, inode, h_inode); ++ if (unlikely(err)) ++ AuIOErr1("au_hin_alloc() %d\n", err); ++ } ++ } ++} ++ ++void au_set_hi_wh(struct inode *inode, aufs_bindex_t bindex, ++ struct dentry *h_wh) ++{ ++ struct au_hinode *hinode; ++ ++ IiMustWriteLock(inode); ++ ++ hinode = au_ii(inode)->ii_hinode + bindex; ++ AuDebugOn(hinode->hi_whdentry); ++ hinode->hi_whdentry = h_wh; ++} ++ ++void au_update_iigen(struct inode *inode) ++{ ++ atomic_set(&au_ii(inode)->ii_generation, au_sigen(inode->i_sb)); ++ /* smp_mb(); */ /* atomic_set */ ++} ++ ++/* it may be called at remount time, too */ ++void au_update_brange(struct inode *inode, int do_put_zero) ++{ ++ struct au_iinfo *iinfo; ++ ++ iinfo = au_ii(inode); ++ if (!iinfo || iinfo->ii_bstart < 0) ++ return; ++ ++ IiMustWriteLock(inode); ++ ++ if (do_put_zero) { ++ aufs_bindex_t bindex; ++ ++ for (bindex = iinfo->ii_bstart; bindex <= iinfo->ii_bend; ++ bindex++) { ++ struct inode *h_i; ++ ++ h_i = iinfo->ii_hinode[0 + bindex].hi_inode; ++ if (h_i && !h_i->i_nlink) ++ au_set_h_iptr(inode, bindex, NULL, 0); ++ } ++ } ++ ++ iinfo->ii_bstart = -1; ++ while (++iinfo->ii_bstart <= iinfo->ii_bend) ++ if (iinfo->ii_hinode[0 + iinfo->ii_bstart].hi_inode) ++ break; ++ if (iinfo->ii_bstart > iinfo->ii_bend) { ++ iinfo->ii_bstart = -1; ++ iinfo->ii_bend = -1; ++ return; ++ } ++ ++ iinfo->ii_bend++; ++ while (0 <= --iinfo->ii_bend) ++ if (iinfo->ii_hinode[0 + iinfo->ii_bend].hi_inode) ++ break; ++ AuDebugOn(iinfo->ii_bstart > iinfo->ii_bend || iinfo->ii_bend < 0); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_iinfo_init(struct inode *inode) ++{ ++ struct au_iinfo *iinfo; ++ struct super_block *sb; ++ int nbr, i; ++ ++ sb = inode->i_sb; ++ iinfo = &(container_of(inode, struct au_icntnr, vfs_inode)->iinfo); ++ nbr = au_sbend(sb) + 1; ++ if (unlikely(nbr <= 0)) ++ nbr = 1; ++ iinfo->ii_hinode = kcalloc(nbr, sizeof(*iinfo->ii_hinode), GFP_NOFS); ++ if (iinfo->ii_hinode) { ++ for (i = 0; i < nbr; i++) ++ iinfo->ii_hinode[i].hi_id = -1; ++ ++ atomic_set(&iinfo->ii_generation, au_sigen(sb)); ++ /* smp_mb(); */ /* atomic_set */ ++ au_rw_init(&iinfo->ii_rwsem); ++ iinfo->ii_bstart = -1; ++ iinfo->ii_bend = -1; ++ iinfo->ii_vdir = NULL; ++ return 0; ++ } ++ return -ENOMEM; ++} ++ ++int au_ii_realloc(struct au_iinfo *iinfo, int nbr) ++{ ++ int err, sz; ++ struct au_hinode *hip; ++ ++ AuRwMustWriteLock(&iinfo->ii_rwsem); ++ ++ err = -ENOMEM; ++ sz = sizeof(*hip) * (iinfo->ii_bend + 1); ++ if (!sz) ++ sz = sizeof(*hip); ++ hip = au_kzrealloc(iinfo->ii_hinode, sz, sizeof(*hip) * nbr, GFP_NOFS); ++ if (hip) { ++ iinfo->ii_hinode = hip; ++ err = 0; ++ } ++ ++ return err; ++} ++ ++static int au_iinfo_write0(struct super_block *sb, struct au_hinode *hinode, ++ ino_t ino) ++{ ++ int err; ++ aufs_bindex_t bindex; ++ unsigned char locked; ++ ++ err = 0; ++ locked = !!si_noflush_read_trylock(sb); ++ bindex = au_br_index(sb, hinode->hi_id); ++ if (bindex >= 0) ++ err = au_xino_write0(sb, bindex, hinode->hi_inode->i_ino, ino); ++ /* error action? */ ++ if (locked) ++ si_read_unlock(sb); ++ return err; ++} ++ ++void au_iinfo_fin(struct inode *inode) ++{ ++ ino_t ino; ++ aufs_bindex_t bend; ++ unsigned char unlinked = !inode->i_nlink; ++ struct au_iinfo *iinfo; ++ struct au_hinode *hi; ++ struct super_block *sb; ++ ++ if (unlinked) { ++ int err = au_xigen_inc(inode); ++ if (unlikely(err)) ++ AuWarn1("failed resetting i_generation, %d\n", err); ++ } ++ ++ iinfo = au_ii(inode); ++ /* bad_inode case */ ++ if (!iinfo) ++ return; ++ ++ if (iinfo->ii_vdir) ++ au_vdir_free(iinfo->ii_vdir); ++ ++ if (iinfo->ii_bstart >= 0) { ++ sb = inode->i_sb; ++ ino = 0; ++ if (unlinked) ++ ino = inode->i_ino; ++ hi = iinfo->ii_hinode + iinfo->ii_bstart; ++ bend = iinfo->ii_bend; ++ while (iinfo->ii_bstart++ <= bend) { ++ if (hi->hi_inode) { ++ if (unlinked || !hi->hi_inode->i_nlink) { ++ au_iinfo_write0(sb, hi, ino); ++ /* ignore this error */ ++ ino = 0; ++ } ++ au_hiput(hi); ++ } ++ hi++; ++ } ++ } ++ ++ kfree(iinfo->ii_hinode); ++ AuRwDestroy(&iinfo->ii_rwsem); ++} +diff --git a/fs/aufs/inode.c b/fs/aufs/inode.c +new file mode 100644 +index 0000000..3833bf4 +--- /dev/null ++++ b/fs/aufs/inode.c +@@ -0,0 +1,412 @@ ++/* ++ * Copyright (C) 2005-2010 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* ++ * inode functions ++ */ ++ ++#include "aufs.h" ++ ++struct inode *au_igrab(struct inode *inode) ++{ ++ if (inode) { ++ AuDebugOn(!atomic_read(&inode->i_count)); ++ atomic_inc_return(&inode->i_count); ++ } ++ return inode; ++} ++ ++static void au_refresh_hinode_attr(struct inode *inode, int do_version) ++{ ++ au_cpup_attr_all(inode, /*force*/0); ++ au_update_iigen(inode); ++ if (do_version) ++ inode->i_version++; ++} ++ ++int au_refresh_hinode_self(struct inode *inode, int do_attr) ++{ ++ int err; ++ aufs_bindex_t bindex, new_bindex; ++ unsigned char update; ++ struct au_hinode *p, *q, tmp; ++ struct super_block *sb; ++ struct au_iinfo *iinfo; ++ ++ IiMustWriteLock(inode); ++ ++ update = 0; ++ sb = inode->i_sb; ++ iinfo = au_ii(inode); ++ err = au_ii_realloc(iinfo, au_sbend(sb) + 1); ++ if (unlikely(err)) ++ goto out; ++ ++ p = iinfo->ii_hinode + iinfo->ii_bstart; ++ err = 0; ++ for (bindex = iinfo->ii_bstart; bindex <= iinfo->ii_bend; ++ bindex++, p++) { ++ if (!p->hi_inode) ++ continue; ++ ++ new_bindex = au_br_index(sb, p->hi_id); ++ if (new_bindex == bindex) ++ continue; ++ ++ if (new_bindex < 0) { ++ update = 1; ++ au_hiput(p); ++ p->hi_inode = NULL; ++ continue; ++ } ++ ++ if (new_bindex < iinfo->ii_bstart) ++ iinfo->ii_bstart = new_bindex; ++ if (iinfo->ii_bend < new_bindex) ++ iinfo->ii_bend = new_bindex; ++ /* swap two lower inode, and loop again */ ++ q = iinfo->ii_hinode + new_bindex; ++ tmp = *q; ++ *q = *p; ++ *p = tmp; ++ if (tmp.hi_inode) { ++ bindex--; ++ p--; ++ } ++ } ++ au_update_brange(inode, /*do_put_zero*/0); ++ if (do_attr) ++ au_refresh_hinode_attr(inode, update && S_ISDIR(inode->i_mode)); ++ ++ out: ++ return err; ++} ++ ++int au_refresh_hinode(struct inode *inode, struct dentry *dentry) ++{ ++ int err; ++ unsigned int flags; ++ aufs_bindex_t bindex, bend; ++ unsigned char isdir, update; ++ struct au_hinode *p; ++ struct au_iinfo *iinfo; ++ ++ err = au_refresh_hinode_self(inode, /*do_attr*/0); ++ if (unlikely(err)) ++ goto out; ++ ++ update = 0; ++ iinfo = au_ii(inode); ++ p = iinfo->ii_hinode + iinfo->ii_bstart; ++ isdir = S_ISDIR(inode->i_mode); ++ flags = au_hi_flags(inode, isdir); ++ bend = au_dbend(dentry); ++ for (bindex = au_dbstart(dentry); bindex <= bend; bindex++) { ++ struct inode *h_i; ++ struct dentry *h_d; ++ ++ h_d = au_h_dptr(dentry, bindex); ++ if (!h_d || !h_d->d_inode) ++ continue; ++ ++ if (iinfo->ii_bstart <= bindex && bindex <= iinfo->ii_bend) { ++ h_i = au_h_iptr(inode, bindex); ++ if (h_i) { ++ if (h_i == h_d->d_inode) ++ continue; ++ err = -EIO; ++ break; ++ } ++ } ++ if (bindex < iinfo->ii_bstart) ++ iinfo->ii_bstart = bindex; ++ if (iinfo->ii_bend < bindex) ++ iinfo->ii_bend = bindex; ++ au_set_h_iptr(inode, bindex, au_igrab(h_d->d_inode), flags); ++ update = 1; ++ } ++ au_update_brange(inode, /*do_put_zero*/0); ++ ++ if (unlikely(err)) ++ goto out; ++ ++ au_refresh_hinode_attr(inode, update && isdir); ++ ++ out: ++ AuTraceErr(err); ++ return err; ++} ++ ++static int set_inode(struct inode *inode, struct dentry *dentry) ++{ ++ int err; ++ unsigned int flags; ++ umode_t mode; ++ aufs_bindex_t bindex, bstart, btail; ++ unsigned char isdir; ++ struct dentry *h_dentry; ++ struct inode *h_inode; ++ struct au_iinfo *iinfo; ++ ++ IiMustWriteLock(inode); ++ ++ err = 0; ++ isdir = 0; ++ bstart = au_dbstart(dentry); ++ h_inode = au_h_dptr(dentry, bstart)->d_inode; ++ mode = h_inode->i_mode; ++ switch (mode & S_IFMT) { ++ case S_IFREG: ++ btail = au_dbtail(dentry); ++ inode->i_op = &aufs_iop; ++ inode->i_fop = &aufs_file_fop; ++ inode->i_mapping->a_ops = &aufs_aop; ++ break; ++ case S_IFDIR: ++ isdir = 1; ++ btail = au_dbtaildir(dentry); ++ inode->i_op = &aufs_dir_iop; ++ inode->i_fop = &aufs_dir_fop; ++ break; ++ case S_IFLNK: ++ btail = au_dbtail(dentry); ++ inode->i_op = &aufs_symlink_iop; ++ break; ++ case S_IFBLK: ++ case S_IFCHR: ++ case S_IFIFO: ++ case S_IFSOCK: ++ btail = au_dbtail(dentry); ++ inode->i_op = &aufs_iop; ++ au_init_special_fop(inode, mode, h_inode->i_rdev); ++ break; ++ default: ++ AuIOErr("Unknown file type 0%o\n", mode); ++ err = -EIO; ++ goto out; ++ } ++ ++ /* do not set inotify for whiteouted dirs (SHWH mode) */ ++ flags = au_hi_flags(inode, isdir); ++ if (au_opt_test(au_mntflags(dentry->d_sb), SHWH) ++ && au_ftest_hi(flags, HINOTIFY) ++ && dentry->d_name.len > AUFS_WH_PFX_LEN ++ && !memcmp(dentry->d_name.name, AUFS_WH_PFX, AUFS_WH_PFX_LEN)) ++ au_fclr_hi(flags, HINOTIFY); ++ iinfo = au_ii(inode); ++ iinfo->ii_bstart = bstart; ++ iinfo->ii_bend = btail; ++ for (bindex = bstart; bindex <= btail; bindex++) { ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (h_dentry) ++ au_set_h_iptr(inode, bindex, ++ au_igrab(h_dentry->d_inode), flags); ++ } ++ au_cpup_attr_all(inode, /*force*/1); ++ ++ out: ++ return err; ++} ++ ++/* successful returns with iinfo write_locked */ ++static int reval_inode(struct inode *inode, struct dentry *dentry, int *matched) ++{ ++ int err; ++ aufs_bindex_t bindex, bend; ++ struct inode *h_inode, *h_dinode; ++ ++ *matched = 0; ++ ++ /* ++ * before this function, if aufs got any iinfo lock, it must be only ++ * one, the parent dir. ++ * it can happen by UDBA and the obsoleted inode number. ++ */ ++ err = -EIO; ++ if (unlikely(inode->i_ino == parent_ino(dentry))) ++ goto out; ++ ++ err = 0; ++ ii_write_lock_new_child(inode); ++ h_dinode = au_h_dptr(dentry, au_dbstart(dentry))->d_inode; ++ bend = au_ibend(inode); ++ for (bindex = au_ibstart(inode); bindex <= bend; bindex++) { ++ h_inode = au_h_iptr(inode, bindex); ++ if (h_inode && h_inode == h_dinode) { ++ *matched = 1; ++ err = 0; ++ if (au_iigen(inode) != au_digen(dentry)) ++ err = au_refresh_hinode(inode, dentry); ++ break; ++ } ++ } ++ ++ if (unlikely(err)) ++ ii_write_unlock(inode); ++ out: ++ return err; ++} ++ ++int au_ino(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, ++ unsigned int d_type, ino_t *ino) ++{ ++ int err; ++ struct mutex *mtx; ++ const int isdir = (d_type == DT_DIR); ++ ++ /* prevent hardlinks from race condition */ ++ mtx = NULL; ++ if (!isdir) { ++ mtx = &au_sbr(sb, bindex)->br_xino.xi_nondir_mtx; ++ mutex_lock(mtx); ++ } ++ err = au_xino_read(sb, bindex, h_ino, ino); ++ if (unlikely(err)) ++ goto out; ++ ++ if (!*ino) { ++ err = -EIO; ++ *ino = au_xino_new_ino(sb); ++ if (unlikely(!*ino)) ++ goto out; ++ err = au_xino_write(sb, bindex, h_ino, *ino); ++ if (unlikely(err)) ++ goto out; ++ } ++ ++ out: ++ if (!isdir) ++ mutex_unlock(mtx); ++ return err; ++} ++ ++/* successful returns with iinfo write_locked */ ++/* todo: return with unlocked? */ ++struct inode *au_new_inode(struct dentry *dentry, int must_new) ++{ ++ struct inode *inode; ++ struct dentry *h_dentry; ++ struct super_block *sb; ++ ino_t h_ino, ino; ++ int err, match; ++ aufs_bindex_t bstart; ++ ++ sb = dentry->d_sb; ++ bstart = au_dbstart(dentry); ++ h_dentry = au_h_dptr(dentry, bstart); ++ h_ino = h_dentry->d_inode->i_ino; ++ err = au_xino_read(sb, bstart, h_ino, &ino); ++ inode = ERR_PTR(err); ++ if (unlikely(err)) ++ goto out; ++ new_ino: ++ if (!ino) { ++ ino = au_xino_new_ino(sb); ++ if (unlikely(!ino)) { ++ inode = ERR_PTR(-EIO); ++ goto out; ++ } ++ } ++ ++ AuDbg("i%lu\n", (unsigned long)ino); ++ inode = au_iget_locked(sb, ino); ++ err = PTR_ERR(inode); ++ if (IS_ERR(inode)) ++ goto out; ++ ++ AuDbg("%lx, new %d\n", inode->i_state, !!(inode->i_state & I_NEW)); ++ if (inode->i_state & I_NEW) { ++ ii_write_lock_new_child(inode); ++ err = set_inode(inode, dentry); ++ if (!err) { ++ unlock_new_inode(inode); ++ goto out; /* success */ ++ } ++ ++ ii_write_unlock(inode); ++ iget_failed(inode); ++ goto out_err; ++ } else if (!must_new) { ++ err = reval_inode(inode, dentry, &match); ++ if (!err) ++ goto out; /* success */ ++ else if (match) ++ goto out_iput; ++ } ++ ++ if (unlikely(au_test_fs_unique_ino(h_dentry->d_inode))) ++ AuWarn1("Warning: Un-notified UDBA or repeatedly renamed dir," ++ " b%d, %s, %.*s, hi%lu, i%lu.\n", ++ bstart, au_sbtype(h_dentry->d_sb), AuDLNPair(dentry), ++ (unsigned long)h_ino, (unsigned long)ino); ++ ino = 0; ++ err = au_xino_write(sb, bstart, h_ino, /*ino*/0); ++ if (!err) { ++ iput(inode); ++ goto new_ino; ++ } ++ ++ out_iput: ++ iput(inode); ++ out_err: ++ inode = ERR_PTR(err); ++ out: ++ return inode; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_test_ro(struct super_block *sb, aufs_bindex_t bindex, ++ struct inode *inode) ++{ ++ int err; ++ ++ err = au_br_rdonly(au_sbr(sb, bindex)); ++ ++ /* pseudo-link after flushed may happen out of bounds */ ++ if (!err ++ && inode ++ && au_ibstart(inode) <= bindex ++ && bindex <= au_ibend(inode)) { ++ /* ++ * permission check is unnecessary since vfsub routine ++ * will be called later ++ */ ++ struct inode *hi = au_h_iptr(inode, bindex); ++ if (hi) ++ err = IS_IMMUTABLE(hi) ? -EROFS : 0; ++ } ++ ++ return err; ++} ++ ++int au_test_h_perm(struct inode *h_inode, int mask) ++{ ++ if (!current_fsuid()) ++ return 0; ++ return inode_permission(h_inode, mask); ++} ++ ++int au_test_h_perm_sio(struct inode *h_inode, int mask) ++{ ++ if (au_test_nfs(h_inode->i_sb) ++ && (mask & MAY_WRITE) ++ && S_ISDIR(h_inode->i_mode)) ++ mask |= MAY_READ; /* force permission check */ ++ return au_test_h_perm(h_inode, mask); ++} +diff --git a/fs/aufs/inode.h b/fs/aufs/inode.h +new file mode 100644 +index 0000000..086791c +--- /dev/null ++++ b/fs/aufs/inode.h +@@ -0,0 +1,474 @@ ++/* ++ * Copyright (C) 2005-2010 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* ++ * inode operations ++ */ ++ ++#ifndef __AUFS_INODE_H__ ++#define __AUFS_INODE_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++#include ++#include "rwsem.h" ++ ++struct vfsmount; ++ ++struct au_hinotify { ++#ifdef CONFIG_AUFS_HINOTIFY ++ struct inotify_watch hin_watch; ++ struct inode *hin_aufs_inode; /* no get/put */ ++#endif ++}; ++ ++struct au_hinode { ++ struct inode *hi_inode; ++ aufs_bindex_t hi_id; ++#ifdef CONFIG_AUFS_HINOTIFY ++ struct au_hinotify *hi_notify; ++#endif ++ ++ /* reference to the copied-up whiteout with get/put */ ++ struct dentry *hi_whdentry; ++}; ++ ++struct au_vdir; ++struct au_iinfo { ++ atomic_t ii_generation; ++ struct super_block *ii_hsb1; /* no get/put */ ++ ++ struct au_rwsem ii_rwsem; ++ aufs_bindex_t ii_bstart, ii_bend; ++ __u32 ii_higen; ++ struct au_hinode *ii_hinode; ++ struct au_vdir *ii_vdir; ++}; ++ ++struct au_icntnr { ++ struct au_iinfo iinfo; ++ struct inode vfs_inode; ++}; ++ ++/* au_pin flags */ ++#define AuPin_DI_LOCKED 1 ++#define AuPin_MNT_WRITE (1 << 1) ++#define au_ftest_pin(flags, name) ((flags) & AuPin_##name) ++#define au_fset_pin(flags, name) { (flags) |= AuPin_##name; } ++#define au_fclr_pin(flags, name) { (flags) &= ~AuPin_##name; } ++ ++struct au_pin { ++ /* input */ ++ struct dentry *dentry; ++ unsigned int udba; ++ unsigned char lsc_di, lsc_hi, flags; ++ aufs_bindex_t bindex; ++ ++ /* output */ ++ struct dentry *parent; ++ struct au_hinode *hdir; ++ struct vfsmount *h_mnt; ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline struct au_iinfo *au_ii(struct inode *inode) ++{ ++ struct au_iinfo *iinfo; ++ ++ iinfo = &(container_of(inode, struct au_icntnr, vfs_inode)->iinfo); ++ if (iinfo->ii_hinode) ++ return iinfo; ++ return NULL; /* debugging bad_inode case */ ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* inode.c */ ++struct inode *au_igrab(struct inode *inode); ++int au_refresh_hinode_self(struct inode *inode, int do_attr); ++int au_refresh_hinode(struct inode *inode, struct dentry *dentry); ++int au_ino(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, ++ unsigned int d_type, ino_t *ino); ++struct inode *au_new_inode(struct dentry *dentry, int must_new); ++int au_test_ro(struct super_block *sb, aufs_bindex_t bindex, ++ struct inode *inode); ++int au_test_h_perm(struct inode *h_inode, int mask); ++int au_test_h_perm_sio(struct inode *h_inode, int mask); ++ ++static inline int au_wh_ino(struct super_block *sb, aufs_bindex_t bindex, ++ ino_t h_ino, unsigned int d_type, ino_t *ino) ++{ ++#ifdef CONFIG_AUFS_SHWH ++ return au_ino(sb, bindex, h_ino, d_type, ino); ++#else ++ return 0; ++#endif ++} ++ ++/* i_op.c */ ++extern struct inode_operations aufs_iop, aufs_symlink_iop, aufs_dir_iop; ++ ++/* au_wr_dir flags */ ++#define AuWrDir_ADD_ENTRY 1 ++#define AuWrDir_ISDIR (1 << 1) ++#define au_ftest_wrdir(flags, name) ((flags) & AuWrDir_##name) ++#define au_fset_wrdir(flags, name) { (flags) |= AuWrDir_##name; } ++#define au_fclr_wrdir(flags, name) { (flags) &= ~AuWrDir_##name; } ++ ++struct au_wr_dir_args { ++ aufs_bindex_t force_btgt; ++ unsigned char flags; ++}; ++int au_wr_dir(struct dentry *dentry, struct dentry *src_dentry, ++ struct au_wr_dir_args *args); ++ ++struct dentry *au_pinned_h_parent(struct au_pin *pin); ++void au_pin_init(struct au_pin *pin, struct dentry *dentry, ++ aufs_bindex_t bindex, int lsc_di, int lsc_hi, ++ unsigned int udba, unsigned char flags); ++int au_pin(struct au_pin *pin, struct dentry *dentry, aufs_bindex_t bindex, ++ unsigned int udba, unsigned char flags) __must_check; ++int au_do_pin(struct au_pin *pin) __must_check; ++void au_unpin(struct au_pin *pin); ++ ++/* i_op_add.c */ ++int au_may_add(struct dentry *dentry, aufs_bindex_t bindex, ++ struct dentry *h_parent, int isdir); ++int aufs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev); ++int aufs_symlink(struct inode *dir, struct dentry *dentry, const char *symname); ++int aufs_create(struct inode *dir, struct dentry *dentry, int mode, ++ struct nameidata *nd); ++int aufs_link(struct dentry *src_dentry, struct inode *dir, ++ struct dentry *dentry); ++int aufs_mkdir(struct inode *dir, struct dentry *dentry, int mode); ++ ++/* i_op_del.c */ ++int au_wr_dir_need_wh(struct dentry *dentry, int isdir, aufs_bindex_t *bcpup); ++int au_may_del(struct dentry *dentry, aufs_bindex_t bindex, ++ struct dentry *h_parent, int isdir); ++int aufs_unlink(struct inode *dir, struct dentry *dentry); ++int aufs_rmdir(struct inode *dir, struct dentry *dentry); ++ ++/* i_op_ren.c */ ++int au_wbr(struct dentry *dentry, aufs_bindex_t btgt); ++int aufs_rename(struct inode *src_dir, struct dentry *src_dentry, ++ struct inode *dir, struct dentry *dentry); ++ ++/* iinfo.c */ ++struct inode *au_h_iptr(struct inode *inode, aufs_bindex_t bindex); ++void au_hiput(struct au_hinode *hinode); ++void au_set_ibstart(struct inode *inode, aufs_bindex_t bindex); ++void au_set_hi_wh(struct inode *inode, aufs_bindex_t bindex, ++ struct dentry *h_wh); ++unsigned int au_hi_flags(struct inode *inode, int isdir); ++ ++/* hinode flags */ ++#define AuHi_XINO 1 ++#define AuHi_HINOTIFY (1 << 1) ++#define au_ftest_hi(flags, name) ((flags) & AuHi_##name) ++#define au_fset_hi(flags, name) { (flags) |= AuHi_##name; } ++#define au_fclr_hi(flags, name) { (flags) &= ~AuHi_##name; } ++ ++#ifndef CONFIG_AUFS_HINOTIFY ++#undef AuHi_HINOTIFY ++#define AuHi_HINOTIFY 0 ++#endif ++ ++void au_set_h_iptr(struct inode *inode, aufs_bindex_t bindex, ++ struct inode *h_inode, unsigned int flags); ++ ++void au_update_iigen(struct inode *inode); ++void au_update_brange(struct inode *inode, int do_put_zero); ++ ++int au_iinfo_init(struct inode *inode); ++void au_iinfo_fin(struct inode *inode); ++int au_ii_realloc(struct au_iinfo *iinfo, int nbr); ++ ++/* plink.c */ ++void au_plink_maint_block(struct super_block *sb); ++void au_plink_maint_leave(struct file *file); ++#ifdef CONFIG_AUFS_DEBUG ++void au_plink_list(struct super_block *sb); ++#else ++AuStubVoid(au_plink_list, struct super_block *sb) ++#endif ++int au_plink_test(struct inode *inode); ++struct dentry *au_plink_lkup(struct inode *inode, aufs_bindex_t bindex); ++void au_plink_append(struct inode *inode, aufs_bindex_t bindex, ++ struct dentry *h_dentry); ++void au_plink_put(struct super_block *sb); ++void au_plink_half_refresh(struct super_block *sb, aufs_bindex_t br_id); ++long au_plink_ioctl(struct file *file, unsigned int cmd); ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* lock subclass for iinfo */ ++enum { ++ AuLsc_II_CHILD, /* child first */ ++ AuLsc_II_CHILD2, /* rename(2), link(2), and cpup at hinotify */ ++ AuLsc_II_CHILD3, /* copyup dirs */ ++ AuLsc_II_PARENT, /* see AuLsc_I_PARENT in vfsub.h */ ++ AuLsc_II_PARENT2, ++ AuLsc_II_PARENT3, /* copyup dirs */ ++ AuLsc_II_NEW_CHILD ++}; ++ ++/* ++ * ii_read_lock_child, ii_write_lock_child, ++ * ii_read_lock_child2, ii_write_lock_child2, ++ * ii_read_lock_child3, ii_write_lock_child3, ++ * ii_read_lock_parent, ii_write_lock_parent, ++ * ii_read_lock_parent2, ii_write_lock_parent2, ++ * ii_read_lock_parent3, ii_write_lock_parent3, ++ * ii_read_lock_new_child, ii_write_lock_new_child, ++ */ ++#define AuReadLockFunc(name, lsc) \ ++static inline void ii_read_lock_##name(struct inode *i) \ ++{ \ ++ au_rw_read_lock_nested(&au_ii(i)->ii_rwsem, AuLsc_II_##lsc); \ ++} ++ ++#define AuWriteLockFunc(name, lsc) \ ++static inline void ii_write_lock_##name(struct inode *i) \ ++{ \ ++ au_rw_write_lock_nested(&au_ii(i)->ii_rwsem, AuLsc_II_##lsc); \ ++} ++ ++#define AuRWLockFuncs(name, lsc) \ ++ AuReadLockFunc(name, lsc) \ ++ AuWriteLockFunc(name, lsc) ++ ++AuRWLockFuncs(child, CHILD); ++AuRWLockFuncs(child2, CHILD2); ++AuRWLockFuncs(child3, CHILD3); ++AuRWLockFuncs(parent, PARENT); ++AuRWLockFuncs(parent2, PARENT2); ++AuRWLockFuncs(parent3, PARENT3); ++AuRWLockFuncs(new_child, NEW_CHILD); ++ ++#undef AuReadLockFunc ++#undef AuWriteLockFunc ++#undef AuRWLockFuncs ++ ++/* ++ * ii_read_unlock, ii_write_unlock, ii_downgrade_lock ++ */ ++AuSimpleUnlockRwsemFuncs(ii, struct inode *i, &au_ii(i)->ii_rwsem); ++ ++#define IiMustNoWaiters(i) AuRwMustNoWaiters(&au_ii(i)->ii_rwsem) ++#define IiMustAnyLock(i) AuRwMustAnyLock(&au_ii(i)->ii_rwsem) ++#define IiMustWriteLock(i) AuRwMustWriteLock(&au_ii(i)->ii_rwsem) ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline unsigned int au_iigen(struct inode *inode) ++{ ++ return atomic_read(&au_ii(inode)->ii_generation); ++} ++ ++/* tiny test for inode number */ ++/* tmpfs generation is too rough */ ++static inline int au_test_higen(struct inode *inode, struct inode *h_inode) ++{ ++ struct au_iinfo *iinfo; ++ ++ iinfo = au_ii(inode); ++ AuRwMustAnyLock(&iinfo->ii_rwsem); ++ return !(iinfo->ii_hsb1 == h_inode->i_sb ++ && iinfo->ii_higen == h_inode->i_generation); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline aufs_bindex_t au_ii_br_id(struct inode *inode, ++ aufs_bindex_t bindex) ++{ ++ IiMustAnyLock(inode); ++ return au_ii(inode)->ii_hinode[0 + bindex].hi_id; ++} ++ ++static inline aufs_bindex_t au_ibstart(struct inode *inode) ++{ ++ IiMustAnyLock(inode); ++ return au_ii(inode)->ii_bstart; ++} ++ ++static inline aufs_bindex_t au_ibend(struct inode *inode) ++{ ++ IiMustAnyLock(inode); ++ return au_ii(inode)->ii_bend; ++} ++ ++static inline struct au_vdir *au_ivdir(struct inode *inode) ++{ ++ IiMustAnyLock(inode); ++ return au_ii(inode)->ii_vdir; ++} ++ ++static inline struct dentry *au_hi_wh(struct inode *inode, aufs_bindex_t bindex) ++{ ++ IiMustAnyLock(inode); ++ return au_ii(inode)->ii_hinode[0 + bindex].hi_whdentry; ++} ++ ++static inline void au_set_ibend(struct inode *inode, aufs_bindex_t bindex) ++{ ++ IiMustWriteLock(inode); ++ au_ii(inode)->ii_bend = bindex; ++} ++ ++static inline void au_set_ivdir(struct inode *inode, struct au_vdir *vdir) ++{ ++ IiMustWriteLock(inode); ++ au_ii(inode)->ii_vdir = vdir; ++} ++ ++static inline struct au_hinode *au_hi(struct inode *inode, aufs_bindex_t bindex) ++{ ++ IiMustAnyLock(inode); ++ return au_ii(inode)->ii_hinode + bindex; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline struct dentry *au_pinned_parent(struct au_pin *pin) ++{ ++ if (pin) ++ return pin->parent; ++ return NULL; ++} ++ ++static inline struct inode *au_pinned_h_dir(struct au_pin *pin) ++{ ++ if (pin && pin->hdir) ++ return pin->hdir->hi_inode; ++ return NULL; ++} ++ ++static inline struct au_hinode *au_pinned_hdir(struct au_pin *pin) ++{ ++ if (pin) ++ return pin->hdir; ++ return NULL; ++} ++ ++static inline void au_pin_set_dentry(struct au_pin *pin, struct dentry *dentry) ++{ ++ if (pin) ++ pin->dentry = dentry; ++} ++ ++static inline void au_pin_set_parent_lflag(struct au_pin *pin, ++ unsigned char lflag) ++{ ++ if (pin) { ++ /* dirty macros require brackets */ ++ if (lflag) { ++ au_fset_pin(pin->flags, DI_LOCKED); ++ } else { ++ au_fclr_pin(pin->flags, DI_LOCKED); ++ } ++ } ++} ++ ++static inline void au_pin_set_parent(struct au_pin *pin, struct dentry *parent) ++{ ++ if (pin) { ++ dput(pin->parent); ++ pin->parent = dget(parent); ++ } ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++#ifdef CONFIG_AUFS_HINOTIFY ++/* hinotify.c */ ++int au_hin_alloc(struct au_hinode *hinode, struct inode *inode, ++ struct inode *h_inode); ++void au_hin_free(struct au_hinode *hinode); ++void au_hin_ctl(struct au_hinode *hinode, int do_set); ++void au_reset_hinotify(struct inode *inode, unsigned int flags); ++ ++int __init au_hinotify_init(void); ++void au_hinotify_fin(void); ++ ++static inline ++void au_hin_init(struct au_hinode *hinode, struct au_hinotify *val) ++{ ++ hinode->hi_notify = val; ++} ++ ++static inline void au_iigen_dec(struct inode *inode) ++{ ++ atomic_dec_return(&au_ii(inode)->ii_generation); ++} ++ ++#else ++static inline ++int au_hin_alloc(struct au_hinode *hinode __maybe_unused, ++ struct inode *inode __maybe_unused, ++ struct inode *h_inode __maybe_unused) ++{ ++ return -EOPNOTSUPP; ++} ++ ++AuStubVoid(au_hin_free, struct au_hinode *hinode __maybe_unused) ++AuStubVoid(au_hin_ctl, struct au_hinode *hinode __maybe_unused, ++ int do_set __maybe_unused) ++AuStubVoid(au_reset_hinotify, struct inode *inode __maybe_unused, ++ unsigned int flags __maybe_unused) ++AuStubInt0(__init au_hinotify_init, void) ++AuStubVoid(au_hinotify_fin, void) ++AuStubVoid(au_hin_init, struct au_hinode *hinode __maybe_unused, ++ struct au_hinotify *val __maybe_unused) ++#endif /* CONFIG_AUFS_HINOTIFY */ ++ ++static inline void au_hin_suspend(struct au_hinode *hdir) ++{ ++ au_hin_ctl(hdir, /*do_set*/0); ++} ++ ++static inline void au_hin_resume(struct au_hinode *hdir) ++{ ++ au_hin_ctl(hdir, /*do_set*/1); ++} ++ ++static inline void au_hin_imtx_lock(struct au_hinode *hdir) ++{ ++ mutex_lock(&hdir->hi_inode->i_mutex); ++ au_hin_suspend(hdir); ++} ++ ++static inline void au_hin_imtx_lock_nested(struct au_hinode *hdir, ++ unsigned int sc __maybe_unused) ++{ ++ mutex_lock_nested(&hdir->hi_inode->i_mutex, sc); ++ au_hin_suspend(hdir); ++} ++ ++static inline void au_hin_imtx_unlock(struct au_hinode *hdir) ++{ ++ au_hin_resume(hdir); ++ mutex_unlock(&hdir->hi_inode->i_mutex); ++} ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_INODE_H__ */ +diff --git a/fs/aufs/ioctl.c b/fs/aufs/ioctl.c +new file mode 100644 +index 0000000..0bc81a0 +--- /dev/null ++++ b/fs/aufs/ioctl.c +@@ -0,0 +1,129 @@ ++/* ++ * Copyright (C) 2005-2010 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* ++ * ioctl ++ * plink-management and readdir in userspace. ++ * assist the pathconf(3) wrapper library. ++ */ ++ ++#include ++#include "aufs.h" ++ ++static int au_wbr_fd(struct path *path) ++{ ++ int err, fd, flags; ++ aufs_bindex_t wbi, bindex, bend; ++ struct file *h_file; ++ struct super_block *sb; ++ struct dentry *root; ++ struct au_branch *wbr; ++ ++ err = get_unused_fd(); ++ if (unlikely(err < 0)) ++ goto out; ++ fd = err; ++ ++ flags = O_RDONLY | O_DIRECTORY; ++ if (force_o_largefile()) ++ flags |= O_LARGEFILE; ++ ++ wbi = 0; ++ sb = path->dentry->d_sb; ++ root = sb->s_root; ++ aufs_read_lock(root, AuLock_IR); ++ wbr = au_sbr(sb, wbi); ++ if (!(path->mnt->mnt_flags & MNT_READONLY) ++ && !au_br_writable(wbr->br_perm)) { ++ bend = au_sbend(sb); ++ for (bindex = 1; bindex <= bend; bindex++) { ++ wbr = au_sbr(sb, bindex); ++ if (au_br_writable(wbr->br_perm)) { ++ wbi = bindex; ++ break; ++ } ++ } ++ wbr = au_sbr(sb, wbi); ++ } ++ AuDbg("wbi %d\n", wbi); ++ h_file = au_h_open(root, wbi, flags, NULL); ++ aufs_read_unlock(root, AuLock_IR); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out_fd; ++ ++ atomic_dec(&wbr->br_count); /* cf. au_h_open() */ ++ fd_install(fd, h_file); ++ err = fd; ++ goto out; /* success */ ++ ++ out_fd: ++ put_unused_fd(fd); ++ out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++long aufs_ioctl_dir(struct file *file, unsigned int cmd, unsigned long arg) ++{ ++ long err; ++ ++ switch (cmd) { ++ case AUFS_CTL_PLINK_MAINT: ++ case AUFS_CTL_PLINK_CLEAN: ++ err = au_plink_ioctl(file, cmd); ++ break; ++ ++ case AUFS_CTL_RDU: ++ case AUFS_CTL_RDU_INO: ++ err = au_rdu_ioctl(file, cmd, arg); ++ break; ++ ++ case AUFS_CTL_WBR_FD: ++ err = au_wbr_fd(&file->f_path); ++ break; ++ ++ default: ++ /* do not call the lower */ ++ AuDbg("0x%x\n", cmd); ++ err = -ENOTTY; ++ } ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++long aufs_ioctl_nondir(struct file *file, unsigned int cmd, unsigned long arg) ++{ ++ long err; ++ ++ switch (cmd) { ++ case AUFS_CTL_WBR_FD: ++ err = au_wbr_fd(&file->f_path); ++ break; ++ ++ default: ++ /* do not call the lower */ ++ AuDbg("0x%x\n", cmd); ++ err = -ENOTTY; ++ } ++ ++ AuTraceErr(err); ++ return err; ++} +diff --git a/fs/aufs/loop.c b/fs/aufs/loop.c +new file mode 100644 +index 0000000..5fceec7 +--- /dev/null ++++ b/fs/aufs/loop.c +@@ -0,0 +1,55 @@ ++/* ++ * Copyright (C) 2005-2010 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* ++ * support for loopback block device as a branch ++ */ ++ ++#include ++#include "aufs.h" ++ ++/* ++ * test if two lower dentries have overlapping branches. ++ */ ++int au_test_loopback_overlap(struct super_block *sb, struct dentry *h_d1, ++ struct dentry *h_d2) ++{ ++ struct inode *h_inode; ++ struct loop_device *l; ++ ++ h_inode = h_d1->d_inode; ++ if (MAJOR(h_inode->i_sb->s_dev) != LOOP_MAJOR) ++ return 0; ++ ++ l = h_inode->i_sb->s_bdev->bd_disk->private_data; ++ h_d1 = l->lo_backing_file->f_dentry; ++ /* h_d1 can be local NFS. in this case aufs cannot detect the loop */ ++ if (unlikely(h_d1->d_sb == sb)) ++ return 1; ++ return !!au_test_subdir(h_d1, h_d2); ++} ++ ++/* true if a kernel thread named 'loop[0-9].*' accesses a file */ ++int au_test_loopback_kthread(void) ++{ ++ const char c = current->comm[4]; ++ ++ return current->mm == NULL ++ && '0' <= c && c <= '9' ++ && strncmp(current->comm, "loop", 4) == 0; ++} +diff --git a/fs/aufs/loop.h b/fs/aufs/loop.h +new file mode 100644 +index 0000000..e655b4f +--- /dev/null ++++ b/fs/aufs/loop.h +@@ -0,0 +1,43 @@ ++/* ++ * Copyright (C) 2005-2010 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* ++ * support for loopback mount as a branch ++ */ ++ ++#ifndef __AUFS_LOOP_H__ ++#define __AUFS_LOOP_H__ ++ ++#ifdef __KERNEL__ ++ ++struct dentry; ++struct super_block; ++ ++#ifdef CONFIG_AUFS_BDEV_LOOP ++/* loop.c */ ++int au_test_loopback_overlap(struct super_block *sb, struct dentry *h_d1, ++ struct dentry *h_d2); ++int au_test_loopback_kthread(void); ++#else ++AuStubInt0(au_test_loopback_overlap, struct super_block *sb, ++ struct dentry *h_d1, struct dentry *h_d2) ++AuStubInt0(au_test_loopback_kthread, void) ++#endif /* BLK_DEV_LOOP */ ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_LOOP_H__ */ +diff --git a/fs/aufs/magic.mk b/fs/aufs/magic.mk +new file mode 100644 +index 0000000..3e6387b +--- /dev/null ++++ b/fs/aufs/magic.mk +@@ -0,0 +1,54 @@ ++ ++# defined in ${srctree}/fs/fuse/inode.c ++# tristate ++ifdef CONFIG_FUSE_FS ++ccflags-y += -DFUSE_SUPER_MAGIC=0x65735546 ++endif ++ ++# defined in ${srctree}/fs/ocfs2/ocfs2_fs.h ++# tristate ++ifdef CONFIG_OCFS2_FS ++ccflags-y += -DOCFS2_SUPER_MAGIC=0x7461636f ++endif ++ ++# defined in ${srctree}/fs/ocfs2/dlm/userdlm.h ++# tristate ++ifdef CONFIG_OCFS2_FS_O2CB ++ccflags-y += -DDLMFS_MAGIC=0x76a9f425 ++endif ++ ++# defined in ${srctree}/fs/cifs/cifsfs.c ++# tristate ++ifdef CONFIG_CIFS_FS ++ccflags-y += -DCIFS_MAGIC_NUMBER=0xFF534D42 ++endif ++ ++# defined in ${srctree}/fs/xfs/xfs_sb.h ++# tristate ++ifdef CONFIG_XFS_FS ++ccflags-y += -DXFS_SB_MAGIC=0x58465342 ++endif ++ ++# defined in ${srctree}/fs/configfs/mount.c ++# tristate ++ifdef CONFIG_CONFIGFS_FS ++ccflags-y += -DCONFIGFS_MAGIC=0x62656570 ++endif ++ ++# defined in ${srctree}/fs/9p/v9fs.h ++# tristate ++ifdef CONFIG_9P_FS ++ccflags-y += -DV9FS_MAGIC=0x01021997 ++endif ++ ++# defined in ${srctree}/fs/ubifs/ubifs.h ++# tristate ++ifdef CONFIG_UBIFS_FS ++ccflags-y += -DUBIFS_SUPER_MAGIC=0x24051905 ++endif ++ ++# defined in ${srctree}/fs/hfsplus/hfsplus_raw.h ++# tristate ++ifdef CONFIG_HFSPLUS_FS ++ccflags-y += -DHFSPLUS_SUPER_MAGIC=0x482b ++endif +diff --git a/fs/aufs/module.c b/fs/aufs/module.c +new file mode 100644 +index 0000000..bfaa7e6 +--- /dev/null ++++ b/fs/aufs/module.c +@@ -0,0 +1,166 @@ ++/* ++ * Copyright (C) 2005-2010 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* ++ * module global variables and operations ++ */ ++ ++#include ++#include ++#include "aufs.h" ++ ++void *au_kzrealloc(void *p, unsigned int nused, unsigned int new_sz, gfp_t gfp) ++{ ++ if (new_sz <= nused) ++ return p; ++ ++ p = krealloc(p, new_sz, gfp); ++ if (p) ++ memset(p + nused, 0, new_sz - nused); ++ return p; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * aufs caches ++ */ ++struct kmem_cache *au_cachep[AuCache_Last]; ++static int __init au_cache_init(void) ++{ ++ au_cachep[AuCache_DINFO] = AuCache(au_dinfo); ++ if (au_cachep[AuCache_DINFO]) ++ au_cachep[AuCache_ICNTNR] = AuCache(au_icntnr); ++ if (au_cachep[AuCache_ICNTNR]) ++ au_cachep[AuCache_FINFO] = AuCache(au_finfo); ++ if (au_cachep[AuCache_FINFO]) ++ au_cachep[AuCache_VDIR] = AuCache(au_vdir); ++ if (au_cachep[AuCache_VDIR]) ++ au_cachep[AuCache_DEHSTR] = AuCache(au_vdir_dehstr); ++ if (au_cachep[AuCache_DEHSTR]) ++ return 0; ++ ++ return -ENOMEM; ++} ++ ++static void au_cache_fin(void) ++{ ++ int i; ++ ++ /* including AuCache_HINOTIFY */ ++ for (i = 0; i < AuCache_Last; i++) ++ if (au_cachep[i]) { ++ kmem_cache_destroy(au_cachep[i]); ++ au_cachep[i] = NULL; ++ } ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_dir_roflags; ++ ++/* ++ * functions for module interface. ++ */ ++MODULE_LICENSE("GPL"); ++/* MODULE_LICENSE("GPL v2"); */ ++MODULE_AUTHOR("Junjiro R. Okajima "); ++MODULE_DESCRIPTION(AUFS_NAME ++ " -- Advanced multi layered unification filesystem"); ++MODULE_VERSION(AUFS_VERSION); ++ ++/* this module parameter has no meaning when SYSFS is disabled */ ++int sysaufs_brs = 1; ++MODULE_PARM_DESC(brs, "use /fs/aufs/si_*/brN"); ++module_param_named(brs, sysaufs_brs, int, S_IRUGO); ++ ++/* ---------------------------------------------------------------------- */ ++ ++static char au_esc_chars[0x20 + 3]; /* 0x01-0x20, backslash, del, and NULL */ ++ ++int au_seq_path(struct seq_file *seq, struct path *path) ++{ ++ return seq_path(seq, path, au_esc_chars); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int __init aufs_init(void) ++{ ++ int err, i; ++ char *p; ++ ++ p = au_esc_chars; ++ for (i = 1; i <= ' '; i++) ++ *p++ = i; ++ *p++ = '\\'; ++ *p++ = '\x7f'; ++ *p = 0; ++ ++ au_dir_roflags = au_file_roflags(O_DIRECTORY | O_LARGEFILE); ++ ++ sysaufs_brs_init(); ++ au_debug_init(); ++ err = sysaufs_init(); ++ if (unlikely(err)) ++ goto out; ++ err = au_wkq_init(); ++ if (unlikely(err)) ++ goto out_sysaufs; ++ err = au_hinotify_init(); ++ if (unlikely(err)) ++ goto out_wkq; ++ err = au_sysrq_init(); ++ if (unlikely(err)) ++ goto out_hin; ++ err = au_cache_init(); ++ if (unlikely(err)) ++ goto out_sysrq; ++ err = register_filesystem(&aufs_fs_type); ++ if (unlikely(err)) ++ goto out_cache; ++ /* since we define pr_fmt, call printk directly */ ++ printk(KERN_INFO AUFS_NAME " " AUFS_VERSION "\n"); ++ goto out; /* success */ ++ ++ out_cache: ++ au_cache_fin(); ++ out_sysrq: ++ au_sysrq_fin(); ++ out_hin: ++ au_hinotify_fin(); ++ out_wkq: ++ au_wkq_fin(); ++ out_sysaufs: ++ sysaufs_fin(); ++ out: ++ return err; ++} ++ ++static void __exit aufs_exit(void) ++{ ++ unregister_filesystem(&aufs_fs_type); ++ au_cache_fin(); ++ au_sysrq_fin(); ++ au_hinotify_fin(); ++ au_wkq_fin(); ++ sysaufs_fin(); ++} ++ ++module_init(aufs_init); ++module_exit(aufs_exit); +diff --git a/fs/aufs/module.h b/fs/aufs/module.h +new file mode 100644 +index 0000000..267ab16 +--- /dev/null ++++ b/fs/aufs/module.h +@@ -0,0 +1,77 @@ ++/* ++ * Copyright (C) 2005-2010 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* ++ * module initialization and module-global ++ */ ++ ++#ifndef __AUFS_MODULE_H__ ++#define __AUFS_MODULE_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++ ++struct path; ++struct seq_file; ++ ++/* module parameters */ ++extern int sysaufs_brs; ++ ++/* ---------------------------------------------------------------------- */ ++ ++extern int au_dir_roflags; ++ ++void *au_kzrealloc(void *p, unsigned int nused, unsigned int new_sz, gfp_t gfp); ++int au_seq_path(struct seq_file *seq, struct path *path); ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* kmem cache */ ++enum { ++ AuCache_DINFO, ++ AuCache_ICNTNR, ++ AuCache_FINFO, ++ AuCache_VDIR, ++ AuCache_DEHSTR, ++#ifdef CONFIG_AUFS_HINOTIFY ++ AuCache_HINOTIFY, ++#endif ++ AuCache_Last ++}; ++ ++#define AuCache(type) KMEM_CACHE(type, SLAB_RECLAIM_ACCOUNT | SLAB_MEM_SPREAD) ++ ++extern struct kmem_cache *au_cachep[]; ++ ++#define AuCacheFuncs(name, index) \ ++static inline struct au_##name *au_cache_alloc_##name(void) \ ++{ return kmem_cache_alloc(au_cachep[AuCache_##index], GFP_NOFS); } \ ++static inline void au_cache_free_##name(struct au_##name *p) \ ++{ kmem_cache_free(au_cachep[AuCache_##index], p); } ++ ++AuCacheFuncs(dinfo, DINFO); ++AuCacheFuncs(icntnr, ICNTNR); ++AuCacheFuncs(finfo, FINFO); ++AuCacheFuncs(vdir, VDIR); ++AuCacheFuncs(vdir_dehstr, DEHSTR); ++ ++/* ---------------------------------------------------------------------- */ ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_MODULE_H__ */ +diff --git a/fs/aufs/opts.c b/fs/aufs/opts.c +new file mode 100644 +index 0000000..a4b330d +--- /dev/null ++++ b/fs/aufs/opts.c +@@ -0,0 +1,1549 @@ ++/* ++ * Copyright (C) 2005-2010 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* ++ * mount options/flags ++ */ ++ ++#include ++#include ++#include /* a distribution requires */ ++#include ++#include "aufs.h" ++ ++/* ---------------------------------------------------------------------- */ ++ ++enum { ++ Opt_br, ++ Opt_add, Opt_del, Opt_mod, Opt_reorder, Opt_append, Opt_prepend, ++ Opt_idel, Opt_imod, Opt_ireorder, ++ Opt_dirwh, Opt_rdcache, Opt_rdblk, Opt_rdhash, Opt_rendir, ++ Opt_rdblk_def, Opt_rdhash_def, ++ Opt_xino, Opt_zxino, Opt_noxino, ++ Opt_trunc_xino, Opt_trunc_xino_v, Opt_notrunc_xino, ++ Opt_trunc_xino_path, Opt_itrunc_xino, ++ Opt_trunc_xib, Opt_notrunc_xib, ++ Opt_shwh, Opt_noshwh, ++ Opt_plink, Opt_noplink, Opt_list_plink, ++ Opt_udba, ++ /* Opt_lock, Opt_unlock, */ ++ Opt_cmd, Opt_cmd_args, ++ Opt_diropq_a, Opt_diropq_w, ++ Opt_warn_perm, Opt_nowarn_perm, ++ Opt_wbr_copyup, Opt_wbr_create, ++ Opt_refrof, Opt_norefrof, ++ Opt_verbose, Opt_noverbose, ++ Opt_sum, Opt_nosum, Opt_wsum, ++ Opt_tail, Opt_ignore, Opt_ignore_silent, Opt_err ++}; ++ ++static match_table_t options = { ++ {Opt_br, "br=%s"}, ++ {Opt_br, "br:%s"}, ++ ++ {Opt_add, "add=%d:%s"}, ++ {Opt_add, "add:%d:%s"}, ++ {Opt_add, "ins=%d:%s"}, ++ {Opt_add, "ins:%d:%s"}, ++ {Opt_append, "append=%s"}, ++ {Opt_append, "append:%s"}, ++ {Opt_prepend, "prepend=%s"}, ++ {Opt_prepend, "prepend:%s"}, ++ ++ {Opt_del, "del=%s"}, ++ {Opt_del, "del:%s"}, ++ /* {Opt_idel, "idel:%d"}, */ ++ {Opt_mod, "mod=%s"}, ++ {Opt_mod, "mod:%s"}, ++ /* {Opt_imod, "imod:%d:%s"}, */ ++ ++ {Opt_dirwh, "dirwh=%d"}, ++ ++ {Opt_xino, "xino=%s"}, ++ {Opt_noxino, "noxino"}, ++ {Opt_trunc_xino, "trunc_xino"}, ++ {Opt_trunc_xino_v, "trunc_xino_v=%d:%d"}, ++ {Opt_notrunc_xino, "notrunc_xino"}, ++ {Opt_trunc_xino_path, "trunc_xino=%s"}, ++ {Opt_itrunc_xino, "itrunc_xino=%d"}, ++ /* {Opt_zxino, "zxino=%s"}, */ ++ {Opt_trunc_xib, "trunc_xib"}, ++ {Opt_notrunc_xib, "notrunc_xib"}, ++ ++ {Opt_plink, "plink"}, ++ {Opt_noplink, "noplink"}, ++#ifdef CONFIG_AUFS_DEBUG ++ {Opt_list_plink, "list_plink"}, ++#endif ++ ++ {Opt_udba, "udba=%s"}, ++ ++ {Opt_diropq_a, "diropq=always"}, ++ {Opt_diropq_a, "diropq=a"}, ++ {Opt_diropq_w, "diropq=whiteouted"}, ++ {Opt_diropq_w, "diropq=w"}, ++ ++ {Opt_warn_perm, "warn_perm"}, ++ {Opt_nowarn_perm, "nowarn_perm"}, ++ ++ /* keep them temporary */ ++ {Opt_ignore_silent, "coo=%s"}, ++ {Opt_ignore_silent, "nodlgt"}, ++ {Opt_ignore_silent, "nodirperm1"}, ++ {Opt_ignore_silent, "clean_plink"}, ++ ++#ifdef CONFIG_AUFS_SHWH ++ {Opt_shwh, "shwh"}, ++#endif ++ {Opt_noshwh, "noshwh"}, ++ ++ {Opt_rendir, "rendir=%d"}, ++ ++ {Opt_refrof, "refrof"}, ++ {Opt_norefrof, "norefrof"}, ++ ++ {Opt_verbose, "verbose"}, ++ {Opt_verbose, "v"}, ++ {Opt_noverbose, "noverbose"}, ++ {Opt_noverbose, "quiet"}, ++ {Opt_noverbose, "q"}, ++ {Opt_noverbose, "silent"}, ++ ++ {Opt_sum, "sum"}, ++ {Opt_nosum, "nosum"}, ++ {Opt_wsum, "wsum"}, ++ ++ {Opt_rdcache, "rdcache=%d"}, ++ {Opt_rdblk, "rdblk=%d"}, ++ {Opt_rdblk_def, "rdblk=def"}, ++ {Opt_rdhash, "rdhash=%d"}, ++ {Opt_rdhash_def, "rdhash=def"}, ++ ++ {Opt_wbr_create, "create=%s"}, ++ {Opt_wbr_create, "create_policy=%s"}, ++ {Opt_wbr_copyup, "cpup=%s"}, ++ {Opt_wbr_copyup, "copyup=%s"}, ++ {Opt_wbr_copyup, "copyup_policy=%s"}, ++ ++ /* internal use for the scripts */ ++ {Opt_ignore_silent, "si=%s"}, ++ ++ {Opt_br, "dirs=%s"}, ++ {Opt_ignore, "debug=%d"}, ++ {Opt_ignore, "delete=whiteout"}, ++ {Opt_ignore, "delete=all"}, ++ {Opt_ignore, "imap=%s"}, ++ ++ /* temporary workaround, due to old mount(8)? */ ++ {Opt_ignore_silent, "relatime"}, ++ ++ {Opt_err, NULL} ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++static const char *au_parser_pattern(int val, struct match_token *token) ++{ ++ while (token->pattern) { ++ if (token->token == val) ++ return token->pattern; ++ token++; ++ } ++ BUG(); ++ return "??"; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static match_table_t brperms = { ++ {AuBrPerm_RO, AUFS_BRPERM_RO}, ++ {AuBrPerm_RR, AUFS_BRPERM_RR}, ++ {AuBrPerm_RW, AUFS_BRPERM_RW}, ++ ++ {AuBrPerm_ROWH, AUFS_BRPERM_ROWH}, ++ {AuBrPerm_RRWH, AUFS_BRPERM_RRWH}, ++ {AuBrPerm_RWNoLinkWH, AUFS_BRPERM_RWNLWH}, ++ ++ {AuBrPerm_ROWH, "nfsro"}, ++ {AuBrPerm_RO, NULL} ++}; ++ ++static int noinline_for_stack br_perm_val(char *perm) ++{ ++ int val; ++ substring_t args[MAX_OPT_ARGS]; ++ ++ val = match_token(perm, brperms, args); ++ return val; ++} ++ ++const char *au_optstr_br_perm(int brperm) ++{ ++ return au_parser_pattern(brperm, (void *)brperms); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static match_table_t udbalevel = { ++ {AuOpt_UDBA_REVAL, "reval"}, ++ {AuOpt_UDBA_NONE, "none"}, ++#ifdef CONFIG_AUFS_HINOTIFY ++ {AuOpt_UDBA_HINOTIFY, "inotify"}, ++#endif ++ {-1, NULL} ++}; ++ ++static int noinline_for_stack udba_val(char *str) ++{ ++ substring_t args[MAX_OPT_ARGS]; ++ ++ return match_token(str, udbalevel, args); ++} ++ ++const char *au_optstr_udba(int udba) ++{ ++ return au_parser_pattern(udba, (void *)udbalevel); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static match_table_t au_wbr_create_policy = { ++ {AuWbrCreate_TDP, "tdp"}, ++ {AuWbrCreate_TDP, "top-down-parent"}, ++ {AuWbrCreate_RR, "rr"}, ++ {AuWbrCreate_RR, "round-robin"}, ++ {AuWbrCreate_MFS, "mfs"}, ++ {AuWbrCreate_MFS, "most-free-space"}, ++ {AuWbrCreate_MFSV, "mfs:%d"}, ++ {AuWbrCreate_MFSV, "most-free-space:%d"}, ++ ++ {AuWbrCreate_MFSRR, "mfsrr:%d"}, ++ {AuWbrCreate_MFSRRV, "mfsrr:%d:%d"}, ++ {AuWbrCreate_PMFS, "pmfs"}, ++ {AuWbrCreate_PMFSV, "pmfs:%d"}, ++ ++ {-1, NULL} ++}; ++ ++/* ++ * cf. linux/lib/parser.c and cmdline.c ++ * gave up calling memparse() since it uses simple_strtoull() instead of ++ * strict_...(). ++ */ ++static int noinline_for_stack ++au_match_ull(substring_t *s, unsigned long long *result) ++{ ++ int err; ++ unsigned int len; ++ char a[32]; ++ ++ err = -ERANGE; ++ len = s->to - s->from; ++ if (len + 1 <= sizeof(a)) { ++ memcpy(a, s->from, len); ++ a[len] = '\0'; ++ err = strict_strtoull(a, 0, result); ++ } ++ return err; ++} ++ ++static int au_wbr_mfs_wmark(substring_t *arg, char *str, ++ struct au_opt_wbr_create *create) ++{ ++ int err; ++ unsigned long long ull; ++ ++ err = 0; ++ if (!au_match_ull(arg, &ull)) ++ create->mfsrr_watermark = ull; ++ else { ++ pr_err("bad integer in %s\n", str); ++ err = -EINVAL; ++ } ++ ++ return err; ++} ++ ++static int au_wbr_mfs_sec(substring_t *arg, char *str, ++ struct au_opt_wbr_create *create) ++{ ++ int n, err; ++ ++ err = 0; ++ if (!match_int(arg, &n) && 0 <= n) ++ create->mfs_second = n; ++ else { ++ pr_err("bad integer in %s\n", str); ++ err = -EINVAL; ++ } ++ ++ return err; ++} ++ ++static int noinline_for_stack ++au_wbr_create_val(char *str, struct au_opt_wbr_create *create) ++{ ++ int err, e; ++ substring_t args[MAX_OPT_ARGS]; ++ ++ err = match_token(str, au_wbr_create_policy, args); ++ create->wbr_create = err; ++ switch (err) { ++ case AuWbrCreate_MFSRRV: ++ e = au_wbr_mfs_wmark(&args[0], str, create); ++ if (!e) ++ e = au_wbr_mfs_sec(&args[1], str, create); ++ if (unlikely(e)) ++ err = e; ++ break; ++ case AuWbrCreate_MFSRR: ++ e = au_wbr_mfs_wmark(&args[0], str, create); ++ if (unlikely(e)) { ++ err = e; ++ break; ++ } ++ /*FALLTHROUGH*/ ++ case AuWbrCreate_MFS: ++ case AuWbrCreate_PMFS: ++ create->mfs_second = AUFS_MFS_SECOND_DEF; ++ break; ++ case AuWbrCreate_MFSV: ++ case AuWbrCreate_PMFSV: ++ e = au_wbr_mfs_sec(&args[0], str, create); ++ if (unlikely(e)) ++ err = e; ++ break; ++ } ++ ++ return err; ++} ++ ++const char *au_optstr_wbr_create(int wbr_create) ++{ ++ return au_parser_pattern(wbr_create, (void *)au_wbr_create_policy); ++} ++ ++static match_table_t au_wbr_copyup_policy = { ++ {AuWbrCopyup_TDP, "tdp"}, ++ {AuWbrCopyup_TDP, "top-down-parent"}, ++ {AuWbrCopyup_BUP, "bup"}, ++ {AuWbrCopyup_BUP, "bottom-up-parent"}, ++ {AuWbrCopyup_BU, "bu"}, ++ {AuWbrCopyup_BU, "bottom-up"}, ++ {-1, NULL} ++}; ++ ++static int noinline_for_stack au_wbr_copyup_val(char *str) ++{ ++ substring_t args[MAX_OPT_ARGS]; ++ ++ return match_token(str, au_wbr_copyup_policy, args); ++} ++ ++const char *au_optstr_wbr_copyup(int wbr_copyup) ++{ ++ return au_parser_pattern(wbr_copyup, (void *)au_wbr_copyup_policy); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static const int lkup_dirflags = LOOKUP_FOLLOW | LOOKUP_DIRECTORY; ++ ++static void dump_opts(struct au_opts *opts) ++{ ++#ifdef CONFIG_AUFS_DEBUG ++ /* reduce stack space */ ++ union { ++ struct au_opt_add *add; ++ struct au_opt_del *del; ++ struct au_opt_mod *mod; ++ struct au_opt_xino *xino; ++ struct au_opt_xino_itrunc *xino_itrunc; ++ struct au_opt_wbr_create *create; ++ } u; ++ struct au_opt *opt; ++ ++ opt = opts->opt; ++ while (opt->type != Opt_tail) { ++ switch (opt->type) { ++ case Opt_add: ++ u.add = &opt->add; ++ AuDbg("add {b%d, %s, 0x%x, %p}\n", ++ u.add->bindex, u.add->pathname, u.add->perm, ++ u.add->path.dentry); ++ break; ++ case Opt_del: ++ case Opt_idel: ++ u.del = &opt->del; ++ AuDbg("del {%s, %p}\n", ++ u.del->pathname, u.del->h_path.dentry); ++ break; ++ case Opt_mod: ++ case Opt_imod: ++ u.mod = &opt->mod; ++ AuDbg("mod {%s, 0x%x, %p}\n", ++ u.mod->path, u.mod->perm, u.mod->h_root); ++ break; ++ case Opt_append: ++ u.add = &opt->add; ++ AuDbg("append {b%d, %s, 0x%x, %p}\n", ++ u.add->bindex, u.add->pathname, u.add->perm, ++ u.add->path.dentry); ++ break; ++ case Opt_prepend: ++ u.add = &opt->add; ++ AuDbg("prepend {b%d, %s, 0x%x, %p}\n", ++ u.add->bindex, u.add->pathname, u.add->perm, ++ u.add->path.dentry); ++ break; ++ case Opt_dirwh: ++ AuDbg("dirwh %d\n", opt->dirwh); ++ break; ++ case Opt_rdcache: ++ AuDbg("rdcache %d\n", opt->rdcache); ++ break; ++ case Opt_rdblk: ++ AuDbg("rdblk %u\n", opt->rdblk); ++ break; ++ case Opt_rdblk_def: ++ AuDbg("rdblk_def\n"); ++ break; ++ case Opt_rdhash: ++ AuDbg("rdhash %u\n", opt->rdhash); ++ break; ++ case Opt_rdhash_def: ++ AuDbg("rdhash_def\n"); ++ break; ++ case Opt_xino: ++ u.xino = &opt->xino; ++ AuDbg("xino {%s %.*s}\n", ++ u.xino->path, ++ AuDLNPair(u.xino->file->f_dentry)); ++ break; ++ case Opt_trunc_xino: ++ AuLabel(trunc_xino); ++ break; ++ case Opt_notrunc_xino: ++ AuLabel(notrunc_xino); ++ break; ++ case Opt_trunc_xino_path: ++ case Opt_itrunc_xino: ++ u.xino_itrunc = &opt->xino_itrunc; ++ AuDbg("trunc_xino %d\n", u.xino_itrunc->bindex); ++ break; ++ ++ case Opt_noxino: ++ AuLabel(noxino); ++ break; ++ case Opt_trunc_xib: ++ AuLabel(trunc_xib); ++ break; ++ case Opt_notrunc_xib: ++ AuLabel(notrunc_xib); ++ break; ++ case Opt_shwh: ++ AuLabel(shwh); ++ break; ++ case Opt_noshwh: ++ AuLabel(noshwh); ++ break; ++ case Opt_plink: ++ AuLabel(plink); ++ break; ++ case Opt_noplink: ++ AuLabel(noplink); ++ break; ++ case Opt_list_plink: ++ AuLabel(list_plink); ++ break; ++ case Opt_udba: ++ AuDbg("udba %d, %s\n", ++ opt->udba, au_optstr_udba(opt->udba)); ++ break; ++ case Opt_diropq_a: ++ AuLabel(diropq_a); ++ break; ++ case Opt_diropq_w: ++ AuLabel(diropq_w); ++ break; ++ case Opt_warn_perm: ++ AuLabel(warn_perm); ++ break; ++ case Opt_nowarn_perm: ++ AuLabel(nowarn_perm); ++ break; ++ case Opt_refrof: ++ AuLabel(refrof); ++ break; ++ case Opt_norefrof: ++ AuLabel(norefrof); ++ break; ++ case Opt_verbose: ++ AuLabel(verbose); ++ break; ++ case Opt_noverbose: ++ AuLabel(noverbose); ++ break; ++ case Opt_sum: ++ AuLabel(sum); ++ break; ++ case Opt_nosum: ++ AuLabel(nosum); ++ break; ++ case Opt_wsum: ++ AuLabel(wsum); ++ break; ++ case Opt_wbr_create: ++ u.create = &opt->wbr_create; ++ AuDbg("create %d, %s\n", u.create->wbr_create, ++ au_optstr_wbr_create(u.create->wbr_create)); ++ switch (u.create->wbr_create) { ++ case AuWbrCreate_MFSV: ++ case AuWbrCreate_PMFSV: ++ AuDbg("%d sec\n", u.create->mfs_second); ++ break; ++ case AuWbrCreate_MFSRR: ++ AuDbg("%llu watermark\n", ++ u.create->mfsrr_watermark); ++ break; ++ case AuWbrCreate_MFSRRV: ++ AuDbg("%llu watermark, %d sec\n", ++ u.create->mfsrr_watermark, ++ u.create->mfs_second); ++ break; ++ } ++ break; ++ case Opt_wbr_copyup: ++ AuDbg("copyup %d, %s\n", opt->wbr_copyup, ++ au_optstr_wbr_copyup(opt->wbr_copyup)); ++ break; ++ default: ++ BUG(); ++ } ++ opt++; ++ } ++#endif ++} ++ ++void au_opts_free(struct au_opts *opts) ++{ ++ struct au_opt *opt; ++ ++ opt = opts->opt; ++ while (opt->type != Opt_tail) { ++ switch (opt->type) { ++ case Opt_add: ++ case Opt_append: ++ case Opt_prepend: ++ path_put(&opt->add.path); ++ break; ++ case Opt_del: ++ case Opt_idel: ++ path_put(&opt->del.h_path); ++ break; ++ case Opt_mod: ++ case Opt_imod: ++ dput(opt->mod.h_root); ++ break; ++ case Opt_xino: ++ fput(opt->xino.file); ++ break; ++ } ++ opt++; ++ } ++} ++ ++static int opt_add(struct au_opt *opt, char *opt_str, unsigned long sb_flags, ++ aufs_bindex_t bindex) ++{ ++ int err; ++ struct au_opt_add *add = &opt->add; ++ char *p; ++ ++ add->bindex = bindex; ++ add->perm = AuBrPerm_Last; ++ add->pathname = opt_str; ++ p = strchr(opt_str, '='); ++ if (p) { ++ *p++ = 0; ++ if (*p) ++ add->perm = br_perm_val(p); ++ } ++ ++ err = vfsub_kern_path(add->pathname, lkup_dirflags, &add->path); ++ if (!err) { ++ if (!p) { ++ add->perm = AuBrPerm_RO; ++ if (au_test_fs_rr(add->path.dentry->d_sb)) ++ add->perm = AuBrPerm_RR; ++ else if (!bindex && !(sb_flags & MS_RDONLY)) ++ add->perm = AuBrPerm_RW; ++ } ++ opt->type = Opt_add; ++ goto out; ++ } ++ pr_err("lookup failed %s (%d)\n", add->pathname, err); ++ err = -EINVAL; ++ ++ out: ++ return err; ++} ++ ++static int au_opts_parse_del(struct au_opt_del *del, substring_t args[]) ++{ ++ int err; ++ ++ del->pathname = args[0].from; ++ AuDbg("del path %s\n", del->pathname); ++ ++ err = vfsub_kern_path(del->pathname, lkup_dirflags, &del->h_path); ++ if (unlikely(err)) ++ pr_err("lookup failed %s (%d)\n", del->pathname, err); ++ ++ return err; ++} ++ ++#if 0 /* reserved for future use */ ++static int au_opts_parse_idel(struct super_block *sb, aufs_bindex_t bindex, ++ struct au_opt_del *del, substring_t args[]) ++{ ++ int err; ++ struct dentry *root; ++ ++ err = -EINVAL; ++ root = sb->s_root; ++ aufs_read_lock(root, AuLock_FLUSH); ++ if (bindex < 0 || au_sbend(sb) < bindex) { ++ pr_err("out of bounds, %d\n", bindex); ++ goto out; ++ } ++ ++ err = 0; ++ del->h_path.dentry = dget(au_h_dptr(root, bindex)); ++ del->h_path.mnt = mntget(au_sbr_mnt(sb, bindex)); ++ ++ out: ++ aufs_read_unlock(root, !AuLock_IR); ++ return err; ++} ++#endif ++ ++static int noinline_for_stack ++au_opts_parse_mod(struct au_opt_mod *mod, substring_t args[]) ++{ ++ int err; ++ struct path path; ++ char *p; ++ ++ err = -EINVAL; ++ mod->path = args[0].from; ++ p = strchr(mod->path, '='); ++ if (unlikely(!p)) { ++ pr_err("no permssion %s\n", args[0].from); ++ goto out; ++ } ++ ++ *p++ = 0; ++ err = vfsub_kern_path(mod->path, lkup_dirflags, &path); ++ if (unlikely(err)) { ++ pr_err("lookup failed %s (%d)\n", mod->path, err); ++ goto out; ++ } ++ ++ mod->perm = br_perm_val(p); ++ AuDbg("mod path %s, perm 0x%x, %s\n", mod->path, mod->perm, p); ++ mod->h_root = dget(path.dentry); ++ path_put(&path); ++ ++ out: ++ return err; ++} ++ ++#if 0 /* reserved for future use */ ++static int au_opts_parse_imod(struct super_block *sb, aufs_bindex_t bindex, ++ struct au_opt_mod *mod, substring_t args[]) ++{ ++ int err; ++ struct dentry *root; ++ ++ err = -EINVAL; ++ root = sb->s_root; ++ aufs_read_lock(root, AuLock_FLUSH); ++ if (bindex < 0 || au_sbend(sb) < bindex) { ++ pr_err("out of bounds, %d\n", bindex); ++ goto out; ++ } ++ ++ err = 0; ++ mod->perm = br_perm_val(args[1].from); ++ AuDbg("mod path %s, perm 0x%x, %s\n", ++ mod->path, mod->perm, args[1].from); ++ mod->h_root = dget(au_h_dptr(root, bindex)); ++ ++ out: ++ aufs_read_unlock(root, !AuLock_IR); ++ return err; ++} ++#endif ++ ++static int au_opts_parse_xino(struct super_block *sb, struct au_opt_xino *xino, ++ substring_t args[]) ++{ ++ int err; ++ struct file *file; ++ ++ file = au_xino_create(sb, args[0].from, /*silent*/0); ++ err = PTR_ERR(file); ++ if (IS_ERR(file)) ++ goto out; ++ ++ err = -EINVAL; ++ if (unlikely(file->f_dentry->d_sb == sb)) { ++ fput(file); ++ pr_err("%s must be outside\n", args[0].from); ++ goto out; ++ } ++ ++ err = 0; ++ xino->file = file; ++ xino->path = args[0].from; ++ ++ out: ++ return err; ++} ++ ++static int noinline_for_stack ++au_opts_parse_xino_itrunc_path(struct super_block *sb, ++ struct au_opt_xino_itrunc *xino_itrunc, ++ substring_t args[]) ++{ ++ int err; ++ aufs_bindex_t bend, bindex; ++ struct path path; ++ struct dentry *root; ++ ++ err = vfsub_kern_path(args[0].from, lkup_dirflags, &path); ++ if (unlikely(err)) { ++ pr_err("lookup failed %s (%d)\n", args[0].from, err); ++ goto out; ++ } ++ ++ xino_itrunc->bindex = -1; ++ root = sb->s_root; ++ aufs_read_lock(root, AuLock_FLUSH); ++ bend = au_sbend(sb); ++ for (bindex = 0; bindex <= bend; bindex++) { ++ if (au_h_dptr(root, bindex) == path.dentry) { ++ xino_itrunc->bindex = bindex; ++ break; ++ } ++ } ++ aufs_read_unlock(root, !AuLock_IR); ++ path_put(&path); ++ ++ if (unlikely(xino_itrunc->bindex < 0)) { ++ pr_err("no such branch %s\n", args[0].from); ++ err = -EINVAL; ++ } ++ ++ out: ++ return err; ++} ++ ++/* called without aufs lock */ ++int au_opts_parse(struct super_block *sb, char *str, struct au_opts *opts) ++{ ++ int err, n, token; ++ aufs_bindex_t bindex; ++ unsigned char skipped; ++ struct dentry *root; ++ struct au_opt *opt, *opt_tail; ++ char *opt_str; ++ /* reduce the stack space */ ++ union { ++ struct au_opt_xino_itrunc *xino_itrunc; ++ struct au_opt_wbr_create *create; ++ } u; ++ struct { ++ substring_t args[MAX_OPT_ARGS]; ++ } *a; ++ ++ err = -ENOMEM; ++ a = kmalloc(sizeof(*a), GFP_NOFS); ++ if (unlikely(!a)) ++ goto out; ++ ++ root = sb->s_root; ++ err = 0; ++ bindex = 0; ++ opt = opts->opt; ++ opt_tail = opt + opts->max_opt - 1; ++ opt->type = Opt_tail; ++ while (!err && (opt_str = strsep(&str, ",")) && *opt_str) { ++ err = -EINVAL; ++ skipped = 0; ++ token = match_token(opt_str, options, a->args); ++ switch (token) { ++ case Opt_br: ++ err = 0; ++ while (!err && (opt_str = strsep(&a->args[0].from, ":")) ++ && *opt_str) { ++ err = opt_add(opt, opt_str, opts->sb_flags, ++ bindex++); ++ if (unlikely(!err && ++opt > opt_tail)) { ++ err = -E2BIG; ++ break; ++ } ++ opt->type = Opt_tail; ++ skipped = 1; ++ } ++ break; ++ case Opt_add: ++ if (unlikely(match_int(&a->args[0], &n))) { ++ pr_err("bad integer in %s\n", opt_str); ++ break; ++ } ++ bindex = n; ++ err = opt_add(opt, a->args[1].from, opts->sb_flags, ++ bindex); ++ if (!err) ++ opt->type = token; ++ break; ++ case Opt_append: ++ err = opt_add(opt, a->args[0].from, opts->sb_flags, ++ /*dummy bindex*/1); ++ if (!err) ++ opt->type = token; ++ break; ++ case Opt_prepend: ++ err = opt_add(opt, a->args[0].from, opts->sb_flags, ++ /*bindex*/0); ++ if (!err) ++ opt->type = token; ++ break; ++ case Opt_del: ++ err = au_opts_parse_del(&opt->del, a->args); ++ if (!err) ++ opt->type = token; ++ break; ++#if 0 /* reserved for future use */ ++ case Opt_idel: ++ del->pathname = "(indexed)"; ++ if (unlikely(match_int(&args[0], &n))) { ++ pr_err("bad integer in %s\n", opt_str); ++ break; ++ } ++ err = au_opts_parse_idel(sb, n, &opt->del, a->args); ++ if (!err) ++ opt->type = token; ++ break; ++#endif ++ case Opt_mod: ++ err = au_opts_parse_mod(&opt->mod, a->args); ++ if (!err) ++ opt->type = token; ++ break; ++#ifdef IMOD /* reserved for future use */ ++ case Opt_imod: ++ u.mod->path = "(indexed)"; ++ if (unlikely(match_int(&a->args[0], &n))) { ++ pr_err("bad integer in %s\n", opt_str); ++ break; ++ } ++ err = au_opts_parse_imod(sb, n, &opt->mod, a->args); ++ if (!err) ++ opt->type = token; ++ break; ++#endif ++ case Opt_xino: ++ err = au_opts_parse_xino(sb, &opt->xino, a->args); ++ if (!err) ++ opt->type = token; ++ break; ++ ++ case Opt_trunc_xino_path: ++ err = au_opts_parse_xino_itrunc_path ++ (sb, &opt->xino_itrunc, a->args); ++ if (!err) ++ opt->type = token; ++ break; ++ ++ case Opt_itrunc_xino: ++ u.xino_itrunc = &opt->xino_itrunc; ++ if (unlikely(match_int(&a->args[0], &n))) { ++ pr_err("bad integer in %s\n", opt_str); ++ break; ++ } ++ u.xino_itrunc->bindex = n; ++ aufs_read_lock(root, AuLock_FLUSH); ++ if (n < 0 || au_sbend(sb) < n) { ++ pr_err("out of bounds, %d\n", n); ++ aufs_read_unlock(root, !AuLock_IR); ++ break; ++ } ++ aufs_read_unlock(root, !AuLock_IR); ++ err = 0; ++ opt->type = token; ++ break; ++ ++ case Opt_dirwh: ++ if (unlikely(match_int(&a->args[0], &opt->dirwh))) ++ break; ++ err = 0; ++ opt->type = token; ++ break; ++ ++ case Opt_rdcache: ++ if (unlikely(match_int(&a->args[0], &opt->rdcache))) ++ break; ++ err = 0; ++ opt->type = token; ++ break; ++ case Opt_rdblk: ++ if (unlikely(match_int(&a->args[0], &n) ++ || n < 0 ++ || n > KMALLOC_MAX_SIZE)) { ++ pr_err("bad integer in %s\n", opt_str); ++ break; ++ } ++ if (unlikely(n && n < NAME_MAX)) { ++ pr_err("rdblk must be larger than %d\n", ++ NAME_MAX); ++ break; ++ } ++ opt->rdblk = n; ++ err = 0; ++ opt->type = token; ++ break; ++ case Opt_rdhash: ++ if (unlikely(match_int(&a->args[0], &n) ++ || n < 0 ++ || n * sizeof(struct hlist_head) ++ > KMALLOC_MAX_SIZE)) { ++ pr_err("bad integer in %s\n", opt_str); ++ break; ++ } ++ opt->rdhash = n; ++ err = 0; ++ opt->type = token; ++ break; ++ ++ case Opt_trunc_xino: ++ case Opt_notrunc_xino: ++ case Opt_noxino: ++ case Opt_trunc_xib: ++ case Opt_notrunc_xib: ++ case Opt_shwh: ++ case Opt_noshwh: ++ case Opt_plink: ++ case Opt_noplink: ++ case Opt_list_plink: ++ case Opt_diropq_a: ++ case Opt_diropq_w: ++ case Opt_warn_perm: ++ case Opt_nowarn_perm: ++ case Opt_refrof: ++ case Opt_norefrof: ++ case Opt_verbose: ++ case Opt_noverbose: ++ case Opt_sum: ++ case Opt_nosum: ++ case Opt_wsum: ++ case Opt_rdblk_def: ++ case Opt_rdhash_def: ++ err = 0; ++ opt->type = token; ++ break; ++ ++ case Opt_udba: ++ opt->udba = udba_val(a->args[0].from); ++ if (opt->udba >= 0) { ++ err = 0; ++ opt->type = token; ++ } else ++ pr_err("wrong value, %s\n", opt_str); ++ break; ++ ++ case Opt_wbr_create: ++ u.create = &opt->wbr_create; ++ u.create->wbr_create ++ = au_wbr_create_val(a->args[0].from, u.create); ++ if (u.create->wbr_create >= 0) { ++ err = 0; ++ opt->type = token; ++ } else ++ pr_err("wrong value, %s\n", opt_str); ++ break; ++ case Opt_wbr_copyup: ++ opt->wbr_copyup = au_wbr_copyup_val(a->args[0].from); ++ if (opt->wbr_copyup >= 0) { ++ err = 0; ++ opt->type = token; ++ } else ++ pr_err("wrong value, %s\n", opt_str); ++ break; ++ ++ case Opt_ignore: ++ pr_warning("ignored %s\n", opt_str); ++ /*FALLTHROUGH*/ ++ case Opt_ignore_silent: ++ skipped = 1; ++ err = 0; ++ break; ++ case Opt_err: ++ pr_err("unknown option %s\n", opt_str); ++ break; ++ } ++ ++ if (!err && !skipped) { ++ if (unlikely(++opt > opt_tail)) { ++ err = -E2BIG; ++ opt--; ++ opt->type = Opt_tail; ++ break; ++ } ++ opt->type = Opt_tail; ++ } ++ } ++ ++ kfree(a); ++ dump_opts(opts); ++ if (unlikely(err)) ++ au_opts_free(opts); ++ ++ out: ++ return err; ++} ++ ++static int au_opt_wbr_create(struct super_block *sb, ++ struct au_opt_wbr_create *create) ++{ ++ int err; ++ struct au_sbinfo *sbinfo; ++ ++ SiMustWriteLock(sb); ++ ++ err = 1; /* handled */ ++ sbinfo = au_sbi(sb); ++ if (sbinfo->si_wbr_create_ops->fin) { ++ err = sbinfo->si_wbr_create_ops->fin(sb); ++ if (!err) ++ err = 1; ++ } ++ ++ sbinfo->si_wbr_create = create->wbr_create; ++ sbinfo->si_wbr_create_ops = au_wbr_create_ops + create->wbr_create; ++ switch (create->wbr_create) { ++ case AuWbrCreate_MFSRRV: ++ case AuWbrCreate_MFSRR: ++ sbinfo->si_wbr_mfs.mfsrr_watermark = create->mfsrr_watermark; ++ /*FALLTHROUGH*/ ++ case AuWbrCreate_MFS: ++ case AuWbrCreate_MFSV: ++ case AuWbrCreate_PMFS: ++ case AuWbrCreate_PMFSV: ++ sbinfo->si_wbr_mfs.mfs_expire = create->mfs_second * HZ; ++ break; ++ } ++ ++ if (sbinfo->si_wbr_create_ops->init) ++ sbinfo->si_wbr_create_ops->init(sb); /* ignore */ ++ ++ return err; ++} ++ ++/* ++ * returns, ++ * plus: processed without an error ++ * zero: unprocessed ++ */ ++static int au_opt_simple(struct super_block *sb, struct au_opt *opt, ++ struct au_opts *opts) ++{ ++ int err; ++ struct au_sbinfo *sbinfo; ++ ++ SiMustWriteLock(sb); ++ ++ err = 1; /* handled */ ++ sbinfo = au_sbi(sb); ++ switch (opt->type) { ++ case Opt_udba: ++ sbinfo->si_mntflags &= ~AuOptMask_UDBA; ++ sbinfo->si_mntflags |= opt->udba; ++ opts->given_udba |= opt->udba; ++ break; ++ ++ case Opt_plink: ++ au_opt_set(sbinfo->si_mntflags, PLINK); ++ break; ++ case Opt_noplink: ++ if (au_opt_test(sbinfo->si_mntflags, PLINK)) ++ au_plink_put(sb); ++ au_opt_clr(sbinfo->si_mntflags, PLINK); ++ break; ++ case Opt_list_plink: ++ if (au_opt_test(sbinfo->si_mntflags, PLINK)) ++ au_plink_list(sb); ++ break; ++ ++ case Opt_diropq_a: ++ au_opt_set(sbinfo->si_mntflags, ALWAYS_DIROPQ); ++ break; ++ case Opt_diropq_w: ++ au_opt_clr(sbinfo->si_mntflags, ALWAYS_DIROPQ); ++ break; ++ ++ case Opt_warn_perm: ++ au_opt_set(sbinfo->si_mntflags, WARN_PERM); ++ break; ++ case Opt_nowarn_perm: ++ au_opt_clr(sbinfo->si_mntflags, WARN_PERM); ++ break; ++ ++ case Opt_refrof: ++ au_opt_set(sbinfo->si_mntflags, REFROF); ++ break; ++ case Opt_norefrof: ++ au_opt_clr(sbinfo->si_mntflags, REFROF); ++ break; ++ ++ case Opt_verbose: ++ au_opt_set(sbinfo->si_mntflags, VERBOSE); ++ break; ++ case Opt_noverbose: ++ au_opt_clr(sbinfo->si_mntflags, VERBOSE); ++ break; ++ ++ case Opt_sum: ++ au_opt_set(sbinfo->si_mntflags, SUM); ++ break; ++ case Opt_wsum: ++ au_opt_clr(sbinfo->si_mntflags, SUM); ++ au_opt_set(sbinfo->si_mntflags, SUM_W); ++ case Opt_nosum: ++ au_opt_clr(sbinfo->si_mntflags, SUM); ++ au_opt_clr(sbinfo->si_mntflags, SUM_W); ++ break; ++ ++ case Opt_wbr_create: ++ err = au_opt_wbr_create(sb, &opt->wbr_create); ++ break; ++ case Opt_wbr_copyup: ++ sbinfo->si_wbr_copyup = opt->wbr_copyup; ++ sbinfo->si_wbr_copyup_ops = au_wbr_copyup_ops + opt->wbr_copyup; ++ break; ++ ++ case Opt_dirwh: ++ sbinfo->si_dirwh = opt->dirwh; ++ break; ++ ++ case Opt_rdcache: ++ sbinfo->si_rdcache = opt->rdcache * HZ; ++ break; ++ case Opt_rdblk: ++ sbinfo->si_rdblk = opt->rdblk; ++ break; ++ case Opt_rdblk_def: ++ sbinfo->si_rdblk = AUFS_RDBLK_DEF; ++ break; ++ case Opt_rdhash: ++ sbinfo->si_rdhash = opt->rdhash; ++ break; ++ case Opt_rdhash_def: ++ sbinfo->si_rdhash = AUFS_RDHASH_DEF; ++ break; ++ ++ case Opt_shwh: ++ au_opt_set(sbinfo->si_mntflags, SHWH); ++ break; ++ case Opt_noshwh: ++ au_opt_clr(sbinfo->si_mntflags, SHWH); ++ break; ++ ++ case Opt_trunc_xino: ++ au_opt_set(sbinfo->si_mntflags, TRUNC_XINO); ++ break; ++ case Opt_notrunc_xino: ++ au_opt_clr(sbinfo->si_mntflags, TRUNC_XINO); ++ break; ++ ++ case Opt_trunc_xino_path: ++ case Opt_itrunc_xino: ++ err = au_xino_trunc(sb, opt->xino_itrunc.bindex); ++ if (!err) ++ err = 1; ++ break; ++ ++ case Opt_trunc_xib: ++ au_fset_opts(opts->flags, TRUNC_XIB); ++ break; ++ case Opt_notrunc_xib: ++ au_fclr_opts(opts->flags, TRUNC_XIB); ++ break; ++ ++ default: ++ err = 0; ++ break; ++ } ++ ++ return err; ++} ++ ++/* ++ * returns tri-state. ++ * plus: processed without an error ++ * zero: unprocessed ++ * minus: error ++ */ ++static int au_opt_br(struct super_block *sb, struct au_opt *opt, ++ struct au_opts *opts) ++{ ++ int err, do_refresh; ++ ++ err = 0; ++ switch (opt->type) { ++ case Opt_append: ++ opt->add.bindex = au_sbend(sb) + 1; ++ if (opt->add.bindex < 0) ++ opt->add.bindex = 0; ++ goto add; ++ case Opt_prepend: ++ opt->add.bindex = 0; ++ add: ++ case Opt_add: ++ err = au_br_add(sb, &opt->add, ++ au_ftest_opts(opts->flags, REMOUNT)); ++ if (!err) { ++ err = 1; ++ au_fset_opts(opts->flags, REFRESH_DIR); ++ if (au_br_whable(opt->add.perm)) ++ au_fset_opts(opts->flags, REFRESH_NONDIR); ++ } ++ break; ++ ++ case Opt_del: ++ case Opt_idel: ++ err = au_br_del(sb, &opt->del, ++ au_ftest_opts(opts->flags, REMOUNT)); ++ if (!err) { ++ err = 1; ++ au_fset_opts(opts->flags, TRUNC_XIB); ++ au_fset_opts(opts->flags, REFRESH_DIR); ++ au_fset_opts(opts->flags, REFRESH_NONDIR); ++ } ++ break; ++ ++ case Opt_mod: ++ case Opt_imod: ++ err = au_br_mod(sb, &opt->mod, ++ au_ftest_opts(opts->flags, REMOUNT), ++ &do_refresh); ++ if (!err) { ++ err = 1; ++ if (do_refresh) { ++ au_fset_opts(opts->flags, REFRESH_DIR); ++ au_fset_opts(opts->flags, REFRESH_NONDIR); ++ } ++ } ++ break; ++ } ++ ++ return err; ++} ++ ++static int au_opt_xino(struct super_block *sb, struct au_opt *opt, ++ struct au_opt_xino **opt_xino, ++ struct au_opts *opts) ++{ ++ int err; ++ aufs_bindex_t bend, bindex; ++ struct dentry *root, *parent, *h_root; ++ ++ err = 0; ++ switch (opt->type) { ++ case Opt_xino: ++ err = au_xino_set(sb, &opt->xino, ++ !!au_ftest_opts(opts->flags, REMOUNT)); ++ if (unlikely(err)) ++ break; ++ ++ *opt_xino = &opt->xino; ++ au_xino_brid_set(sb, -1); ++ ++ /* safe d_parent access */ ++ parent = opt->xino.file->f_dentry->d_parent; ++ root = sb->s_root; ++ bend = au_sbend(sb); ++ for (bindex = 0; bindex <= bend; bindex++) { ++ h_root = au_h_dptr(root, bindex); ++ if (h_root == parent) { ++ au_xino_brid_set(sb, au_sbr_id(sb, bindex)); ++ break; ++ } ++ } ++ break; ++ ++ case Opt_noxino: ++ au_xino_clr(sb); ++ au_xino_brid_set(sb, -1); ++ *opt_xino = (void *)-1; ++ break; ++ } ++ ++ return err; ++} ++ ++int au_opts_verify(struct super_block *sb, unsigned long sb_flags, ++ unsigned int pending) ++{ ++ int err; ++ aufs_bindex_t bindex, bend; ++ unsigned char do_plink, skip, do_free; ++ struct au_branch *br; ++ struct au_wbr *wbr; ++ struct dentry *root; ++ struct inode *dir, *h_dir; ++ struct au_sbinfo *sbinfo; ++ struct au_hinode *hdir; ++ ++ SiMustAnyLock(sb); ++ ++ sbinfo = au_sbi(sb); ++ AuDebugOn(!(sbinfo->si_mntflags & AuOptMask_UDBA)); ++ ++ if (!(sb_flags & MS_RDONLY)) { ++ if (unlikely(!au_br_writable(au_sbr_perm(sb, 0)))) ++ pr_warning("first branch should be rw\n"); ++ if (unlikely(au_opt_test(sbinfo->si_mntflags, SHWH))) ++ pr_warning("shwh should be used with ro\n"); ++ } ++ ++ if (au_opt_test((sbinfo->si_mntflags | pending), UDBA_HINOTIFY) ++ && !au_opt_test(sbinfo->si_mntflags, XINO)) ++ pr_warning("udba=inotify requires xino\n"); ++ ++ err = 0; ++ root = sb->s_root; ++ dir = sb->s_root->d_inode; ++ do_plink = !!au_opt_test(sbinfo->si_mntflags, PLINK); ++ bend = au_sbend(sb); ++ for (bindex = 0; !err && bindex <= bend; bindex++) { ++ skip = 0; ++ h_dir = au_h_iptr(dir, bindex); ++ br = au_sbr(sb, bindex); ++ do_free = 0; ++ ++ wbr = br->br_wbr; ++ if (wbr) ++ wbr_wh_read_lock(wbr); ++ ++ switch (br->br_perm) { ++ case AuBrPerm_RO: ++ case AuBrPerm_ROWH: ++ case AuBrPerm_RR: ++ case AuBrPerm_RRWH: ++ do_free = !!wbr; ++ skip = (!wbr ++ || (!wbr->wbr_whbase ++ && !wbr->wbr_plink ++ && !wbr->wbr_orph)); ++ break; ++ ++ case AuBrPerm_RWNoLinkWH: ++ /* skip = (!br->br_whbase && !br->br_orph); */ ++ skip = (!wbr || !wbr->wbr_whbase); ++ if (skip && wbr) { ++ if (do_plink) ++ skip = !!wbr->wbr_plink; ++ else ++ skip = !wbr->wbr_plink; ++ } ++ break; ++ ++ case AuBrPerm_RW: ++ /* skip = (br->br_whbase && br->br_ohph); */ ++ skip = (wbr && wbr->wbr_whbase); ++ if (skip) { ++ if (do_plink) ++ skip = !!wbr->wbr_plink; ++ else ++ skip = !wbr->wbr_plink; ++ } ++ break; ++ ++ default: ++ BUG(); ++ } ++ if (wbr) ++ wbr_wh_read_unlock(wbr); ++ ++ if (skip) ++ continue; ++ ++ hdir = au_hi(dir, bindex); ++ au_hin_imtx_lock_nested(hdir, AuLsc_I_PARENT); ++ if (wbr) ++ wbr_wh_write_lock(wbr); ++ err = au_wh_init(au_h_dptr(root, bindex), br, sb); ++ if (wbr) ++ wbr_wh_write_unlock(wbr); ++ au_hin_imtx_unlock(hdir); ++ ++ if (!err && do_free) { ++ kfree(wbr); ++ br->br_wbr = NULL; ++ } ++ } ++ ++ return err; ++} ++ ++int au_opts_mount(struct super_block *sb, struct au_opts *opts) ++{ ++ int err; ++ unsigned int tmp; ++ aufs_bindex_t bend; ++ struct au_opt *opt; ++ struct au_opt_xino *opt_xino, xino; ++ struct au_sbinfo *sbinfo; ++ ++ SiMustWriteLock(sb); ++ ++ err = 0; ++ opt_xino = NULL; ++ opt = opts->opt; ++ while (err >= 0 && opt->type != Opt_tail) ++ err = au_opt_simple(sb, opt++, opts); ++ if (err > 0) ++ err = 0; ++ else if (unlikely(err < 0)) ++ goto out; ++ ++ /* disable xino and udba temporary */ ++ sbinfo = au_sbi(sb); ++ tmp = sbinfo->si_mntflags; ++ au_opt_clr(sbinfo->si_mntflags, XINO); ++ au_opt_set_udba(sbinfo->si_mntflags, UDBA_REVAL); ++ ++ opt = opts->opt; ++ while (err >= 0 && opt->type != Opt_tail) ++ err = au_opt_br(sb, opt++, opts); ++ if (err > 0) ++ err = 0; ++ else if (unlikely(err < 0)) ++ goto out; ++ ++ bend = au_sbend(sb); ++ if (unlikely(bend < 0)) { ++ err = -EINVAL; ++ pr_err("no branches\n"); ++ goto out; ++ } ++ ++ if (au_opt_test(tmp, XINO)) ++ au_opt_set(sbinfo->si_mntflags, XINO); ++ opt = opts->opt; ++ while (!err && opt->type != Opt_tail) ++ err = au_opt_xino(sb, opt++, &opt_xino, opts); ++ if (unlikely(err)) ++ goto out; ++ ++ err = au_opts_verify(sb, sb->s_flags, tmp); ++ if (unlikely(err)) ++ goto out; ++ ++ /* restore xino */ ++ if (au_opt_test(tmp, XINO) && !opt_xino) { ++ xino.file = au_xino_def(sb); ++ err = PTR_ERR(xino.file); ++ if (IS_ERR(xino.file)) ++ goto out; ++ ++ err = au_xino_set(sb, &xino, /*remount*/0); ++ fput(xino.file); ++ if (unlikely(err)) ++ goto out; ++ } ++ ++ /* restore udba */ ++ sbinfo->si_mntflags &= ~AuOptMask_UDBA; ++ sbinfo->si_mntflags |= (tmp & AuOptMask_UDBA); ++ if (au_opt_test(tmp, UDBA_HINOTIFY)) { ++ struct inode *dir = sb->s_root->d_inode; ++ au_reset_hinotify(dir, ++ au_hi_flags(dir, /*isdir*/1) & ~AuHi_XINO); ++ } ++ ++ out: ++ return err; ++} ++ ++int au_opts_remount(struct super_block *sb, struct au_opts *opts) ++{ ++ int err, rerr; ++ struct inode *dir; ++ struct au_opt_xino *opt_xino; ++ struct au_opt *opt; ++ struct au_sbinfo *sbinfo; ++ ++ SiMustWriteLock(sb); ++ ++ dir = sb->s_root->d_inode; ++ sbinfo = au_sbi(sb); ++ err = 0; ++ opt_xino = NULL; ++ opt = opts->opt; ++ while (err >= 0 && opt->type != Opt_tail) { ++ err = au_opt_simple(sb, opt, opts); ++ if (!err) ++ err = au_opt_br(sb, opt, opts); ++ if (!err) ++ err = au_opt_xino(sb, opt, &opt_xino, opts); ++ opt++; ++ } ++ if (err > 0) ++ err = 0; ++ AuTraceErr(err); ++ /* go on even err */ ++ ++ rerr = au_opts_verify(sb, opts->sb_flags, /*pending*/0); ++ if (unlikely(rerr && !err)) ++ err = rerr; ++ ++ if (au_ftest_opts(opts->flags, TRUNC_XIB)) { ++ rerr = au_xib_trunc(sb); ++ if (unlikely(rerr && !err)) ++ err = rerr; ++ } ++ ++ /* will be handled by the caller */ ++ if (!au_ftest_opts(opts->flags, REFRESH_DIR) ++ && (opts->given_udba || au_opt_test(sbinfo->si_mntflags, XINO))) ++ au_fset_opts(opts->flags, REFRESH_DIR); ++ ++ AuDbg("status 0x%x\n", opts->flags); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++unsigned int au_opt_udba(struct super_block *sb) ++{ ++ return au_mntflags(sb) & AuOptMask_UDBA; ++} +diff --git a/fs/aufs/opts.h b/fs/aufs/opts.h +new file mode 100644 +index 0000000..83a00ef +--- /dev/null ++++ b/fs/aufs/opts.h +@@ -0,0 +1,196 @@ ++/* ++ * Copyright (C) 2005-2010 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* ++ * mount options/flags ++ */ ++ ++#ifndef __AUFS_OPTS_H__ ++#define __AUFS_OPTS_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++ ++struct file; ++struct super_block; ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* mount flags */ ++#define AuOpt_XINO 1 /* external inode number bitmap ++ and translation table */ ++#define AuOpt_TRUNC_XINO (1 << 1) /* truncate xino files */ ++#define AuOpt_UDBA_NONE (1 << 2) /* users direct branch access */ ++#define AuOpt_UDBA_REVAL (1 << 3) ++#define AuOpt_UDBA_HINOTIFY (1 << 4) ++#define AuOpt_SHWH (1 << 5) /* show whiteout */ ++#define AuOpt_PLINK (1 << 6) /* pseudo-link */ ++#define AuOpt_DIRPERM1 (1 << 7) /* unimplemented */ ++#define AuOpt_REFROF (1 << 8) /* unimplemented */ ++#define AuOpt_ALWAYS_DIROPQ (1 << 9) /* policy to creating diropq */ ++#define AuOpt_SUM (1 << 10) /* summation for statfs(2) */ ++#define AuOpt_SUM_W (1 << 11) /* unimplemented */ ++#define AuOpt_WARN_PERM (1 << 12) /* warn when add-branch */ ++#define AuOpt_VERBOSE (1 << 13) /* busy inode when del-branch */ ++ ++#ifndef CONFIG_AUFS_HINOTIFY ++#undef AuOpt_UDBA_HINOTIFY ++#define AuOpt_UDBA_HINOTIFY 0 ++#endif ++#ifndef CONFIG_AUFS_SHWH ++#undef AuOpt_SHWH ++#define AuOpt_SHWH 0 ++#endif ++ ++#define AuOpt_Def (AuOpt_XINO \ ++ | AuOpt_UDBA_REVAL \ ++ | AuOpt_PLINK \ ++ /* | AuOpt_DIRPERM1 */ \ ++ | AuOpt_WARN_PERM) ++#define AuOptMask_UDBA (AuOpt_UDBA_NONE \ ++ | AuOpt_UDBA_REVAL \ ++ | AuOpt_UDBA_HINOTIFY) ++ ++#define au_opt_test(flags, name) (flags & AuOpt_##name) ++#define au_opt_set(flags, name) do { \ ++ BUILD_BUG_ON(AuOpt_##name & AuOptMask_UDBA); \ ++ ((flags) |= AuOpt_##name); \ ++} while (0) ++#define au_opt_set_udba(flags, name) do { \ ++ (flags) &= ~AuOptMask_UDBA; \ ++ ((flags) |= AuOpt_##name); \ ++} while (0) ++#define au_opt_clr(flags, name) { ((flags) &= ~AuOpt_##name); } ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* policies to select one among multiple writable branches */ ++enum { ++ AuWbrCreate_TDP, /* top down parent */ ++ AuWbrCreate_RR, /* round robin */ ++ AuWbrCreate_MFS, /* most free space */ ++ AuWbrCreate_MFSV, /* mfs with seconds */ ++ AuWbrCreate_MFSRR, /* mfs then rr */ ++ AuWbrCreate_MFSRRV, /* mfs then rr with seconds */ ++ AuWbrCreate_PMFS, /* parent and mfs */ ++ AuWbrCreate_PMFSV, /* parent and mfs with seconds */ ++ ++ AuWbrCreate_Def = AuWbrCreate_TDP ++}; ++ ++enum { ++ AuWbrCopyup_TDP, /* top down parent */ ++ AuWbrCopyup_BUP, /* bottom up parent */ ++ AuWbrCopyup_BU, /* bottom up */ ++ ++ AuWbrCopyup_Def = AuWbrCopyup_TDP ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct au_opt_add { ++ aufs_bindex_t bindex; ++ char *pathname; ++ int perm; ++ struct path path; ++}; ++ ++struct au_opt_del { ++ char *pathname; ++ struct path h_path; ++}; ++ ++struct au_opt_mod { ++ char *path; ++ int perm; ++ struct dentry *h_root; ++}; ++ ++struct au_opt_xino { ++ char *path; ++ struct file *file; ++}; ++ ++struct au_opt_xino_itrunc { ++ aufs_bindex_t bindex; ++}; ++ ++struct au_opt_wbr_create { ++ int wbr_create; ++ int mfs_second; ++ unsigned long long mfsrr_watermark; ++}; ++ ++struct au_opt { ++ int type; ++ union { ++ struct au_opt_xino xino; ++ struct au_opt_xino_itrunc xino_itrunc; ++ struct au_opt_add add; ++ struct au_opt_del del; ++ struct au_opt_mod mod; ++ int dirwh; ++ int rdcache; ++ unsigned int rdblk; ++ unsigned int rdhash; ++ int udba; ++ struct au_opt_wbr_create wbr_create; ++ int wbr_copyup; ++ }; ++}; ++ ++/* opts flags */ ++#define AuOpts_REMOUNT 1 ++#define AuOpts_REFRESH_DIR (1 << 1) ++#define AuOpts_REFRESH_NONDIR (1 << 2) ++#define AuOpts_TRUNC_XIB (1 << 3) ++#define au_ftest_opts(flags, name) ((flags) & AuOpts_##name) ++#define au_fset_opts(flags, name) { (flags) |= AuOpts_##name; } ++#define au_fclr_opts(flags, name) { (flags) &= ~AuOpts_##name; } ++ ++struct au_opts { ++ struct au_opt *opt; ++ int max_opt; ++ ++ unsigned int given_udba; ++ unsigned int flags; ++ unsigned long sb_flags; ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++const char *au_optstr_br_perm(int brperm); ++const char *au_optstr_udba(int udba); ++const char *au_optstr_wbr_copyup(int wbr_copyup); ++const char *au_optstr_wbr_create(int wbr_create); ++ ++void au_opts_free(struct au_opts *opts); ++int au_opts_parse(struct super_block *sb, char *str, struct au_opts *opts); ++int au_opts_verify(struct super_block *sb, unsigned long sb_flags, ++ unsigned int pending); ++int au_opts_mount(struct super_block *sb, struct au_opts *opts); ++int au_opts_remount(struct super_block *sb, struct au_opts *opts); ++ ++unsigned int au_opt_udba(struct super_block *sb); ++ ++/* ---------------------------------------------------------------------- */ ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_OPTS_H__ */ +diff --git a/fs/aufs/plink.c b/fs/aufs/plink.c +new file mode 100644 +index 0000000..80832e6 +--- /dev/null ++++ b/fs/aufs/plink.c +@@ -0,0 +1,430 @@ ++/* ++ * Copyright (C) 2005-2010 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* ++ * pseudo-link ++ */ ++ ++#include "aufs.h" ++ ++/* ++ * during a user process maintains the pseudo-links, ++ * prohibit adding a new plink and branch manipulation. ++ */ ++void au_plink_maint_block(struct super_block *sb) ++{ ++ struct au_sbinfo *sbi = au_sbi(sb); ++ ++ SiMustAnyLock(sb); ++ ++ /* gave up wake_up_bit() */ ++ wait_event(sbi->si_plink_wq, !sbi->si_plink_maint); ++} ++ ++void au_plink_maint_leave(struct file *file) ++{ ++ struct au_sbinfo *sbinfo; ++ int iam; ++ ++ AuDebugOn(atomic_long_read(&file->f_count)); ++ ++ sbinfo = au_sbi(file->f_dentry->d_sb); ++ spin_lock(&sbinfo->si_plink_maint_lock); ++ iam = (sbinfo->si_plink_maint == file); ++ if (iam) ++ sbinfo->si_plink_maint = NULL; ++ spin_unlock(&sbinfo->si_plink_maint_lock); ++ if (iam) ++ wake_up_all(&sbinfo->si_plink_wq); ++} ++ ++static int au_plink_maint_enter(struct file *file) ++{ ++ int err; ++ struct super_block *sb; ++ struct au_sbinfo *sbinfo; ++ ++ err = 0; ++ sb = file->f_dentry->d_sb; ++ sbinfo = au_sbi(sb); ++ /* make sure i am the only one in this fs */ ++ si_write_lock(sb); ++ /* spin_lock(&sbinfo->si_plink_maint_lock); */ ++ if (!sbinfo->si_plink_maint) ++ sbinfo->si_plink_maint = file; ++ else ++ err = -EBUSY; ++ /* spin_unlock(&sbinfo->si_plink_maint_lock); */ ++ si_write_unlock(sb); ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct pseudo_link { ++ struct list_head list; ++ struct inode *inode; ++}; ++ ++#ifdef CONFIG_AUFS_DEBUG ++void au_plink_list(struct super_block *sb) ++{ ++ struct au_sbinfo *sbinfo; ++ struct list_head *plink_list; ++ struct pseudo_link *plink; ++ ++ SiMustAnyLock(sb); ++ ++ sbinfo = au_sbi(sb); ++ AuDebugOn(!au_opt_test(au_mntflags(sb), PLINK)); ++ ++ plink_list = &sbinfo->si_plink.head; ++ spin_lock(&sbinfo->si_plink.spin); ++ list_for_each_entry(plink, plink_list, list) ++ AuDbg("%lu\n", plink->inode->i_ino); ++ spin_unlock(&sbinfo->si_plink.spin); ++} ++#endif ++ ++/* is the inode pseudo-linked? */ ++int au_plink_test(struct inode *inode) ++{ ++ int found; ++ struct au_sbinfo *sbinfo; ++ struct list_head *plink_list; ++ struct pseudo_link *plink; ++ ++ sbinfo = au_sbi(inode->i_sb); ++ AuRwMustAnyLock(&sbinfo->si_rwsem); ++ AuDebugOn(!au_opt_test(au_mntflags(inode->i_sb), PLINK)); ++ ++ found = 0; ++ plink_list = &sbinfo->si_plink.head; ++ spin_lock(&sbinfo->si_plink.spin); ++ list_for_each_entry(plink, plink_list, list) ++ if (plink->inode == inode) { ++ found = 1; ++ break; ++ } ++ spin_unlock(&sbinfo->si_plink.spin); ++ return found; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * generate a name for plink. ++ * the file will be stored under AUFS_WH_PLINKDIR. ++ */ ++/* 20 is max digits length of ulong 64 */ ++#define PLINK_NAME_LEN ((20 + 1) * 2) ++ ++static int plink_name(char *name, int len, struct inode *inode, ++ aufs_bindex_t bindex) ++{ ++ int rlen; ++ struct inode *h_inode; ++ ++ h_inode = au_h_iptr(inode, bindex); ++ rlen = snprintf(name, len, "%lu.%lu", inode->i_ino, h_inode->i_ino); ++ return rlen; ++} ++ ++/* lookup the plink-ed @inode under the branch at @bindex */ ++struct dentry *au_plink_lkup(struct inode *inode, aufs_bindex_t bindex) ++{ ++ struct dentry *h_dentry, *h_parent; ++ struct au_branch *br; ++ struct inode *h_dir; ++ char a[PLINK_NAME_LEN]; ++ struct qstr tgtname = { ++ .name = a ++ }; ++ ++ br = au_sbr(inode->i_sb, bindex); ++ h_parent = br->br_wbr->wbr_plink; ++ h_dir = h_parent->d_inode; ++ tgtname.len = plink_name(a, sizeof(a), inode, bindex); ++ ++ /* always superio. */ ++ mutex_lock_nested(&h_dir->i_mutex, AuLsc_I_CHILD2); ++ h_dentry = au_sio_lkup_one(&tgtname, h_parent, br); ++ mutex_unlock(&h_dir->i_mutex); ++ return h_dentry; ++} ++ ++/* create a pseudo-link */ ++static int do_whplink(struct qstr *tgt, struct dentry *h_parent, ++ struct dentry *h_dentry, struct au_branch *br) ++{ ++ int err; ++ struct path h_path = { ++ .mnt = br->br_mnt ++ }; ++ struct inode *h_dir; ++ ++ h_dir = h_parent->d_inode; ++ again: ++ h_path.dentry = au_lkup_one(tgt, h_parent, br, /*nd*/NULL); ++ err = PTR_ERR(h_path.dentry); ++ if (IS_ERR(h_path.dentry)) ++ goto out; ++ ++ err = 0; ++ /* wh.plink dir is not monitored */ ++ if (h_path.dentry->d_inode ++ && h_path.dentry->d_inode != h_dentry->d_inode) { ++ err = vfsub_unlink(h_dir, &h_path, /*force*/0); ++ dput(h_path.dentry); ++ h_path.dentry = NULL; ++ if (!err) ++ goto again; ++ } ++ if (!err && !h_path.dentry->d_inode) ++ err = vfsub_link(h_dentry, h_dir, &h_path); ++ dput(h_path.dentry); ++ ++ out: ++ return err; ++} ++ ++struct do_whplink_args { ++ int *errp; ++ struct qstr *tgt; ++ struct dentry *h_parent; ++ struct dentry *h_dentry; ++ struct au_branch *br; ++}; ++ ++static void call_do_whplink(void *args) ++{ ++ struct do_whplink_args *a = args; ++ *a->errp = do_whplink(a->tgt, a->h_parent, a->h_dentry, a->br); ++} ++ ++static int whplink(struct dentry *h_dentry, struct inode *inode, ++ aufs_bindex_t bindex, struct au_branch *br) ++{ ++ int err, wkq_err; ++ struct au_wbr *wbr; ++ struct dentry *h_parent; ++ struct inode *h_dir; ++ char a[PLINK_NAME_LEN]; ++ struct qstr tgtname = { ++ .name = a ++ }; ++ ++ wbr = au_sbr(inode->i_sb, bindex)->br_wbr; ++ h_parent = wbr->wbr_plink; ++ h_dir = h_parent->d_inode; ++ tgtname.len = plink_name(a, sizeof(a), inode, bindex); ++ ++ /* always superio. */ ++ mutex_lock_nested(&h_dir->i_mutex, AuLsc_I_CHILD2); ++ if (!au_test_wkq(current)) { ++ struct do_whplink_args args = { ++ .errp = &err, ++ .tgt = &tgtname, ++ .h_parent = h_parent, ++ .h_dentry = h_dentry, ++ .br = br ++ }; ++ wkq_err = au_wkq_wait(call_do_whplink, &args); ++ if (unlikely(wkq_err)) ++ err = wkq_err; ++ } else ++ err = do_whplink(&tgtname, h_parent, h_dentry, br); ++ mutex_unlock(&h_dir->i_mutex); ++ ++ return err; ++} ++ ++/* free a single plink */ ++static void do_put_plink(struct pseudo_link *plink, int do_del) ++{ ++ iput(plink->inode); ++ if (do_del) ++ list_del(&plink->list); ++ kfree(plink); ++} ++ ++/* ++ * create a new pseudo-link for @h_dentry on @bindex. ++ * the linked inode is held in aufs @inode. ++ */ ++void au_plink_append(struct inode *inode, aufs_bindex_t bindex, ++ struct dentry *h_dentry) ++{ ++ struct super_block *sb; ++ struct au_sbinfo *sbinfo; ++ struct list_head *plink_list; ++ struct pseudo_link *plink; ++ int found, err, cnt; ++ ++ sb = inode->i_sb; ++ sbinfo = au_sbi(sb); ++ AuDebugOn(!au_opt_test(au_mntflags(sb), PLINK)); ++ ++ err = 0; ++ cnt = 0; ++ found = 0; ++ plink_list = &sbinfo->si_plink.head; ++ spin_lock(&sbinfo->si_plink.spin); ++ list_for_each_entry(plink, plink_list, list) { ++ cnt++; ++ if (plink->inode == inode) { ++ found = 1; ++ break; ++ } ++ } ++ if (found) { ++ spin_unlock(&sbinfo->si_plink.spin); ++ return; ++ } ++ ++ plink = NULL; ++ if (!found) { ++ plink = kmalloc(sizeof(*plink), GFP_ATOMIC); ++ if (plink) { ++ plink->inode = au_igrab(inode); ++ list_add(&plink->list, plink_list); ++ cnt++; ++ } else ++ err = -ENOMEM; ++ } ++ spin_unlock(&sbinfo->si_plink.spin); ++ ++ if (!err) { ++ au_plink_maint_block(sb); ++ err = whplink(h_dentry, inode, bindex, au_sbr(sb, bindex)); ++ } ++ ++ if (unlikely(cnt > AUFS_PLINK_WARN)) ++ AuWarn1("unexpectedly many pseudo links, %d\n", cnt); ++ if (unlikely(err)) { ++ pr_warning("err %d, damaged pseudo link.\n", err); ++ if (!found && plink) ++ do_put_plink(plink, /*do_del*/1); ++ } ++} ++ ++/* free all plinks */ ++void au_plink_put(struct super_block *sb) ++{ ++ struct au_sbinfo *sbinfo; ++ struct list_head *plink_list; ++ struct pseudo_link *plink, *tmp; ++ ++ SiMustWriteLock(sb); ++ ++ sbinfo = au_sbi(sb); ++ AuDebugOn(!au_opt_test(au_mntflags(sb), PLINK)); ++ ++ plink_list = &sbinfo->si_plink.head; ++ /* no spin_lock since sbinfo is write-locked */ ++ list_for_each_entry_safe(plink, tmp, plink_list, list) ++ do_put_plink(plink, 0); ++ INIT_LIST_HEAD(plink_list); ++} ++ ++/* free the plinks on a branch specified by @br_id */ ++void au_plink_half_refresh(struct super_block *sb, aufs_bindex_t br_id) ++{ ++ struct au_sbinfo *sbinfo; ++ struct list_head *plink_list; ++ struct pseudo_link *plink, *tmp; ++ struct inode *inode; ++ aufs_bindex_t bstart, bend, bindex; ++ unsigned char do_put; ++ ++ SiMustWriteLock(sb); ++ ++ sbinfo = au_sbi(sb); ++ AuDebugOn(!au_opt_test(au_mntflags(sb), PLINK)); ++ ++ plink_list = &sbinfo->si_plink.head; ++ /* no spin_lock since sbinfo is write-locked */ ++ list_for_each_entry_safe(plink, tmp, plink_list, list) { ++ do_put = 0; ++ inode = au_igrab(plink->inode); ++ ii_write_lock_child(inode); ++ bstart = au_ibstart(inode); ++ bend = au_ibend(inode); ++ if (bstart >= 0) { ++ for (bindex = bstart; bindex <= bend; bindex++) { ++ if (!au_h_iptr(inode, bindex) ++ || au_ii_br_id(inode, bindex) != br_id) ++ continue; ++ au_set_h_iptr(inode, bindex, NULL, 0); ++ do_put = 1; ++ break; ++ } ++ } else ++ do_put_plink(plink, 1); ++ ++ if (do_put) { ++ for (bindex = bstart; bindex <= bend; bindex++) ++ if (au_h_iptr(inode, bindex)) { ++ do_put = 0; ++ break; ++ } ++ if (do_put) ++ do_put_plink(plink, 1); ++ } ++ ii_write_unlock(inode); ++ iput(inode); ++ } ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++long au_plink_ioctl(struct file *file, unsigned int cmd) ++{ ++ long err; ++ struct super_block *sb; ++ struct au_sbinfo *sbinfo; ++ ++ err = -EACCES; ++ if (!capable(CAP_SYS_ADMIN)) ++ goto out; ++ ++ err = 0; ++ sb = file->f_dentry->d_sb; ++ sbinfo = au_sbi(sb); ++ switch (cmd) { ++ case AUFS_CTL_PLINK_MAINT: ++ /* ++ * pseudo-link maintenance mode, ++ * cleared by aufs_release_dir() ++ */ ++ err = au_plink_maint_enter(file); ++ break; ++ case AUFS_CTL_PLINK_CLEAN: ++ aufs_write_lock(sb->s_root); ++ if (au_opt_test(sbinfo->si_mntflags, PLINK)) ++ au_plink_put(sb); ++ aufs_write_unlock(sb->s_root); ++ break; ++ default: ++ /* err = -ENOTTY; */ ++ err = -EINVAL; ++ } ++ out: ++ return err; ++} +diff --git a/fs/aufs/poll.c b/fs/aufs/poll.c +new file mode 100644 +index 0000000..49dc0aa +--- /dev/null ++++ b/fs/aufs/poll.c +@@ -0,0 +1,56 @@ ++/* ++ * Copyright (C) 2005-2010 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* ++ * poll operation ++ * There is only one filesystem which implements ->poll operation, currently. ++ */ ++ ++#include "aufs.h" ++ ++unsigned int aufs_poll(struct file *file, poll_table *wait) ++{ ++ unsigned int mask; ++ int err; ++ struct file *h_file; ++ struct dentry *dentry; ++ struct super_block *sb; ++ ++ /* We should pretend an error happened. */ ++ mask = POLLERR /* | POLLIN | POLLOUT */; ++ dentry = file->f_dentry; ++ sb = dentry->d_sb; ++ si_read_lock(sb, AuLock_FLUSH); ++ err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/0); ++ if (unlikely(err)) ++ goto out; ++ ++ /* it is not an error if h_file has no operation */ ++ mask = DEFAULT_POLLMASK; ++ h_file = au_h_fptr(file, au_fbstart(file)); ++ if (h_file->f_op && h_file->f_op->poll) ++ mask = h_file->f_op->poll(h_file, wait); ++ ++ di_read_unlock(dentry, AuLock_IR); ++ fi_read_unlock(file); ++ ++ out: ++ si_read_unlock(sb); ++ AuTraceErr((int)mask); ++ return mask; ++} +diff --git a/fs/aufs/rdu.c b/fs/aufs/rdu.c +new file mode 100644 +index 0000000..8a69402 +--- /dev/null ++++ b/fs/aufs/rdu.c +@@ -0,0 +1,330 @@ ++/* ++ * Copyright (C) 2005-2010 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* ++ * readdir in userspace. ++ */ ++ ++#include ++#include ++#include ++#include ++#include "aufs.h" ++ ++/* bits for struct aufs_rdu.flags */ ++#define AuRdu_CALLED 1 ++#define AuRdu_CONT (1 << 1) ++#define AuRdu_FULL (1 << 2) ++#define au_ftest_rdu(flags, name) ((flags) & AuRdu_##name) ++#define au_fset_rdu(flags, name) { (flags) |= AuRdu_##name; } ++#define au_fclr_rdu(flags, name) { (flags) &= ~AuRdu_##name; } ++ ++struct au_rdu_arg { ++ struct aufs_rdu *rdu; ++ union au_rdu_ent_ul ent; ++ unsigned long end; ++ ++ struct super_block *sb; ++ int err; ++}; ++ ++static int au_rdu_fill(void *__arg, const char *name, int nlen, ++ loff_t offset, u64 h_ino, unsigned int d_type) ++{ ++ int err, len; ++ struct au_rdu_arg *arg = __arg; ++ struct aufs_rdu *rdu = arg->rdu; ++ struct au_rdu_ent ent; ++ ++ err = 0; ++ arg->err = 0; ++ au_fset_rdu(rdu->cookie.flags, CALLED); ++ len = au_rdu_len(nlen); ++ if (arg->ent.ul + len < arg->end) { ++ ent.ino = h_ino; ++ ent.bindex = rdu->cookie.bindex; ++ ent.type = d_type; ++ ent.nlen = nlen; ++ if (unlikely(nlen > AUFS_MAX_NAMELEN)) ++ ent.type = DT_UNKNOWN; ++ ++ err = -EFAULT; ++ if (copy_to_user(arg->ent.e, &ent, sizeof(ent))) ++ goto out; ++ if (copy_to_user(arg->ent.e->name, name, nlen)) ++ goto out; ++ /* the terminating NULL */ ++ if (__put_user(0, arg->ent.e->name + nlen)) ++ goto out; ++ err = 0; ++ /* AuDbg("%p, %.*s\n", arg->ent.p, nlen, name); */ ++ arg->ent.ul += len; ++ rdu->rent++; ++ } else { ++ err = -EFAULT; ++ au_fset_rdu(rdu->cookie.flags, FULL); ++ rdu->full = 1; ++ rdu->tail = arg->ent; ++ } ++ ++ out: ++ /* AuTraceErr(err); */ ++ return err; ++} ++ ++static int au_rdu_do(struct file *h_file, struct au_rdu_arg *arg) ++{ ++ int err; ++ loff_t offset; ++ struct au_rdu_cookie *cookie = &arg->rdu->cookie; ++ ++ offset = vfsub_llseek(h_file, cookie->h_pos, SEEK_SET); ++ err = offset; ++ if (unlikely(offset != cookie->h_pos)) ++ goto out; ++ ++ err = 0; ++ do { ++ arg->err = 0; ++ au_fclr_rdu(cookie->flags, CALLED); ++ /* smp_mb(); */ ++ err = vfsub_readdir(h_file, au_rdu_fill, arg); ++ if (err >= 0) ++ err = arg->err; ++ } while (!err ++ && au_ftest_rdu(cookie->flags, CALLED) ++ && !au_ftest_rdu(cookie->flags, FULL)); ++ cookie->h_pos = h_file->f_pos; ++ ++ out: ++ AuTraceErr(err); ++ return err; ++} ++ ++static int au_rdu(struct file *file, struct aufs_rdu *rdu) ++{ ++ int err; ++ aufs_bindex_t bend; ++ struct au_rdu_arg arg; ++ struct dentry *dentry; ++ struct inode *inode; ++ struct file *h_file; ++ struct au_rdu_cookie *cookie = &rdu->cookie; ++ ++ err = !access_ok(VERIFY_WRITE, rdu->ent.e, rdu->sz); ++ if (unlikely(err)) { ++ err = -EFAULT; ++ AuTraceErr(err); ++ goto out; ++ } ++ rdu->rent = 0; ++ rdu->tail = rdu->ent; ++ rdu->full = 0; ++ arg.rdu = rdu; ++ arg.ent = rdu->ent; ++ arg.end = arg.ent.ul; ++ arg.end += rdu->sz; ++ ++ err = -ENOTDIR; ++ if (unlikely(!file->f_op || !file->f_op->readdir)) ++ goto out; ++ ++ err = security_file_permission(file, MAY_READ); ++ AuTraceErr(err); ++ if (unlikely(err)) ++ goto out; ++ ++ dentry = file->f_dentry; ++ inode = dentry->d_inode; ++#if 1 ++ mutex_lock(&inode->i_mutex); ++#else ++ err = mutex_lock_killable(&inode->i_mutex); ++ AuTraceErr(err); ++ if (unlikely(err)) ++ goto out; ++#endif ++ err = -ENOENT; ++ if (unlikely(IS_DEADDIR(inode))) ++ goto out_mtx; ++ ++ arg.sb = inode->i_sb; ++ si_read_lock(arg.sb, AuLock_FLUSH); ++ fi_read_lock(file); ++ ++ err = -EAGAIN; ++ if (unlikely(au_ftest_rdu(cookie->flags, CONT) ++ && cookie->generation != au_figen(file))) ++ goto out_unlock; ++ ++ err = 0; ++ if (!rdu->blk) { ++ rdu->blk = au_sbi(arg.sb)->si_rdblk; ++ if (!rdu->blk) ++ rdu->blk = au_dir_size(file, /*dentry*/NULL); ++ } ++ bend = au_fbstart(file); ++ if (cookie->bindex < bend) ++ cookie->bindex = bend; ++ bend = au_fbend(file); ++ /* AuDbg("b%d, b%d\n", cookie->bindex, bend); */ ++ for (; !err && cookie->bindex <= bend; ++ cookie->bindex++, cookie->h_pos = 0) { ++ h_file = au_h_fptr(file, cookie->bindex); ++ if (!h_file) ++ continue; ++ ++ au_fclr_rdu(cookie->flags, FULL); ++ err = au_rdu_do(h_file, &arg); ++ AuTraceErr(err); ++ if (unlikely(au_ftest_rdu(cookie->flags, FULL) || err)) ++ break; ++ } ++ AuDbg("rent %llu\n", rdu->rent); ++ ++ if (!err && !au_ftest_rdu(cookie->flags, CONT)) { ++ rdu->shwh = !!au_opt_test(au_sbi(arg.sb)->si_mntflags, SHWH); ++ au_fset_rdu(cookie->flags, CONT); ++ cookie->generation = au_figen(file); ++ } ++ ++ ii_read_lock_child(inode); ++ fsstack_copy_attr_atime(inode, au_h_iptr(inode, au_ibstart(inode))); ++ ii_read_unlock(inode); ++ ++ out_unlock: ++ fi_read_unlock(file); ++ si_read_unlock(arg.sb); ++ out_mtx: ++ mutex_unlock(&inode->i_mutex); ++ out: ++ AuTraceErr(err); ++ return err; ++} ++ ++static int au_rdu_ino(struct file *file, struct aufs_rdu *rdu) ++{ ++ int err; ++ ino_t ino; ++ unsigned long long nent; ++ union au_rdu_ent_ul *u; ++ struct au_rdu_ent ent; ++ struct super_block *sb; ++ ++ err = 0; ++ nent = rdu->nent; ++ u = &rdu->ent; ++ sb = file->f_dentry->d_sb; ++ si_read_lock(sb, AuLock_FLUSH); ++ while (nent-- > 0) { ++ err = copy_from_user(&ent, u->e, sizeof(ent)); ++ if (!err) ++ err = !access_ok(VERIFY_WRITE, &u->e->ino, sizeof(ino)); ++ if (unlikely(err)) { ++ err = -EFAULT; ++ AuTraceErr(err); ++ break; ++ } ++ ++ /* AuDbg("b%d, i%llu\n", ent.bindex, ent.ino); */ ++ if (!ent.wh) ++ err = au_ino(sb, ent.bindex, ent.ino, ent.type, &ino); ++ else ++ err = au_wh_ino(sb, ent.bindex, ent.ino, ent.type, ++ &ino); ++ if (unlikely(err)) { ++ AuTraceErr(err); ++ break; ++ } ++ ++ err = __put_user(ino, &u->e->ino); ++ if (unlikely(err)) { ++ err = -EFAULT; ++ AuTraceErr(err); ++ break; ++ } ++ u->ul += au_rdu_len(ent.nlen); ++ } ++ si_read_unlock(sb); ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_rdu_verify(struct aufs_rdu *rdu) ++{ ++ AuDbg("rdu{%llu, %p, (%u, %u) | %u | %llu, %u, %u | " ++ "%llu, b%d, 0x%x, g%u}\n", ++ rdu->sz, rdu->ent.e, rdu->verify[0], rdu->verify[1], ++ rdu->blk, ++ rdu->rent, rdu->shwh, rdu->full, ++ rdu->cookie.h_pos, rdu->cookie.bindex, rdu->cookie.flags, ++ rdu->cookie.generation); ++ ++ if (rdu->verify[AufsCtlRduV_SZ] == sizeof(*rdu) ++ && rdu->verify[AufsCtlRduV_SZ_PTR] == sizeof(rdu)) ++ return 0; ++ ++ AuDbg("%u:%u, %u:%u\n", ++ rdu->verify[AufsCtlRduV_SZ], (unsigned int)sizeof(*rdu), ++ rdu->verify[AufsCtlRduV_SZ_PTR], (unsigned int)sizeof(rdu)); ++ return -EINVAL; ++} ++ ++long au_rdu_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ++{ ++ long err, e; ++ struct aufs_rdu rdu; ++ void __user *p = (void __user *)arg; ++ ++ err = copy_from_user(&rdu, p, sizeof(rdu)); ++ if (unlikely(err)) { ++ err = -EFAULT; ++ AuTraceErr(err); ++ goto out; ++ } ++ err = au_rdu_verify(&rdu); ++ if (unlikely(err)) ++ goto out; ++ ++ switch (cmd) { ++ case AUFS_CTL_RDU: ++ err = au_rdu(file, &rdu); ++ if (unlikely(err)) ++ break; ++ ++ e = copy_to_user(p, &rdu, sizeof(rdu)); ++ if (unlikely(e)) { ++ err = -EFAULT; ++ AuTraceErr(err); ++ } ++ break; ++ case AUFS_CTL_RDU_INO: ++ err = au_rdu_ino(file, &rdu); ++ break; ++ ++ default: ++ /* err = -ENOTTY; */ ++ err = -EINVAL; ++ } ++ ++ out: ++ AuTraceErr(err); ++ return err; ++} +diff --git a/fs/aufs/rwsem.h b/fs/aufs/rwsem.h +new file mode 100644 +index 0000000..d608e24 +--- /dev/null ++++ b/fs/aufs/rwsem.h +@@ -0,0 +1,186 @@ ++/* ++ * Copyright (C) 2005-2010 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* ++ * simple read-write semaphore wrappers ++ */ ++ ++#ifndef __AUFS_RWSEM_H__ ++#define __AUFS_RWSEM_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++ ++struct au_rwsem { ++ struct rw_semaphore rwsem; ++#ifdef CONFIG_AUFS_DEBUG ++ /* just for debugging, not almighty counter */ ++ atomic_t rcnt, wcnt; ++#endif ++}; ++ ++#ifdef CONFIG_AUFS_DEBUG ++#define AuDbgCntInit(rw) do { \ ++ atomic_set(&(rw)->rcnt, 0); \ ++ atomic_set(&(rw)->wcnt, 0); \ ++ smp_mb(); /* atomic set */ \ ++} while (0) ++ ++#define AuDbgRcntInc(rw) atomic_inc_return(&(rw)->rcnt) ++#define AuDbgRcntDec(rw) WARN_ON(atomic_dec_return(&(rw)->rcnt) < 0) ++#define AuDbgWcntInc(rw) WARN_ON(atomic_inc_return(&(rw)->wcnt) > 1) ++#define AuDbgWcntDec(rw) WARN_ON(atomic_dec_return(&(rw)->wcnt) < 0) ++#else ++#define AuDbgCntInit(rw) do {} while (0) ++#define AuDbgRcntInc(rw) do {} while (0) ++#define AuDbgRcntDec(rw) do {} while (0) ++#define AuDbgWcntInc(rw) do {} while (0) ++#define AuDbgWcntDec(rw) do {} while (0) ++#endif /* CONFIG_AUFS_DEBUG */ ++ ++/* to debug easier, do not make them inlined functions */ ++#define AuRwMustNoWaiters(rw) AuDebugOn(!list_empty(&(rw)->rwsem.wait_list)) ++/* rwsem_is_locked() is unusable */ ++#define AuRwMustReadLock(rw) AuDebugOn(atomic_read(&(rw)->rcnt) <= 0) ++#define AuRwMustWriteLock(rw) AuDebugOn(atomic_read(&(rw)->wcnt) <= 0) ++#define AuRwMustAnyLock(rw) AuDebugOn(atomic_read(&(rw)->rcnt) <= 0 \ ++ && atomic_read(&(rw)->wcnt) <= 0) ++#define AuRwDestroy(rw) AuDebugOn(atomic_read(&(rw)->rcnt) \ ++ || atomic_read(&(rw)->wcnt)) ++ ++static inline void au_rw_init(struct au_rwsem *rw) ++{ ++ AuDbgCntInit(rw); ++ init_rwsem(&rw->rwsem); ++} ++ ++static inline void au_rw_init_wlock(struct au_rwsem *rw) ++{ ++ au_rw_init(rw); ++ down_write(&rw->rwsem); ++ AuDbgWcntInc(rw); ++} ++ ++static inline void au_rw_init_wlock_nested(struct au_rwsem *rw, ++ unsigned int lsc) ++{ ++ au_rw_init(rw); ++ down_write_nested(&rw->rwsem, lsc); ++ AuDbgWcntInc(rw); ++} ++ ++static inline void au_rw_read_lock(struct au_rwsem *rw) ++{ ++ down_read(&rw->rwsem); ++ AuDbgRcntInc(rw); ++} ++ ++static inline void au_rw_read_lock_nested(struct au_rwsem *rw, unsigned int lsc) ++{ ++ down_read_nested(&rw->rwsem, lsc); ++ AuDbgRcntInc(rw); ++} ++ ++static inline void au_rw_read_unlock(struct au_rwsem *rw) ++{ ++ AuRwMustReadLock(rw); ++ AuDbgRcntDec(rw); ++ up_read(&rw->rwsem); ++} ++ ++static inline void au_rw_dgrade_lock(struct au_rwsem *rw) ++{ ++ AuRwMustWriteLock(rw); ++ AuDbgRcntInc(rw); ++ AuDbgWcntDec(rw); ++ downgrade_write(&rw->rwsem); ++} ++ ++static inline void au_rw_write_lock(struct au_rwsem *rw) ++{ ++ down_write(&rw->rwsem); ++ AuDbgWcntInc(rw); ++} ++ ++static inline void au_rw_write_lock_nested(struct au_rwsem *rw, ++ unsigned int lsc) ++{ ++ down_write_nested(&rw->rwsem, lsc); ++ AuDbgWcntInc(rw); ++} ++ ++static inline void au_rw_write_unlock(struct au_rwsem *rw) ++{ ++ AuRwMustWriteLock(rw); ++ AuDbgWcntDec(rw); ++ up_write(&rw->rwsem); ++} ++ ++/* why is not _nested version defined */ ++static inline int au_rw_read_trylock(struct au_rwsem *rw) ++{ ++ int ret = down_read_trylock(&rw->rwsem); ++ if (ret) ++ AuDbgRcntInc(rw); ++ return ret; ++} ++ ++static inline int au_rw_write_trylock(struct au_rwsem *rw) ++{ ++ int ret = down_write_trylock(&rw->rwsem); ++ if (ret) ++ AuDbgWcntInc(rw); ++ return ret; ++} ++ ++#undef AuDbgCntInit ++#undef AuDbgRcntInc ++#undef AuDbgRcntDec ++#undef AuDbgWcntInc ++#undef AuDbgWcntDec ++ ++#define AuSimpleLockRwsemFuncs(prefix, param, rwsem) \ ++static inline void prefix##_read_lock(param) \ ++{ au_rw_read_lock(rwsem); } \ ++static inline void prefix##_write_lock(param) \ ++{ au_rw_write_lock(rwsem); } \ ++static inline int prefix##_read_trylock(param) \ ++{ return au_rw_read_trylock(rwsem); } \ ++static inline int prefix##_write_trylock(param) \ ++{ return au_rw_write_trylock(rwsem); } ++/* why is not _nested version defined */ ++/* static inline void prefix##_read_trylock_nested(param, lsc) ++{ au_rw_read_trylock_nested(rwsem, lsc)); } ++static inline void prefix##_write_trylock_nestd(param, lsc) ++{ au_rw_write_trylock_nested(rwsem, lsc); } */ ++ ++#define AuSimpleUnlockRwsemFuncs(prefix, param, rwsem) \ ++static inline void prefix##_read_unlock(param) \ ++{ au_rw_read_unlock(rwsem); } \ ++static inline void prefix##_write_unlock(param) \ ++{ au_rw_write_unlock(rwsem); } \ ++static inline void prefix##_downgrade_lock(param) \ ++{ au_rw_dgrade_lock(rwsem); } ++ ++#define AuSimpleRwsemFuncs(prefix, param, rwsem) \ ++ AuSimpleLockRwsemFuncs(prefix, param, rwsem) \ ++ AuSimpleUnlockRwsemFuncs(prefix, param, rwsem) ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_RWSEM_H__ */ +diff --git a/fs/aufs/sbinfo.c b/fs/aufs/sbinfo.c +new file mode 100644 +index 0000000..89b2b6a +--- /dev/null ++++ b/fs/aufs/sbinfo.c +@@ -0,0 +1,202 @@ ++/* ++ * Copyright (C) 2005-2010 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* ++ * superblock private data ++ */ ++ ++#include "aufs.h" ++ ++/* ++ * they are necessary regardless sysfs is disabled. ++ */ ++void au_si_free(struct kobject *kobj) ++{ ++ struct au_sbinfo *sbinfo; ++ struct super_block *sb; ++ ++ sbinfo = container_of(kobj, struct au_sbinfo, si_kobj); ++ AuDebugOn(!list_empty(&sbinfo->si_plink.head)); ++ AuDebugOn(sbinfo->si_plink_maint); ++ ++ sb = sbinfo->si_sb; ++ si_write_lock(sb); ++ au_xino_clr(sb); ++ au_br_free(sbinfo); ++ kfree(sbinfo->si_branch); ++ mutex_destroy(&sbinfo->si_xib_mtx); ++ si_write_unlock(sb); ++ AuRwDestroy(&sbinfo->si_rwsem); ++ ++ kfree(sbinfo); ++} ++ ++int au_si_alloc(struct super_block *sb) ++{ ++ int err; ++ struct au_sbinfo *sbinfo; ++ ++ err = -ENOMEM; ++ sbinfo = kzalloc(sizeof(*sbinfo), GFP_NOFS); ++ if (unlikely(!sbinfo)) ++ goto out; ++ ++ /* will be reallocated separately */ ++ sbinfo->si_branch = kzalloc(sizeof(*sbinfo->si_branch), GFP_NOFS); ++ if (unlikely(!sbinfo->si_branch)) ++ goto out_sbinfo; ++ ++ err = sysaufs_si_init(sbinfo); ++ if (unlikely(err)) ++ goto out_br; ++ ++ au_nwt_init(&sbinfo->si_nowait); ++ au_rw_init_wlock(&sbinfo->si_rwsem); ++ sbinfo->si_bend = -1; ++ ++ sbinfo->si_wbr_copyup = AuWbrCopyup_Def; ++ sbinfo->si_wbr_create = AuWbrCreate_Def; ++ sbinfo->si_wbr_copyup_ops = au_wbr_copyup_ops + sbinfo->si_wbr_copyup; ++ sbinfo->si_wbr_create_ops = au_wbr_create_ops + sbinfo->si_wbr_create; ++ ++ sbinfo->si_mntflags = AuOpt_Def; ++ ++ mutex_init(&sbinfo->si_xib_mtx); ++ sbinfo->si_xino_brid = -1; ++ /* leave si_xib_last_pindex and si_xib_next_bit */ ++ ++ sbinfo->si_rdcache = AUFS_RDCACHE_DEF * HZ; ++ sbinfo->si_rdblk = AUFS_RDBLK_DEF; ++ sbinfo->si_rdhash = AUFS_RDHASH_DEF; ++ sbinfo->si_dirwh = AUFS_DIRWH_DEF; ++ ++ au_spl_init(&sbinfo->si_plink); ++ init_waitqueue_head(&sbinfo->si_plink_wq); ++ spin_lock_init(&sbinfo->si_plink_maint_lock); ++ ++ /* leave other members for sysaufs and si_mnt. */ ++ sbinfo->si_sb = sb; ++ sb->s_fs_info = sbinfo; ++ au_debug_sbinfo_init(sbinfo); ++ return 0; /* success */ ++ ++ out_br: ++ kfree(sbinfo->si_branch); ++ out_sbinfo: ++ kfree(sbinfo); ++ out: ++ return err; ++} ++ ++int au_sbr_realloc(struct au_sbinfo *sbinfo, int nbr) ++{ ++ int err, sz; ++ struct au_branch **brp; ++ ++ AuRwMustWriteLock(&sbinfo->si_rwsem); ++ ++ err = -ENOMEM; ++ sz = sizeof(*brp) * (sbinfo->si_bend + 1); ++ if (unlikely(!sz)) ++ sz = sizeof(*brp); ++ brp = au_kzrealloc(sbinfo->si_branch, sz, sizeof(*brp) * nbr, GFP_NOFS); ++ if (brp) { ++ sbinfo->si_branch = brp; ++ err = 0; ++ } ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++unsigned int au_sigen_inc(struct super_block *sb) ++{ ++ unsigned int gen; ++ ++ SiMustWriteLock(sb); ++ ++ gen = ++au_sbi(sb)->si_generation; ++ au_update_digen(sb->s_root); ++ au_update_iigen(sb->s_root->d_inode); ++ sb->s_root->d_inode->i_version++; ++ return gen; ++} ++ ++aufs_bindex_t au_new_br_id(struct super_block *sb) ++{ ++ aufs_bindex_t br_id; ++ int i; ++ struct au_sbinfo *sbinfo; ++ ++ SiMustWriteLock(sb); ++ ++ sbinfo = au_sbi(sb); ++ for (i = 0; i <= AUFS_BRANCH_MAX; i++) { ++ br_id = ++sbinfo->si_last_br_id; ++ if (br_id && au_br_index(sb, br_id) < 0) ++ return br_id; ++ } ++ ++ return -1; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* dentry and super_block lock. call at entry point */ ++void aufs_read_lock(struct dentry *dentry, int flags) ++{ ++ si_read_lock(dentry->d_sb, flags); ++ if (au_ftest_lock(flags, DW)) ++ di_write_lock_child(dentry); ++ else ++ di_read_lock_child(dentry, flags); ++} ++ ++void aufs_read_unlock(struct dentry *dentry, int flags) ++{ ++ if (au_ftest_lock(flags, DW)) ++ di_write_unlock(dentry); ++ else ++ di_read_unlock(dentry, flags); ++ si_read_unlock(dentry->d_sb); ++} ++ ++void aufs_write_lock(struct dentry *dentry) ++{ ++ si_write_lock(dentry->d_sb); ++ di_write_lock_child(dentry); ++} ++ ++void aufs_write_unlock(struct dentry *dentry) ++{ ++ di_write_unlock(dentry); ++ si_write_unlock(dentry->d_sb); ++} ++ ++void aufs_read_and_write_lock2(struct dentry *d1, struct dentry *d2, int flags) ++{ ++ si_read_lock(d1->d_sb, flags); ++ di_write_lock2_child(d1, d2, au_ftest_lock(flags, DIR)); ++} ++ ++void aufs_read_and_write_unlock2(struct dentry *d1, struct dentry *d2) ++{ ++ di_write_unlock2(d1, d2); ++ si_read_unlock(d1->d_sb); ++} +diff --git a/fs/aufs/spl.h b/fs/aufs/spl.h +new file mode 100644 +index 0000000..261edc4 +--- /dev/null ++++ b/fs/aufs/spl.h +@@ -0,0 +1,57 @@ ++/* ++ * Copyright (C) 2005-2010 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* ++ * simple list protected by a spinlock ++ */ ++ ++#ifndef __AUFS_SPL_H__ ++#define __AUFS_SPL_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++ ++struct au_splhead { ++ spinlock_t spin; ++ struct list_head head; ++}; ++ ++static inline void au_spl_init(struct au_splhead *spl) ++{ ++ spin_lock_init(&spl->spin); ++ INIT_LIST_HEAD(&spl->head); ++} ++ ++static inline void au_spl_add(struct list_head *list, struct au_splhead *spl) ++{ ++ spin_lock(&spl->spin); ++ list_add(list, &spl->head); ++ spin_unlock(&spl->spin); ++} ++ ++static inline void au_spl_del(struct list_head *list, struct au_splhead *spl) ++{ ++ spin_lock(&spl->spin); ++ list_del(list); ++ spin_unlock(&spl->spin); ++} ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_SPL_H__ */ +diff --git a/fs/aufs/super.c b/fs/aufs/super.c +new file mode 100644 +index 0000000..f2d1ead +--- /dev/null ++++ b/fs/aufs/super.c +@@ -0,0 +1,870 @@ ++/* ++ * Copyright (C) 2005-2010 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* ++ * mount and super_block operations ++ */ ++ ++#include ++#include ++#include ++#include ++#include "aufs.h" ++ ++/* ++ * super_operations ++ */ ++static struct inode *aufs_alloc_inode(struct super_block *sb __maybe_unused) ++{ ++ struct au_icntnr *c; ++ ++ c = au_cache_alloc_icntnr(); ++ if (c) { ++ inode_init_once(&c->vfs_inode); ++ c->vfs_inode.i_version = 1; /* sigen(sb); */ ++ c->iinfo.ii_hinode = NULL; ++ return &c->vfs_inode; ++ } ++ return NULL; ++} ++ ++static void aufs_destroy_inode(struct inode *inode) ++{ ++ au_iinfo_fin(inode); ++ au_cache_free_icntnr(container_of(inode, struct au_icntnr, vfs_inode)); ++} ++ ++struct inode *au_iget_locked(struct super_block *sb, ino_t ino) ++{ ++ struct inode *inode; ++ int err; ++ ++ inode = iget_locked(sb, ino); ++ if (unlikely(!inode)) { ++ inode = ERR_PTR(-ENOMEM); ++ goto out; ++ } ++ if (!(inode->i_state & I_NEW)) ++ goto out; ++ ++ err = au_xigen_new(inode); ++ if (!err) ++ err = au_iinfo_init(inode); ++ if (!err) ++ inode->i_version++; ++ else { ++ iget_failed(inode); ++ inode = ERR_PTR(err); ++ } ++ ++ out: ++ /* never return NULL */ ++ AuDebugOn(!inode); ++ AuTraceErrPtr(inode); ++ return inode; ++} ++ ++/* lock free root dinfo */ ++static int au_show_brs(struct seq_file *seq, struct super_block *sb) ++{ ++ int err; ++ aufs_bindex_t bindex, bend; ++ struct path path; ++ struct au_hdentry *hd; ++ struct au_branch *br; ++ ++ err = 0; ++ bend = au_sbend(sb); ++ hd = au_di(sb->s_root)->di_hdentry; ++ for (bindex = 0; !err && bindex <= bend; bindex++) { ++ br = au_sbr(sb, bindex); ++ path.mnt = br->br_mnt; ++ path.dentry = hd[bindex].hd_dentry; ++ err = au_seq_path(seq, &path); ++ if (err > 0) ++ err = seq_printf(seq, "=%s", ++ au_optstr_br_perm(br->br_perm)); ++ if (!err && bindex != bend) ++ err = seq_putc(seq, ':'); ++ } ++ ++ return err; ++} ++ ++static void au_show_wbr_create(struct seq_file *m, int v, ++ struct au_sbinfo *sbinfo) ++{ ++ const char *pat; ++ ++ AuRwMustAnyLock(&sbinfo->si_rwsem); ++ ++ seq_printf(m, ",create="); ++ pat = au_optstr_wbr_create(v); ++ switch (v) { ++ case AuWbrCreate_TDP: ++ case AuWbrCreate_RR: ++ case AuWbrCreate_MFS: ++ case AuWbrCreate_PMFS: ++ seq_printf(m, pat); ++ break; ++ case AuWbrCreate_MFSV: ++ seq_printf(m, /*pat*/"mfs:%lu", ++ sbinfo->si_wbr_mfs.mfs_expire / HZ); ++ break; ++ case AuWbrCreate_PMFSV: ++ seq_printf(m, /*pat*/"pmfs:%lu", ++ sbinfo->si_wbr_mfs.mfs_expire / HZ); ++ break; ++ case AuWbrCreate_MFSRR: ++ seq_printf(m, /*pat*/"mfsrr:%llu", ++ sbinfo->si_wbr_mfs.mfsrr_watermark); ++ break; ++ case AuWbrCreate_MFSRRV: ++ seq_printf(m, /*pat*/"mfsrr:%llu:%lu", ++ sbinfo->si_wbr_mfs.mfsrr_watermark, ++ sbinfo->si_wbr_mfs.mfs_expire / HZ); ++ break; ++ } ++} ++ ++static int au_show_xino(struct seq_file *seq, struct vfsmount *mnt) ++{ ++#ifdef CONFIG_SYSFS ++ return 0; ++#else ++ int err; ++ const int len = sizeof(AUFS_XINO_FNAME) - 1; ++ aufs_bindex_t bindex, brid; ++ struct super_block *sb; ++ struct qstr *name; ++ struct file *f; ++ struct dentry *d, *h_root; ++ ++ AuRwMustAnyLock(&sbinfo->si_rwsem); ++ ++ err = 0; ++ sb = mnt->mnt_sb; ++ f = au_sbi(sb)->si_xib; ++ if (!f) ++ goto out; ++ ++ /* stop printing the default xino path on the first writable branch */ ++ h_root = NULL; ++ brid = au_xino_brid(sb); ++ if (brid >= 0) { ++ bindex = au_br_index(sb, brid); ++ h_root = au_di(sb->s_root)->di_hdentry[0 + bindex].hd_dentry; ++ } ++ d = f->f_dentry; ++ name = &d->d_name; ++ /* safe ->d_parent because the file is unlinked */ ++ if (d->d_parent == h_root ++ && name->len == len ++ && !memcmp(name->name, AUFS_XINO_FNAME, len)) ++ goto out; ++ ++ seq_puts(seq, ",xino="); ++ err = au_xino_path(seq, f); ++ ++ out: ++ return err; ++#endif ++} ++ ++/* seq_file will re-call me in case of too long string */ ++static int aufs_show_options(struct seq_file *m, struct vfsmount *mnt) ++{ ++ int err, n; ++ unsigned int mnt_flags, v; ++ struct super_block *sb; ++ struct au_sbinfo *sbinfo; ++ ++#define AuBool(name, str) do { \ ++ v = au_opt_test(mnt_flags, name); \ ++ if (v != au_opt_test(AuOpt_Def, name)) \ ++ seq_printf(m, ",%s" #str, v ? "" : "no"); \ ++} while (0) ++ ++#define AuStr(name, str) do { \ ++ v = mnt_flags & AuOptMask_##name; \ ++ if (v != (AuOpt_Def & AuOptMask_##name)) \ ++ seq_printf(m, "," #str "=%s", au_optstr_##str(v)); \ ++} while (0) ++ ++#define AuUInt(name, str, val) do { \ ++ if (val != AUFS_##name##_DEF) \ ++ seq_printf(m, "," #str "=%u", val); \ ++} while (0) ++ ++ /* lock free root dinfo */ ++ sb = mnt->mnt_sb; ++ si_noflush_read_lock(sb); ++ sbinfo = au_sbi(sb); ++ seq_printf(m, ",si=%lx", sysaufs_si_id(sbinfo)); ++ ++ mnt_flags = au_mntflags(sb); ++ if (au_opt_test(mnt_flags, XINO)) { ++ err = au_show_xino(m, mnt); ++ if (unlikely(err)) ++ goto out; ++ } else ++ seq_puts(m, ",noxino"); ++ ++ AuBool(TRUNC_XINO, trunc_xino); ++ AuStr(UDBA, udba); ++ AuBool(SHWH, shwh); ++ AuBool(PLINK, plink); ++ /* AuBool(DIRPERM1, dirperm1); */ ++ /* AuBool(REFROF, refrof); */ ++ ++ v = sbinfo->si_wbr_create; ++ if (v != AuWbrCreate_Def) ++ au_show_wbr_create(m, v, sbinfo); ++ ++ v = sbinfo->si_wbr_copyup; ++ if (v != AuWbrCopyup_Def) ++ seq_printf(m, ",cpup=%s", au_optstr_wbr_copyup(v)); ++ ++ v = au_opt_test(mnt_flags, ALWAYS_DIROPQ); ++ if (v != au_opt_test(AuOpt_Def, ALWAYS_DIROPQ)) ++ seq_printf(m, ",diropq=%c", v ? 'a' : 'w'); ++ ++ AuUInt(DIRWH, dirwh, sbinfo->si_dirwh); ++ ++ n = sbinfo->si_rdcache / HZ; ++ AuUInt(RDCACHE, rdcache, n); ++ ++ AuUInt(RDBLK, rdblk, sbinfo->si_rdblk); ++ AuUInt(RDHASH, rdhash, sbinfo->si_rdhash); ++ ++ AuBool(SUM, sum); ++ /* AuBool(SUM_W, wsum); */ ++ AuBool(WARN_PERM, warn_perm); ++ AuBool(VERBOSE, verbose); ++ ++ out: ++ /* be sure to print "br:" last */ ++ if (!sysaufs_brs) { ++ seq_puts(m, ",br:"); ++ au_show_brs(m, sb); ++ } ++ si_read_unlock(sb); ++ return 0; ++ ++#undef AuBool ++#undef AuStr ++#undef AuUInt ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* sum mode which returns the summation for statfs(2) */ ++ ++static u64 au_add_till_max(u64 a, u64 b) ++{ ++ u64 old; ++ ++ old = a; ++ a += b; ++ if (old < a) ++ return a; ++ return ULLONG_MAX; ++} ++ ++static int au_statfs_sum(struct super_block *sb, struct kstatfs *buf) ++{ ++ int err; ++ u64 blocks, bfree, bavail, files, ffree; ++ aufs_bindex_t bend, bindex, i; ++ unsigned char shared; ++ struct vfsmount *h_mnt; ++ struct super_block *h_sb; ++ ++ blocks = 0; ++ bfree = 0; ++ bavail = 0; ++ files = 0; ++ ffree = 0; ++ ++ err = 0; ++ bend = au_sbend(sb); ++ for (bindex = bend; bindex >= 0; bindex--) { ++ h_mnt = au_sbr_mnt(sb, bindex); ++ h_sb = h_mnt->mnt_sb; ++ shared = 0; ++ for (i = bindex + 1; !shared && i <= bend; i++) ++ shared = (au_sbr_sb(sb, i) == h_sb); ++ if (shared) ++ continue; ++ ++ /* sb->s_root for NFS is unreliable */ ++ err = vfs_statfs(h_mnt->mnt_root, buf); ++ if (unlikely(err)) ++ goto out; ++ ++ blocks = au_add_till_max(blocks, buf->f_blocks); ++ bfree = au_add_till_max(bfree, buf->f_bfree); ++ bavail = au_add_till_max(bavail, buf->f_bavail); ++ files = au_add_till_max(files, buf->f_files); ++ ffree = au_add_till_max(ffree, buf->f_ffree); ++ } ++ ++ buf->f_blocks = blocks; ++ buf->f_bfree = bfree; ++ buf->f_bavail = bavail; ++ buf->f_files = files; ++ buf->f_ffree = ffree; ++ ++ out: ++ return err; ++} ++ ++static int aufs_statfs(struct dentry *dentry, struct kstatfs *buf) ++{ ++ int err; ++ struct super_block *sb; ++ ++ /* lock free root dinfo */ ++ sb = dentry->d_sb; ++ si_noflush_read_lock(sb); ++ if (!au_opt_test(au_mntflags(sb), SUM)) ++ /* sb->s_root for NFS is unreliable */ ++ err = vfs_statfs(au_sbr_mnt(sb, 0)->mnt_root, buf); ++ else ++ err = au_statfs_sum(sb, buf); ++ si_read_unlock(sb); ++ ++ if (!err) { ++ buf->f_type = AUFS_SUPER_MAGIC; ++ buf->f_namelen = AUFS_MAX_NAMELEN; ++ memset(&buf->f_fsid, 0, sizeof(buf->f_fsid)); ++ } ++ /* buf->f_bsize = buf->f_blocks = buf->f_bfree = buf->f_bavail = -1; */ ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* try flushing the lower fs at aufs remount/unmount time */ ++ ++static void au_fsync_br(struct super_block *sb) ++{ ++ aufs_bindex_t bend, bindex; ++ int brperm; ++ struct au_branch *br; ++ struct super_block *h_sb; ++ ++ bend = au_sbend(sb); ++ for (bindex = 0; bindex < bend; bindex++) { ++ br = au_sbr(sb, bindex); ++ brperm = br->br_perm; ++ if (brperm == AuBrPerm_RR || brperm == AuBrPerm_RRWH) ++ continue; ++ h_sb = br->br_mnt->mnt_sb; ++ if (bdev_read_only(h_sb->s_bdev)) ++ continue; ++ ++ /* lockdep_off(); */ ++ down_write(&h_sb->s_umount); ++ shrink_dcache_sb(h_sb); ++ sync_filesystem(h_sb); ++ up_write(&h_sb->s_umount); ++ /* lockdep_on(); */ ++ } ++} ++ ++/* ++ * this IS NOT for super_operations. ++ * I guess it will be reverted someday. ++ */ ++static void aufs_umount_begin(struct super_block *sb) ++{ ++ struct au_sbinfo *sbinfo; ++ ++ sbinfo = au_sbi(sb); ++ if (!sbinfo) ++ return; ++ ++ si_write_lock(sb); ++ au_fsync_br(sb); ++ if (au_opt_test(au_mntflags(sb), PLINK)) ++ au_plink_put(sb); ++ if (sbinfo->si_wbr_create_ops->fin) ++ sbinfo->si_wbr_create_ops->fin(sb); ++ si_write_unlock(sb); ++} ++ ++/* final actions when unmounting a file system */ ++static void aufs_put_super(struct super_block *sb) ++{ ++ struct au_sbinfo *sbinfo; ++ ++ sbinfo = au_sbi(sb); ++ if (!sbinfo) ++ return; ++ ++ aufs_umount_begin(sb); ++ dbgaufs_si_fin(sbinfo); ++ kobject_put(&sbinfo->si_kobj); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * refresh dentry and inode at remount time. ++ */ ++static int do_refresh(struct dentry *dentry, mode_t type, ++ unsigned int dir_flags) ++{ ++ int err; ++ struct dentry *parent; ++ ++ di_write_lock_child(dentry); ++ parent = dget_parent(dentry); ++ di_read_lock_parent(parent, AuLock_IR); ++ ++ /* returns the number of positive dentries */ ++ err = au_refresh_hdentry(dentry, type); ++ if (err >= 0) { ++ struct inode *inode = dentry->d_inode; ++ err = au_refresh_hinode(inode, dentry); ++ if (!err && type == S_IFDIR) ++ au_reset_hinotify(inode, dir_flags); ++ } ++ if (unlikely(err)) ++ pr_err("unrecoverable error %d, %.*s\n", ++ err, AuDLNPair(dentry)); ++ ++ di_read_unlock(parent, AuLock_IR); ++ dput(parent); ++ di_write_unlock(dentry); ++ ++ return err; ++} ++ ++static int test_dir(struct dentry *dentry, void *arg __maybe_unused) ++{ ++ return S_ISDIR(dentry->d_inode->i_mode); ++} ++ ++/* gave up consolidating with refresh_nondir() */ ++static int refresh_dir(struct dentry *root, unsigned int sigen) ++{ ++ int err, i, j, ndentry, e; ++ struct au_dcsub_pages dpages; ++ struct au_dpage *dpage; ++ struct dentry **dentries; ++ struct inode *inode; ++ const unsigned int flags = au_hi_flags(root->d_inode, /*isdir*/1); ++ ++ err = 0; ++ list_for_each_entry(inode, &root->d_sb->s_inodes, i_sb_list) ++ if (S_ISDIR(inode->i_mode) && au_iigen(inode) != sigen) { ++ ii_write_lock_child(inode); ++ e = au_refresh_hinode_self(inode, /*do_attr*/1); ++ ii_write_unlock(inode); ++ if (unlikely(e)) { ++ AuDbg("e %d, i%lu\n", e, inode->i_ino); ++ if (!err) ++ err = e; ++ /* go on even if err */ ++ } ++ } ++ ++ e = au_dpages_init(&dpages, GFP_NOFS); ++ if (unlikely(e)) { ++ if (!err) ++ err = e; ++ goto out; ++ } ++ e = au_dcsub_pages(&dpages, root, test_dir, NULL); ++ if (unlikely(e)) { ++ if (!err) ++ err = e; ++ goto out_dpages; ++ } ++ ++ for (i = 0; !e && i < dpages.ndpage; i++) { ++ dpage = dpages.dpages + i; ++ dentries = dpage->dentries; ++ ndentry = dpage->ndentry; ++ for (j = 0; !e && j < ndentry; j++) { ++ struct dentry *d; ++ ++ d = dentries[j]; ++ au_dbg_verify_dir_parent(d, sigen); ++ if (au_digen(d) != sigen) { ++ e = do_refresh(d, S_IFDIR, flags); ++ if (unlikely(e && !err)) ++ err = e; ++ /* break on err */ ++ } ++ } ++ } ++ ++ out_dpages: ++ au_dpages_free(&dpages); ++ out: ++ return err; ++} ++ ++static int test_nondir(struct dentry *dentry, void *arg __maybe_unused) ++{ ++ return !S_ISDIR(dentry->d_inode->i_mode); ++} ++ ++static int refresh_nondir(struct dentry *root, unsigned int sigen, ++ int do_dentry) ++{ ++ int err, i, j, ndentry, e; ++ struct au_dcsub_pages dpages; ++ struct au_dpage *dpage; ++ struct dentry **dentries; ++ struct inode *inode; ++ ++ err = 0; ++ list_for_each_entry(inode, &root->d_sb->s_inodes, i_sb_list) ++ if (!S_ISDIR(inode->i_mode) && au_iigen(inode) != sigen) { ++ ii_write_lock_child(inode); ++ e = au_refresh_hinode_self(inode, /*do_attr*/1); ++ ii_write_unlock(inode); ++ if (unlikely(e)) { ++ AuDbg("e %d, i%lu\n", e, inode->i_ino); ++ if (!err) ++ err = e; ++ /* go on even if err */ ++ } ++ } ++ ++ if (!do_dentry) ++ goto out; ++ ++ e = au_dpages_init(&dpages, GFP_NOFS); ++ if (unlikely(e)) { ++ if (!err) ++ err = e; ++ goto out; ++ } ++ e = au_dcsub_pages(&dpages, root, test_nondir, NULL); ++ if (unlikely(e)) { ++ if (!err) ++ err = e; ++ goto out_dpages; ++ } ++ ++ for (i = 0; i < dpages.ndpage; i++) { ++ dpage = dpages.dpages + i; ++ dentries = dpage->dentries; ++ ndentry = dpage->ndentry; ++ for (j = 0; j < ndentry; j++) { ++ struct dentry *d; ++ ++ d = dentries[j]; ++ au_dbg_verify_nondir_parent(d, sigen); ++ inode = d->d_inode; ++ if (inode && au_digen(d) != sigen) { ++ e = do_refresh(d, inode->i_mode & S_IFMT, ++ /*dir_flags*/0); ++ if (unlikely(e && !err)) ++ err = e; ++ /* go on even err */ ++ } ++ } ++ } ++ ++ out_dpages: ++ au_dpages_free(&dpages); ++ out: ++ return err; ++} ++ ++static void au_remount_refresh(struct super_block *sb, unsigned int flags) ++{ ++ int err; ++ unsigned int sigen; ++ struct au_sbinfo *sbinfo; ++ struct dentry *root; ++ struct inode *inode; ++ ++ au_sigen_inc(sb); ++ sigen = au_sigen(sb); ++ sbinfo = au_sbi(sb); ++ au_fclr_si(sbinfo, FAILED_REFRESH_DIRS); ++ ++ root = sb->s_root; ++ DiMustNoWaiters(root); ++ inode = root->d_inode; ++ IiMustNoWaiters(inode); ++ au_reset_hinotify(inode, au_hi_flags(inode, /*isdir*/1)); ++ di_write_unlock(root); ++ ++ err = refresh_dir(root, sigen); ++ if (unlikely(err)) { ++ au_fset_si(sbinfo, FAILED_REFRESH_DIRS); ++ pr_warning("Refreshing directories failed, ignored (%d)\n", ++ err); ++ } ++ ++ if (au_ftest_opts(flags, REFRESH_NONDIR)) { ++ err = refresh_nondir(root, sigen, !err); ++ if (unlikely(err)) ++ pr_warning("Refreshing non-directories failed, ignored" ++ "(%d)\n", err); ++ } ++ ++ /* aufs_write_lock() calls ..._child() */ ++ di_write_lock_child(root); ++ au_cpup_attr_all(root->d_inode, /*force*/1); ++} ++ ++/* stop extra interpretation of errno in mount(8), and strange error messages */ ++static int cvt_err(int err) ++{ ++ AuTraceErr(err); ++ ++ switch (err) { ++ case -ENOENT: ++ case -ENOTDIR: ++ case -EEXIST: ++ case -EIO: ++ err = -EINVAL; ++ } ++ return err; ++} ++ ++static int aufs_remount_fs(struct super_block *sb, int *flags, char *data) ++{ ++ int err; ++ struct au_opts opts; ++ struct dentry *root; ++ struct inode *inode; ++ struct au_sbinfo *sbinfo; ++ ++ err = 0; ++ root = sb->s_root; ++ if (!data || !*data) { ++ aufs_write_lock(root); ++ err = au_opts_verify(sb, *flags, /*pending*/0); ++ if (!err) ++ au_fsync_br(sb); ++ aufs_write_unlock(root); ++ goto out; ++ } ++ ++ err = -ENOMEM; ++ memset(&opts, 0, sizeof(opts)); ++ opts.opt = (void *)__get_free_page(GFP_NOFS); ++ if (unlikely(!opts.opt)) ++ goto out; ++ opts.max_opt = PAGE_SIZE / sizeof(*opts.opt); ++ opts.flags = AuOpts_REMOUNT; ++ opts.sb_flags = *flags; ++ ++ /* parse it before aufs lock */ ++ err = au_opts_parse(sb, data, &opts); ++ if (unlikely(err)) ++ goto out_opts; ++ ++ sbinfo = au_sbi(sb); ++ inode = root->d_inode; ++ mutex_lock(&inode->i_mutex); ++ aufs_write_lock(root); ++ au_fsync_br(sb); ++ ++ /* au_opts_remount() may return an error */ ++ err = au_opts_remount(sb, &opts); ++ au_opts_free(&opts); ++ ++ if (au_ftest_opts(opts.flags, REFRESH_DIR) ++ || au_ftest_opts(opts.flags, REFRESH_NONDIR)) ++ au_remount_refresh(sb, opts.flags); ++ ++ aufs_write_unlock(root); ++ mutex_unlock(&inode->i_mutex); ++ ++ out_opts: ++ free_page((unsigned long)opts.opt); ++ out: ++ err = cvt_err(err); ++ AuTraceErr(err); ++ return err; ++} ++ ++static const struct super_operations aufs_sop = { ++ .alloc_inode = aufs_alloc_inode, ++ .destroy_inode = aufs_destroy_inode, ++ .drop_inode = generic_delete_inode, ++ .show_options = aufs_show_options, ++ .statfs = aufs_statfs, ++ .put_super = aufs_put_super, ++ .remount_fs = aufs_remount_fs ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int alloc_root(struct super_block *sb) ++{ ++ int err; ++ struct inode *inode; ++ struct dentry *root; ++ ++ err = -ENOMEM; ++ inode = au_iget_locked(sb, AUFS_ROOT_INO); ++ err = PTR_ERR(inode); ++ if (IS_ERR(inode)) ++ goto out; ++ ++ inode->i_op = &aufs_dir_iop; ++ inode->i_fop = &aufs_dir_fop; ++ inode->i_mode = S_IFDIR; ++ inode->i_nlink = 2; ++ unlock_new_inode(inode); ++ ++ root = d_alloc_root(inode); ++ if (unlikely(!root)) ++ goto out_iput; ++ err = PTR_ERR(root); ++ if (IS_ERR(root)) ++ goto out_iput; ++ ++ err = au_alloc_dinfo(root); ++ if (!err) { ++ sb->s_root = root; ++ return 0; /* success */ ++ } ++ dput(root); ++ goto out; /* do not iput */ ++ ++ out_iput: ++ iget_failed(inode); ++ iput(inode); ++ out: ++ return err; ++ ++} ++ ++static int aufs_fill_super(struct super_block *sb, void *raw_data, ++ int silent __maybe_unused) ++{ ++ int err; ++ struct au_opts opts; ++ struct dentry *root; ++ struct inode *inode; ++ char *arg = raw_data; ++ ++ if (unlikely(!arg || !*arg)) { ++ err = -EINVAL; ++ pr_err("no arg\n"); ++ goto out; ++ } ++ ++ err = -ENOMEM; ++ memset(&opts, 0, sizeof(opts)); ++ opts.opt = (void *)__get_free_page(GFP_NOFS); ++ if (unlikely(!opts.opt)) ++ goto out; ++ opts.max_opt = PAGE_SIZE / sizeof(*opts.opt); ++ opts.sb_flags = sb->s_flags; ++ ++ err = au_si_alloc(sb); ++ if (unlikely(err)) ++ goto out_opts; ++ ++ /* all timestamps always follow the ones on the branch */ ++ sb->s_flags |= MS_NOATIME | MS_NODIRATIME; ++ sb->s_op = &aufs_sop; ++ sb->s_magic = AUFS_SUPER_MAGIC; ++ sb->s_maxbytes = 0; ++ au_export_init(sb); ++ ++ err = alloc_root(sb); ++ if (unlikely(err)) { ++ si_write_unlock(sb); ++ goto out_info; ++ } ++ root = sb->s_root; ++ inode = root->d_inode; ++ ++ /* ++ * actually we can parse options regardless aufs lock here. ++ * but at remount time, parsing must be done before aufs lock. ++ * so we follow the same rule. ++ */ ++ ii_write_lock_parent(inode); ++ aufs_write_unlock(root); ++ err = au_opts_parse(sb, arg, &opts); ++ if (unlikely(err)) ++ goto out_root; ++ ++ /* lock vfs_inode first, then aufs. */ ++ mutex_lock(&inode->i_mutex); ++ aufs_write_lock(root); ++ err = au_opts_mount(sb, &opts); ++ au_opts_free(&opts); ++ aufs_write_unlock(root); ++ mutex_unlock(&inode->i_mutex); ++ if (!err) ++ goto out_opts; /* success */ ++ ++ out_root: ++ dput(root); ++ sb->s_root = NULL; ++ out_info: ++ kobject_put(&au_sbi(sb)->si_kobj); ++ sb->s_fs_info = NULL; ++ out_opts: ++ free_page((unsigned long)opts.opt); ++ out: ++ AuTraceErr(err); ++ err = cvt_err(err); ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int aufs_get_sb(struct file_system_type *fs_type, int flags, ++ const char *dev_name __maybe_unused, void *raw_data, ++ struct vfsmount *mnt) ++{ ++ int err; ++ struct super_block *sb; ++ ++ /* all timestamps always follow the ones on the branch */ ++ /* mnt->mnt_flags |= MNT_NOATIME | MNT_NODIRATIME; */ ++ err = get_sb_nodev(fs_type, flags, raw_data, aufs_fill_super, mnt); ++ if (!err) { ++ sb = mnt->mnt_sb; ++ si_write_lock(sb); ++ sysaufs_brs_add(sb, 0); ++ si_write_unlock(sb); ++ } ++ return err; ++} ++ ++struct file_system_type aufs_fs_type = { ++ .name = AUFS_FSTYPE, ++ .fs_flags = ++ FS_RENAME_DOES_D_MOVE /* a race between rename and others */ ++ | FS_REVAL_DOT, /* for NFS branch and udba */ ++ .get_sb = aufs_get_sb, ++ .kill_sb = generic_shutdown_super, ++ /* no need to __module_get() and module_put(). */ ++ .owner = THIS_MODULE, ++}; +diff --git a/fs/aufs/super.h b/fs/aufs/super.h +new file mode 100644 +index 0000000..cd6fdc4 +--- /dev/null ++++ b/fs/aufs/super.h +@@ -0,0 +1,361 @@ ++/* ++ * Copyright (C) 2005-2010 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* ++ * super_block operations ++ */ ++ ++#ifndef __AUFS_SUPER_H__ ++#define __AUFS_SUPER_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++#include "rwsem.h" ++#include "spl.h" ++#include "wkq.h" ++ ++typedef ssize_t (*au_readf_t)(struct file *, char __user *, size_t, loff_t *); ++typedef ssize_t (*au_writef_t)(struct file *, const char __user *, size_t, ++ loff_t *); ++ ++/* policies to select one among multiple writable branches */ ++struct au_wbr_copyup_operations { ++ int (*copyup)(struct dentry *dentry); ++}; ++ ++struct au_wbr_create_operations { ++ int (*create)(struct dentry *dentry, int isdir); ++ int (*init)(struct super_block *sb); ++ int (*fin)(struct super_block *sb); ++}; ++ ++struct au_wbr_mfs { ++ struct mutex mfs_lock; /* protect this structure */ ++ unsigned long mfs_jiffy; ++ unsigned long mfs_expire; ++ aufs_bindex_t mfs_bindex; ++ ++ unsigned long long mfsrr_bytes; ++ unsigned long long mfsrr_watermark; ++}; ++ ++struct au_branch; ++struct au_sbinfo { ++ /* nowait tasks in the system-wide workqueue */ ++ struct au_nowait_tasks si_nowait; ++ ++ struct au_rwsem si_rwsem; ++ ++ /* branch management */ ++ unsigned int si_generation; ++ ++ /* see above flags */ ++ unsigned char au_si_status; ++ ++ aufs_bindex_t si_bend; ++ aufs_bindex_t si_last_br_id; ++ struct au_branch **si_branch; ++ ++ /* policy to select a writable branch */ ++ unsigned char si_wbr_copyup; ++ unsigned char si_wbr_create; ++ struct au_wbr_copyup_operations *si_wbr_copyup_ops; ++ struct au_wbr_create_operations *si_wbr_create_ops; ++ ++ /* round robin */ ++ atomic_t si_wbr_rr_next; ++ ++ /* most free space */ ++ struct au_wbr_mfs si_wbr_mfs; ++ ++ /* mount flags */ ++ /* include/asm-ia64/siginfo.h defines a macro named si_flags */ ++ unsigned int si_mntflags; ++ ++ /* external inode number (bitmap and translation table) */ ++ au_readf_t si_xread; ++ au_writef_t si_xwrite; ++ struct file *si_xib; ++ struct mutex si_xib_mtx; /* protect xib members */ ++ unsigned long *si_xib_buf; ++ unsigned long si_xib_last_pindex; ++ int si_xib_next_bit; ++ aufs_bindex_t si_xino_brid; ++ /* reserved for future use */ ++ /* unsigned long long si_xib_limit; */ /* Max xib file size */ ++ ++#ifdef CONFIG_AUFS_EXPORT ++ /* i_generation */ ++ struct file *si_xigen; ++ atomic_t si_xigen_next; ++#endif ++ ++ /* vdir parameters */ ++ unsigned long si_rdcache; /* max cache time in HZ */ ++ unsigned int si_rdblk; /* deblk size */ ++ unsigned int si_rdhash; /* hash size */ ++ ++ /* ++ * If the number of whiteouts are larger than si_dirwh, leave all of ++ * them after au_whtmp_ren to reduce the cost of rmdir(2). ++ * future fsck.aufs or kernel thread will remove them later. ++ * Otherwise, remove all whiteouts and the dir in rmdir(2). ++ */ ++ unsigned int si_dirwh; ++ ++ /* ++ * rename(2) a directory with all children. ++ */ ++ /* reserved for future use */ ++ /* int si_rendir; */ ++ ++ /* pseudo_link list */ ++ struct au_splhead si_plink; ++ wait_queue_head_t si_plink_wq; ++ spinlock_t si_plink_maint_lock; ++ struct file *si_plink_maint; ++ ++ /* ++ * sysfs and lifetime management. ++ * this is not a small structure and it may be a waste of memory in case ++ * of sysfs is disabled, particulary when many aufs-es are mounted. ++ * but using sysfs is majority. ++ */ ++ struct kobject si_kobj; ++#ifdef CONFIG_DEBUG_FS ++ struct dentry *si_dbgaufs, *si_dbgaufs_xib; ++#ifdef CONFIG_AUFS_EXPORT ++ struct dentry *si_dbgaufs_xigen; ++#endif ++#endif ++ ++ /* dirty, necessary for unmounting, sysfs and sysrq */ ++ struct super_block *si_sb; ++}; ++ ++/* sbinfo status flags */ ++/* ++ * set true when refresh_dirs() failed at remount time. ++ * then try refreshing dirs at access time again. ++ * if it is false, refreshing dirs at access time is unnecesary ++ */ ++#define AuSi_FAILED_REFRESH_DIRS 1 ++static inline unsigned char au_do_ftest_si(struct au_sbinfo *sbi, ++ unsigned int flag) ++{ ++ AuRwMustAnyLock(&sbi->si_rwsem); ++ return sbi->au_si_status & flag; ++} ++#define au_ftest_si(sbinfo, name) au_do_ftest_si(sbinfo, AuSi_##name) ++#define au_fset_si(sbinfo, name) do { \ ++ AuRwMustWriteLock(&(sbinfo)->si_rwsem); \ ++ (sbinfo)->au_si_status |= AuSi_##name; \ ++} while (0) ++#define au_fclr_si(sbinfo, name) do { \ ++ AuRwMustWriteLock(&(sbinfo)->si_rwsem); \ ++ (sbinfo)->au_si_status &= ~AuSi_##name; \ ++} while (0) ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* policy to select one among writable branches */ ++#define AuWbrCopyup(sbinfo, ...) \ ++ ((sbinfo)->si_wbr_copyup_ops->copyup(__VA_ARGS__)) ++#define AuWbrCreate(sbinfo, ...) \ ++ ((sbinfo)->si_wbr_create_ops->create(__VA_ARGS__)) ++ ++/* flags for si_read_lock()/aufs_read_lock()/di_read_lock() */ ++#define AuLock_DW 1 /* write-lock dentry */ ++#define AuLock_IR (1 << 1) /* read-lock inode */ ++#define AuLock_IW (1 << 2) /* write-lock inode */ ++#define AuLock_FLUSH (1 << 3) /* wait for 'nowait' tasks */ ++#define AuLock_DIR (1 << 4) /* target is a dir */ ++#define au_ftest_lock(flags, name) ((flags) & AuLock_##name) ++#define au_fset_lock(flags, name) { (flags) |= AuLock_##name; } ++#define au_fclr_lock(flags, name) { (flags) &= ~AuLock_##name; } ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* super.c */ ++extern struct file_system_type aufs_fs_type; ++struct inode *au_iget_locked(struct super_block *sb, ino_t ino); ++ ++/* sbinfo.c */ ++void au_si_free(struct kobject *kobj); ++int au_si_alloc(struct super_block *sb); ++int au_sbr_realloc(struct au_sbinfo *sbinfo, int nbr); ++ ++unsigned int au_sigen_inc(struct super_block *sb); ++aufs_bindex_t au_new_br_id(struct super_block *sb); ++ ++void aufs_read_lock(struct dentry *dentry, int flags); ++void aufs_read_unlock(struct dentry *dentry, int flags); ++void aufs_write_lock(struct dentry *dentry); ++void aufs_write_unlock(struct dentry *dentry); ++void aufs_read_and_write_lock2(struct dentry *d1, struct dentry *d2, int isdir); ++void aufs_read_and_write_unlock2(struct dentry *d1, struct dentry *d2); ++ ++/* wbr_policy.c */ ++extern struct au_wbr_copyup_operations au_wbr_copyup_ops[]; ++extern struct au_wbr_create_operations au_wbr_create_ops[]; ++int au_cpdown_dirs(struct dentry *dentry, aufs_bindex_t bdst); ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline struct au_sbinfo *au_sbi(struct super_block *sb) ++{ ++ return sb->s_fs_info; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++#ifdef CONFIG_AUFS_EXPORT ++void au_export_init(struct super_block *sb); ++ ++static inline int au_test_nfsd(struct task_struct *tsk) ++{ ++ return !tsk->mm && !strcmp(tsk->comm, "nfsd"); ++} ++ ++int au_xigen_inc(struct inode *inode); ++int au_xigen_new(struct inode *inode); ++int au_xigen_set(struct super_block *sb, struct file *base); ++void au_xigen_clr(struct super_block *sb); ++ ++static inline int au_busy_or_stale(void) ++{ ++ if (!au_test_nfsd(current)) ++ return -EBUSY; ++ return -ESTALE; ++} ++#else ++AuStubVoid(au_export_init, struct super_block *sb) ++AuStubInt0(au_test_nfsd, struct task_struct *tsk) ++AuStubInt0(au_xigen_inc, struct inode *inode) ++AuStubInt0(au_xigen_new, struct inode *inode) ++AuStubInt0(au_xigen_set, struct super_block *sb, struct file *base) ++AuStubVoid(au_xigen_clr, struct super_block *sb) ++static inline int au_busy_or_stale(void) ++{ ++ return -EBUSY; ++} ++#endif /* CONFIG_AUFS_EXPORT */ ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline void dbgaufs_si_null(struct au_sbinfo *sbinfo) ++{ ++ /* ++ * This function is a dynamic '__init' fucntion actually, ++ * so the tiny check for si_rwsem is unnecessary. ++ */ ++ /* AuRwMustWriteLock(&sbinfo->si_rwsem); */ ++#ifdef CONFIG_DEBUG_FS ++ sbinfo->si_dbgaufs = NULL; ++ sbinfo->si_dbgaufs_xib = NULL; ++#ifdef CONFIG_AUFS_EXPORT ++ sbinfo->si_dbgaufs_xigen = NULL; ++#endif ++#endif ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* lock superblock. mainly for entry point functions */ ++/* ++ * si_noflush_read_lock, si_noflush_write_lock, ++ * si_read_unlock, si_write_unlock, si_downgrade_lock ++ */ ++AuSimpleLockRwsemFuncs(si_noflush, struct super_block *sb, ++ &au_sbi(sb)->si_rwsem); ++AuSimpleUnlockRwsemFuncs(si, struct super_block *sb, &au_sbi(sb)->si_rwsem); ++ ++#define SiMustNoWaiters(sb) AuRwMustNoWaiters(&au_sbi(sb)->si_rwsem) ++#define SiMustAnyLock(sb) AuRwMustAnyLock(&au_sbi(sb)->si_rwsem) ++#define SiMustWriteLock(sb) AuRwMustWriteLock(&au_sbi(sb)->si_rwsem) ++ ++static inline void si_read_lock(struct super_block *sb, int flags) ++{ ++ if (au_ftest_lock(flags, FLUSH)) ++ au_nwt_flush(&au_sbi(sb)->si_nowait); ++ si_noflush_read_lock(sb); ++} ++ ++static inline void si_write_lock(struct super_block *sb) ++{ ++ au_nwt_flush(&au_sbi(sb)->si_nowait); ++ si_noflush_write_lock(sb); ++} ++ ++static inline int si_read_trylock(struct super_block *sb, int flags) ++{ ++ if (au_ftest_lock(flags, FLUSH)) ++ au_nwt_flush(&au_sbi(sb)->si_nowait); ++ return si_noflush_read_trylock(sb); ++} ++ ++static inline int si_write_trylock(struct super_block *sb, int flags) ++{ ++ if (au_ftest_lock(flags, FLUSH)) ++ au_nwt_flush(&au_sbi(sb)->si_nowait); ++ return si_noflush_write_trylock(sb); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline aufs_bindex_t au_sbend(struct super_block *sb) ++{ ++ SiMustAnyLock(sb); ++ return au_sbi(sb)->si_bend; ++} ++ ++static inline unsigned int au_mntflags(struct super_block *sb) ++{ ++ SiMustAnyLock(sb); ++ return au_sbi(sb)->si_mntflags; ++} ++ ++static inline unsigned int au_sigen(struct super_block *sb) ++{ ++ SiMustAnyLock(sb); ++ return au_sbi(sb)->si_generation; ++} ++ ++static inline struct au_branch *au_sbr(struct super_block *sb, ++ aufs_bindex_t bindex) ++{ ++ SiMustAnyLock(sb); ++ return au_sbi(sb)->si_branch[0 + bindex]; ++} ++ ++static inline void au_xino_brid_set(struct super_block *sb, aufs_bindex_t brid) ++{ ++ SiMustWriteLock(sb); ++ au_sbi(sb)->si_xino_brid = brid; ++} ++ ++static inline aufs_bindex_t au_xino_brid(struct super_block *sb) ++{ ++ SiMustAnyLock(sb); ++ return au_sbi(sb)->si_xino_brid; ++} ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_SUPER_H__ */ +diff --git a/fs/aufs/sysaufs.c b/fs/aufs/sysaufs.c +new file mode 100644 +index 0000000..919e1b0 +--- /dev/null ++++ b/fs/aufs/sysaufs.c +@@ -0,0 +1,104 @@ ++/* ++ * Copyright (C) 2005-2010 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* ++ * sysfs interface and lifetime management ++ * they are necessary regardless sysfs is disabled. ++ */ ++ ++#include ++#include ++#include ++#include "aufs.h" ++ ++unsigned long sysaufs_si_mask; ++struct kset *sysaufs_ket; ++ ++#define AuSiAttr(_name) { \ ++ .attr = { .name = __stringify(_name), .mode = 0444 }, \ ++ .show = sysaufs_si_##_name, \ ++} ++ ++static struct sysaufs_si_attr sysaufs_si_attr_xi_path = AuSiAttr(xi_path); ++struct attribute *sysaufs_si_attrs[] = { ++ &sysaufs_si_attr_xi_path.attr, ++ NULL, ++}; ++ ++static struct sysfs_ops au_sbi_ops = { ++ .show = sysaufs_si_show ++}; ++ ++static struct kobj_type au_sbi_ktype = { ++ .release = au_si_free, ++ .sysfs_ops = &au_sbi_ops, ++ .default_attrs = sysaufs_si_attrs ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++int sysaufs_si_init(struct au_sbinfo *sbinfo) ++{ ++ int err; ++ ++ sbinfo->si_kobj.kset = sysaufs_ket; ++ /* cf. sysaufs_name() */ ++ err = kobject_init_and_add ++ (&sbinfo->si_kobj, &au_sbi_ktype, /*&sysaufs_ket->kobj*/NULL, ++ SysaufsSiNamePrefix "%lx", sysaufs_si_id(sbinfo)); ++ ++ dbgaufs_si_null(sbinfo); ++ if (!err) { ++ err = dbgaufs_si_init(sbinfo); ++ if (unlikely(err)) ++ kobject_put(&sbinfo->si_kobj); ++ } ++ return err; ++} ++ ++void sysaufs_fin(void) ++{ ++ dbgaufs_fin(); ++ sysfs_remove_group(&sysaufs_ket->kobj, sysaufs_attr_group); ++ kset_unregister(sysaufs_ket); ++} ++ ++int __init sysaufs_init(void) ++{ ++ int err; ++ ++ do { ++ get_random_bytes(&sysaufs_si_mask, sizeof(sysaufs_si_mask)); ++ } while (!sysaufs_si_mask); ++ ++ sysaufs_ket = kset_create_and_add(AUFS_NAME, NULL, fs_kobj); ++ err = PTR_ERR(sysaufs_ket); ++ if (IS_ERR(sysaufs_ket)) ++ goto out; ++ err = sysfs_create_group(&sysaufs_ket->kobj, sysaufs_attr_group); ++ if (unlikely(err)) { ++ kset_unregister(sysaufs_ket); ++ goto out; ++ } ++ ++ err = dbgaufs_init(); ++ if (unlikely(err)) ++ sysaufs_fin(); ++ out: ++ return err; ++} +diff --git a/fs/aufs/sysaufs.h b/fs/aufs/sysaufs.h +new file mode 100644 +index 0000000..6796934 +--- /dev/null ++++ b/fs/aufs/sysaufs.h +@@ -0,0 +1,105 @@ ++/* ++ * Copyright (C) 2005-2010 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* ++ * sysfs interface and mount lifetime management ++ */ ++ ++#ifndef __SYSAUFS_H__ ++#define __SYSAUFS_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++#include "module.h" ++ ++struct super_block; ++struct au_sbinfo; ++ ++struct sysaufs_si_attr { ++ struct attribute attr; ++ int (*show)(struct seq_file *seq, struct super_block *sb); ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* sysaufs.c */ ++extern unsigned long sysaufs_si_mask; ++extern struct kset *sysaufs_ket; ++extern struct attribute *sysaufs_si_attrs[]; ++int sysaufs_si_init(struct au_sbinfo *sbinfo); ++int __init sysaufs_init(void); ++void sysaufs_fin(void); ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* some people doesn't like to show a pointer in kernel */ ++static inline unsigned long sysaufs_si_id(struct au_sbinfo *sbinfo) ++{ ++ return sysaufs_si_mask ^ (unsigned long)sbinfo; ++} ++ ++#define SysaufsSiNamePrefix "si_" ++#define SysaufsSiNameLen (sizeof(SysaufsSiNamePrefix) + 16) ++static inline void sysaufs_name(struct au_sbinfo *sbinfo, char *name) ++{ ++ snprintf(name, SysaufsSiNameLen, SysaufsSiNamePrefix "%lx", ++ sysaufs_si_id(sbinfo)); ++} ++ ++struct au_branch; ++#ifdef CONFIG_SYSFS ++/* sysfs.c */ ++extern struct attribute_group *sysaufs_attr_group; ++ ++int sysaufs_si_xi_path(struct seq_file *seq, struct super_block *sb); ++ssize_t sysaufs_si_show(struct kobject *kobj, struct attribute *attr, ++ char *buf); ++ ++void sysaufs_br_init(struct au_branch *br); ++void sysaufs_brs_add(struct super_block *sb, aufs_bindex_t bindex); ++void sysaufs_brs_del(struct super_block *sb, aufs_bindex_t bindex); ++ ++#define sysaufs_brs_init() do {} while (0) ++ ++#else ++#define sysaufs_attr_group NULL ++ ++AuStubInt0(sysaufs_si_xi_path, struct seq_file *seq, struct super_block *sb) ++ ++static inline ++ssize_t sysaufs_si_show(struct kobject *kobj, struct attribute *attr, ++ char *buf) ++{ ++ return 0; ++} ++ ++AuStubVoid(sysaufs_br_init, struct au_branch *br) ++AuStubVoid(sysaufs_brs_add, struct super_block *sb, aufs_bindex_t bindex) ++AuStubVoid(sysaufs_brs_del, struct super_block *sb, aufs_bindex_t bindex) ++ ++static inline void sysaufs_brs_init(void) ++{ ++ sysaufs_brs = 0; ++} ++ ++#endif /* CONFIG_SYSFS */ ++ ++#endif /* __KERNEL__ */ ++#endif /* __SYSAUFS_H__ */ +diff --git a/fs/aufs/sysfs.c b/fs/aufs/sysfs.c +new file mode 100644 +index 0000000..6340cf9 +--- /dev/null ++++ b/fs/aufs/sysfs.c +@@ -0,0 +1,248 @@ ++/* ++ * Copyright (C) 2005-2010 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* ++ * sysfs interface ++ */ ++ ++#include ++#include ++#include ++#include ++#include "aufs.h" ++ ++#ifdef CONFIG_AUFS_FS_MODULE ++/* this entry violates the "one line per file" policy of sysfs */ ++static ssize_t config_show(struct kobject *kobj, struct kobj_attribute *attr, ++ char *buf) ++{ ++ ssize_t err; ++ static char *conf = ++/* this file is generated at compiling */ ++#include "conf.str" ++ ; ++ ++ err = snprintf(buf, PAGE_SIZE, conf); ++ if (unlikely(err >= PAGE_SIZE)) ++ err = -EFBIG; ++ return err; ++} ++ ++static struct kobj_attribute au_config_attr = __ATTR_RO(config); ++#endif ++ ++static struct attribute *au_attr[] = { ++#ifdef CONFIG_AUFS_FS_MODULE ++ &au_config_attr.attr, ++#endif ++ NULL, /* need to NULL terminate the list of attributes */ ++}; ++ ++static struct attribute_group sysaufs_attr_group_body = { ++ .attrs = au_attr ++}; ++ ++struct attribute_group *sysaufs_attr_group = &sysaufs_attr_group_body; ++ ++/* ---------------------------------------------------------------------- */ ++ ++int sysaufs_si_xi_path(struct seq_file *seq, struct super_block *sb) ++{ ++ int err; ++ ++ SiMustAnyLock(sb); ++ ++ err = 0; ++ if (au_opt_test(au_mntflags(sb), XINO)) { ++ err = au_xino_path(seq, au_sbi(sb)->si_xib); ++ seq_putc(seq, '\n'); ++ } ++ return err; ++} ++ ++/* ++ * the lifetime of branch is independent from the entry under sysfs. ++ * sysfs handles the lifetime of the entry, and never call ->show() after it is ++ * unlinked. ++ */ ++static int sysaufs_si_br(struct seq_file *seq, struct super_block *sb, ++ aufs_bindex_t bindex) ++{ ++ struct path path; ++ struct dentry *root; ++ struct au_branch *br; ++ ++ AuDbg("b%d\n", bindex); ++ ++ root = sb->s_root; ++ di_read_lock_parent(root, !AuLock_IR); ++ br = au_sbr(sb, bindex); ++ path.mnt = br->br_mnt; ++ path.dentry = au_h_dptr(root, bindex); ++ au_seq_path(seq, &path); ++ di_read_unlock(root, !AuLock_IR); ++ seq_printf(seq, "=%s\n", au_optstr_br_perm(br->br_perm)); ++ return 0; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static struct seq_file *au_seq(char *p, ssize_t len) ++{ ++ struct seq_file *seq; ++ ++ seq = kzalloc(sizeof(*seq), GFP_NOFS); ++ if (seq) { ++ /* mutex_init(&seq.lock); */ ++ seq->buf = p; ++ seq->size = len; ++ return seq; /* success */ ++ } ++ ++ seq = ERR_PTR(-ENOMEM); ++ return seq; ++} ++ ++#define SysaufsBr_PREFIX "br" ++ ++/* todo: file size may exceed PAGE_SIZE */ ++ssize_t sysaufs_si_show(struct kobject *kobj, struct attribute *attr, ++ char *buf) ++{ ++ ssize_t err; ++ long l; ++ aufs_bindex_t bend; ++ struct au_sbinfo *sbinfo; ++ struct super_block *sb; ++ struct seq_file *seq; ++ char *name; ++ struct attribute **cattr; ++ ++ sbinfo = container_of(kobj, struct au_sbinfo, si_kobj); ++ sb = sbinfo->si_sb; ++ ++ /* ++ * prevent a race condition between sysfs and aufs. ++ * for instance, sysfs_file_read() calls sysfs_get_active_two() which ++ * prohibits maintaining the sysfs entries. ++ * hew we acquire read lock after sysfs_get_active_two(). ++ * on the other hand, the remount process may maintain the sysfs/aufs ++ * entries after acquiring write lock. ++ * it can cause a deadlock. ++ * simply we gave up processing read here. ++ */ ++ err = -EBUSY; ++ if (unlikely(!si_noflush_read_trylock(sb))) ++ goto out; ++ ++ seq = au_seq(buf, PAGE_SIZE); ++ err = PTR_ERR(seq); ++ if (IS_ERR(seq)) ++ goto out_unlock; ++ ++ name = (void *)attr->name; ++ cattr = sysaufs_si_attrs; ++ while (*cattr) { ++ if (!strcmp(name, (*cattr)->name)) { ++ err = container_of(*cattr, struct sysaufs_si_attr, attr) ++ ->show(seq, sb); ++ goto out_seq; ++ } ++ cattr++; ++ } ++ ++ bend = au_sbend(sb); ++ if (!strncmp(name, SysaufsBr_PREFIX, sizeof(SysaufsBr_PREFIX) - 1)) { ++ name += sizeof(SysaufsBr_PREFIX) - 1; ++ err = strict_strtol(name, 10, &l); ++ if (!err) { ++ if (l <= bend) ++ err = sysaufs_si_br(seq, sb, (aufs_bindex_t)l); ++ else ++ err = -ENOENT; ++ } ++ goto out_seq; ++ } ++ BUG(); ++ ++ out_seq: ++ if (!err) { ++ err = seq->count; ++ /* sysfs limit */ ++ if (unlikely(err == PAGE_SIZE)) ++ err = -EFBIG; ++ } ++ kfree(seq); ++ out_unlock: ++ si_read_unlock(sb); ++ out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void sysaufs_br_init(struct au_branch *br) ++{ ++ br->br_attr.name = br->br_name; ++ br->br_attr.mode = S_IRUGO; ++ br->br_attr.owner = THIS_MODULE; ++} ++ ++void sysaufs_brs_del(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ struct au_branch *br; ++ struct kobject *kobj; ++ aufs_bindex_t bend; ++ ++ dbgaufs_brs_del(sb, bindex); ++ ++ if (!sysaufs_brs) ++ return; ++ ++ kobj = &au_sbi(sb)->si_kobj; ++ bend = au_sbend(sb); ++ for (; bindex <= bend; bindex++) { ++ br = au_sbr(sb, bindex); ++ sysfs_remove_file(kobj, &br->br_attr); ++ } ++} ++ ++void sysaufs_brs_add(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ int err; ++ aufs_bindex_t bend; ++ struct kobject *kobj; ++ struct au_branch *br; ++ ++ dbgaufs_brs_add(sb, bindex); ++ ++ if (!sysaufs_brs) ++ return; ++ ++ kobj = &au_sbi(sb)->si_kobj; ++ bend = au_sbend(sb); ++ for (; bindex <= bend; bindex++) { ++ br = au_sbr(sb, bindex); ++ snprintf(br->br_name, sizeof(br->br_name), SysaufsBr_PREFIX ++ "%d", bindex); ++ err = sysfs_create_file(kobj, &br->br_attr); ++ if (unlikely(err)) ++ pr_warning("failed %s under sysfs(%d)\n", ++ br->br_name, err); ++ } ++} +diff --git a/fs/aufs/sysrq.c b/fs/aufs/sysrq.c +new file mode 100644 +index 0000000..b2f09f7 +--- /dev/null ++++ b/fs/aufs/sysrq.c +@@ -0,0 +1,119 @@ ++/* ++ * Copyright (C) 2005-2010 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* ++ * magic sysrq hanlder ++ */ ++ ++#include ++#include ++#include ++/* #include */ ++#include "aufs.h" ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void sysrq_sb(struct super_block *sb) ++{ ++ char *plevel; ++ struct au_sbinfo *sbinfo; ++ struct file *file; ++ ++ plevel = au_plevel; ++ au_plevel = KERN_WARNING; ++ au_debug(1); ++ ++ sbinfo = au_sbi(sb); ++ /* since we define pr_fmt, call printk directly */ ++ printk(KERN_WARNING "si=%lx\n", sysaufs_si_id(sbinfo)); ++ printk(KERN_WARNING AUFS_NAME ": superblock\n"); ++ au_dpri_sb(sb); ++ printk(KERN_WARNING AUFS_NAME ": root dentry\n"); ++ au_dpri_dentry(sb->s_root); ++ printk(KERN_WARNING AUFS_NAME ": root inode\n"); ++ au_dpri_inode(sb->s_root->d_inode); ++#if 0 ++ struct inode *i; ++ printk(KERN_WARNING AUFS_NAME ": isolated inode\n"); ++ list_for_each_entry(i, &sb->s_inodes, i_sb_list) ++ if (list_empty(&i->i_dentry)) ++ au_dpri_inode(i); ++#endif ++ printk(KERN_WARNING AUFS_NAME ": files\n"); ++ list_for_each_entry(file, &sb->s_files, f_u.fu_list) { ++ umode_t mode; ++ mode = file->f_dentry->d_inode->i_mode; ++ if (!special_file(mode) || au_special_file(mode)) ++ au_dpri_file(file); ++ } ++ ++ au_plevel = plevel; ++ au_debug(0); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* module parameter */ ++static char *aufs_sysrq_key = "a"; ++module_param_named(sysrq, aufs_sysrq_key, charp, S_IRUGO); ++MODULE_PARM_DESC(sysrq, "MagicSysRq key for " AUFS_NAME); ++ ++static void au_sysrq(int key __maybe_unused, ++ struct tty_struct *tty __maybe_unused) ++{ ++ struct kobject *kobj; ++ struct au_sbinfo *sbinfo; ++ ++ /* spin_lock(&sysaufs_ket->list_lock); */ ++ list_for_each_entry(kobj, &sysaufs_ket->list, entry) { ++ sbinfo = container_of(kobj, struct au_sbinfo, si_kobj); ++ sysrq_sb(sbinfo->si_sb); ++ } ++ /* spin_unlock(&sysaufs_ket->list_lock); */ ++} ++ ++static struct sysrq_key_op au_sysrq_op = { ++ .handler = au_sysrq, ++ .help_msg = "Aufs", ++ .action_msg = "Aufs", ++ .enable_mask = SYSRQ_ENABLE_DUMP ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++int __init au_sysrq_init(void) ++{ ++ int err; ++ char key; ++ ++ err = -1; ++ key = *aufs_sysrq_key; ++ if ('a' <= key && key <= 'z') ++ err = register_sysrq_key(key, &au_sysrq_op); ++ if (unlikely(err)) ++ pr_err("err %d, sysrq=%c\n", err, key); ++ return err; ++} ++ ++void au_sysrq_fin(void) ++{ ++ int err; ++ err = unregister_sysrq_key(*aufs_sysrq_key, &au_sysrq_op); ++ if (unlikely(err)) ++ pr_err("err %d (ignored)\n", err); ++} +diff --git a/fs/aufs/vdir.c b/fs/aufs/vdir.c +new file mode 100644 +index 0000000..36435c9 +--- /dev/null ++++ b/fs/aufs/vdir.c +@@ -0,0 +1,884 @@ ++/* ++ * Copyright (C) 2005-2010 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* ++ * virtual or vertical directory ++ */ ++ ++#include ++#include "aufs.h" ++ ++static unsigned int calc_size(int nlen) ++{ ++ return ALIGN(sizeof(struct au_vdir_de) + nlen, sizeof(ino_t)); ++} ++ ++static int set_deblk_end(union au_vdir_deblk_p *p, ++ union au_vdir_deblk_p *deblk_end) ++{ ++ if (calc_size(0) <= deblk_end->deblk - p->deblk) { ++ p->de->de_str.len = 0; ++ /* smp_mb(); */ ++ return 0; ++ } ++ return -1; /* error */ ++} ++ ++/* returns true or false */ ++static int is_deblk_end(union au_vdir_deblk_p *p, ++ union au_vdir_deblk_p *deblk_end) ++{ ++ if (calc_size(0) <= deblk_end->deblk - p->deblk) ++ return !p->de->de_str.len; ++ return 1; ++} ++ ++static unsigned char *last_deblk(struct au_vdir *vdir) ++{ ++ return vdir->vd_deblk[vdir->vd_nblk - 1]; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* estimate the apropriate size for name hash table */ ++unsigned int au_rdhash_est(loff_t sz) ++{ ++ unsigned int n; ++ ++ n = UINT_MAX; ++ sz >>= 10; ++ if (sz < n) ++ n = sz; ++ if (sz < AUFS_RDHASH_DEF) ++ n = AUFS_RDHASH_DEF; ++ /* pr_info("n %u\n", n); */ ++ return n; ++} ++ ++/* ++ * the allocated memory has to be freed by ++ * au_nhash_wh_free() or au_nhash_de_free(). ++ */ ++int au_nhash_alloc(struct au_nhash *nhash, unsigned int num_hash, gfp_t gfp) ++{ ++ struct hlist_head *head; ++ unsigned int u; ++ ++ head = kmalloc(sizeof(*nhash->nh_head) * num_hash, gfp); ++ if (head) { ++ nhash->nh_num = num_hash; ++ nhash->nh_head = head; ++ for (u = 0; u < num_hash; u++) ++ INIT_HLIST_HEAD(head++); ++ return 0; /* success */ ++ } ++ ++ return -ENOMEM; ++} ++ ++static void nhash_count(struct hlist_head *head) ++{ ++#if 0 ++ unsigned long n; ++ struct hlist_node *pos; ++ ++ n = 0; ++ hlist_for_each(pos, head) ++ n++; ++ pr_info("%lu\n", n); ++#endif ++} ++ ++static void au_nhash_wh_do_free(struct hlist_head *head) ++{ ++ struct au_vdir_wh *tpos; ++ struct hlist_node *pos, *node; ++ ++ hlist_for_each_entry_safe(tpos, pos, node, head, wh_hash) { ++ /* hlist_del(pos); */ ++ kfree(tpos); ++ } ++} ++ ++static void au_nhash_de_do_free(struct hlist_head *head) ++{ ++ struct au_vdir_dehstr *tpos; ++ struct hlist_node *pos, *node; ++ ++ hlist_for_each_entry_safe(tpos, pos, node, head, hash) { ++ /* hlist_del(pos); */ ++ au_cache_free_vdir_dehstr(tpos); ++ } ++} ++ ++static void au_nhash_do_free(struct au_nhash *nhash, ++ void (*free)(struct hlist_head *head)) ++{ ++ unsigned int n; ++ struct hlist_head *head; ++ ++ n = nhash->nh_num; ++ if (!n) ++ return; ++ ++ head = nhash->nh_head; ++ while (n-- > 0) { ++ nhash_count(head); ++ free(head++); ++ } ++ kfree(nhash->nh_head); ++} ++ ++void au_nhash_wh_free(struct au_nhash *whlist) ++{ ++ au_nhash_do_free(whlist, au_nhash_wh_do_free); ++} ++ ++static void au_nhash_de_free(struct au_nhash *delist) ++{ ++ au_nhash_do_free(delist, au_nhash_de_do_free); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_nhash_test_longer_wh(struct au_nhash *whlist, aufs_bindex_t btgt, ++ int limit) ++{ ++ int num; ++ unsigned int u, n; ++ struct hlist_head *head; ++ struct au_vdir_wh *tpos; ++ struct hlist_node *pos; ++ ++ num = 0; ++ n = whlist->nh_num; ++ head = whlist->nh_head; ++ for (u = 0; u < n; u++, head++) ++ hlist_for_each_entry(tpos, pos, head, wh_hash) ++ if (tpos->wh_bindex == btgt && ++num > limit) ++ return 1; ++ return 0; ++} ++ ++static struct hlist_head *au_name_hash(struct au_nhash *nhash, ++ unsigned char *name, ++ unsigned int len) ++{ ++ unsigned int v; ++ /* const unsigned int magic_bit = 12; */ ++ ++ AuDebugOn(!nhash->nh_num || !nhash->nh_head); ++ ++ v = 0; ++ while (len--) ++ v += *name++; ++ /* v = hash_long(v, magic_bit); */ ++ v %= nhash->nh_num; ++ return nhash->nh_head + v; ++} ++ ++static int au_nhash_test_name(struct au_vdir_destr *str, const char *name, ++ int nlen) ++{ ++ return str->len == nlen && !memcmp(str->name, name, nlen); ++} ++ ++/* returns found or not */ ++int au_nhash_test_known_wh(struct au_nhash *whlist, char *name, int nlen) ++{ ++ struct hlist_head *head; ++ struct au_vdir_wh *tpos; ++ struct hlist_node *pos; ++ struct au_vdir_destr *str; ++ ++ head = au_name_hash(whlist, name, nlen); ++ hlist_for_each_entry(tpos, pos, head, wh_hash) { ++ str = &tpos->wh_str; ++ AuDbg("%.*s\n", str->len, str->name); ++ if (au_nhash_test_name(str, name, nlen)) ++ return 1; ++ } ++ return 0; ++} ++ ++/* returns found(true) or not */ ++static int test_known(struct au_nhash *delist, char *name, int nlen) ++{ ++ struct hlist_head *head; ++ struct au_vdir_dehstr *tpos; ++ struct hlist_node *pos; ++ struct au_vdir_destr *str; ++ ++ head = au_name_hash(delist, name, nlen); ++ hlist_for_each_entry(tpos, pos, head, hash) { ++ str = tpos->str; ++ AuDbg("%.*s\n", str->len, str->name); ++ if (au_nhash_test_name(str, name, nlen)) ++ return 1; ++ } ++ return 0; ++} ++ ++static void au_shwh_init_wh(struct au_vdir_wh *wh, ino_t ino, ++ unsigned char d_type) ++{ ++#ifdef CONFIG_AUFS_SHWH ++ wh->wh_ino = ino; ++ wh->wh_type = d_type; ++#endif ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_nhash_append_wh(struct au_nhash *whlist, char *name, int nlen, ino_t ino, ++ unsigned int d_type, aufs_bindex_t bindex, ++ unsigned char shwh) ++{ ++ int err; ++ struct au_vdir_destr *str; ++ struct au_vdir_wh *wh; ++ ++ AuDbg("%.*s\n", nlen, name); ++ AuDebugOn(!whlist->nh_num || !whlist->nh_head); ++ ++ err = -ENOMEM; ++ wh = kmalloc(sizeof(*wh) + nlen, GFP_NOFS); ++ if (unlikely(!wh)) ++ goto out; ++ ++ err = 0; ++ wh->wh_bindex = bindex; ++ if (shwh) ++ au_shwh_init_wh(wh, ino, d_type); ++ str = &wh->wh_str; ++ str->len = nlen; ++ memcpy(str->name, name, nlen); ++ hlist_add_head(&wh->wh_hash, au_name_hash(whlist, name, nlen)); ++ /* smp_mb(); */ ++ ++ out: ++ return err; ++} ++ ++static int append_deblk(struct au_vdir *vdir) ++{ ++ int err; ++ unsigned long ul; ++ const unsigned int deblk_sz = vdir->vd_deblk_sz; ++ union au_vdir_deblk_p p, deblk_end; ++ unsigned char **o; ++ ++ err = -ENOMEM; ++ o = krealloc(vdir->vd_deblk, sizeof(*o) * (vdir->vd_nblk + 1), ++ GFP_NOFS); ++ if (unlikely(!o)) ++ goto out; ++ ++ vdir->vd_deblk = o; ++ p.deblk = kmalloc(deblk_sz, GFP_NOFS); ++ if (p.deblk) { ++ ul = vdir->vd_nblk++; ++ vdir->vd_deblk[ul] = p.deblk; ++ vdir->vd_last.ul = ul; ++ vdir->vd_last.p.deblk = p.deblk; ++ deblk_end.deblk = p.deblk + deblk_sz; ++ err = set_deblk_end(&p, &deblk_end); ++ } ++ ++ out: ++ return err; ++} ++ ++static int append_de(struct au_vdir *vdir, char *name, int nlen, ino_t ino, ++ unsigned int d_type, struct au_nhash *delist) ++{ ++ int err; ++ unsigned int sz; ++ const unsigned int deblk_sz = vdir->vd_deblk_sz; ++ union au_vdir_deblk_p p, *room, deblk_end; ++ struct au_vdir_dehstr *dehstr; ++ ++ p.deblk = last_deblk(vdir); ++ deblk_end.deblk = p.deblk + deblk_sz; ++ room = &vdir->vd_last.p; ++ AuDebugOn(room->deblk < p.deblk || deblk_end.deblk <= room->deblk ++ || !is_deblk_end(room, &deblk_end)); ++ ++ sz = calc_size(nlen); ++ if (unlikely(sz > deblk_end.deblk - room->deblk)) { ++ err = append_deblk(vdir); ++ if (unlikely(err)) ++ goto out; ++ ++ p.deblk = last_deblk(vdir); ++ deblk_end.deblk = p.deblk + deblk_sz; ++ /* smp_mb(); */ ++ AuDebugOn(room->deblk != p.deblk); ++ } ++ ++ err = -ENOMEM; ++ dehstr = au_cache_alloc_vdir_dehstr(); ++ if (unlikely(!dehstr)) ++ goto out; ++ ++ dehstr->str = &room->de->de_str; ++ hlist_add_head(&dehstr->hash, au_name_hash(delist, name, nlen)); ++ room->de->de_ino = ino; ++ room->de->de_type = d_type; ++ room->de->de_str.len = nlen; ++ memcpy(room->de->de_str.name, name, nlen); ++ ++ err = 0; ++ room->deblk += sz; ++ if (unlikely(set_deblk_end(room, &deblk_end))) ++ err = append_deblk(vdir); ++ /* smp_mb(); */ ++ ++ out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void au_vdir_free(struct au_vdir *vdir) ++{ ++ unsigned char **deblk; ++ ++ deblk = vdir->vd_deblk; ++ while (vdir->vd_nblk--) ++ kfree(*deblk++); ++ kfree(vdir->vd_deblk); ++ au_cache_free_vdir(vdir); ++} ++ ++static struct au_vdir *alloc_vdir(struct file *file) ++{ ++ struct au_vdir *vdir; ++ struct super_block *sb; ++ int err; ++ ++ sb = file->f_dentry->d_sb; ++ SiMustAnyLock(sb); ++ ++ err = -ENOMEM; ++ vdir = au_cache_alloc_vdir(); ++ if (unlikely(!vdir)) ++ goto out; ++ ++ vdir->vd_deblk = kzalloc(sizeof(*vdir->vd_deblk), GFP_NOFS); ++ if (unlikely(!vdir->vd_deblk)) ++ goto out_free; ++ ++ vdir->vd_deblk_sz = au_sbi(sb)->si_rdblk; ++ if (!vdir->vd_deblk_sz) { ++ /* estimate the apropriate size for deblk */ ++ vdir->vd_deblk_sz = au_dir_size(file, /*dentry*/NULL); ++ /* pr_info("vd_deblk_sz %u\n", vdir->vd_deblk_sz); */ ++ } ++ vdir->vd_nblk = 0; ++ vdir->vd_version = 0; ++ vdir->vd_jiffy = 0; ++ err = append_deblk(vdir); ++ if (!err) ++ return vdir; /* success */ ++ ++ kfree(vdir->vd_deblk); ++ ++ out_free: ++ au_cache_free_vdir(vdir); ++ out: ++ vdir = ERR_PTR(err); ++ return vdir; ++} ++ ++static int reinit_vdir(struct au_vdir *vdir) ++{ ++ int err; ++ union au_vdir_deblk_p p, deblk_end; ++ ++ while (vdir->vd_nblk > 1) { ++ kfree(vdir->vd_deblk[vdir->vd_nblk - 1]); ++ /* vdir->vd_deblk[vdir->vd_nblk - 1] = NULL; */ ++ vdir->vd_nblk--; ++ } ++ p.deblk = vdir->vd_deblk[0]; ++ deblk_end.deblk = p.deblk + vdir->vd_deblk_sz; ++ err = set_deblk_end(&p, &deblk_end); ++ /* keep vd_dblk_sz */ ++ vdir->vd_last.ul = 0; ++ vdir->vd_last.p.deblk = vdir->vd_deblk[0]; ++ vdir->vd_version = 0; ++ vdir->vd_jiffy = 0; ++ /* smp_mb(); */ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++#define AuFillVdir_CALLED 1 ++#define AuFillVdir_WHABLE (1 << 1) ++#define AuFillVdir_SHWH (1 << 2) ++#define au_ftest_fillvdir(flags, name) ((flags) & AuFillVdir_##name) ++#define au_fset_fillvdir(flags, name) { (flags) |= AuFillVdir_##name; } ++#define au_fclr_fillvdir(flags, name) { (flags) &= ~AuFillVdir_##name; } ++ ++#ifndef CONFIG_AUFS_SHWH ++#undef AuFillVdir_SHWH ++#define AuFillVdir_SHWH 0 ++#endif ++ ++struct fillvdir_arg { ++ struct file *file; ++ struct au_vdir *vdir; ++ struct au_nhash delist; ++ struct au_nhash whlist; ++ aufs_bindex_t bindex; ++ unsigned int flags; ++ int err; ++}; ++ ++static int fillvdir(void *__arg, const char *__name, int nlen, ++ loff_t offset __maybe_unused, u64 h_ino, ++ unsigned int d_type) ++{ ++ struct fillvdir_arg *arg = __arg; ++ char *name = (void *)__name; ++ struct super_block *sb; ++ ino_t ino; ++ const unsigned char shwh = !!au_ftest_fillvdir(arg->flags, SHWH); ++ ++ arg->err = 0; ++ sb = arg->file->f_dentry->d_sb; ++ au_fset_fillvdir(arg->flags, CALLED); ++ /* smp_mb(); */ ++ if (nlen <= AUFS_WH_PFX_LEN ++ || memcmp(name, AUFS_WH_PFX, AUFS_WH_PFX_LEN)) { ++ if (test_known(&arg->delist, name, nlen) ++ || au_nhash_test_known_wh(&arg->whlist, name, nlen)) ++ goto out; /* already exists or whiteouted */ ++ ++ sb = arg->file->f_dentry->d_sb; ++ arg->err = au_ino(sb, arg->bindex, h_ino, d_type, &ino); ++ if (!arg->err) { ++ if (unlikely(nlen > AUFS_MAX_NAMELEN)) ++ d_type = DT_UNKNOWN; ++ arg->err = append_de(arg->vdir, name, nlen, ino, ++ d_type, &arg->delist); ++ } ++ } else if (au_ftest_fillvdir(arg->flags, WHABLE)) { ++ name += AUFS_WH_PFX_LEN; ++ nlen -= AUFS_WH_PFX_LEN; ++ if (au_nhash_test_known_wh(&arg->whlist, name, nlen)) ++ goto out; /* already whiteouted */ ++ ++ if (shwh) ++ arg->err = au_wh_ino(sb, arg->bindex, h_ino, d_type, ++ &ino); ++ if (!arg->err) { ++ if (nlen <= AUFS_MAX_NAMELEN + AUFS_WH_PFX_LEN) ++ d_type = DT_UNKNOWN; ++ arg->err = au_nhash_append_wh ++ (&arg->whlist, name, nlen, ino, d_type, ++ arg->bindex, shwh); ++ } ++ } ++ ++ out: ++ if (!arg->err) ++ arg->vdir->vd_jiffy = jiffies; ++ /* smp_mb(); */ ++ AuTraceErr(arg->err); ++ return arg->err; ++} ++ ++static int au_handle_shwh(struct super_block *sb, struct au_vdir *vdir, ++ struct au_nhash *whlist, struct au_nhash *delist) ++{ ++#ifdef CONFIG_AUFS_SHWH ++ int err; ++ unsigned int nh, u; ++ struct hlist_head *head; ++ struct au_vdir_wh *tpos; ++ struct hlist_node *pos, *n; ++ char *p, *o; ++ struct au_vdir_destr *destr; ++ ++ AuDebugOn(!au_opt_test(au_mntflags(sb), SHWH)); ++ ++ err = -ENOMEM; ++ o = p = __getname(); ++ if (unlikely(!p)) ++ goto out; ++ ++ err = 0; ++ nh = whlist->nh_num; ++ memcpy(p, AUFS_WH_PFX, AUFS_WH_PFX_LEN); ++ p += AUFS_WH_PFX_LEN; ++ for (u = 0; u < nh; u++) { ++ head = whlist->nh_head + u; ++ hlist_for_each_entry_safe(tpos, pos, n, head, wh_hash) { ++ destr = &tpos->wh_str; ++ memcpy(p, destr->name, destr->len); ++ err = append_de(vdir, o, destr->len + AUFS_WH_PFX_LEN, ++ tpos->wh_ino, tpos->wh_type, delist); ++ if (unlikely(err)) ++ break; ++ } ++ } ++ ++ __putname(o); ++ ++ out: ++ AuTraceErr(err); ++ return err; ++#else ++ return 0; ++#endif ++} ++ ++static int au_do_read_vdir(struct fillvdir_arg *arg) ++{ ++ int err; ++ unsigned int rdhash; ++ loff_t offset; ++ aufs_bindex_t bend, bindex, bstart; ++ unsigned char shwh; ++ struct file *hf, *file; ++ struct super_block *sb; ++ ++ file = arg->file; ++ sb = file->f_dentry->d_sb; ++ SiMustAnyLock(sb); ++ ++ rdhash = au_sbi(sb)->si_rdhash; ++ if (!rdhash) ++ rdhash = au_rdhash_est(au_dir_size(file, /*dentry*/NULL)); ++ err = au_nhash_alloc(&arg->delist, rdhash, GFP_NOFS); ++ if (unlikely(err)) ++ goto out; ++ err = au_nhash_alloc(&arg->whlist, rdhash, GFP_NOFS); ++ if (unlikely(err)) ++ goto out_delist; ++ ++ err = 0; ++ arg->flags = 0; ++ shwh = 0; ++ if (au_opt_test(au_mntflags(sb), SHWH)) { ++ shwh = 1; ++ au_fset_fillvdir(arg->flags, SHWH); ++ } ++ bstart = au_fbstart(file); ++ bend = au_fbend(file); ++ for (bindex = bstart; !err && bindex <= bend; bindex++) { ++ hf = au_h_fptr(file, bindex); ++ if (!hf) ++ continue; ++ ++ offset = vfsub_llseek(hf, 0, SEEK_SET); ++ err = offset; ++ if (unlikely(offset)) ++ break; ++ ++ arg->bindex = bindex; ++ au_fclr_fillvdir(arg->flags, WHABLE); ++ if (shwh ++ || (bindex != bend ++ && au_br_whable(au_sbr_perm(sb, bindex)))) ++ au_fset_fillvdir(arg->flags, WHABLE); ++ do { ++ arg->err = 0; ++ au_fclr_fillvdir(arg->flags, CALLED); ++ /* smp_mb(); */ ++ err = vfsub_readdir(hf, fillvdir, arg); ++ if (err >= 0) ++ err = arg->err; ++ } while (!err && au_ftest_fillvdir(arg->flags, CALLED)); ++ } ++ ++ if (!err && shwh) ++ err = au_handle_shwh(sb, arg->vdir, &arg->whlist, &arg->delist); ++ ++ au_nhash_wh_free(&arg->whlist); ++ ++ out_delist: ++ au_nhash_de_free(&arg->delist); ++ out: ++ return err; ++} ++ ++static int read_vdir(struct file *file, int may_read) ++{ ++ int err; ++ unsigned long expire; ++ unsigned char do_read; ++ struct fillvdir_arg arg; ++ struct inode *inode; ++ struct au_vdir *vdir, *allocated; ++ ++ err = 0; ++ inode = file->f_dentry->d_inode; ++ IMustLock(inode); ++ SiMustAnyLock(inode->i_sb); ++ ++ allocated = NULL; ++ do_read = 0; ++ expire = au_sbi(inode->i_sb)->si_rdcache; ++ vdir = au_ivdir(inode); ++ if (!vdir) { ++ do_read = 1; ++ vdir = alloc_vdir(file); ++ err = PTR_ERR(vdir); ++ if (IS_ERR(vdir)) ++ goto out; ++ err = 0; ++ allocated = vdir; ++ } else if (may_read ++ && (inode->i_version != vdir->vd_version ++ || time_after(jiffies, vdir->vd_jiffy + expire))) { ++ do_read = 1; ++ err = reinit_vdir(vdir); ++ if (unlikely(err)) ++ goto out; ++ } ++ ++ if (!do_read) ++ return 0; /* success */ ++ ++ arg.file = file; ++ arg.vdir = vdir; ++ err = au_do_read_vdir(&arg); ++ if (!err) { ++ /* file->f_pos = 0; */ ++ vdir->vd_version = inode->i_version; ++ vdir->vd_last.ul = 0; ++ vdir->vd_last.p.deblk = vdir->vd_deblk[0]; ++ if (allocated) ++ au_set_ivdir(inode, allocated); ++ } else if (allocated) ++ au_vdir_free(allocated); ++ ++ out: ++ return err; ++} ++ ++static int copy_vdir(struct au_vdir *tgt, struct au_vdir *src) ++{ ++ int err, rerr; ++ unsigned long ul, n; ++ const unsigned int deblk_sz = src->vd_deblk_sz; ++ ++ AuDebugOn(tgt->vd_nblk != 1); ++ ++ err = -ENOMEM; ++ if (tgt->vd_nblk < src->vd_nblk) { ++ unsigned char **p; ++ ++ p = krealloc(tgt->vd_deblk, sizeof(*p) * src->vd_nblk, ++ GFP_NOFS); ++ if (unlikely(!p)) ++ goto out; ++ tgt->vd_deblk = p; ++ } ++ ++ if (tgt->vd_deblk_sz != deblk_sz) { ++ unsigned char *p; ++ ++ tgt->vd_deblk_sz = deblk_sz; ++ p = krealloc(tgt->vd_deblk[0], deblk_sz, GFP_NOFS); ++ if (unlikely(!p)) ++ goto out; ++ tgt->vd_deblk[0] = p; ++ } ++ memcpy(tgt->vd_deblk[0], src->vd_deblk[0], deblk_sz); ++ tgt->vd_version = src->vd_version; ++ tgt->vd_jiffy = src->vd_jiffy; ++ ++ n = src->vd_nblk; ++ for (ul = 1; ul < n; ul++) { ++ tgt->vd_deblk[ul] = kmemdup(src->vd_deblk[ul], deblk_sz, ++ GFP_NOFS); ++ if (unlikely(!tgt->vd_deblk[ul])) ++ goto out; ++ tgt->vd_nblk++; ++ } ++ tgt->vd_nblk = n; ++ tgt->vd_last.ul = tgt->vd_last.ul; ++ tgt->vd_last.p.deblk = tgt->vd_deblk[tgt->vd_last.ul]; ++ tgt->vd_last.p.deblk += src->vd_last.p.deblk ++ - src->vd_deblk[src->vd_last.ul]; ++ /* smp_mb(); */ ++ return 0; /* success */ ++ ++ out: ++ rerr = reinit_vdir(tgt); ++ BUG_ON(rerr); ++ return err; ++} ++ ++int au_vdir_init(struct file *file) ++{ ++ int err; ++ struct inode *inode; ++ struct au_vdir *vdir_cache, *allocated; ++ ++ err = read_vdir(file, !file->f_pos); ++ if (unlikely(err)) ++ goto out; ++ ++ allocated = NULL; ++ vdir_cache = au_fvdir_cache(file); ++ if (!vdir_cache) { ++ vdir_cache = alloc_vdir(file); ++ err = PTR_ERR(vdir_cache); ++ if (IS_ERR(vdir_cache)) ++ goto out; ++ allocated = vdir_cache; ++ } else if (!file->f_pos && vdir_cache->vd_version != file->f_version) { ++ err = reinit_vdir(vdir_cache); ++ if (unlikely(err)) ++ goto out; ++ } else ++ return 0; /* success */ ++ ++ inode = file->f_dentry->d_inode; ++ err = copy_vdir(vdir_cache, au_ivdir(inode)); ++ if (!err) { ++ file->f_version = inode->i_version; ++ if (allocated) ++ au_set_fvdir_cache(file, allocated); ++ } else if (allocated) ++ au_vdir_free(allocated); ++ ++ out: ++ return err; ++} ++ ++static loff_t calc_offset(struct au_vdir *vdir) ++{ ++ loff_t offset; ++ union au_vdir_deblk_p p; ++ ++ p.deblk = vdir->vd_deblk[vdir->vd_last.ul]; ++ offset = vdir->vd_last.p.deblk - p.deblk; ++ offset += vdir->vd_deblk_sz * vdir->vd_last.ul; ++ return offset; ++} ++ ++/* returns true or false */ ++static int seek_vdir(struct file *file) ++{ ++ int valid; ++ unsigned int deblk_sz; ++ unsigned long ul, n; ++ loff_t offset; ++ union au_vdir_deblk_p p, deblk_end; ++ struct au_vdir *vdir_cache; ++ ++ valid = 1; ++ vdir_cache = au_fvdir_cache(file); ++ offset = calc_offset(vdir_cache); ++ AuDbg("offset %lld\n", offset); ++ if (file->f_pos == offset) ++ goto out; ++ ++ vdir_cache->vd_last.ul = 0; ++ vdir_cache->vd_last.p.deblk = vdir_cache->vd_deblk[0]; ++ if (!file->f_pos) ++ goto out; ++ ++ valid = 0; ++ deblk_sz = vdir_cache->vd_deblk_sz; ++ ul = div64_u64(file->f_pos, deblk_sz); ++ AuDbg("ul %lu\n", ul); ++ if (ul >= vdir_cache->vd_nblk) ++ goto out; ++ ++ n = vdir_cache->vd_nblk; ++ for (; ul < n; ul++) { ++ p.deblk = vdir_cache->vd_deblk[ul]; ++ deblk_end.deblk = p.deblk + deblk_sz; ++ offset = ul; ++ offset *= deblk_sz; ++ while (!is_deblk_end(&p, &deblk_end) && offset < file->f_pos) { ++ unsigned int l; ++ ++ l = calc_size(p.de->de_str.len); ++ offset += l; ++ p.deblk += l; ++ } ++ if (!is_deblk_end(&p, &deblk_end)) { ++ valid = 1; ++ vdir_cache->vd_last.ul = ul; ++ vdir_cache->vd_last.p = p; ++ break; ++ } ++ } ++ ++ out: ++ /* smp_mb(); */ ++ AuTraceErr(!valid); ++ return valid; ++} ++ ++int au_vdir_fill_de(struct file *file, void *dirent, filldir_t filldir) ++{ ++ int err; ++ unsigned int l, deblk_sz; ++ union au_vdir_deblk_p deblk_end; ++ struct au_vdir *vdir_cache; ++ struct au_vdir_de *de; ++ ++ vdir_cache = au_fvdir_cache(file); ++ if (!seek_vdir(file)) ++ return 0; ++ ++ deblk_sz = vdir_cache->vd_deblk_sz; ++ while (1) { ++ deblk_end.deblk = vdir_cache->vd_deblk[vdir_cache->vd_last.ul]; ++ deblk_end.deblk += deblk_sz; ++ while (!is_deblk_end(&vdir_cache->vd_last.p, &deblk_end)) { ++ de = vdir_cache->vd_last.p.de; ++ AuDbg("%.*s, off%lld, i%lu, dt%d\n", ++ de->de_str.len, de->de_str.name, file->f_pos, ++ (unsigned long)de->de_ino, de->de_type); ++ err = filldir(dirent, de->de_str.name, de->de_str.len, ++ file->f_pos, de->de_ino, de->de_type); ++ if (unlikely(err)) { ++ AuTraceErr(err); ++ /* todo: ignore the error caused by udba? */ ++ /* return err; */ ++ return 0; ++ } ++ ++ l = calc_size(de->de_str.len); ++ vdir_cache->vd_last.p.deblk += l; ++ file->f_pos += l; ++ } ++ if (vdir_cache->vd_last.ul < vdir_cache->vd_nblk - 1) { ++ vdir_cache->vd_last.ul++; ++ vdir_cache->vd_last.p.deblk ++ = vdir_cache->vd_deblk[vdir_cache->vd_last.ul]; ++ file->f_pos = deblk_sz * vdir_cache->vd_last.ul; ++ continue; ++ } ++ break; ++ } ++ ++ /* smp_mb(); */ ++ return 0; ++} +diff --git a/fs/aufs/vfsub.c b/fs/aufs/vfsub.c +new file mode 100644 +index 0000000..2f21c2f +--- /dev/null ++++ b/fs/aufs/vfsub.c +@@ -0,0 +1,790 @@ ++/* ++ * Copyright (C) 2005-2010 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* ++ * sub-routines for VFS ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "aufs.h" ++ ++int vfsub_update_h_iattr(struct path *h_path, int *did) ++{ ++ int err; ++ struct kstat st; ++ struct super_block *h_sb; ++ ++ /* for remote fs, leave work for its getattr or d_revalidate */ ++ /* for bad i_attr fs, handle them in aufs_getattr() */ ++ /* still some fs may acquire i_mutex. we need to skip them */ ++ err = 0; ++ if (!did) ++ did = &err; ++ h_sb = h_path->dentry->d_sb; ++ *did = (!au_test_fs_remote(h_sb) && au_test_fs_refresh_iattr(h_sb)); ++ if (*did) ++ err = vfs_getattr(h_path->mnt, h_path->dentry, &st); ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_conv_oflags(int flags) ++{ ++ int mask = 0; ++ ++#ifdef CONFIG_IMA ++ fmode_t fmode; ++ ++ /* mask = MAY_OPEN; */ ++ fmode = OPEN_FMODE(flags); ++ if (fmode & FMODE_READ) ++ mask |= MAY_READ; ++ if ((fmode & FMODE_WRITE) ++ || (flags & O_TRUNC)) ++ mask |= MAY_WRITE; ++ /* ++ * if (flags & O_APPEND) ++ * mask |= MAY_APPEND; ++ */ ++ if (flags & vfsub_fmode_to_uint(FMODE_EXEC)) ++ mask |= MAY_EXEC; ++ ++ AuDbg("flags 0x%x, mask 0x%x\n", flags, mask); ++#endif ++ ++ return mask; ++} ++ ++struct file *vfsub_dentry_open(struct path *path, int flags) ++{ ++ struct file *file; ++ int err; ++ ++ path_get(path); ++ file = dentry_open(path->dentry, path->mnt, flags, current_cred()); ++ if (IS_ERR(file)) ++ goto out; ++ ++ err = ima_file_check(file, au_conv_oflags(flags)); ++ if (unlikely(err)) { ++ fput(file); ++ file = ERR_PTR(err); ++ } ++out: ++ return file; ++} ++ ++struct file *vfsub_filp_open(const char *path, int oflags, int mode) ++{ ++ struct file *file; ++ ++ /* lockdep_off(); */ ++ file = filp_open(path, oflags, mode); ++ /* lockdep_on(); */ ++ if (IS_ERR(file)) ++ goto out; ++ vfsub_update_h_iattr(&file->f_path, /*did*/NULL); /*ignore*/ ++ ++ out: ++ return file; ++} ++ ++int vfsub_kern_path(const char *name, unsigned int flags, struct path *path) ++{ ++ int err; ++ ++ /* lockdep_off(); */ ++ err = kern_path(name, flags, path); ++ /* lockdep_on(); */ ++ if (!err && path->dentry->d_inode) ++ vfsub_update_h_iattr(path, /*did*/NULL); /*ignore*/ ++ return err; ++} ++ ++struct dentry *vfsub_lookup_one_len(const char *name, struct dentry *parent, ++ int len) ++{ ++ struct path path = { ++ .mnt = NULL ++ }; ++ ++ /* VFS checks it too, but by WARN_ON_ONCE() */ ++ IMustLock(parent->d_inode); ++ ++ path.dentry = lookup_one_len(name, parent, len); ++ if (IS_ERR(path.dentry)) ++ goto out; ++ if (path.dentry->d_inode) ++ vfsub_update_h_iattr(&path, /*did*/NULL); /*ignore*/ ++ ++ out: ++ AuTraceErrPtr(path.dentry); ++ return path.dentry; ++} ++ ++struct dentry *vfsub_lookup_hash(struct nameidata *nd) ++{ ++ struct path path = { ++ .mnt = nd->path.mnt ++ }; ++ ++ IMustLock(nd->path.dentry->d_inode); ++ ++ path.dentry = lookup_hash(nd); ++ if (IS_ERR(path.dentry)) ++ goto out; ++ if (path.dentry->d_inode) ++ vfsub_update_h_iattr(&path, /*did*/NULL); /*ignore*/ ++ ++ out: ++ AuTraceErrPtr(path.dentry); ++ return path.dentry; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct dentry *vfsub_lock_rename(struct dentry *d1, struct au_hinode *hdir1, ++ struct dentry *d2, struct au_hinode *hdir2) ++{ ++ struct dentry *d; ++ ++ lockdep_off(); ++ d = lock_rename(d1, d2); ++ lockdep_on(); ++ au_hin_suspend(hdir1); ++ if (hdir1 != hdir2) ++ au_hin_suspend(hdir2); ++ ++ return d; ++} ++ ++void vfsub_unlock_rename(struct dentry *d1, struct au_hinode *hdir1, ++ struct dentry *d2, struct au_hinode *hdir2) ++{ ++ au_hin_resume(hdir1); ++ if (hdir1 != hdir2) ++ au_hin_resume(hdir2); ++ lockdep_off(); ++ unlock_rename(d1, d2); ++ lockdep_on(); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int vfsub_create(struct inode *dir, struct path *path, int mode) ++{ ++ int err; ++ struct dentry *d; ++ ++ IMustLock(dir); ++ ++ d = path->dentry; ++ path->dentry = d->d_parent; ++ err = security_path_mknod(path, path->dentry, mode, 0); ++ path->dentry = d; ++ if (unlikely(err)) ++ goto out; ++ ++ if (au_test_fs_null_nd(dir->i_sb)) ++ err = vfs_create(dir, path->dentry, mode, NULL); ++ else { ++ struct nameidata h_nd; ++ ++ memset(&h_nd, 0, sizeof(h_nd)); ++ h_nd.flags = LOOKUP_CREATE; ++ h_nd.intent.open.flags = O_CREAT ++ | vfsub_fmode_to_uint(FMODE_READ); ++ h_nd.intent.open.create_mode = mode; ++ h_nd.path.dentry = path->dentry->d_parent; ++ h_nd.path.mnt = path->mnt; ++ path_get(&h_nd.path); ++ err = vfs_create(dir, path->dentry, mode, &h_nd); ++ path_put(&h_nd.path); ++ } ++ ++ if (!err) { ++ struct path tmp = *path; ++ int did; ++ ++ vfsub_update_h_iattr(&tmp, &did); ++ if (did) { ++ tmp.dentry = path->dentry->d_parent; ++ vfsub_update_h_iattr(&tmp, /*did*/NULL); ++ } ++ /*ignore*/ ++ } ++ ++ out: ++ return err; ++} ++ ++int vfsub_symlink(struct inode *dir, struct path *path, const char *symname) ++{ ++ int err; ++ struct dentry *d; ++ ++ IMustLock(dir); ++ ++ d = path->dentry; ++ path->dentry = d->d_parent; ++ err = security_path_symlink(path, path->dentry, symname); ++ path->dentry = d; ++ if (unlikely(err)) ++ goto out; ++ ++ err = vfs_symlink(dir, path->dentry, symname); ++ if (!err) { ++ struct path tmp = *path; ++ int did; ++ ++ vfsub_update_h_iattr(&tmp, &did); ++ if (did) { ++ tmp.dentry = path->dentry->d_parent; ++ vfsub_update_h_iattr(&tmp, /*did*/NULL); ++ } ++ /*ignore*/ ++ } ++ ++ out: ++ return err; ++} ++ ++int vfsub_mknod(struct inode *dir, struct path *path, int mode, dev_t dev) ++{ ++ int err; ++ struct dentry *d; ++ ++ IMustLock(dir); ++ ++ d = path->dentry; ++ path->dentry = d->d_parent; ++ err = security_path_mknod(path, path->dentry, mode, dev); ++ path->dentry = d; ++ if (unlikely(err)) ++ goto out; ++ ++ err = vfs_mknod(dir, path->dentry, mode, dev); ++ if (!err) { ++ struct path tmp = *path; ++ int did; ++ ++ vfsub_update_h_iattr(&tmp, &did); ++ if (did) { ++ tmp.dentry = path->dentry->d_parent; ++ vfsub_update_h_iattr(&tmp, /*did*/NULL); ++ } ++ /*ignore*/ ++ } ++ ++ out: ++ return err; ++} ++ ++static int au_test_nlink(struct inode *inode) ++{ ++ const unsigned int link_max = UINT_MAX >> 1; /* rough margin */ ++ ++ if (!au_test_fs_no_limit_nlink(inode->i_sb) ++ || inode->i_nlink < link_max) ++ return 0; ++ return -EMLINK; ++} ++ ++int vfsub_link(struct dentry *src_dentry, struct inode *dir, struct path *path) ++{ ++ int err; ++ struct dentry *d; ++ ++ IMustLock(dir); ++ ++ err = au_test_nlink(src_dentry->d_inode); ++ if (unlikely(err)) ++ return err; ++ ++ d = path->dentry; ++ path->dentry = d->d_parent; ++ err = security_path_link(src_dentry, path, path->dentry); ++ path->dentry = d; ++ if (unlikely(err)) ++ goto out; ++ ++ /* lockdep_off(); */ ++ err = vfs_link(src_dentry, dir, path->dentry); ++ /* lockdep_on(); */ ++ if (!err) { ++ struct path tmp = *path; ++ int did; ++ ++ /* fuse has different memory inode for the same inumber */ ++ vfsub_update_h_iattr(&tmp, &did); ++ if (did) { ++ tmp.dentry = path->dentry->d_parent; ++ vfsub_update_h_iattr(&tmp, /*did*/NULL); ++ tmp.dentry = src_dentry; ++ vfsub_update_h_iattr(&tmp, /*did*/NULL); ++ } ++ /*ignore*/ ++ } ++ ++ out: ++ return err; ++} ++ ++int vfsub_rename(struct inode *src_dir, struct dentry *src_dentry, ++ struct inode *dir, struct path *path) ++{ ++ int err; ++ struct path tmp = { ++ .mnt = path->mnt ++ }; ++ struct dentry *d; ++ ++ IMustLock(dir); ++ IMustLock(src_dir); ++ ++ d = path->dentry; ++ path->dentry = d->d_parent; ++ tmp.dentry = src_dentry->d_parent; ++ err = security_path_rename(&tmp, src_dentry, path, path->dentry); ++ path->dentry = d; ++ if (unlikely(err)) ++ goto out; ++ ++ /* lockdep_off(); */ ++ err = vfs_rename(src_dir, src_dentry, dir, path->dentry); ++ /* lockdep_on(); */ ++ if (!err) { ++ int did; ++ ++ tmp.dentry = d->d_parent; ++ vfsub_update_h_iattr(&tmp, &did); ++ if (did) { ++ tmp.dentry = src_dentry; ++ vfsub_update_h_iattr(&tmp, /*did*/NULL); ++ tmp.dentry = src_dentry->d_parent; ++ vfsub_update_h_iattr(&tmp, /*did*/NULL); ++ } ++ /*ignore*/ ++ } ++ ++ out: ++ return err; ++} ++ ++int vfsub_mkdir(struct inode *dir, struct path *path, int mode) ++{ ++ int err; ++ struct dentry *d; ++ ++ IMustLock(dir); ++ ++ d = path->dentry; ++ path->dentry = d->d_parent; ++ err = security_path_mkdir(path, path->dentry, mode); ++ path->dentry = d; ++ if (unlikely(err)) ++ goto out; ++ ++ err = vfs_mkdir(dir, path->dentry, mode); ++ if (!err) { ++ struct path tmp = *path; ++ int did; ++ ++ vfsub_update_h_iattr(&tmp, &did); ++ if (did) { ++ tmp.dentry = path->dentry->d_parent; ++ vfsub_update_h_iattr(&tmp, /*did*/NULL); ++ } ++ /*ignore*/ ++ } ++ ++ out: ++ return err; ++} ++ ++int vfsub_rmdir(struct inode *dir, struct path *path) ++{ ++ int err; ++ struct dentry *d; ++ ++ IMustLock(dir); ++ ++ d = path->dentry; ++ path->dentry = d->d_parent; ++ err = security_path_rmdir(path, path->dentry); ++ path->dentry = d; ++ if (unlikely(err)) ++ goto out; ++ ++ /* lockdep_off(); */ ++ err = vfs_rmdir(dir, path->dentry); ++ /* lockdep_on(); */ ++ if (!err) { ++ struct path tmp = { ++ .dentry = path->dentry->d_parent, ++ .mnt = path->mnt ++ }; ++ ++ vfsub_update_h_iattr(&tmp, /*did*/NULL); /*ignore*/ ++ } ++ ++ out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++ssize_t vfsub_read_u(struct file *file, char __user *ubuf, size_t count, ++ loff_t *ppos) ++{ ++ ssize_t err; ++ ++ err = vfs_read(file, ubuf, count, ppos); ++ if (err >= 0) ++ vfsub_update_h_iattr(&file->f_path, /*did*/NULL); /*ignore*/ ++ return err; ++} ++ ++/* todo: kernel_read()? */ ++ssize_t vfsub_read_k(struct file *file, void *kbuf, size_t count, ++ loff_t *ppos) ++{ ++ ssize_t err; ++ mm_segment_t oldfs; ++ ++ oldfs = get_fs(); ++ set_fs(KERNEL_DS); ++ err = vfsub_read_u(file, (char __user *)kbuf, count, ppos); ++ set_fs(oldfs); ++ return err; ++} ++ ++ssize_t vfsub_write_u(struct file *file, const char __user *ubuf, size_t count, ++ loff_t *ppos) ++{ ++ ssize_t err; ++ ++ /* lockdep_off(); */ ++ err = vfs_write(file, ubuf, count, ppos); ++ /* lockdep_on(); */ ++ if (err >= 0) ++ vfsub_update_h_iattr(&file->f_path, /*did*/NULL); /*ignore*/ ++ return err; ++} ++ ++ssize_t vfsub_write_k(struct file *file, void *kbuf, size_t count, loff_t *ppos) ++{ ++ ssize_t err; ++ mm_segment_t oldfs; ++ ++ oldfs = get_fs(); ++ set_fs(KERNEL_DS); ++ err = vfsub_write_u(file, (const char __user *)kbuf, count, ppos); ++ set_fs(oldfs); ++ return err; ++} ++ ++int vfsub_readdir(struct file *file, filldir_t filldir, void *arg) ++{ ++ int err; ++ ++ /* lockdep_off(); */ ++ err = vfs_readdir(file, filldir, arg); ++ /* lockdep_on(); */ ++ if (err >= 0) ++ vfsub_update_h_iattr(&file->f_path, /*did*/NULL); /*ignore*/ ++ return err; ++} ++ ++long vfsub_splice_to(struct file *in, loff_t *ppos, ++ struct pipe_inode_info *pipe, size_t len, ++ unsigned int flags) ++{ ++ long err; ++ ++ /* lockdep_off(); */ ++ err = do_splice_to(in, ppos, pipe, len, flags); ++ /* lockdep_on(); */ ++ if (err >= 0) ++ vfsub_update_h_iattr(&in->f_path, /*did*/NULL); /*ignore*/ ++ return err; ++} ++ ++long vfsub_splice_from(struct pipe_inode_info *pipe, struct file *out, ++ loff_t *ppos, size_t len, unsigned int flags) ++{ ++ long err; ++ ++ /* lockdep_off(); */ ++ err = do_splice_from(pipe, out, ppos, len, flags); ++ /* lockdep_on(); */ ++ if (err >= 0) ++ vfsub_update_h_iattr(&out->f_path, /*did*/NULL); /*ignore*/ ++ return err; ++} ++ ++/* cf. open.c:do_sys_truncate() and do_sys_ftruncate() */ ++int vfsub_trunc(struct path *h_path, loff_t length, unsigned int attr, ++ struct file *h_file) ++{ ++ int err; ++ struct inode *h_inode; ++ ++ h_inode = h_path->dentry->d_inode; ++ if (!h_file) { ++ err = mnt_want_write(h_path->mnt); ++ if (err) ++ goto out; ++ err = inode_permission(h_inode, MAY_WRITE); ++ if (err) ++ goto out_mnt; ++ err = get_write_access(h_inode); ++ if (err) ++ goto out_mnt; ++ err = break_lease(h_inode, vfsub_fmode_to_uint(FMODE_WRITE)); ++ if (err) ++ goto out_inode; ++ } ++ ++ err = locks_verify_truncate(h_inode, h_file, length); ++ if (!err) ++ err = security_path_truncate(h_path, length, attr); ++ if (!err) { ++ /* lockdep_off(); */ ++ err = do_truncate(h_path->dentry, length, attr, h_file); ++ /* lockdep_on(); */ ++ } ++ ++ out_inode: ++ if (!h_file) ++ put_write_access(h_inode); ++ out_mnt: ++ if (!h_file) ++ mnt_drop_write(h_path->mnt); ++ out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct au_vfsub_mkdir_args { ++ int *errp; ++ struct inode *dir; ++ struct path *path; ++ int mode; ++}; ++ ++static void au_call_vfsub_mkdir(void *args) ++{ ++ struct au_vfsub_mkdir_args *a = args; ++ *a->errp = vfsub_mkdir(a->dir, a->path, a->mode); ++} ++ ++int vfsub_sio_mkdir(struct inode *dir, struct path *path, int mode) ++{ ++ int err, do_sio, wkq_err; ++ ++ do_sio = au_test_h_perm_sio(dir, MAY_EXEC | MAY_WRITE); ++ if (!do_sio) ++ err = vfsub_mkdir(dir, path, mode); ++ else { ++ struct au_vfsub_mkdir_args args = { ++ .errp = &err, ++ .dir = dir, ++ .path = path, ++ .mode = mode ++ }; ++ wkq_err = au_wkq_wait(au_call_vfsub_mkdir, &args); ++ if (unlikely(wkq_err)) ++ err = wkq_err; ++ } ++ ++ return err; ++} ++ ++struct au_vfsub_rmdir_args { ++ int *errp; ++ struct inode *dir; ++ struct path *path; ++}; ++ ++static void au_call_vfsub_rmdir(void *args) ++{ ++ struct au_vfsub_rmdir_args *a = args; ++ *a->errp = vfsub_rmdir(a->dir, a->path); ++} ++ ++int vfsub_sio_rmdir(struct inode *dir, struct path *path) ++{ ++ int err, do_sio, wkq_err; ++ ++ do_sio = au_test_h_perm_sio(dir, MAY_EXEC | MAY_WRITE); ++ if (!do_sio) ++ err = vfsub_rmdir(dir, path); ++ else { ++ struct au_vfsub_rmdir_args args = { ++ .errp = &err, ++ .dir = dir, ++ .path = path ++ }; ++ wkq_err = au_wkq_wait(au_call_vfsub_rmdir, &args); ++ if (unlikely(wkq_err)) ++ err = wkq_err; ++ } ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct notify_change_args { ++ int *errp; ++ struct path *path; ++ struct iattr *ia; ++}; ++ ++static void call_notify_change(void *args) ++{ ++ struct notify_change_args *a = args; ++ struct inode *h_inode; ++ ++ h_inode = a->path->dentry->d_inode; ++ IMustLock(h_inode); ++ ++ *a->errp = -EPERM; ++ if (!IS_IMMUTABLE(h_inode) && !IS_APPEND(h_inode)) { ++ /* lockdep_off(); */ ++ *a->errp = notify_change(a->path->dentry, a->ia); ++ /* lockdep_on(); */ ++ if (!*a->errp) ++ vfsub_update_h_iattr(a->path, /*did*/NULL); /*ignore*/ ++ } ++ AuTraceErr(*a->errp); ++} ++ ++int vfsub_notify_change(struct path *path, struct iattr *ia) ++{ ++ int err; ++ struct notify_change_args args = { ++ .errp = &err, ++ .path = path, ++ .ia = ia ++ }; ++ ++ call_notify_change(&args); ++ ++ return err; ++} ++ ++int vfsub_sio_notify_change(struct path *path, struct iattr *ia) ++{ ++ int err, wkq_err; ++ struct notify_change_args args = { ++ .errp = &err, ++ .path = path, ++ .ia = ia ++ }; ++ ++ wkq_err = au_wkq_wait(call_notify_change, &args); ++ if (unlikely(wkq_err)) ++ err = wkq_err; ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct unlink_args { ++ int *errp; ++ struct inode *dir; ++ struct path *path; ++}; ++ ++static void call_unlink(void *args) ++{ ++ struct unlink_args *a = args; ++ struct dentry *d = a->path->dentry; ++ struct inode *h_inode; ++ const int stop_sillyrename = (au_test_nfs(d->d_sb) ++ && atomic_read(&d->d_count) == 1); ++ ++ IMustLock(a->dir); ++ ++ a->path->dentry = d->d_parent; ++ *a->errp = security_path_unlink(a->path, d); ++ a->path->dentry = d; ++ if (unlikely(*a->errp)) ++ return; ++ ++ if (!stop_sillyrename) ++ dget(d); ++ h_inode = d->d_inode; ++ if (h_inode) ++ atomic_inc(&h_inode->i_count); ++ ++ /* lockdep_off(); */ ++ *a->errp = vfs_unlink(a->dir, d); ++ /* lockdep_on(); */ ++ if (!*a->errp) { ++ struct path tmp = { ++ .dentry = d->d_parent, ++ .mnt = a->path->mnt ++ }; ++ vfsub_update_h_iattr(&tmp, /*did*/NULL); /*ignore*/ ++ } ++ ++ if (!stop_sillyrename) ++ dput(d); ++ if (h_inode) ++ iput(h_inode); ++ ++ AuTraceErr(*a->errp); ++} ++ ++/* ++ * @dir: must be locked. ++ * @dentry: target dentry. ++ */ ++int vfsub_unlink(struct inode *dir, struct path *path, int force) ++{ ++ int err; ++ struct unlink_args args = { ++ .errp = &err, ++ .dir = dir, ++ .path = path ++ }; ++ ++ if (!force) ++ call_unlink(&args); ++ else { ++ int wkq_err; ++ ++ wkq_err = au_wkq_wait(call_unlink, &args); ++ if (unlikely(wkq_err)) ++ err = wkq_err; ++ } ++ ++ return err; ++} +diff --git a/fs/aufs/vfsub.h b/fs/aufs/vfsub.h +new file mode 100644 +index 0000000..4bb36b8 +--- /dev/null ++++ b/fs/aufs/vfsub.h +@@ -0,0 +1,175 @@ ++/* ++ * Copyright (C) 2005-2010 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* ++ * sub-routines for VFS ++ */ ++ ++#ifndef __AUFS_VFSUB_H__ ++#define __AUFS_VFSUB_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* lock subclass for lower inode */ ++/* default MAX_LOCKDEP_SUBCLASSES(8) is not enough */ ++/* reduce? gave up. */ ++enum { ++ AuLsc_I_Begin = I_MUTEX_QUOTA, /* 4 */ ++ AuLsc_I_PARENT, /* lower inode, parent first */ ++ AuLsc_I_PARENT2, /* copyup dirs */ ++ AuLsc_I_PARENT3, /* copyup wh */ ++ AuLsc_I_CHILD, ++ AuLsc_I_CHILD2, ++ AuLsc_I_End ++}; ++ ++/* to debug easier, do not make them inlined functions */ ++#define MtxMustLock(mtx) AuDebugOn(!mutex_is_locked(mtx)) ++#define IMustLock(i) MtxMustLock(&(i)->i_mutex) ++ ++/* ---------------------------------------------------------------------- */ ++ ++int vfsub_update_h_iattr(struct path *h_path, int *did); ++struct file *vfsub_dentry_open(struct path *path, int flags); ++struct file *vfsub_filp_open(const char *path, int oflags, int mode); ++int vfsub_kern_path(const char *name, unsigned int flags, struct path *path); ++struct dentry *vfsub_lookup_one_len(const char *name, struct dentry *parent, ++ int len); ++struct dentry *vfsub_lookup_hash(struct nameidata *nd); ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct au_hinode; ++struct dentry *vfsub_lock_rename(struct dentry *d1, struct au_hinode *hdir1, ++ struct dentry *d2, struct au_hinode *hdir2); ++void vfsub_unlock_rename(struct dentry *d1, struct au_hinode *hdir1, ++ struct dentry *d2, struct au_hinode *hdir2); ++ ++int vfsub_create(struct inode *dir, struct path *path, int mode); ++int vfsub_symlink(struct inode *dir, struct path *path, ++ const char *symname); ++int vfsub_mknod(struct inode *dir, struct path *path, int mode, dev_t dev); ++int vfsub_link(struct dentry *src_dentry, struct inode *dir, ++ struct path *path); ++int vfsub_rename(struct inode *src_hdir, struct dentry *src_dentry, ++ struct inode *hdir, struct path *path); ++int vfsub_mkdir(struct inode *dir, struct path *path, int mode); ++int vfsub_rmdir(struct inode *dir, struct path *path); ++ ++/* ---------------------------------------------------------------------- */ ++ ++ssize_t vfsub_read_u(struct file *file, char __user *ubuf, size_t count, ++ loff_t *ppos); ++ssize_t vfsub_read_k(struct file *file, void *kbuf, size_t count, ++ loff_t *ppos); ++ssize_t vfsub_write_u(struct file *file, const char __user *ubuf, size_t count, ++ loff_t *ppos); ++ssize_t vfsub_write_k(struct file *file, void *kbuf, size_t count, ++ loff_t *ppos); ++int vfsub_readdir(struct file *file, filldir_t filldir, void *arg); ++ ++static inline unsigned int vfsub_file_flags(struct file *file) ++{ ++ unsigned int flags; ++ ++ spin_lock(&file->f_lock); ++ flags = file->f_flags; ++ spin_unlock(&file->f_lock); ++ ++ return flags; ++} ++ ++static inline void vfsub_file_accessed(struct file *h_file) ++{ ++ file_accessed(h_file); ++ vfsub_update_h_iattr(&h_file->f_path, /*did*/NULL); /*ignore*/ ++} ++ ++static inline void vfsub_touch_atime(struct vfsmount *h_mnt, ++ struct dentry *h_dentry) ++{ ++ struct path h_path = { ++ .dentry = h_dentry, ++ .mnt = h_mnt ++ }; ++ touch_atime(h_mnt, h_dentry); ++ vfsub_update_h_iattr(&h_path, /*did*/NULL); /*ignore*/ ++} ++ ++long vfsub_splice_to(struct file *in, loff_t *ppos, ++ struct pipe_inode_info *pipe, size_t len, ++ unsigned int flags); ++long vfsub_splice_from(struct pipe_inode_info *pipe, struct file *out, ++ loff_t *ppos, size_t len, unsigned int flags); ++int vfsub_trunc(struct path *h_path, loff_t length, unsigned int attr, ++ struct file *h_file); ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline loff_t vfsub_llseek(struct file *file, loff_t offset, int origin) ++{ ++ loff_t err; ++ ++ /* lockdep_off(); */ ++ err = vfs_llseek(file, offset, origin); ++ /* lockdep_on(); */ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* dirty workaround for strict type of fmode_t */ ++union vfsub_fmu { ++ fmode_t fm; ++ unsigned int ui; ++}; ++ ++static inline unsigned int vfsub_fmode_to_uint(fmode_t fm) ++{ ++ union vfsub_fmu u = { ++ .fm = fm ++ }; ++ ++ BUILD_BUG_ON(sizeof(u.fm) != sizeof(u.ui)); ++ ++ return u.ui; ++} ++ ++static inline fmode_t vfsub_uint_to_fmode(unsigned int ui) ++{ ++ union vfsub_fmu u = { ++ .ui = ui ++ }; ++ ++ return u.fm; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int vfsub_sio_mkdir(struct inode *dir, struct path *path, int mode); ++int vfsub_sio_rmdir(struct inode *dir, struct path *path); ++int vfsub_sio_notify_change(struct path *path, struct iattr *ia); ++int vfsub_notify_change(struct path *path, struct iattr *ia); ++int vfsub_unlink(struct inode *dir, struct path *path, int force); ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_VFSUB_H__ */ +diff --git a/fs/aufs/wbr_policy.c b/fs/aufs/wbr_policy.c +new file mode 100644 +index 0000000..1e888d3 +--- /dev/null ++++ b/fs/aufs/wbr_policy.c +@@ -0,0 +1,637 @@ ++/* ++ * Copyright (C) 2005-2010 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* ++ * policies for selecting one among multiple writable branches ++ */ ++ ++#include ++#include "aufs.h" ++ ++/* subset of cpup_attr() */ ++static noinline_for_stack ++int au_cpdown_attr(struct path *h_path, struct dentry *h_src) ++{ ++ int err, sbits; ++ struct iattr ia; ++ struct inode *h_isrc; ++ ++ h_isrc = h_src->d_inode; ++ ia.ia_valid = ATTR_FORCE | ATTR_MODE | ATTR_UID | ATTR_GID; ++ ia.ia_mode = h_isrc->i_mode; ++ ia.ia_uid = h_isrc->i_uid; ++ ia.ia_gid = h_isrc->i_gid; ++ sbits = !!(ia.ia_mode & (S_ISUID | S_ISGID)); ++ au_cpup_attr_flags(h_path->dentry->d_inode, h_isrc); ++ err = vfsub_sio_notify_change(h_path, &ia); ++ ++ /* is this nfs only? */ ++ if (!err && sbits && au_test_nfs(h_path->dentry->d_sb)) { ++ ia.ia_valid = ATTR_FORCE | ATTR_MODE; ++ ia.ia_mode = h_isrc->i_mode; ++ err = vfsub_sio_notify_change(h_path, &ia); ++ } ++ ++ return err; ++} ++ ++#define AuCpdown_PARENT_OPQ 1 ++#define AuCpdown_WHED (1 << 1) ++#define AuCpdown_MADE_DIR (1 << 2) ++#define AuCpdown_DIROPQ (1 << 3) ++#define au_ftest_cpdown(flags, name) ((flags) & AuCpdown_##name) ++#define au_fset_cpdown(flags, name) { (flags) |= AuCpdown_##name; } ++#define au_fclr_cpdown(flags, name) { (flags) &= ~AuCpdown_##name; } ++ ++struct au_cpdown_dir_args { ++ struct dentry *parent; ++ unsigned int flags; ++}; ++ ++static int au_cpdown_dir_opq(struct dentry *dentry, aufs_bindex_t bdst, ++ struct au_cpdown_dir_args *a) ++{ ++ int err; ++ struct dentry *opq_dentry; ++ ++ opq_dentry = au_diropq_create(dentry, bdst); ++ err = PTR_ERR(opq_dentry); ++ if (IS_ERR(opq_dentry)) ++ goto out; ++ dput(opq_dentry); ++ au_fset_cpdown(a->flags, DIROPQ); ++ ++ out: ++ return err; ++} ++ ++static int au_cpdown_dir_wh(struct dentry *dentry, struct dentry *h_parent, ++ struct inode *dir, aufs_bindex_t bdst) ++{ ++ int err; ++ struct path h_path; ++ struct au_branch *br; ++ ++ br = au_sbr(dentry->d_sb, bdst); ++ h_path.dentry = au_wh_lkup(h_parent, &dentry->d_name, br); ++ err = PTR_ERR(h_path.dentry); ++ if (IS_ERR(h_path.dentry)) ++ goto out; ++ ++ err = 0; ++ if (h_path.dentry->d_inode) { ++ h_path.mnt = br->br_mnt; ++ err = au_wh_unlink_dentry(au_h_iptr(dir, bdst), &h_path, ++ dentry); ++ } ++ dput(h_path.dentry); ++ ++ out: ++ return err; ++} ++ ++static int au_cpdown_dir(struct dentry *dentry, aufs_bindex_t bdst, ++ struct dentry *h_parent, void *arg) ++{ ++ int err, rerr; ++ aufs_bindex_t bopq, bstart; ++ struct path h_path; ++ struct dentry *parent; ++ struct inode *h_dir, *h_inode, *inode, *dir; ++ struct au_cpdown_dir_args *args = arg; ++ ++ bstart = au_dbstart(dentry); ++ /* dentry is di-locked */ ++ parent = dget_parent(dentry); ++ dir = parent->d_inode; ++ h_dir = h_parent->d_inode; ++ AuDebugOn(h_dir != au_h_iptr(dir, bdst)); ++ IMustLock(h_dir); ++ ++ err = au_lkup_neg(dentry, bdst); ++ if (unlikely(err < 0)) ++ goto out; ++ h_path.dentry = au_h_dptr(dentry, bdst); ++ h_path.mnt = au_sbr_mnt(dentry->d_sb, bdst); ++ err = vfsub_sio_mkdir(au_h_iptr(dir, bdst), &h_path, ++ S_IRWXU | S_IRUGO | S_IXUGO); ++ if (unlikely(err)) ++ goto out_put; ++ au_fset_cpdown(args->flags, MADE_DIR); ++ ++ bopq = au_dbdiropq(dentry); ++ au_fclr_cpdown(args->flags, WHED); ++ au_fclr_cpdown(args->flags, DIROPQ); ++ if (au_dbwh(dentry) == bdst) ++ au_fset_cpdown(args->flags, WHED); ++ if (!au_ftest_cpdown(args->flags, PARENT_OPQ) && bopq <= bdst) ++ au_fset_cpdown(args->flags, PARENT_OPQ); ++ h_inode = h_path.dentry->d_inode; ++ mutex_lock_nested(&h_inode->i_mutex, AuLsc_I_CHILD); ++ if (au_ftest_cpdown(args->flags, WHED)) { ++ err = au_cpdown_dir_opq(dentry, bdst, args); ++ if (unlikely(err)) { ++ mutex_unlock(&h_inode->i_mutex); ++ goto out_dir; ++ } ++ } ++ ++ err = au_cpdown_attr(&h_path, au_h_dptr(dentry, bstart)); ++ mutex_unlock(&h_inode->i_mutex); ++ if (unlikely(err)) ++ goto out_opq; ++ ++ if (au_ftest_cpdown(args->flags, WHED)) { ++ err = au_cpdown_dir_wh(dentry, h_parent, dir, bdst); ++ if (unlikely(err)) ++ goto out_opq; ++ } ++ ++ inode = dentry->d_inode; ++ if (au_ibend(inode) < bdst) ++ au_set_ibend(inode, bdst); ++ au_set_h_iptr(inode, bdst, au_igrab(h_inode), ++ au_hi_flags(inode, /*isdir*/1)); ++ goto out; /* success */ ++ ++ /* revert */ ++ out_opq: ++ if (au_ftest_cpdown(args->flags, DIROPQ)) { ++ mutex_lock_nested(&h_inode->i_mutex, AuLsc_I_CHILD); ++ rerr = au_diropq_remove(dentry, bdst); ++ mutex_unlock(&h_inode->i_mutex); ++ if (unlikely(rerr)) { ++ AuIOErr("failed removing diropq for %.*s b%d (%d)\n", ++ AuDLNPair(dentry), bdst, rerr); ++ err = -EIO; ++ goto out; ++ } ++ } ++ out_dir: ++ if (au_ftest_cpdown(args->flags, MADE_DIR)) { ++ rerr = vfsub_sio_rmdir(au_h_iptr(dir, bdst), &h_path); ++ if (unlikely(rerr)) { ++ AuIOErr("failed removing %.*s b%d (%d)\n", ++ AuDLNPair(dentry), bdst, rerr); ++ err = -EIO; ++ } ++ } ++ out_put: ++ au_set_h_dptr(dentry, bdst, NULL); ++ if (au_dbend(dentry) == bdst) ++ au_update_dbend(dentry); ++ out: ++ dput(parent); ++ return err; ++} ++ ++int au_cpdown_dirs(struct dentry *dentry, aufs_bindex_t bdst) ++{ ++ int err; ++ struct au_cpdown_dir_args args = { ++ .parent = dget_parent(dentry), ++ .flags = 0 ++ }; ++ ++ err = au_cp_dirs(dentry, bdst, au_cpdown_dir, &args); ++ dput(args.parent); ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* policies for create */ ++ ++static int au_wbr_bu(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ for (; bindex >= 0; bindex--) ++ if (!au_br_rdonly(au_sbr(sb, bindex))) ++ return bindex; ++ return -EROFS; ++} ++ ++/* top down parent */ ++static int au_wbr_create_tdp(struct dentry *dentry, int isdir __maybe_unused) ++{ ++ int err; ++ aufs_bindex_t bstart, bindex; ++ struct super_block *sb; ++ struct dentry *parent, *h_parent; ++ ++ sb = dentry->d_sb; ++ bstart = au_dbstart(dentry); ++ err = bstart; ++ if (!au_br_rdonly(au_sbr(sb, bstart))) ++ goto out; ++ ++ err = -EROFS; ++ parent = dget_parent(dentry); ++ for (bindex = au_dbstart(parent); bindex < bstart; bindex++) { ++ h_parent = au_h_dptr(parent, bindex); ++ if (!h_parent || !h_parent->d_inode) ++ continue; ++ ++ if (!au_br_rdonly(au_sbr(sb, bindex))) { ++ err = bindex; ++ break; ++ } ++ } ++ dput(parent); ++ ++ /* bottom up here */ ++ if (unlikely(err < 0)) ++ err = au_wbr_bu(sb, bstart - 1); ++ ++ out: ++ AuDbg("b%d\n", err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* an exception for the policy other than tdp */ ++static int au_wbr_create_exp(struct dentry *dentry) ++{ ++ int err; ++ aufs_bindex_t bwh, bdiropq; ++ struct dentry *parent; ++ ++ err = -1; ++ bwh = au_dbwh(dentry); ++ parent = dget_parent(dentry); ++ bdiropq = au_dbdiropq(parent); ++ if (bwh >= 0) { ++ if (bdiropq >= 0) ++ err = min(bdiropq, bwh); ++ else ++ err = bwh; ++ AuDbg("%d\n", err); ++ } else if (bdiropq >= 0) { ++ err = bdiropq; ++ AuDbg("%d\n", err); ++ } ++ dput(parent); ++ ++ if (err >= 0 && au_br_rdonly(au_sbr(dentry->d_sb, err))) ++ err = -1; ++ ++ AuDbg("%d\n", err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* round robin */ ++static int au_wbr_create_init_rr(struct super_block *sb) ++{ ++ int err; ++ ++ err = au_wbr_bu(sb, au_sbend(sb)); ++ atomic_set(&au_sbi(sb)->si_wbr_rr_next, -err); /* less important */ ++ /* smp_mb(); */ ++ ++ AuDbg("b%d\n", err); ++ return err; ++} ++ ++static int au_wbr_create_rr(struct dentry *dentry, int isdir) ++{ ++ int err, nbr; ++ unsigned int u; ++ aufs_bindex_t bindex, bend; ++ struct super_block *sb; ++ atomic_t *next; ++ ++ err = au_wbr_create_exp(dentry); ++ if (err >= 0) ++ goto out; ++ ++ sb = dentry->d_sb; ++ next = &au_sbi(sb)->si_wbr_rr_next; ++ bend = au_sbend(sb); ++ nbr = bend + 1; ++ for (bindex = 0; bindex <= bend; bindex++) { ++ if (!isdir) { ++ err = atomic_dec_return(next) + 1; ++ /* modulo for 0 is meaningless */ ++ if (unlikely(!err)) ++ err = atomic_dec_return(next) + 1; ++ } else ++ err = atomic_read(next); ++ AuDbg("%d\n", err); ++ u = err; ++ err = u % nbr; ++ AuDbg("%d\n", err); ++ if (!au_br_rdonly(au_sbr(sb, err))) ++ break; ++ err = -EROFS; ++ } ++ ++ out: ++ AuDbg("%d\n", err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* most free space */ ++static void au_mfs(struct dentry *dentry) ++{ ++ struct super_block *sb; ++ struct au_branch *br; ++ struct au_wbr_mfs *mfs; ++ aufs_bindex_t bindex, bend; ++ int err; ++ unsigned long long b, bavail; ++ /* reduce the stack usage */ ++ struct kstatfs *st; ++ ++ st = kmalloc(sizeof(*st), GFP_NOFS); ++ if (unlikely(!st)) { ++ AuWarn1("failed updating mfs(%d), ignored\n", -ENOMEM); ++ return; ++ } ++ ++ bavail = 0; ++ sb = dentry->d_sb; ++ mfs = &au_sbi(sb)->si_wbr_mfs; ++ MtxMustLock(&mfs->mfs_lock); ++ mfs->mfs_bindex = -EROFS; ++ mfs->mfsrr_bytes = 0; ++ bend = au_sbend(sb); ++ for (bindex = 0; bindex <= bend; bindex++) { ++ br = au_sbr(sb, bindex); ++ if (au_br_rdonly(br)) ++ continue; ++ ++ /* sb->s_root for NFS is unreliable */ ++ err = vfs_statfs(br->br_mnt->mnt_root, st); ++ if (unlikely(err)) { ++ AuWarn1("failed statfs, b%d, %d\n", bindex, err); ++ continue; ++ } ++ ++ /* when the available size is equal, select the lower one */ ++ BUILD_BUG_ON(sizeof(b) < sizeof(st->f_bavail) ++ || sizeof(b) < sizeof(st->f_bsize)); ++ b = st->f_bavail * st->f_bsize; ++ br->br_wbr->wbr_bytes = b; ++ if (b >= bavail) { ++ bavail = b; ++ mfs->mfs_bindex = bindex; ++ mfs->mfs_jiffy = jiffies; ++ } ++ } ++ ++ mfs->mfsrr_bytes = bavail; ++ AuDbg("b%d\n", mfs->mfs_bindex); ++ kfree(st); ++} ++ ++static int au_wbr_create_mfs(struct dentry *dentry, int isdir __maybe_unused) ++{ ++ int err; ++ struct super_block *sb; ++ struct au_wbr_mfs *mfs; ++ ++ err = au_wbr_create_exp(dentry); ++ if (err >= 0) ++ goto out; ++ ++ sb = dentry->d_sb; ++ mfs = &au_sbi(sb)->si_wbr_mfs; ++ mutex_lock(&mfs->mfs_lock); ++ if (time_after(jiffies, mfs->mfs_jiffy + mfs->mfs_expire) ++ || mfs->mfs_bindex < 0 ++ || au_br_rdonly(au_sbr(sb, mfs->mfs_bindex))) ++ au_mfs(dentry); ++ mutex_unlock(&mfs->mfs_lock); ++ err = mfs->mfs_bindex; ++ ++ out: ++ AuDbg("b%d\n", err); ++ return err; ++} ++ ++static int au_wbr_create_init_mfs(struct super_block *sb) ++{ ++ struct au_wbr_mfs *mfs; ++ ++ mfs = &au_sbi(sb)->si_wbr_mfs; ++ mutex_init(&mfs->mfs_lock); ++ mfs->mfs_jiffy = 0; ++ mfs->mfs_bindex = -EROFS; ++ ++ return 0; ++} ++ ++static int au_wbr_create_fin_mfs(struct super_block *sb __maybe_unused) ++{ ++ mutex_destroy(&au_sbi(sb)->si_wbr_mfs.mfs_lock); ++ return 0; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* most free space and then round robin */ ++static int au_wbr_create_mfsrr(struct dentry *dentry, int isdir) ++{ ++ int err; ++ struct au_wbr_mfs *mfs; ++ ++ err = au_wbr_create_mfs(dentry, isdir); ++ if (err >= 0) { ++ mfs = &au_sbi(dentry->d_sb)->si_wbr_mfs; ++ mutex_lock(&mfs->mfs_lock); ++ if (mfs->mfsrr_bytes < mfs->mfsrr_watermark) ++ err = au_wbr_create_rr(dentry, isdir); ++ mutex_unlock(&mfs->mfs_lock); ++ } ++ ++ AuDbg("b%d\n", err); ++ return err; ++} ++ ++static int au_wbr_create_init_mfsrr(struct super_block *sb) ++{ ++ int err; ++ ++ au_wbr_create_init_mfs(sb); /* ignore */ ++ err = au_wbr_create_init_rr(sb); ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* top down parent and most free space */ ++static int au_wbr_create_pmfs(struct dentry *dentry, int isdir) ++{ ++ int err, e2; ++ unsigned long long b; ++ aufs_bindex_t bindex, bstart, bend; ++ struct super_block *sb; ++ struct dentry *parent, *h_parent; ++ struct au_branch *br; ++ ++ err = au_wbr_create_tdp(dentry, isdir); ++ if (unlikely(err < 0)) ++ goto out; ++ parent = dget_parent(dentry); ++ bstart = au_dbstart(parent); ++ bend = au_dbtaildir(parent); ++ if (bstart == bend) ++ goto out_parent; /* success */ ++ ++ e2 = au_wbr_create_mfs(dentry, isdir); ++ if (e2 < 0) ++ goto out_parent; /* success */ ++ ++ /* when the available size is equal, select upper one */ ++ sb = dentry->d_sb; ++ br = au_sbr(sb, err); ++ b = br->br_wbr->wbr_bytes; ++ AuDbg("b%d, %llu\n", err, b); ++ ++ for (bindex = bstart; bindex <= bend; bindex++) { ++ h_parent = au_h_dptr(parent, bindex); ++ if (!h_parent || !h_parent->d_inode) ++ continue; ++ ++ br = au_sbr(sb, bindex); ++ if (!au_br_rdonly(br) && br->br_wbr->wbr_bytes > b) { ++ b = br->br_wbr->wbr_bytes; ++ err = bindex; ++ AuDbg("b%d, %llu\n", err, b); ++ } ++ } ++ ++ out_parent: ++ dput(parent); ++ out: ++ AuDbg("b%d\n", err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* policies for copyup */ ++ ++/* top down parent */ ++static int au_wbr_copyup_tdp(struct dentry *dentry) ++{ ++ return au_wbr_create_tdp(dentry, /*isdir, anything is ok*/0); ++} ++ ++/* bottom up parent */ ++static int au_wbr_copyup_bup(struct dentry *dentry) ++{ ++ int err; ++ aufs_bindex_t bindex, bstart; ++ struct dentry *parent, *h_parent; ++ struct super_block *sb; ++ ++ err = -EROFS; ++ sb = dentry->d_sb; ++ parent = dget_parent(dentry); ++ bstart = au_dbstart(parent); ++ for (bindex = au_dbstart(dentry); bindex >= bstart; bindex--) { ++ h_parent = au_h_dptr(parent, bindex); ++ if (!h_parent || !h_parent->d_inode) ++ continue; ++ ++ if (!au_br_rdonly(au_sbr(sb, bindex))) { ++ err = bindex; ++ break; ++ } ++ } ++ dput(parent); ++ ++ /* bottom up here */ ++ if (unlikely(err < 0)) ++ err = au_wbr_bu(sb, bstart - 1); ++ ++ AuDbg("b%d\n", err); ++ return err; ++} ++ ++/* bottom up */ ++static int au_wbr_copyup_bu(struct dentry *dentry) ++{ ++ int err; ++ ++ err = au_wbr_bu(dentry->d_sb, au_dbstart(dentry)); ++ ++ AuDbg("b%d\n", err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct au_wbr_copyup_operations au_wbr_copyup_ops[] = { ++ [AuWbrCopyup_TDP] = { ++ .copyup = au_wbr_copyup_tdp ++ }, ++ [AuWbrCopyup_BUP] = { ++ .copyup = au_wbr_copyup_bup ++ }, ++ [AuWbrCopyup_BU] = { ++ .copyup = au_wbr_copyup_bu ++ } ++}; ++ ++struct au_wbr_create_operations au_wbr_create_ops[] = { ++ [AuWbrCreate_TDP] = { ++ .create = au_wbr_create_tdp ++ }, ++ [AuWbrCreate_RR] = { ++ .create = au_wbr_create_rr, ++ .init = au_wbr_create_init_rr ++ }, ++ [AuWbrCreate_MFS] = { ++ .create = au_wbr_create_mfs, ++ .init = au_wbr_create_init_mfs, ++ .fin = au_wbr_create_fin_mfs ++ }, ++ [AuWbrCreate_MFSV] = { ++ .create = au_wbr_create_mfs, ++ .init = au_wbr_create_init_mfs, ++ .fin = au_wbr_create_fin_mfs ++ }, ++ [AuWbrCreate_MFSRR] = { ++ .create = au_wbr_create_mfsrr, ++ .init = au_wbr_create_init_mfsrr, ++ .fin = au_wbr_create_fin_mfs ++ }, ++ [AuWbrCreate_MFSRRV] = { ++ .create = au_wbr_create_mfsrr, ++ .init = au_wbr_create_init_mfsrr, ++ .fin = au_wbr_create_fin_mfs ++ }, ++ [AuWbrCreate_PMFS] = { ++ .create = au_wbr_create_pmfs, ++ .init = au_wbr_create_init_mfs, ++ .fin = au_wbr_create_fin_mfs ++ }, ++ [AuWbrCreate_PMFSV] = { ++ .create = au_wbr_create_pmfs, ++ .init = au_wbr_create_init_mfs, ++ .fin = au_wbr_create_fin_mfs ++ } ++}; +diff --git a/fs/aufs/whout.c b/fs/aufs/whout.c +new file mode 100644 +index 0000000..eedec93 +--- /dev/null ++++ b/fs/aufs/whout.c +@@ -0,0 +1,1052 @@ ++/* ++ * Copyright (C) 2005-2010 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* ++ * whiteout for logical deletion and opaque directory ++ */ ++ ++#include ++#include "aufs.h" ++ ++#define WH_MASK S_IRUGO ++ ++/* ++ * If a directory contains this file, then it is opaque. We start with the ++ * .wh. flag so that it is blocked by lookup. ++ */ ++static struct qstr diropq_name = { ++ .name = AUFS_WH_DIROPQ, ++ .len = sizeof(AUFS_WH_DIROPQ) - 1 ++}; ++ ++/* ++ * generate whiteout name, which is NOT terminated by NULL. ++ * @name: original d_name.name ++ * @len: original d_name.len ++ * @wh: whiteout qstr ++ * returns zero when succeeds, otherwise error. ++ * succeeded value as wh->name should be freed by kfree(). ++ */ ++int au_wh_name_alloc(struct qstr *wh, const struct qstr *name) ++{ ++ char *p; ++ ++ if (unlikely(name->len > PATH_MAX - AUFS_WH_PFX_LEN)) ++ return -ENAMETOOLONG; ++ ++ wh->len = name->len + AUFS_WH_PFX_LEN; ++ p = kmalloc(wh->len, GFP_NOFS); ++ wh->name = p; ++ if (p) { ++ memcpy(p, AUFS_WH_PFX, AUFS_WH_PFX_LEN); ++ memcpy(p + AUFS_WH_PFX_LEN, name->name, name->len); ++ /* smp_mb(); */ ++ return 0; ++ } ++ return -ENOMEM; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * test if the @wh_name exists under @h_parent. ++ * @try_sio specifies the necessary of super-io. ++ */ ++int au_wh_test(struct dentry *h_parent, struct qstr *wh_name, ++ struct au_branch *br, int try_sio) ++{ ++ int err; ++ struct dentry *wh_dentry; ++ ++ if (!try_sio) ++ wh_dentry = au_lkup_one(wh_name, h_parent, br, /*nd*/NULL); ++ else ++ wh_dentry = au_sio_lkup_one(wh_name, h_parent, br); ++ err = PTR_ERR(wh_dentry); ++ if (IS_ERR(wh_dentry)) ++ goto out; ++ ++ err = 0; ++ if (!wh_dentry->d_inode) ++ goto out_wh; /* success */ ++ ++ err = 1; ++ if (S_ISREG(wh_dentry->d_inode->i_mode)) ++ goto out_wh; /* success */ ++ ++ err = -EIO; ++ AuIOErr("%.*s Invalid whiteout entry type 0%o.\n", ++ AuDLNPair(wh_dentry), wh_dentry->d_inode->i_mode); ++ ++ out_wh: ++ dput(wh_dentry); ++ out: ++ return err; ++} ++ ++/* ++ * test if the @h_dentry sets opaque or not. ++ */ ++int au_diropq_test(struct dentry *h_dentry, struct au_branch *br) ++{ ++ int err; ++ struct inode *h_dir; ++ ++ h_dir = h_dentry->d_inode; ++ err = au_wh_test(h_dentry, &diropq_name, br, ++ au_test_h_perm_sio(h_dir, MAY_EXEC)); ++ return err; ++} ++ ++/* ++ * returns a negative dentry whose name is unique and temporary. ++ */ ++struct dentry *au_whtmp_lkup(struct dentry *h_parent, struct au_branch *br, ++ struct qstr *prefix) ++{ ++ struct dentry *dentry; ++ int i; ++ char defname[NAME_MAX - AUFS_MAX_NAMELEN + DNAME_INLINE_LEN_MIN + 1], ++ *name, *p; ++ static unsigned short cnt; ++ struct qstr qs; ++ ++ BUILD_BUG_ON(sizeof(cnt) * 2 > AUFS_WH_TMP_LEN); ++ ++ name = defname; ++ qs.len = sizeof(defname) - DNAME_INLINE_LEN_MIN + prefix->len - 1; ++ if (unlikely(prefix->len > DNAME_INLINE_LEN_MIN)) { ++ dentry = ERR_PTR(-ENAMETOOLONG); ++ if (unlikely(qs.len > NAME_MAX)) ++ goto out; ++ dentry = ERR_PTR(-ENOMEM); ++ name = kmalloc(qs.len + 1, GFP_NOFS); ++ if (unlikely(!name)) ++ goto out; ++ } ++ ++ /* doubly whiteout-ed */ ++ memcpy(name, AUFS_WH_PFX AUFS_WH_PFX, AUFS_WH_PFX_LEN * 2); ++ p = name + AUFS_WH_PFX_LEN * 2; ++ memcpy(p, prefix->name, prefix->len); ++ p += prefix->len; ++ *p++ = '.'; ++ AuDebugOn(name + qs.len + 1 - p <= AUFS_WH_TMP_LEN); ++ ++ qs.name = name; ++ for (i = 0; i < 3; i++) { ++ sprintf(p, "%.*d", AUFS_WH_TMP_LEN, cnt++); ++ dentry = au_sio_lkup_one(&qs, h_parent, br); ++ if (IS_ERR(dentry) || !dentry->d_inode) ++ goto out_name; ++ dput(dentry); ++ } ++ /* pr_warning("could not get random name\n"); */ ++ dentry = ERR_PTR(-EEXIST); ++ AuDbg("%.*s\n", AuLNPair(&qs)); ++ BUG(); ++ ++ out_name: ++ if (name != defname) ++ kfree(name); ++ out: ++ AuTraceErrPtr(dentry); ++ return dentry; ++} ++ ++/* ++ * rename the @h_dentry on @br to the whiteouted temporary name. ++ */ ++int au_whtmp_ren(struct dentry *h_dentry, struct au_branch *br) ++{ ++ int err; ++ struct path h_path = { ++ .mnt = br->br_mnt ++ }; ++ struct inode *h_dir; ++ struct dentry *h_parent; ++ ++ h_parent = h_dentry->d_parent; /* dir inode is locked */ ++ h_dir = h_parent->d_inode; ++ IMustLock(h_dir); ++ ++ h_path.dentry = au_whtmp_lkup(h_parent, br, &h_dentry->d_name); ++ err = PTR_ERR(h_path.dentry); ++ if (IS_ERR(h_path.dentry)) ++ goto out; ++ ++ /* under the same dir, no need to lock_rename() */ ++ err = vfsub_rename(h_dir, h_dentry, h_dir, &h_path); ++ AuTraceErr(err); ++ dput(h_path.dentry); ++ ++ out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++/* ++ * functions for removing a whiteout ++ */ ++ ++static int do_unlink_wh(struct inode *h_dir, struct path *h_path) ++{ ++ int force; ++ ++ /* ++ * forces superio when the dir has a sticky bit. ++ * this may be a violation of unix fs semantics. ++ */ ++ force = (h_dir->i_mode & S_ISVTX) ++ && h_path->dentry->d_inode->i_uid != current_fsuid(); ++ return vfsub_unlink(h_dir, h_path, force); ++} ++ ++int au_wh_unlink_dentry(struct inode *h_dir, struct path *h_path, ++ struct dentry *dentry) ++{ ++ int err; ++ ++ err = do_unlink_wh(h_dir, h_path); ++ if (!err && dentry) ++ au_set_dbwh(dentry, -1); ++ ++ return err; ++} ++ ++static int unlink_wh_name(struct dentry *h_parent, struct qstr *wh, ++ struct au_branch *br) ++{ ++ int err; ++ struct path h_path = { ++ .mnt = br->br_mnt ++ }; ++ ++ err = 0; ++ h_path.dentry = au_lkup_one(wh, h_parent, br, /*nd*/NULL); ++ if (IS_ERR(h_path.dentry)) ++ err = PTR_ERR(h_path.dentry); ++ else { ++ if (h_path.dentry->d_inode ++ && S_ISREG(h_path.dentry->d_inode->i_mode)) ++ err = do_unlink_wh(h_parent->d_inode, &h_path); ++ dput(h_path.dentry); ++ } ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++/* ++ * initialize/clean whiteout for a branch ++ */ ++ ++static void au_wh_clean(struct inode *h_dir, struct path *whpath, ++ const int isdir) ++{ ++ int err; ++ ++ if (!whpath->dentry->d_inode) ++ return; ++ ++ err = mnt_want_write(whpath->mnt); ++ if (!err) { ++ if (isdir) ++ err = vfsub_rmdir(h_dir, whpath); ++ else ++ err = vfsub_unlink(h_dir, whpath, /*force*/0); ++ mnt_drop_write(whpath->mnt); ++ } ++ if (unlikely(err)) ++ pr_warning("failed removing %.*s (%d), ignored.\n", ++ AuDLNPair(whpath->dentry), err); ++} ++ ++static int test_linkable(struct dentry *h_root) ++{ ++ struct inode *h_dir = h_root->d_inode; ++ ++ if (h_dir->i_op->link) ++ return 0; ++ ++ pr_err("%.*s (%s) doesn't support link(2), use noplink and rw+nolwh\n", ++ AuDLNPair(h_root), au_sbtype(h_root->d_sb)); ++ return -ENOSYS; ++} ++ ++/* todo: should this mkdir be done in /sbin/mount.aufs helper? */ ++static int au_whdir(struct inode *h_dir, struct path *path) ++{ ++ int err; ++ ++ err = -EEXIST; ++ if (!path->dentry->d_inode) { ++ int mode = S_IRWXU; ++ ++ if (au_test_nfs(path->dentry->d_sb)) ++ mode |= S_IXUGO; ++ err = mnt_want_write(path->mnt); ++ if (!err) { ++ err = vfsub_mkdir(h_dir, path, mode); ++ mnt_drop_write(path->mnt); ++ } ++ } else if (S_ISDIR(path->dentry->d_inode->i_mode)) ++ err = 0; ++ else ++ pr_err("unknown %.*s exists\n", AuDLNPair(path->dentry)); ++ ++ return err; ++} ++ ++struct au_wh_base { ++ const struct qstr *name; ++ struct dentry *dentry; ++}; ++ ++static void au_wh_init_ro(struct inode *h_dir, struct au_wh_base base[], ++ struct path *h_path) ++{ ++ h_path->dentry = base[AuBrWh_BASE].dentry; ++ au_wh_clean(h_dir, h_path, /*isdir*/0); ++ h_path->dentry = base[AuBrWh_PLINK].dentry; ++ au_wh_clean(h_dir, h_path, /*isdir*/1); ++ h_path->dentry = base[AuBrWh_ORPH].dentry; ++ au_wh_clean(h_dir, h_path, /*isdir*/1); ++} ++ ++/* ++ * returns tri-state, ++ * minus: error, caller should print the mesage ++ * zero: succuess ++ * plus: error, caller should NOT print the mesage ++ */ ++static int au_wh_init_rw_nolink(struct dentry *h_root, struct au_wbr *wbr, ++ int do_plink, struct au_wh_base base[], ++ struct path *h_path) ++{ ++ int err; ++ struct inode *h_dir; ++ ++ h_dir = h_root->d_inode; ++ h_path->dentry = base[AuBrWh_BASE].dentry; ++ au_wh_clean(h_dir, h_path, /*isdir*/0); ++ h_path->dentry = base[AuBrWh_PLINK].dentry; ++ if (do_plink) { ++ err = test_linkable(h_root); ++ if (unlikely(err)) { ++ err = 1; ++ goto out; ++ } ++ ++ err = au_whdir(h_dir, h_path); ++ if (unlikely(err)) ++ goto out; ++ wbr->wbr_plink = dget(base[AuBrWh_PLINK].dentry); ++ } else ++ au_wh_clean(h_dir, h_path, /*isdir*/1); ++ h_path->dentry = base[AuBrWh_ORPH].dentry; ++ err = au_whdir(h_dir, h_path); ++ if (unlikely(err)) ++ goto out; ++ wbr->wbr_orph = dget(base[AuBrWh_ORPH].dentry); ++ ++ out: ++ return err; ++} ++ ++/* ++ * for the moment, aufs supports the branch filesystem which does not support ++ * link(2). testing on FAT which does not support i_op->setattr() fully either, ++ * copyup failed. finally, such filesystem will not be used as the writable ++ * branch. ++ * ++ * returns tri-state, see above. ++ */ ++static int au_wh_init_rw(struct dentry *h_root, struct au_wbr *wbr, ++ int do_plink, struct au_wh_base base[], ++ struct path *h_path) ++{ ++ int err; ++ struct inode *h_dir; ++ ++ WbrWhMustWriteLock(wbr); ++ ++ err = test_linkable(h_root); ++ if (unlikely(err)) { ++ err = 1; ++ goto out; ++ } ++ ++ /* ++ * todo: should this create be done in /sbin/mount.aufs helper? ++ */ ++ err = -EEXIST; ++ h_dir = h_root->d_inode; ++ if (!base[AuBrWh_BASE].dentry->d_inode) { ++ err = mnt_want_write(h_path->mnt); ++ if (!err) { ++ h_path->dentry = base[AuBrWh_BASE].dentry; ++ err = vfsub_create(h_dir, h_path, WH_MASK); ++ mnt_drop_write(h_path->mnt); ++ } ++ } else if (S_ISREG(base[AuBrWh_BASE].dentry->d_inode->i_mode)) ++ err = 0; ++ else ++ pr_err("unknown %.*s/%.*s exists\n", ++ AuDLNPair(h_root), AuDLNPair(base[AuBrWh_BASE].dentry)); ++ if (unlikely(err)) ++ goto out; ++ ++ h_path->dentry = base[AuBrWh_PLINK].dentry; ++ if (do_plink) { ++ err = au_whdir(h_dir, h_path); ++ if (unlikely(err)) ++ goto out; ++ wbr->wbr_plink = dget(base[AuBrWh_PLINK].dentry); ++ } else ++ au_wh_clean(h_dir, h_path, /*isdir*/1); ++ wbr->wbr_whbase = dget(base[AuBrWh_BASE].dentry); ++ ++ h_path->dentry = base[AuBrWh_ORPH].dentry; ++ err = au_whdir(h_dir, h_path); ++ if (unlikely(err)) ++ goto out; ++ wbr->wbr_orph = dget(base[AuBrWh_ORPH].dentry); ++ ++ out: ++ return err; ++} ++ ++/* ++ * initialize the whiteout base file/dir for @br. ++ */ ++int au_wh_init(struct dentry *h_root, struct au_branch *br, ++ struct super_block *sb) ++{ ++ int err, i; ++ const unsigned char do_plink ++ = !!au_opt_test(au_mntflags(sb), PLINK); ++ struct path path = { ++ .mnt = br->br_mnt ++ }; ++ struct inode *h_dir; ++ struct au_wbr *wbr = br->br_wbr; ++ static const struct qstr base_name[] = { ++ [AuBrWh_BASE] = { ++ .name = AUFS_BASE_NAME, ++ .len = sizeof(AUFS_BASE_NAME) - 1 ++ }, ++ [AuBrWh_PLINK] = { ++ .name = AUFS_PLINKDIR_NAME, ++ .len = sizeof(AUFS_PLINKDIR_NAME) - 1 ++ }, ++ [AuBrWh_ORPH] = { ++ .name = AUFS_ORPHDIR_NAME, ++ .len = sizeof(AUFS_ORPHDIR_NAME) - 1 ++ } ++ }; ++ struct au_wh_base base[] = { ++ [AuBrWh_BASE] = { ++ .name = base_name + AuBrWh_BASE, ++ .dentry = NULL ++ }, ++ [AuBrWh_PLINK] = { ++ .name = base_name + AuBrWh_PLINK, ++ .dentry = NULL ++ }, ++ [AuBrWh_ORPH] = { ++ .name = base_name + AuBrWh_ORPH, ++ .dentry = NULL ++ } ++ }; ++ ++ if (wbr) ++ WbrWhMustWriteLock(wbr); ++ ++ for (i = 0; i < AuBrWh_Last; i++) { ++ /* doubly whiteouted */ ++ struct dentry *d; ++ ++ d = au_wh_lkup(h_root, (void *)base[i].name, br); ++ err = PTR_ERR(d); ++ if (IS_ERR(d)) ++ goto out; ++ ++ base[i].dentry = d; ++ AuDebugOn(wbr ++ && wbr->wbr_wh[i] ++ && wbr->wbr_wh[i] != base[i].dentry); ++ } ++ ++ if (wbr) ++ for (i = 0; i < AuBrWh_Last; i++) { ++ dput(wbr->wbr_wh[i]); ++ wbr->wbr_wh[i] = NULL; ++ } ++ ++ err = 0; ++ switch (br->br_perm) { ++ case AuBrPerm_RO: ++ case AuBrPerm_ROWH: ++ case AuBrPerm_RR: ++ case AuBrPerm_RRWH: ++ h_dir = h_root->d_inode; ++ au_wh_init_ro(h_dir, base, &path); ++ break; ++ ++ case AuBrPerm_RWNoLinkWH: ++ err = au_wh_init_rw_nolink(h_root, wbr, do_plink, base, &path); ++ if (err > 0) ++ goto out; ++ else if (err) ++ goto out_err; ++ break; ++ ++ case AuBrPerm_RW: ++ err = au_wh_init_rw(h_root, wbr, do_plink, base, &path); ++ if (err > 0) ++ goto out; ++ else if (err) ++ goto out_err; ++ break; ++ ++ default: ++ BUG(); ++ } ++ goto out; /* success */ ++ ++ out_err: ++ pr_err("an error(%d) on the writable branch %.*s(%s)\n", ++ err, AuDLNPair(h_root), au_sbtype(h_root->d_sb)); ++ out: ++ for (i = 0; i < AuBrWh_Last; i++) ++ dput(base[i].dentry); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++/* ++ * whiteouts are all hard-linked usually. ++ * when its link count reaches a ceiling, we create a new whiteout base ++ * asynchronously. ++ */ ++ ++struct reinit_br_wh { ++ struct super_block *sb; ++ struct au_branch *br; ++}; ++ ++static void reinit_br_wh(void *arg) ++{ ++ int err; ++ aufs_bindex_t bindex; ++ struct path h_path; ++ struct reinit_br_wh *a = arg; ++ struct au_wbr *wbr; ++ struct inode *dir; ++ struct dentry *h_root; ++ struct au_hinode *hdir; ++ ++ err = 0; ++ wbr = a->br->br_wbr; ++ /* big aufs lock */ ++ si_noflush_write_lock(a->sb); ++ if (!au_br_writable(a->br->br_perm)) ++ goto out; ++ bindex = au_br_index(a->sb, a->br->br_id); ++ if (unlikely(bindex < 0)) ++ goto out; ++ ++ di_read_lock_parent(a->sb->s_root, AuLock_IR); ++ dir = a->sb->s_root->d_inode; ++ hdir = au_hi(dir, bindex); ++ h_root = au_h_dptr(a->sb->s_root, bindex); ++ ++ au_hin_imtx_lock_nested(hdir, AuLsc_I_PARENT); ++ wbr_wh_write_lock(wbr); ++ err = au_h_verify(wbr->wbr_whbase, au_opt_udba(a->sb), hdir->hi_inode, ++ h_root, a->br); ++ if (!err) { ++ err = mnt_want_write(a->br->br_mnt); ++ if (!err) { ++ h_path.dentry = wbr->wbr_whbase; ++ h_path.mnt = a->br->br_mnt; ++ err = vfsub_unlink(hdir->hi_inode, &h_path, /*force*/0); ++ mnt_drop_write(a->br->br_mnt); ++ } ++ } else { ++ pr_warning("%.*s is moved, ignored\n", ++ AuDLNPair(wbr->wbr_whbase)); ++ err = 0; ++ } ++ dput(wbr->wbr_whbase); ++ wbr->wbr_whbase = NULL; ++ if (!err) ++ err = au_wh_init(h_root, a->br, a->sb); ++ wbr_wh_write_unlock(wbr); ++ au_hin_imtx_unlock(hdir); ++ di_read_unlock(a->sb->s_root, AuLock_IR); ++ ++ out: ++ if (wbr) ++ atomic_dec(&wbr->wbr_wh_running); ++ atomic_dec(&a->br->br_count); ++ au_nwt_done(&au_sbi(a->sb)->si_nowait); ++ si_write_unlock(a->sb); ++ kfree(arg); ++ if (unlikely(err)) ++ AuIOErr("err %d\n", err); ++} ++ ++static void kick_reinit_br_wh(struct super_block *sb, struct au_branch *br) ++{ ++ int do_dec, wkq_err; ++ struct reinit_br_wh *arg; ++ ++ do_dec = 1; ++ if (atomic_inc_return(&br->br_wbr->wbr_wh_running) != 1) ++ goto out; ++ ++ /* ignore ENOMEM */ ++ arg = kmalloc(sizeof(*arg), GFP_NOFS); ++ if (arg) { ++ /* ++ * dec(wh_running), kfree(arg) and dec(br_count) ++ * in reinit function ++ */ ++ arg->sb = sb; ++ arg->br = br; ++ atomic_inc(&br->br_count); ++ wkq_err = au_wkq_nowait(reinit_br_wh, arg, sb); ++ if (unlikely(wkq_err)) { ++ atomic_dec(&br->br_wbr->wbr_wh_running); ++ atomic_dec(&br->br_count); ++ kfree(arg); ++ } ++ do_dec = 0; ++ } ++ ++ out: ++ if (do_dec) ++ atomic_dec(&br->br_wbr->wbr_wh_running); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * create the whiteout @wh. ++ */ ++static int link_or_create_wh(struct super_block *sb, aufs_bindex_t bindex, ++ struct dentry *wh) ++{ ++ int err; ++ struct path h_path = { ++ .dentry = wh ++ }; ++ struct au_branch *br; ++ struct au_wbr *wbr; ++ struct dentry *h_parent; ++ struct inode *h_dir; ++ ++ h_parent = wh->d_parent; /* dir inode is locked */ ++ h_dir = h_parent->d_inode; ++ IMustLock(h_dir); ++ ++ br = au_sbr(sb, bindex); ++ h_path.mnt = br->br_mnt; ++ wbr = br->br_wbr; ++ wbr_wh_read_lock(wbr); ++ if (wbr->wbr_whbase) { ++ err = vfsub_link(wbr->wbr_whbase, h_dir, &h_path); ++ if (!err || err != -EMLINK) ++ goto out; ++ ++ /* link count full. re-initialize br_whbase. */ ++ kick_reinit_br_wh(sb, br); ++ } ++ ++ /* return this error in this context */ ++ err = vfsub_create(h_dir, &h_path, WH_MASK); ++ ++ out: ++ wbr_wh_read_unlock(wbr); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * create or remove the diropq. ++ */ ++static struct dentry *do_diropq(struct dentry *dentry, aufs_bindex_t bindex, ++ unsigned int flags) ++{ ++ struct dentry *opq_dentry, *h_dentry; ++ struct super_block *sb; ++ struct au_branch *br; ++ int err; ++ ++ sb = dentry->d_sb; ++ br = au_sbr(sb, bindex); ++ h_dentry = au_h_dptr(dentry, bindex); ++ opq_dentry = au_lkup_one(&diropq_name, h_dentry, br, /*nd*/NULL); ++ if (IS_ERR(opq_dentry)) ++ goto out; ++ ++ if (au_ftest_diropq(flags, CREATE)) { ++ err = link_or_create_wh(sb, bindex, opq_dentry); ++ if (!err) { ++ au_set_dbdiropq(dentry, bindex); ++ goto out; /* success */ ++ } ++ } else { ++ struct path tmp = { ++ .dentry = opq_dentry, ++ .mnt = br->br_mnt ++ }; ++ err = do_unlink_wh(au_h_iptr(dentry->d_inode, bindex), &tmp); ++ if (!err) ++ au_set_dbdiropq(dentry, -1); ++ } ++ dput(opq_dentry); ++ opq_dentry = ERR_PTR(err); ++ ++ out: ++ return opq_dentry; ++} ++ ++struct do_diropq_args { ++ struct dentry **errp; ++ struct dentry *dentry; ++ aufs_bindex_t bindex; ++ unsigned int flags; ++}; ++ ++static void call_do_diropq(void *args) ++{ ++ struct do_diropq_args *a = args; ++ *a->errp = do_diropq(a->dentry, a->bindex, a->flags); ++} ++ ++struct dentry *au_diropq_sio(struct dentry *dentry, aufs_bindex_t bindex, ++ unsigned int flags) ++{ ++ struct dentry *diropq, *h_dentry; ++ ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (!au_test_h_perm_sio(h_dentry->d_inode, MAY_EXEC | MAY_WRITE)) ++ diropq = do_diropq(dentry, bindex, flags); ++ else { ++ int wkq_err; ++ struct do_diropq_args args = { ++ .errp = &diropq, ++ .dentry = dentry, ++ .bindex = bindex, ++ .flags = flags ++ }; ++ ++ wkq_err = au_wkq_wait(call_do_diropq, &args); ++ if (unlikely(wkq_err)) ++ diropq = ERR_PTR(wkq_err); ++ } ++ ++ return diropq; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * lookup whiteout dentry. ++ * @h_parent: lower parent dentry which must exist and be locked ++ * @base_name: name of dentry which will be whiteouted ++ * returns dentry for whiteout. ++ */ ++struct dentry *au_wh_lkup(struct dentry *h_parent, struct qstr *base_name, ++ struct au_branch *br) ++{ ++ int err; ++ struct qstr wh_name; ++ struct dentry *wh_dentry; ++ ++ err = au_wh_name_alloc(&wh_name, base_name); ++ wh_dentry = ERR_PTR(err); ++ if (!err) { ++ wh_dentry = au_lkup_one(&wh_name, h_parent, br, /*nd*/NULL); ++ kfree(wh_name.name); ++ } ++ return wh_dentry; ++} ++ ++/* ++ * link/create a whiteout for @dentry on @bindex. ++ */ ++struct dentry *au_wh_create(struct dentry *dentry, aufs_bindex_t bindex, ++ struct dentry *h_parent) ++{ ++ struct dentry *wh_dentry; ++ struct super_block *sb; ++ int err; ++ ++ sb = dentry->d_sb; ++ wh_dentry = au_wh_lkup(h_parent, &dentry->d_name, au_sbr(sb, bindex)); ++ if (!IS_ERR(wh_dentry) && !wh_dentry->d_inode) { ++ err = link_or_create_wh(sb, bindex, wh_dentry); ++ if (!err) ++ au_set_dbwh(dentry, bindex); ++ else { ++ dput(wh_dentry); ++ wh_dentry = ERR_PTR(err); ++ } ++ } ++ ++ return wh_dentry; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* Delete all whiteouts in this directory on branch bindex. */ ++static int del_wh_children(struct dentry *h_dentry, struct au_nhash *whlist, ++ aufs_bindex_t bindex, struct au_branch *br) ++{ ++ int err; ++ unsigned long ul, n; ++ struct qstr wh_name; ++ char *p; ++ struct hlist_head *head; ++ struct au_vdir_wh *tpos; ++ struct hlist_node *pos; ++ struct au_vdir_destr *str; ++ ++ err = -ENOMEM; ++ p = __getname(); ++ wh_name.name = p; ++ if (unlikely(!wh_name.name)) ++ goto out; ++ ++ err = 0; ++ memcpy(p, AUFS_WH_PFX, AUFS_WH_PFX_LEN); ++ p += AUFS_WH_PFX_LEN; ++ n = whlist->nh_num; ++ head = whlist->nh_head; ++ for (ul = 0; !err && ul < n; ul++, head++) { ++ hlist_for_each_entry(tpos, pos, head, wh_hash) { ++ if (tpos->wh_bindex != bindex) ++ continue; ++ ++ str = &tpos->wh_str; ++ if (str->len + AUFS_WH_PFX_LEN <= PATH_MAX) { ++ memcpy(p, str->name, str->len); ++ wh_name.len = AUFS_WH_PFX_LEN + str->len; ++ err = unlink_wh_name(h_dentry, &wh_name, br); ++ if (!err) ++ continue; ++ break; ++ } ++ AuIOErr("whiteout name too long %.*s\n", ++ str->len, str->name); ++ err = -EIO; ++ break; ++ } ++ } ++ __putname(wh_name.name); ++ ++ out: ++ return err; ++} ++ ++struct del_wh_children_args { ++ int *errp; ++ struct dentry *h_dentry; ++ struct au_nhash *whlist; ++ aufs_bindex_t bindex; ++ struct au_branch *br; ++}; ++ ++static void call_del_wh_children(void *args) ++{ ++ struct del_wh_children_args *a = args; ++ *a->errp = del_wh_children(a->h_dentry, a->whlist, a->bindex, a->br); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct au_whtmp_rmdir *au_whtmp_rmdir_alloc(struct super_block *sb, gfp_t gfp) ++{ ++ struct au_whtmp_rmdir *whtmp; ++ int err; ++ unsigned int rdhash; ++ ++ SiMustAnyLock(sb); ++ ++ whtmp = kmalloc(sizeof(*whtmp), gfp); ++ if (unlikely(!whtmp)) { ++ whtmp = ERR_PTR(-ENOMEM); ++ goto out; ++ } ++ ++ whtmp->dir = NULL; ++ whtmp->wh_dentry = NULL; ++ /* no estimation for dir size */ ++ rdhash = au_sbi(sb)->si_rdhash; ++ if (!rdhash) ++ rdhash = AUFS_RDHASH_DEF; ++ err = au_nhash_alloc(&whtmp->whlist, rdhash, gfp); ++ if (unlikely(err)) { ++ kfree(whtmp); ++ whtmp = ERR_PTR(err); ++ } ++ ++ out: ++ return whtmp; ++} ++ ++void au_whtmp_rmdir_free(struct au_whtmp_rmdir *whtmp) ++{ ++ dput(whtmp->wh_dentry); ++ iput(whtmp->dir); ++ au_nhash_wh_free(&whtmp->whlist); ++ kfree(whtmp); ++} ++ ++/* ++ * rmdir the whiteouted temporary named dir @h_dentry. ++ * @whlist: whiteouted children. ++ */ ++int au_whtmp_rmdir(struct inode *dir, aufs_bindex_t bindex, ++ struct dentry *wh_dentry, struct au_nhash *whlist) ++{ ++ int err; ++ struct path h_tmp; ++ struct inode *wh_inode, *h_dir; ++ struct au_branch *br; ++ ++ h_dir = wh_dentry->d_parent->d_inode; /* dir inode is locked */ ++ IMustLock(h_dir); ++ ++ br = au_sbr(dir->i_sb, bindex); ++ wh_inode = wh_dentry->d_inode; ++ mutex_lock_nested(&wh_inode->i_mutex, AuLsc_I_CHILD); ++ ++ /* ++ * someone else might change some whiteouts while we were sleeping. ++ * it means this whlist may have an obsoleted entry. ++ */ ++ if (!au_test_h_perm_sio(wh_inode, MAY_EXEC | MAY_WRITE)) ++ err = del_wh_children(wh_dentry, whlist, bindex, br); ++ else { ++ int wkq_err; ++ struct del_wh_children_args args = { ++ .errp = &err, ++ .h_dentry = wh_dentry, ++ .whlist = whlist, ++ .bindex = bindex, ++ .br = br ++ }; ++ ++ wkq_err = au_wkq_wait(call_del_wh_children, &args); ++ if (unlikely(wkq_err)) ++ err = wkq_err; ++ } ++ mutex_unlock(&wh_inode->i_mutex); ++ ++ if (!err) { ++ h_tmp.dentry = wh_dentry; ++ h_tmp.mnt = br->br_mnt; ++ err = vfsub_rmdir(h_dir, &h_tmp); ++ /* d_drop(h_dentry); */ ++ } ++ ++ if (!err) { ++ if (au_ibstart(dir) == bindex) { ++ au_cpup_attr_timesizes(dir); ++ drop_nlink(dir); ++ } ++ return 0; /* success */ ++ } ++ ++ pr_warning("failed removing %.*s(%d), ignored\n", ++ AuDLNPair(wh_dentry), err); ++ return err; ++} ++ ++static void call_rmdir_whtmp(void *args) ++{ ++ int err; ++ struct au_whtmp_rmdir *a = args; ++ struct super_block *sb; ++ struct dentry *h_parent; ++ struct inode *h_dir; ++ struct au_branch *br; ++ struct au_hinode *hdir; ++ ++ /* rmdir by nfsd may cause deadlock with this i_mutex */ ++ /* mutex_lock(&a->dir->i_mutex); */ ++ sb = a->dir->i_sb; ++ si_noflush_read_lock(sb); ++ err = au_test_ro(sb, a->bindex, NULL); ++ if (unlikely(err)) ++ goto out; ++ ++ err = -EIO; ++ br = au_sbr(sb, a->bindex); ++ ii_write_lock_parent(a->dir); ++ h_parent = dget_parent(a->wh_dentry); ++ h_dir = h_parent->d_inode; ++ hdir = au_hi(a->dir, a->bindex); ++ au_hin_imtx_lock_nested(hdir, AuLsc_I_PARENT); ++ err = au_h_verify(a->wh_dentry, au_opt_udba(sb), h_dir, h_parent, br); ++ if (!err) { ++ err = mnt_want_write(br->br_mnt); ++ if (!err) { ++ err = au_whtmp_rmdir(a->dir, a->bindex, a->wh_dentry, ++ &a->whlist); ++ mnt_drop_write(br->br_mnt); ++ } ++ } ++ au_hin_imtx_unlock(hdir); ++ dput(h_parent); ++ ii_write_unlock(a->dir); ++ ++ out: ++ /* mutex_unlock(&a->dir->i_mutex); */ ++ au_nwt_done(&au_sbi(sb)->si_nowait); ++ si_read_unlock(sb); ++ au_whtmp_rmdir_free(a); ++ if (unlikely(err)) ++ AuIOErr("err %d\n", err); ++} ++ ++void au_whtmp_kick_rmdir(struct inode *dir, aufs_bindex_t bindex, ++ struct dentry *wh_dentry, struct au_whtmp_rmdir *args) ++{ ++ int wkq_err; ++ ++ IMustLock(dir); ++ ++ /* all post-process will be done in do_rmdir_whtmp(). */ ++ args->dir = au_igrab(dir); ++ args->bindex = bindex; ++ args->wh_dentry = dget(wh_dentry); ++ wkq_err = au_wkq_nowait(call_rmdir_whtmp, args, dir->i_sb); ++ if (unlikely(wkq_err)) { ++ pr_warning("rmdir error %.*s (%d), ignored\n", ++ AuDLNPair(wh_dentry), wkq_err); ++ au_whtmp_rmdir_free(args); ++ } ++} +diff --git a/fs/aufs/whout.h b/fs/aufs/whout.h +new file mode 100644 +index 0000000..a59158b +--- /dev/null ++++ b/fs/aufs/whout.h +@@ -0,0 +1,87 @@ ++/* ++ * Copyright (C) 2005-2010 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* ++ * whiteout for logical deletion and opaque directory ++ */ ++ ++#ifndef __AUFS_WHOUT_H__ ++#define __AUFS_WHOUT_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include "dir.h" ++ ++/* whout.c */ ++int au_wh_name_alloc(struct qstr *wh, const struct qstr *name); ++struct au_branch; ++int au_wh_test(struct dentry *h_parent, struct qstr *wh_name, ++ struct au_branch *br, int try_sio); ++int au_diropq_test(struct dentry *h_dentry, struct au_branch *br); ++struct dentry *au_whtmp_lkup(struct dentry *h_parent, struct au_branch *br, ++ struct qstr *prefix); ++int au_whtmp_ren(struct dentry *h_dentry, struct au_branch *br); ++int au_wh_unlink_dentry(struct inode *h_dir, struct path *h_path, ++ struct dentry *dentry); ++int au_wh_init(struct dentry *h_parent, struct au_branch *br, ++ struct super_block *sb); ++ ++/* diropq flags */ ++#define AuDiropq_CREATE 1 ++#define au_ftest_diropq(flags, name) ((flags) & AuDiropq_##name) ++#define au_fset_diropq(flags, name) { (flags) |= AuDiropq_##name; } ++#define au_fclr_diropq(flags, name) { (flags) &= ~AuDiropq_##name; } ++ ++struct dentry *au_diropq_sio(struct dentry *dentry, aufs_bindex_t bindex, ++ unsigned int flags); ++struct dentry *au_wh_lkup(struct dentry *h_parent, struct qstr *base_name, ++ struct au_branch *br); ++struct dentry *au_wh_create(struct dentry *dentry, aufs_bindex_t bindex, ++ struct dentry *h_parent); ++ ++/* real rmdir for the whiteout-ed dir */ ++struct au_whtmp_rmdir { ++ struct inode *dir; ++ aufs_bindex_t bindex; ++ struct dentry *wh_dentry; ++ struct au_nhash whlist; ++}; ++ ++struct au_whtmp_rmdir *au_whtmp_rmdir_alloc(struct super_block *sb, gfp_t gfp); ++void au_whtmp_rmdir_free(struct au_whtmp_rmdir *whtmp); ++int au_whtmp_rmdir(struct inode *dir, aufs_bindex_t bindex, ++ struct dentry *wh_dentry, struct au_nhash *whlist); ++void au_whtmp_kick_rmdir(struct inode *dir, aufs_bindex_t bindex, ++ struct dentry *wh_dentry, struct au_whtmp_rmdir *args); ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline struct dentry *au_diropq_create(struct dentry *dentry, ++ aufs_bindex_t bindex) ++{ ++ return au_diropq_sio(dentry, bindex, AuDiropq_CREATE); ++} ++ ++static inline int au_diropq_remove(struct dentry *dentry, aufs_bindex_t bindex) ++{ ++ return PTR_ERR(au_diropq_sio(dentry, bindex, !AuDiropq_CREATE)); ++} ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_WHOUT_H__ */ +diff --git a/fs/aufs/wkq.c b/fs/aufs/wkq.c +new file mode 100644 +index 0000000..307b1c4 +--- /dev/null ++++ b/fs/aufs/wkq.c +@@ -0,0 +1,180 @@ ++/* ++ * Copyright (C) 2005-2010 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* ++ * workqueue for asynchronous/super-io operations ++ * todo: try new dredential scheme ++ */ ++ ++#include ++#include "aufs.h" ++ ++/* internal workqueue named AUFS_WKQ_NAME */ ++static struct workqueue_struct *au_wkq; ++ ++struct au_wkinfo { ++ struct work_struct wk; ++ struct super_block *sb; ++ ++ unsigned int flags; /* see wkq.h */ ++ ++ au_wkq_func_t func; ++ void *args; ++ ++ struct completion *comp; ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void wkq_func(struct work_struct *wk) ++{ ++ struct au_wkinfo *wkinfo = container_of(wk, struct au_wkinfo, wk); ++ ++ wkinfo->func(wkinfo->args); ++ if (au_ftest_wkq(wkinfo->flags, WAIT)) ++ complete(wkinfo->comp); ++ else { ++ kobject_put(&au_sbi(wkinfo->sb)->si_kobj); ++ module_put(THIS_MODULE); ++ kfree(wkinfo); ++ } ++} ++ ++/* ++ * Since struct completion is large, try allocating it dynamically. ++ */ ++#if defined(CONFIG_4KSTACKS) || defined(AuTest4KSTACKS) ++#define AuWkqCompDeclare(name) struct completion *comp = NULL ++ ++static int au_wkq_comp_alloc(struct au_wkinfo *wkinfo, struct completion **comp) ++{ ++ *comp = kmalloc(sizeof(**comp), GFP_NOFS); ++ if (*comp) { ++ init_completion(*comp); ++ wkinfo->comp = *comp; ++ return 0; ++ } ++ return -ENOMEM; ++} ++ ++static void au_wkq_comp_free(struct completion *comp) ++{ ++ kfree(comp); ++} ++ ++#else ++ ++/* no braces */ ++#define AuWkqCompDeclare(name) \ ++ DECLARE_COMPLETION_ONSTACK(_ ## name); \ ++ struct completion *comp = &_ ## name ++ ++static int au_wkq_comp_alloc(struct au_wkinfo *wkinfo, struct completion **comp) ++{ ++ wkinfo->comp = *comp; ++ return 0; ++} ++ ++static void au_wkq_comp_free(struct completion *comp __maybe_unused) ++{ ++ /* empty */ ++} ++#endif /* 4KSTACKS */ ++ ++static void au_wkq_run(struct au_wkinfo *wkinfo, int do_wait) ++{ ++ au_dbg_verify_kthread(); ++ INIT_WORK(&wkinfo->wk, wkq_func); ++ if (do_wait) ++ queue_work(au_wkq, &wkinfo->wk); ++ else ++ schedule_work(&wkinfo->wk); ++} ++ ++int au_wkq_wait(au_wkq_func_t func, void *args) ++{ ++ int err; ++ AuWkqCompDeclare(comp); ++ struct au_wkinfo wkinfo = { ++ .flags = AuWkq_WAIT, ++ .func = func, ++ .args = args ++ }; ++ ++ err = au_wkq_comp_alloc(&wkinfo, &comp); ++ if (!err) { ++ au_wkq_run(&wkinfo, AuWkq_WAIT); ++ /* no timeout, no interrupt */ ++ wait_for_completion(wkinfo.comp); ++ au_wkq_comp_free(comp); ++ } ++ ++ return err; ++ ++} ++ ++int au_wkq_nowait(au_wkq_func_t func, void *args, struct super_block *sb) ++{ ++ int err; ++ struct au_wkinfo *wkinfo; ++ ++ atomic_inc(&au_sbi(sb)->si_nowait.nw_len); ++ ++ /* ++ * wkq_func() must free this wkinfo. ++ * it highly depends upon the implementation of workqueue. ++ */ ++ err = 0; ++ wkinfo = kmalloc(sizeof(*wkinfo), GFP_NOFS); ++ if (wkinfo) { ++ wkinfo->sb = sb; ++ wkinfo->flags = !AuWkq_WAIT; ++ wkinfo->func = func; ++ wkinfo->args = args; ++ wkinfo->comp = NULL; ++ kobject_get(&au_sbi(sb)->si_kobj); ++ __module_get(THIS_MODULE); ++ ++ au_wkq_run(wkinfo, !AuWkq_WAIT); ++ } else { ++ err = -ENOMEM; ++ atomic_dec(&au_sbi(sb)->si_nowait.nw_len); ++ } ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void au_nwt_init(struct au_nowait_tasks *nwt) ++{ ++ atomic_set(&nwt->nw_len, 0); ++ /* smp_mb(); */ /* atomic_set */ ++ init_waitqueue_head(&nwt->nw_wq); ++} ++ ++void au_wkq_fin(void) ++{ ++ destroy_workqueue(au_wkq); ++} ++ ++int __init au_wkq_init(void) ++{ ++ au_wkq = create_workqueue(AUFS_WKQ_NAME); ++ return 0; ++} +diff --git a/fs/aufs/wkq.h b/fs/aufs/wkq.h +new file mode 100644 +index 0000000..3fe36b3 +--- /dev/null ++++ b/fs/aufs/wkq.h +@@ -0,0 +1,84 @@ ++/* ++ * Copyright (C) 2005-2010 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* ++ * workqueue for asynchronous/super-io operations ++ * todo: try new credentials management scheme ++ */ ++ ++#ifndef __AUFS_WKQ_H__ ++#define __AUFS_WKQ_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++#include ++ ++struct super_block; ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * in the next operation, wait for the 'nowait' tasks in system-wide workqueue ++ */ ++struct au_nowait_tasks { ++ atomic_t nw_len; ++ wait_queue_head_t nw_wq; ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++typedef void (*au_wkq_func_t)(void *args); ++ ++/* wkq flags */ ++#define AuWkq_WAIT 1 ++#define au_ftest_wkq(flags, name) ((flags) & AuWkq_##name) ++#define au_fset_wkq(flags, name) { (flags) |= AuWkq_##name; } ++#define au_fclr_wkq(flags, name) { (flags) &= ~AuWkq_##name; } ++ ++/* wkq.c */ ++int au_wkq_wait(au_wkq_func_t func, void *args); ++int au_wkq_nowait(au_wkq_func_t func, void *args, struct super_block *sb); ++void au_nwt_init(struct au_nowait_tasks *nwt); ++int __init au_wkq_init(void); ++void au_wkq_fin(void); ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline int au_test_wkq(struct task_struct *tsk) ++{ ++ return !tsk->mm ++ && !strncmp(tsk->comm, AUFS_WKQ_NAME "/", ++ sizeof(AUFS_WKQ_NAME)); ++} ++ ++static inline void au_nwt_done(struct au_nowait_tasks *nwt) ++{ ++ if (!atomic_dec_return(&nwt->nw_len)) ++ wake_up_all(&nwt->nw_wq); ++} ++ ++static inline int au_nwt_flush(struct au_nowait_tasks *nwt) ++{ ++ wait_event(nwt->nw_wq, !atomic_read(&nwt->nw_len)); ++ return 0; ++} ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_WKQ_H__ */ +diff --git a/fs/aufs/xino.c b/fs/aufs/xino.c +new file mode 100644 +index 0000000..a5362dc +--- /dev/null ++++ b/fs/aufs/xino.c +@@ -0,0 +1,1202 @@ ++/* ++ * Copyright (C) 2005-2010 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* ++ * external inode number translation table and bitmap ++ */ ++ ++#include ++#include ++#include ++#include "aufs.h" ++ ++ssize_t xino_fread(au_readf_t func, struct file *file, void *buf, size_t size, ++ loff_t *pos) ++{ ++ ssize_t err; ++ mm_segment_t oldfs; ++ ++ oldfs = get_fs(); ++ set_fs(KERNEL_DS); ++ do { ++ /* todo: signal_pending? */ ++ err = func(file, (char __user *)buf, size, pos); ++ } while (err == -EAGAIN || err == -EINTR); ++ set_fs(oldfs); ++ ++#if 0 /* reserved for future use */ ++ if (err > 0) ++ fsnotify_access(file->f_dentry); ++#endif ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static ssize_t do_xino_fwrite(au_writef_t func, struct file *file, void *buf, ++ size_t size, loff_t *pos) ++{ ++ ssize_t err; ++ mm_segment_t oldfs; ++ ++ oldfs = get_fs(); ++ set_fs(KERNEL_DS); ++ /* lockdep_off(); */ ++ do { ++ /* todo: signal_pending? */ ++ err = func(file, (const char __user *)buf, size, pos); ++ } while (err == -EAGAIN || err == -EINTR); ++ /* lockdep_on(); */ ++ set_fs(oldfs); ++ ++#if 0 /* reserved for future use */ ++ if (err > 0) ++ fsnotify_modify(file->f_dentry); ++#endif ++ ++ return err; ++} ++ ++struct do_xino_fwrite_args { ++ ssize_t *errp; ++ au_writef_t func; ++ struct file *file; ++ void *buf; ++ size_t size; ++ loff_t *pos; ++}; ++ ++static void call_do_xino_fwrite(void *args) ++{ ++ struct do_xino_fwrite_args *a = args; ++ *a->errp = do_xino_fwrite(a->func, a->file, a->buf, a->size, a->pos); ++} ++ ++ssize_t xino_fwrite(au_writef_t func, struct file *file, void *buf, size_t size, ++ loff_t *pos) ++{ ++ ssize_t err; ++ ++ /* todo: signal block and no wkq? */ ++ /* todo: new credential scheme */ ++ /* ++ * it breaks RLIMIT_FSIZE and normal user's limit, ++ * users should care about quota and real 'filesystem full.' ++ */ ++ if (!au_test_wkq(current)) { ++ int wkq_err; ++ struct do_xino_fwrite_args args = { ++ .errp = &err, ++ .func = func, ++ .file = file, ++ .buf = buf, ++ .size = size, ++ .pos = pos ++ }; ++ ++ wkq_err = au_wkq_wait(call_do_xino_fwrite, &args); ++ if (unlikely(wkq_err)) ++ err = wkq_err; ++ } else ++ err = do_xino_fwrite(func, file, buf, size, pos); ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * create a new xinofile at the same place/path as @base_file. ++ */ ++struct file *au_xino_create2(struct file *base_file, struct file *copy_src) ++{ ++ struct file *file; ++ struct dentry *base, *parent; ++ struct inode *dir; ++ struct qstr *name; ++ struct path path; ++ int err; ++ ++ base = base_file->f_dentry; ++ parent = base->d_parent; /* dir inode is locked */ ++ dir = parent->d_inode; ++ IMustLock(dir); ++ ++ file = ERR_PTR(-EINVAL); ++ name = &base->d_name; ++ path.dentry = vfsub_lookup_one_len(name->name, parent, name->len); ++ if (IS_ERR(path.dentry)) { ++ file = (void *)path.dentry; ++ pr_err("%.*s lookup err %ld\n", ++ AuLNPair(name), PTR_ERR(path.dentry)); ++ goto out; ++ } ++ ++ /* no need to mnt_want_write() since we call dentry_open() later */ ++ err = vfs_create(dir, path.dentry, S_IRUGO | S_IWUGO, NULL); ++ if (unlikely(err)) { ++ file = ERR_PTR(err); ++ pr_err("%.*s create err %d\n", AuLNPair(name), err); ++ goto out_dput; ++ } ++ ++ path.mnt = base_file->f_vfsmnt; ++ file = vfsub_dentry_open(&path, ++ O_RDWR | O_CREAT | O_EXCL | O_LARGEFILE); ++ if (IS_ERR(file)) { ++ pr_err("%.*s open err %ld\n", AuLNPair(name), PTR_ERR(file)); ++ goto out_dput; ++ } ++ ++ err = vfsub_unlink(dir, &file->f_path, /*force*/0); ++ if (unlikely(err)) { ++ pr_err("%.*s unlink err %d\n", AuLNPair(name), err); ++ goto out_fput; ++ } ++ ++ if (copy_src) { ++ /* no one can touch copy_src xino */ ++ err = au_copy_file(file, copy_src, ++ i_size_read(copy_src->f_dentry->d_inode)); ++ if (unlikely(err)) { ++ pr_err("%.*s copy err %d\n", AuLNPair(name), err); ++ goto out_fput; ++ } ++ } ++ goto out_dput; /* success */ ++ ++ out_fput: ++ fput(file); ++ file = ERR_PTR(err); ++ out_dput: ++ dput(path.dentry); ++ out: ++ return file; ++} ++ ++struct au_xino_lock_dir { ++ struct au_hinode *hdir; ++ struct dentry *parent; ++ struct mutex *mtx; ++}; ++ ++static void au_xino_lock_dir(struct super_block *sb, struct file *xino, ++ struct au_xino_lock_dir *ldir) ++{ ++ aufs_bindex_t brid, bindex; ++ ++ ldir->hdir = NULL; ++ bindex = -1; ++ brid = au_xino_brid(sb); ++ if (brid >= 0) ++ bindex = au_br_index(sb, brid); ++ if (bindex >= 0) { ++ ldir->hdir = au_hi(sb->s_root->d_inode, bindex); ++ au_hin_imtx_lock_nested(ldir->hdir, AuLsc_I_PARENT); ++ } else { ++ ldir->parent = dget_parent(xino->f_dentry); ++ ldir->mtx = &ldir->parent->d_inode->i_mutex; ++ mutex_lock_nested(ldir->mtx, AuLsc_I_PARENT); ++ } ++} ++ ++static void au_xino_unlock_dir(struct au_xino_lock_dir *ldir) ++{ ++ if (ldir->hdir) ++ au_hin_imtx_unlock(ldir->hdir); ++ else { ++ mutex_unlock(ldir->mtx); ++ dput(ldir->parent); ++ } ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* trucate xino files asynchronously */ ++ ++int au_xino_trunc(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ int err; ++ aufs_bindex_t bi, bend; ++ struct au_branch *br; ++ struct file *new_xino, *file; ++ struct super_block *h_sb; ++ struct au_xino_lock_dir ldir; ++ ++ err = -EINVAL; ++ bend = au_sbend(sb); ++ if (unlikely(bindex < 0 || bend < bindex)) ++ goto out; ++ br = au_sbr(sb, bindex); ++ file = br->br_xino.xi_file; ++ if (!file) ++ goto out; ++ ++ au_xino_lock_dir(sb, file, &ldir); ++ /* mnt_want_write() is unnecessary here */ ++ new_xino = au_xino_create2(file, file); ++ au_xino_unlock_dir(&ldir); ++ err = PTR_ERR(new_xino); ++ if (IS_ERR(new_xino)) ++ goto out; ++ err = 0; ++ fput(file); ++ br->br_xino.xi_file = new_xino; ++ ++ h_sb = br->br_mnt->mnt_sb; ++ for (bi = 0; bi <= bend; bi++) { ++ if (unlikely(bi == bindex)) ++ continue; ++ br = au_sbr(sb, bi); ++ if (br->br_mnt->mnt_sb != h_sb) ++ continue; ++ ++ fput(br->br_xino.xi_file); ++ br->br_xino.xi_file = new_xino; ++ get_file(new_xino); ++ } ++ ++ out: ++ return err; ++} ++ ++struct xino_do_trunc_args { ++ struct super_block *sb; ++ struct au_branch *br; ++}; ++ ++static void xino_do_trunc(void *_args) ++{ ++ struct xino_do_trunc_args *args = _args; ++ struct super_block *sb; ++ struct au_branch *br; ++ struct inode *dir; ++ int err; ++ aufs_bindex_t bindex; ++ ++ err = 0; ++ sb = args->sb; ++ dir = sb->s_root->d_inode; ++ br = args->br; ++ ++ si_noflush_write_lock(sb); ++ ii_read_lock_parent(dir); ++ bindex = au_br_index(sb, br->br_id); ++ err = au_xino_trunc(sb, bindex); ++ if (!err ++ && br->br_xino.xi_file->f_dentry->d_inode->i_blocks ++ >= br->br_xino_upper) ++ br->br_xino_upper += AUFS_XINO_TRUNC_STEP; ++ ++ ii_read_unlock(dir); ++ if (unlikely(err)) ++ pr_warning("err b%d, (%d)\n", bindex, err); ++ atomic_dec(&br->br_xino_running); ++ atomic_dec(&br->br_count); ++ au_nwt_done(&au_sbi(sb)->si_nowait); ++ si_write_unlock(sb); ++ kfree(args); ++} ++ ++static void xino_try_trunc(struct super_block *sb, struct au_branch *br) ++{ ++ struct xino_do_trunc_args *args; ++ int wkq_err; ++ ++ if (br->br_xino.xi_file->f_dentry->d_inode->i_blocks ++ < br->br_xino_upper) ++ return; ++ ++ if (atomic_inc_return(&br->br_xino_running) > 1) ++ goto out; ++ ++ /* lock and kfree() will be called in trunc_xino() */ ++ args = kmalloc(sizeof(*args), GFP_NOFS); ++ if (unlikely(!args)) { ++ AuErr1("no memory\n"); ++ goto out_args; ++ } ++ ++ atomic_inc_return(&br->br_count); ++ args->sb = sb; ++ args->br = br; ++ wkq_err = au_wkq_nowait(xino_do_trunc, args, sb); ++ if (!wkq_err) ++ return; /* success */ ++ ++ pr_err("wkq %d\n", wkq_err); ++ atomic_dec_return(&br->br_count); ++ ++ out_args: ++ kfree(args); ++ out: ++ atomic_dec_return(&br->br_xino_running); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_xino_do_write(au_writef_t write, struct file *file, ++ ino_t h_ino, ino_t ino) ++{ ++ loff_t pos; ++ ssize_t sz; ++ ++ pos = h_ino; ++ if (unlikely(au_loff_max / sizeof(ino) - 1 < pos)) { ++ AuIOErr1("too large hi%lu\n", (unsigned long)h_ino); ++ return -EFBIG; ++ } ++ pos *= sizeof(ino); ++ sz = xino_fwrite(write, file, &ino, sizeof(ino), &pos); ++ if (sz == sizeof(ino)) ++ return 0; /* success */ ++ ++ AuIOErr("write failed (%zd)\n", sz); ++ return -EIO; ++} ++ ++/* ++ * write @ino to the xinofile for the specified branch{@sb, @bindex} ++ * at the position of @h_ino. ++ * even if @ino is zero, it is written to the xinofile and means no entry. ++ * if the size of the xino file on a specific filesystem exceeds the watermark, ++ * try truncating it. ++ */ ++int au_xino_write(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, ++ ino_t ino) ++{ ++ int err; ++ unsigned int mnt_flags; ++ struct au_branch *br; ++ ++ BUILD_BUG_ON(sizeof(long long) != sizeof(au_loff_max) ++ || ((loff_t)-1) > 0); ++ SiMustAnyLock(sb); ++ ++ mnt_flags = au_mntflags(sb); ++ if (!au_opt_test(mnt_flags, XINO)) ++ return 0; ++ ++ br = au_sbr(sb, bindex); ++ err = au_xino_do_write(au_sbi(sb)->si_xwrite, br->br_xino.xi_file, ++ h_ino, ino); ++ if (!err) { ++ if (au_opt_test(mnt_flags, TRUNC_XINO) ++ && au_test_fs_trunc_xino(br->br_mnt->mnt_sb)) ++ xino_try_trunc(sb, br); ++ return 0; /* success */ ++ } ++ ++ AuIOErr("write failed (%d)\n", err); ++ return -EIO; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* aufs inode number bitmap */ ++ ++static const int page_bits = (int)PAGE_SIZE * BITS_PER_BYTE; ++static ino_t xib_calc_ino(unsigned long pindex, int bit) ++{ ++ ino_t ino; ++ ++ AuDebugOn(bit < 0 || page_bits <= bit); ++ ino = AUFS_FIRST_INO + pindex * page_bits + bit; ++ return ino; ++} ++ ++static void xib_calc_bit(ino_t ino, unsigned long *pindex, int *bit) ++{ ++ AuDebugOn(ino < AUFS_FIRST_INO); ++ ino -= AUFS_FIRST_INO; ++ *pindex = ino / page_bits; ++ *bit = ino % page_bits; ++} ++ ++static int xib_pindex(struct super_block *sb, unsigned long pindex) ++{ ++ int err; ++ loff_t pos; ++ ssize_t sz; ++ struct au_sbinfo *sbinfo; ++ struct file *xib; ++ unsigned long *p; ++ ++ sbinfo = au_sbi(sb); ++ MtxMustLock(&sbinfo->si_xib_mtx); ++ AuDebugOn(pindex > ULONG_MAX / PAGE_SIZE ++ || !au_opt_test(sbinfo->si_mntflags, XINO)); ++ ++ if (pindex == sbinfo->si_xib_last_pindex) ++ return 0; ++ ++ xib = sbinfo->si_xib; ++ p = sbinfo->si_xib_buf; ++ pos = sbinfo->si_xib_last_pindex; ++ pos *= PAGE_SIZE; ++ sz = xino_fwrite(sbinfo->si_xwrite, xib, p, PAGE_SIZE, &pos); ++ if (unlikely(sz != PAGE_SIZE)) ++ goto out; ++ ++ pos = pindex; ++ pos *= PAGE_SIZE; ++ if (i_size_read(xib->f_dentry->d_inode) >= pos + PAGE_SIZE) ++ sz = xino_fread(sbinfo->si_xread, xib, p, PAGE_SIZE, &pos); ++ else { ++ memset(p, 0, PAGE_SIZE); ++ sz = xino_fwrite(sbinfo->si_xwrite, xib, p, PAGE_SIZE, &pos); ++ } ++ if (sz == PAGE_SIZE) { ++ sbinfo->si_xib_last_pindex = pindex; ++ return 0; /* success */ ++ } ++ ++ out: ++ AuIOErr1("write failed (%zd)\n", sz); ++ err = sz; ++ if (sz >= 0) ++ err = -EIO; ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_xino_write0(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, ++ ino_t ino) ++{ ++ int err, bit; ++ unsigned long pindex; ++ struct au_sbinfo *sbinfo; ++ ++ if (!au_opt_test(au_mntflags(sb), XINO)) ++ return 0; ++ ++ err = 0; ++ if (ino) { ++ sbinfo = au_sbi(sb); ++ xib_calc_bit(ino, &pindex, &bit); ++ AuDebugOn(page_bits <= bit); ++ mutex_lock(&sbinfo->si_xib_mtx); ++ err = xib_pindex(sb, pindex); ++ if (!err) { ++ clear_bit(bit, sbinfo->si_xib_buf); ++ sbinfo->si_xib_next_bit = bit; ++ } ++ mutex_unlock(&sbinfo->si_xib_mtx); ++ } ++ ++ if (!err) ++ err = au_xino_write(sb, bindex, h_ino, 0); ++ return err; ++} ++ ++/* get an unused inode number from bitmap */ ++ino_t au_xino_new_ino(struct super_block *sb) ++{ ++ ino_t ino; ++ unsigned long *p, pindex, ul, pend; ++ struct au_sbinfo *sbinfo; ++ struct file *file; ++ int free_bit, err; ++ ++ if (!au_opt_test(au_mntflags(sb), XINO)) ++ return iunique(sb, AUFS_FIRST_INO); ++ ++ sbinfo = au_sbi(sb); ++ mutex_lock(&sbinfo->si_xib_mtx); ++ p = sbinfo->si_xib_buf; ++ free_bit = sbinfo->si_xib_next_bit; ++ if (free_bit < page_bits && !test_bit(free_bit, p)) ++ goto out; /* success */ ++ free_bit = find_first_zero_bit(p, page_bits); ++ if (free_bit < page_bits) ++ goto out; /* success */ ++ ++ pindex = sbinfo->si_xib_last_pindex; ++ for (ul = pindex - 1; ul < ULONG_MAX; ul--) { ++ err = xib_pindex(sb, ul); ++ if (unlikely(err)) ++ goto out_err; ++ free_bit = find_first_zero_bit(p, page_bits); ++ if (free_bit < page_bits) ++ goto out; /* success */ ++ } ++ ++ file = sbinfo->si_xib; ++ pend = i_size_read(file->f_dentry->d_inode) / PAGE_SIZE; ++ for (ul = pindex + 1; ul <= pend; ul++) { ++ err = xib_pindex(sb, ul); ++ if (unlikely(err)) ++ goto out_err; ++ free_bit = find_first_zero_bit(p, page_bits); ++ if (free_bit < page_bits) ++ goto out; /* success */ ++ } ++ BUG(); ++ ++ out: ++ set_bit(free_bit, p); ++ sbinfo->si_xib_next_bit++; ++ pindex = sbinfo->si_xib_last_pindex; ++ mutex_unlock(&sbinfo->si_xib_mtx); ++ ino = xib_calc_ino(pindex, free_bit); ++ AuDbg("i%lu\n", (unsigned long)ino); ++ return ino; ++ out_err: ++ mutex_unlock(&sbinfo->si_xib_mtx); ++ AuDbg("i0\n"); ++ return 0; ++} ++ ++/* ++ * read @ino from xinofile for the specified branch{@sb, @bindex} ++ * at the position of @h_ino. ++ * if @ino does not exist and @do_new is true, get new one. ++ */ ++int au_xino_read(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, ++ ino_t *ino) ++{ ++ int err; ++ ssize_t sz; ++ loff_t pos; ++ struct file *file; ++ struct au_sbinfo *sbinfo; ++ ++ *ino = 0; ++ if (!au_opt_test(au_mntflags(sb), XINO)) ++ return 0; /* no xino */ ++ ++ err = 0; ++ sbinfo = au_sbi(sb); ++ pos = h_ino; ++ if (unlikely(au_loff_max / sizeof(*ino) - 1 < pos)) { ++ AuIOErr1("too large hi%lu\n", (unsigned long)h_ino); ++ return -EFBIG; ++ } ++ pos *= sizeof(*ino); ++ ++ file = au_sbr(sb, bindex)->br_xino.xi_file; ++ if (i_size_read(file->f_dentry->d_inode) < pos + sizeof(*ino)) ++ return 0; /* no ino */ ++ ++ sz = xino_fread(sbinfo->si_xread, file, ino, sizeof(*ino), &pos); ++ if (sz == sizeof(*ino)) ++ return 0; /* success */ ++ ++ err = sz; ++ if (unlikely(sz >= 0)) { ++ err = -EIO; ++ AuIOErr("xino read error (%zd)\n", sz); ++ } ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* create and set a new xino file */ ++ ++struct file *au_xino_create(struct super_block *sb, char *fname, int silent) ++{ ++ struct file *file; ++ struct dentry *h_parent, *d; ++ struct inode *h_dir; ++ int err; ++ ++ /* ++ * at mount-time, and the xino file is the default path, ++ * hinotify is disabled so we have no inotify events to ignore. ++ * when a user specified the xino, we cannot get au_hdir to be ignored. ++ */ ++ file = vfsub_filp_open(fname, O_RDWR | O_CREAT | O_EXCL | O_LARGEFILE, ++ S_IRUGO | S_IWUGO); ++ if (IS_ERR(file)) { ++ if (!silent) ++ pr_err("open %s(%ld)\n", fname, PTR_ERR(file)); ++ return file; ++ } ++ ++ /* keep file count */ ++ h_parent = dget_parent(file->f_dentry); ++ h_dir = h_parent->d_inode; ++ mutex_lock_nested(&h_dir->i_mutex, AuLsc_I_PARENT); ++ /* mnt_want_write() is unnecessary here */ ++ err = vfsub_unlink(h_dir, &file->f_path, /*force*/0); ++ mutex_unlock(&h_dir->i_mutex); ++ dput(h_parent); ++ if (unlikely(err)) { ++ if (!silent) ++ pr_err("unlink %s(%d)\n", fname, err); ++ goto out; ++ } ++ ++ err = -EINVAL; ++ d = file->f_dentry; ++ if (unlikely(sb == d->d_sb)) { ++ if (!silent) ++ pr_err("%s must be outside\n", fname); ++ goto out; ++ } ++ if (unlikely(au_test_fs_bad_xino(d->d_sb))) { ++ if (!silent) ++ pr_err("xino doesn't support %s(%s)\n", ++ fname, au_sbtype(d->d_sb)); ++ goto out; ++ } ++ return file; /* success */ ++ ++ out: ++ fput(file); ++ file = ERR_PTR(err); ++ return file; ++} ++ ++/* ++ * find another branch who is on the same filesystem of the specified ++ * branch{@btgt}. search until @bend. ++ */ ++static int is_sb_shared(struct super_block *sb, aufs_bindex_t btgt, ++ aufs_bindex_t bend) ++{ ++ aufs_bindex_t bindex; ++ struct super_block *tgt_sb = au_sbr_sb(sb, btgt); ++ ++ for (bindex = 0; bindex < btgt; bindex++) ++ if (unlikely(tgt_sb == au_sbr_sb(sb, bindex))) ++ return bindex; ++ for (bindex++; bindex <= bend; bindex++) ++ if (unlikely(tgt_sb == au_sbr_sb(sb, bindex))) ++ return bindex; ++ return -1; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * initialize the xinofile for the specified branch @br ++ * at the place/path where @base_file indicates. ++ * test whether another branch is on the same filesystem or not, ++ * if @do_test is true. ++ */ ++int au_xino_br(struct super_block *sb, struct au_branch *br, ino_t h_ino, ++ struct file *base_file, int do_test) ++{ ++ int err; ++ ino_t ino; ++ aufs_bindex_t bend, bindex; ++ struct au_branch *shared_br, *b; ++ struct file *file; ++ struct super_block *tgt_sb; ++ ++ shared_br = NULL; ++ bend = au_sbend(sb); ++ if (do_test) { ++ tgt_sb = br->br_mnt->mnt_sb; ++ for (bindex = 0; bindex <= bend; bindex++) { ++ b = au_sbr(sb, bindex); ++ if (tgt_sb == b->br_mnt->mnt_sb) { ++ shared_br = b; ++ break; ++ } ++ } ++ } ++ ++ if (!shared_br || !shared_br->br_xino.xi_file) { ++ struct au_xino_lock_dir ldir; ++ ++ au_xino_lock_dir(sb, base_file, &ldir); ++ /* mnt_want_write() is unnecessary here */ ++ file = au_xino_create2(base_file, NULL); ++ au_xino_unlock_dir(&ldir); ++ err = PTR_ERR(file); ++ if (IS_ERR(file)) ++ goto out; ++ br->br_xino.xi_file = file; ++ } else { ++ br->br_xino.xi_file = shared_br->br_xino.xi_file; ++ get_file(br->br_xino.xi_file); ++ } ++ ++ ino = AUFS_ROOT_INO; ++ err = au_xino_do_write(au_sbi(sb)->si_xwrite, br->br_xino.xi_file, ++ h_ino, ino); ++ if (!err) ++ return 0; /* success */ ++ ++ ++ out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* trucate a xino bitmap file */ ++ ++/* todo: slow */ ++static int do_xib_restore(struct super_block *sb, struct file *file, void *page) ++{ ++ int err, bit; ++ ssize_t sz; ++ unsigned long pindex; ++ loff_t pos, pend; ++ struct au_sbinfo *sbinfo; ++ au_readf_t func; ++ ino_t *ino; ++ unsigned long *p; ++ ++ err = 0; ++ sbinfo = au_sbi(sb); ++ MtxMustLock(&sbinfo->si_xib_mtx); ++ p = sbinfo->si_xib_buf; ++ func = sbinfo->si_xread; ++ pend = i_size_read(file->f_dentry->d_inode); ++ pos = 0; ++ while (pos < pend) { ++ sz = xino_fread(func, file, page, PAGE_SIZE, &pos); ++ err = sz; ++ if (unlikely(sz <= 0)) ++ goto out; ++ ++ err = 0; ++ for (ino = page; sz > 0; ino++, sz -= sizeof(ino)) { ++ if (unlikely(*ino < AUFS_FIRST_INO)) ++ continue; ++ ++ xib_calc_bit(*ino, &pindex, &bit); ++ AuDebugOn(page_bits <= bit); ++ err = xib_pindex(sb, pindex); ++ if (!err) ++ set_bit(bit, p); ++ else ++ goto out; ++ } ++ } ++ ++ out: ++ return err; ++} ++ ++static int xib_restore(struct super_block *sb) ++{ ++ int err; ++ aufs_bindex_t bindex, bend; ++ void *page; ++ ++ err = -ENOMEM; ++ page = (void *)__get_free_page(GFP_NOFS); ++ if (unlikely(!page)) ++ goto out; ++ ++ err = 0; ++ bend = au_sbend(sb); ++ for (bindex = 0; !err && bindex <= bend; bindex++) ++ if (!bindex || is_sb_shared(sb, bindex, bindex - 1) < 0) ++ err = do_xib_restore ++ (sb, au_sbr(sb, bindex)->br_xino.xi_file, page); ++ else ++ AuDbg("b%d\n", bindex); ++ free_page((unsigned long)page); ++ ++ out: ++ return err; ++} ++ ++int au_xib_trunc(struct super_block *sb) ++{ ++ int err; ++ ssize_t sz; ++ loff_t pos; ++ struct au_xino_lock_dir ldir; ++ struct au_sbinfo *sbinfo; ++ unsigned long *p; ++ struct file *file; ++ ++ SiMustWriteLock(sb); ++ ++ err = 0; ++ sbinfo = au_sbi(sb); ++ if (!au_opt_test(sbinfo->si_mntflags, XINO)) ++ goto out; ++ ++ file = sbinfo->si_xib; ++ if (i_size_read(file->f_dentry->d_inode) <= PAGE_SIZE) ++ goto out; ++ ++ au_xino_lock_dir(sb, file, &ldir); ++ /* mnt_want_write() is unnecessary here */ ++ file = au_xino_create2(sbinfo->si_xib, NULL); ++ au_xino_unlock_dir(&ldir); ++ err = PTR_ERR(file); ++ if (IS_ERR(file)) ++ goto out; ++ fput(sbinfo->si_xib); ++ sbinfo->si_xib = file; ++ ++ p = sbinfo->si_xib_buf; ++ memset(p, 0, PAGE_SIZE); ++ pos = 0; ++ sz = xino_fwrite(sbinfo->si_xwrite, sbinfo->si_xib, p, PAGE_SIZE, &pos); ++ if (unlikely(sz != PAGE_SIZE)) { ++ err = sz; ++ AuIOErr("err %d\n", err); ++ if (sz >= 0) ++ err = -EIO; ++ goto out; ++ } ++ ++ mutex_lock(&sbinfo->si_xib_mtx); ++ /* mnt_want_write() is unnecessary here */ ++ err = xib_restore(sb); ++ mutex_unlock(&sbinfo->si_xib_mtx); ++ ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * xino mount option handlers ++ */ ++static au_readf_t find_readf(struct file *h_file) ++{ ++ const struct file_operations *fop = h_file->f_op; ++ ++ if (fop) { ++ if (fop->read) ++ return fop->read; ++ if (fop->aio_read) ++ return do_sync_read; ++ } ++ return ERR_PTR(-ENOSYS); ++} ++ ++static au_writef_t find_writef(struct file *h_file) ++{ ++ const struct file_operations *fop = h_file->f_op; ++ ++ if (fop) { ++ if (fop->write) ++ return fop->write; ++ if (fop->aio_write) ++ return do_sync_write; ++ } ++ return ERR_PTR(-ENOSYS); ++} ++ ++/* xino bitmap */ ++static void xino_clear_xib(struct super_block *sb) ++{ ++ struct au_sbinfo *sbinfo; ++ ++ SiMustWriteLock(sb); ++ ++ sbinfo = au_sbi(sb); ++ sbinfo->si_xread = NULL; ++ sbinfo->si_xwrite = NULL; ++ if (sbinfo->si_xib) ++ fput(sbinfo->si_xib); ++ sbinfo->si_xib = NULL; ++ free_page((unsigned long)sbinfo->si_xib_buf); ++ sbinfo->si_xib_buf = NULL; ++} ++ ++static int au_xino_set_xib(struct super_block *sb, struct file *base) ++{ ++ int err; ++ loff_t pos; ++ struct au_sbinfo *sbinfo; ++ struct file *file; ++ ++ SiMustWriteLock(sb); ++ ++ sbinfo = au_sbi(sb); ++ file = au_xino_create2(base, sbinfo->si_xib); ++ err = PTR_ERR(file); ++ if (IS_ERR(file)) ++ goto out; ++ if (sbinfo->si_xib) ++ fput(sbinfo->si_xib); ++ sbinfo->si_xib = file; ++ sbinfo->si_xread = find_readf(file); ++ sbinfo->si_xwrite = find_writef(file); ++ ++ err = -ENOMEM; ++ if (!sbinfo->si_xib_buf) ++ sbinfo->si_xib_buf = (void *)get_zeroed_page(GFP_NOFS); ++ if (unlikely(!sbinfo->si_xib_buf)) ++ goto out_unset; ++ ++ sbinfo->si_xib_last_pindex = 0; ++ sbinfo->si_xib_next_bit = 0; ++ if (i_size_read(file->f_dentry->d_inode) < PAGE_SIZE) { ++ pos = 0; ++ err = xino_fwrite(sbinfo->si_xwrite, file, sbinfo->si_xib_buf, ++ PAGE_SIZE, &pos); ++ if (unlikely(err != PAGE_SIZE)) ++ goto out_free; ++ } ++ err = 0; ++ goto out; /* success */ ++ ++ out_free: ++ free_page((unsigned long)sbinfo->si_xib_buf); ++ sbinfo->si_xib_buf = NULL; ++ if (err >= 0) ++ err = -EIO; ++ out_unset: ++ fput(sbinfo->si_xib); ++ sbinfo->si_xib = NULL; ++ sbinfo->si_xread = NULL; ++ sbinfo->si_xwrite = NULL; ++ out: ++ return err; ++} ++ ++/* xino for each branch */ ++static void xino_clear_br(struct super_block *sb) ++{ ++ aufs_bindex_t bindex, bend; ++ struct au_branch *br; ++ ++ bend = au_sbend(sb); ++ for (bindex = 0; bindex <= bend; bindex++) { ++ br = au_sbr(sb, bindex); ++ if (!br || !br->br_xino.xi_file) ++ continue; ++ ++ fput(br->br_xino.xi_file); ++ br->br_xino.xi_file = NULL; ++ } ++} ++ ++static int au_xino_set_br(struct super_block *sb, struct file *base) ++{ ++ int err; ++ ino_t ino; ++ aufs_bindex_t bindex, bend, bshared; ++ struct { ++ struct file *old, *new; ++ } *fpair, *p; ++ struct au_branch *br; ++ struct inode *inode; ++ au_writef_t writef; ++ ++ SiMustWriteLock(sb); ++ ++ err = -ENOMEM; ++ bend = au_sbend(sb); ++ fpair = kcalloc(bend + 1, sizeof(*fpair), GFP_NOFS); ++ if (unlikely(!fpair)) ++ goto out; ++ ++ inode = sb->s_root->d_inode; ++ ino = AUFS_ROOT_INO; ++ writef = au_sbi(sb)->si_xwrite; ++ for (bindex = 0, p = fpair; bindex <= bend; bindex++, p++) { ++ br = au_sbr(sb, bindex); ++ bshared = is_sb_shared(sb, bindex, bindex - 1); ++ if (bshared >= 0) { ++ /* shared xino */ ++ *p = fpair[bshared]; ++ get_file(p->new); ++ } ++ ++ if (!p->new) { ++ /* new xino */ ++ p->old = br->br_xino.xi_file; ++ p->new = au_xino_create2(base, br->br_xino.xi_file); ++ err = PTR_ERR(p->new); ++ if (IS_ERR(p->new)) { ++ p->new = NULL; ++ goto out_pair; ++ } ++ } ++ ++ err = au_xino_do_write(writef, p->new, ++ au_h_iptr(inode, bindex)->i_ino, ino); ++ if (unlikely(err)) ++ goto out_pair; ++ } ++ ++ for (bindex = 0, p = fpair; bindex <= bend; bindex++, p++) { ++ br = au_sbr(sb, bindex); ++ if (br->br_xino.xi_file) ++ fput(br->br_xino.xi_file); ++ get_file(p->new); ++ br->br_xino.xi_file = p->new; ++ } ++ ++ out_pair: ++ for (bindex = 0, p = fpair; bindex <= bend; bindex++, p++) ++ if (p->new) ++ fput(p->new); ++ else ++ break; ++ kfree(fpair); ++ out: ++ return err; ++} ++ ++void au_xino_clr(struct super_block *sb) ++{ ++ struct au_sbinfo *sbinfo; ++ ++ au_xigen_clr(sb); ++ xino_clear_xib(sb); ++ xino_clear_br(sb); ++ sbinfo = au_sbi(sb); ++ /* lvalue, do not call au_mntflags() */ ++ au_opt_clr(sbinfo->si_mntflags, XINO); ++} ++ ++int au_xino_set(struct super_block *sb, struct au_opt_xino *xino, int remount) ++{ ++ int err, skip; ++ struct dentry *parent, *cur_parent; ++ struct qstr *dname, *cur_name; ++ struct file *cur_xino; ++ struct inode *dir; ++ struct au_sbinfo *sbinfo; ++ ++ SiMustWriteLock(sb); ++ ++ err = 0; ++ sbinfo = au_sbi(sb); ++ parent = dget_parent(xino->file->f_dentry); ++ if (remount) { ++ skip = 0; ++ dname = &xino->file->f_dentry->d_name; ++ cur_xino = sbinfo->si_xib; ++ if (cur_xino) { ++ cur_parent = dget_parent(cur_xino->f_dentry); ++ cur_name = &cur_xino->f_dentry->d_name; ++ skip = (cur_parent == parent ++ && dname->len == cur_name->len ++ && !memcmp(dname->name, cur_name->name, ++ dname->len)); ++ dput(cur_parent); ++ } ++ if (skip) ++ goto out; ++ } ++ ++ au_opt_set(sbinfo->si_mntflags, XINO); ++ dir = parent->d_inode; ++ mutex_lock_nested(&dir->i_mutex, AuLsc_I_PARENT); ++ /* mnt_want_write() is unnecessary here */ ++ err = au_xino_set_xib(sb, xino->file); ++ if (!err) ++ err = au_xigen_set(sb, xino->file); ++ if (!err) ++ err = au_xino_set_br(sb, xino->file); ++ mutex_unlock(&dir->i_mutex); ++ if (!err) ++ goto out; /* success */ ++ ++ /* reset all */ ++ AuIOErr("failed creating xino(%d).\n", err); ++ ++ out: ++ dput(parent); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * create a xinofile at the default place/path. ++ */ ++struct file *au_xino_def(struct super_block *sb) ++{ ++ struct file *file; ++ char *page, *p; ++ struct au_branch *br; ++ struct super_block *h_sb; ++ struct path path; ++ aufs_bindex_t bend, bindex, bwr; ++ ++ br = NULL; ++ bend = au_sbend(sb); ++ bwr = -1; ++ for (bindex = 0; bindex <= bend; bindex++) { ++ br = au_sbr(sb, bindex); ++ if (au_br_writable(br->br_perm) ++ && !au_test_fs_bad_xino(br->br_mnt->mnt_sb)) { ++ bwr = bindex; ++ break; ++ } ++ } ++ ++ if (bwr >= 0) { ++ file = ERR_PTR(-ENOMEM); ++ page = __getname(); ++ if (unlikely(!page)) ++ goto out; ++ path.mnt = br->br_mnt; ++ path.dentry = au_h_dptr(sb->s_root, bwr); ++ p = d_path(&path, page, PATH_MAX - sizeof(AUFS_XINO_FNAME)); ++ file = (void *)p; ++ if (!IS_ERR(p)) { ++ strcat(p, "/" AUFS_XINO_FNAME); ++ AuDbg("%s\n", p); ++ file = au_xino_create(sb, p, /*silent*/0); ++ if (!IS_ERR(file)) ++ au_xino_brid_set(sb, br->br_id); ++ } ++ __putname(page); ++ } else { ++ file = au_xino_create(sb, AUFS_XINO_DEFPATH, /*silent*/0); ++ if (IS_ERR(file)) ++ goto out; ++ h_sb = file->f_dentry->d_sb; ++ if (unlikely(au_test_fs_bad_xino(h_sb))) { ++ pr_err("xino doesn't support %s(%s)\n", ++ AUFS_XINO_DEFPATH, au_sbtype(h_sb)); ++ fput(file); ++ file = ERR_PTR(-EINVAL); ++ } ++ if (!IS_ERR(file)) ++ au_xino_brid_set(sb, -1); ++ } ++ ++ out: ++ return file; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_xino_path(struct seq_file *seq, struct file *file) ++{ ++ int err; ++ ++ err = au_seq_path(seq, &file->f_path); ++ if (unlikely(err < 0)) ++ goto out; ++ ++ err = 0; ++#define Deleted "\\040(deleted)" ++ seq->count -= sizeof(Deleted) - 1; ++ AuDebugOn(memcmp(seq->buf + seq->count, Deleted, ++ sizeof(Deleted) - 1)); ++#undef Deleted ++ ++ out: ++ return err; ++} +diff --git a/include/linux/aufs_type.h b/include/linux/aufs_type.h +new file mode 100644 +index 0000000..431317b +--- /dev/null ++++ b/include/linux/aufs_type.h +@@ -0,0 +1,194 @@ ++/* ++ * Copyright (C) 2005-2010 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++#ifndef __AUFS_TYPE_H__ ++#define __AUFS_TYPE_H__ ++ ++#include ++#include ++#include ++ ++#define AUFS_VERSION "2-standalone.tree-33-20100308" ++ ++/* todo? move this to linux-2.6.19/include/magic.h */ ++#define AUFS_SUPER_MAGIC ('a' << 24 | 'u' << 16 | 'f' << 8 | 's') ++ ++/* ---------------------------------------------------------------------- */ ++ ++#ifdef CONFIG_AUFS_BRANCH_MAX_127 ++typedef __s8 aufs_bindex_t; ++#define AUFS_BRANCH_MAX 127 ++#else ++typedef __s16 aufs_bindex_t; ++#ifdef CONFIG_AUFS_BRANCH_MAX_511 ++#define AUFS_BRANCH_MAX 511 ++#elif defined(CONFIG_AUFS_BRANCH_MAX_1023) ++#define AUFS_BRANCH_MAX 1023 ++#elif defined(CONFIG_AUFS_BRANCH_MAX_32767) ++#define AUFS_BRANCH_MAX 32767 ++#endif ++#endif ++ ++#ifdef __KERNEL__ ++#ifndef AUFS_BRANCH_MAX ++#error unknown CONFIG_AUFS_BRANCH_MAX value ++#endif ++#endif /* __KERNEL__ */ ++ ++/* ---------------------------------------------------------------------- */ ++ ++#define AUFS_NAME "aufs" ++#define AUFS_FSTYPE AUFS_NAME ++ ++#define AUFS_ROOT_INO 2 ++#define AUFS_FIRST_INO 11 ++ ++#define AUFS_WH_PFX ".wh." ++#define AUFS_WH_PFX_LEN ((int)sizeof(AUFS_WH_PFX) - 1) ++#define AUFS_WH_TMP_LEN 4 ++/* a limit for rmdir/rename a dir */ ++#define AUFS_MAX_NAMELEN (NAME_MAX \ ++ - AUFS_WH_PFX_LEN * 2 /* doubly whiteouted */\ ++ - 1 /* dot */\ ++ - AUFS_WH_TMP_LEN) /* hex */ ++#define AUFS_XINO_FNAME "." AUFS_NAME ".xino" ++#define AUFS_XINO_DEFPATH "/tmp/" AUFS_XINO_FNAME ++#define AUFS_XINO_TRUNC_INIT 64 /* blocks */ ++#define AUFS_XINO_TRUNC_STEP 4 /* blocks */ ++#define AUFS_DIRWH_DEF 3 ++#define AUFS_RDCACHE_DEF 10 /* seconds */ ++#define AUFS_RDBLK_DEF 512 /* bytes */ ++#define AUFS_RDHASH_DEF 32 ++#define AUFS_WKQ_NAME AUFS_NAME "d" ++#define AUFS_MFS_SECOND_DEF 30 /* seconds */ ++#define AUFS_PLINK_WARN 100 /* number of plinks */ ++ ++#define AUFS_DIROPQ_NAME AUFS_WH_PFX ".opq" /* whiteouted doubly */ ++#define AUFS_WH_DIROPQ AUFS_WH_PFX AUFS_DIROPQ_NAME ++ ++#define AUFS_BASE_NAME AUFS_WH_PFX AUFS_NAME ++#define AUFS_PLINKDIR_NAME AUFS_WH_PFX "plnk" ++#define AUFS_ORPHDIR_NAME AUFS_WH_PFX "orph" ++ ++/* doubly whiteouted */ ++#define AUFS_WH_BASE AUFS_WH_PFX AUFS_BASE_NAME ++#define AUFS_WH_PLINKDIR AUFS_WH_PFX AUFS_PLINKDIR_NAME ++#define AUFS_WH_ORPHDIR AUFS_WH_PFX AUFS_ORPHDIR_NAME ++ ++/* branch permission */ ++#define AUFS_BRPERM_RW "rw" ++#define AUFS_BRPERM_RO "ro" ++#define AUFS_BRPERM_RR "rr" ++#define AUFS_BRPERM_WH "wh" ++#define AUFS_BRPERM_NLWH "nolwh" ++#define AUFS_BRPERM_ROWH AUFS_BRPERM_RO "+" AUFS_BRPERM_WH ++#define AUFS_BRPERM_RRWH AUFS_BRPERM_RR "+" AUFS_BRPERM_WH ++#define AUFS_BRPERM_RWNLWH AUFS_BRPERM_RW "+" AUFS_BRPERM_NLWH ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ioctl */ ++enum { ++ AuCtl_PLINK_MAINT, ++ AuCtl_PLINK_CLEAN, ++ ++ /* readdir in userspace */ ++ AuCtl_RDU, ++ AuCtl_RDU_INO, ++ ++ /* pathconf wrapper */ ++ AuCtl_WBR_FD ++}; ++ ++/* borrowed from linux/include/linux/kernel.h */ ++#ifndef ALIGN ++#define ALIGN(x, a) __ALIGN_MASK(x, (typeof(x))(a)-1) ++#define __ALIGN_MASK(x, mask) (((x)+(mask))&~(mask)) ++#endif ++ ++/* borrowed from linux/include/linux/compiler-gcc3.h */ ++#ifndef __aligned ++#define __aligned(x) __attribute__((aligned(x))) ++#define __packed __attribute__((packed)) ++#endif ++ ++struct au_rdu_cookie { ++ __u64 h_pos; ++ __s16 bindex; ++ __u8 flags; ++ __u8 pad; ++ __u32 generation; ++} __aligned(8); ++ ++struct au_rdu_ent { ++ __u64 ino; ++ __s16 bindex; ++ __u8 type; ++ __u8 nlen; ++ __u8 wh; ++ char name[0]; ++} __aligned(8); ++ ++static inline int au_rdu_len(int nlen) ++{ ++ /* include the terminating NULL */ ++ return ALIGN(sizeof(struct au_rdu_ent) + nlen + 1, ++ sizeof(__u64)); ++} ++ ++union au_rdu_ent_ul { ++ struct au_rdu_ent __user *e; ++ unsigned long ul; ++}; ++ ++enum { ++ AufsCtlRduV_SZ, ++ AufsCtlRduV_SZ_PTR, ++ AufsCtlRduV_End ++}; ++ ++struct aufs_rdu { ++ /* input */ ++ union { ++ __u64 sz; /* AuCtl_RDU */ ++ __u64 nent; /* AuCtl_RDU_INO */ ++ }; ++ union au_rdu_ent_ul ent; ++ __u16 verify[AufsCtlRduV_End]; ++ ++ /* input/output */ ++ __u32 blk; ++ ++ /* output */ ++ union au_rdu_ent_ul tail; ++ /* number of entries which were added in a single call */ ++ __u64 rent; ++ __u8 full; ++ __u8 shwh; ++ ++ struct au_rdu_cookie cookie; ++} __aligned(8); ++ ++#define AuCtlType 'A' ++#define AUFS_CTL_PLINK_MAINT _IO(AuCtlType, AuCtl_PLINK_MAINT) ++#define AUFS_CTL_PLINK_CLEAN _IO(AuCtlType, AuCtl_PLINK_CLEAN) ++#define AUFS_CTL_RDU _IOWR(AuCtlType, AuCtl_RDU, struct aufs_rdu) ++#define AUFS_CTL_RDU_INO _IOWR(AuCtlType, AuCtl_RDU_INO, struct aufs_rdu) ++#define AUFS_CTL_WBR_FD _IO(AuCtlType, AuCtl_WBR_FD) ++ ++#endif /* __AUFS_TYPE_H__ */ diff --git a/debian/patches/features/all/aufs2/aufs2-base.patch b/debian/patches/features/all/aufs2/aufs2-base.patch new file mode 100644 index 000000000..e37bc564e --- /dev/null +++ b/debian/patches/features/all/aufs2/aufs2-base.patch @@ -0,0 +1,81 @@ +aufs2 base patch for linux-2.6.33 + +diff --git a/fs/namei.c b/fs/namei.c +index a4855af..1d12d37 100644 +--- a/fs/namei.c ++++ b/fs/namei.c +@@ -1207,7 +1207,7 @@ out: + * needs parent already locked. Doesn't follow mounts. + * SMP-safe. + */ +-static struct dentry *lookup_hash(struct nameidata *nd) ++struct dentry *lookup_hash(struct nameidata *nd) + { + int err; + +@@ -1217,7 +1217,7 @@ static struct dentry *lookup_hash(struct nameidata *nd) + return __lookup_hash(&nd->last, nd->path.dentry, nd); + } + +-static int __lookup_one_len(const char *name, struct qstr *this, ++int __lookup_one_len(const char *name, struct qstr *this, + struct dentry *base, int len) + { + unsigned long hash; +diff --git a/fs/splice.c b/fs/splice.c +index 3920866..b13a9a2 100644 +--- a/fs/splice.c ++++ b/fs/splice.c +@@ -1053,8 +1053,8 @@ EXPORT_SYMBOL_GPL(generic_splice_sendpage); + /* + * Attempt to initiate a splice from pipe to file. + */ +-static long do_splice_from(struct pipe_inode_info *pipe, struct file *out, +- loff_t *ppos, size_t len, unsigned int flags) ++long do_splice_from(struct pipe_inode_info *pipe, struct file *out, ++ loff_t *ppos, size_t len, unsigned int flags) + { + ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, + loff_t *, size_t, unsigned int); +@@ -1081,9 +1081,9 @@ static long do_splice_from(struct pipe_inode_info *pipe, struct file *out, + /* + * Attempt to initiate a splice from a file to a pipe. + */ +-static long do_splice_to(struct file *in, loff_t *ppos, +- struct pipe_inode_info *pipe, size_t len, +- unsigned int flags) ++long do_splice_to(struct file *in, loff_t *ppos, ++ struct pipe_inode_info *pipe, size_t len, ++ unsigned int flags) + { + ssize_t (*splice_read)(struct file *, loff_t *, + struct pipe_inode_info *, size_t, unsigned int); +diff --git a/include/linux/namei.h b/include/linux/namei.h +index 05b441d..91bc74e 100644 +--- a/include/linux/namei.h ++++ b/include/linux/namei.h +@@ -73,6 +73,9 @@ extern int vfs_path_lookup(struct dentry *, struct vfsmount *, + extern struct file *lookup_instantiate_filp(struct nameidata *nd, struct dentry *dentry, + int (*open)(struct inode *, struct file *)); + ++extern struct dentry *lookup_hash(struct nameidata *nd); ++extern int __lookup_one_len(const char *name, struct qstr *this, ++ struct dentry *base, int len); + extern struct dentry *lookup_one_len(const char *, struct dentry *, int); + + extern int follow_down(struct path *); +diff --git a/include/linux/splice.h b/include/linux/splice.h +index 18e7c7c..8393b5c 100644 +--- a/include/linux/splice.h ++++ b/include/linux/splice.h +@@ -82,4 +82,10 @@ extern ssize_t splice_to_pipe(struct pipe_inode_info *, + extern ssize_t splice_direct_to_actor(struct file *, struct splice_desc *, + splice_direct_actor *); + ++extern long do_splice_from(struct pipe_inode_info *pipe, struct file *out, ++ loff_t *ppos, size_t len, unsigned int flags); ++extern long do_splice_to(struct file *in, loff_t *ppos, ++ struct pipe_inode_info *pipe, size_t len, ++ unsigned int flags); ++ + #endif diff --git a/debian/patches/features/all/aufs2/aufs2-kbuild.patch b/debian/patches/features/all/aufs2/aufs2-kbuild.patch new file mode 100644 index 000000000..8d1da3a5f --- /dev/null +++ b/debian/patches/features/all/aufs2/aufs2-kbuild.patch @@ -0,0 +1,35 @@ +aufs2 kbuild patch for linux-2.6.33 + +diff --git a/fs/Kconfig b/fs/Kconfig +index 64d44ef..3e1f2f0 100644 +--- a/fs/Kconfig ++++ b/fs/Kconfig +@@ -188,6 +188,7 @@ source "fs/romfs/Kconfig" + source "fs/sysv/Kconfig" + source "fs/ufs/Kconfig" + source "fs/exofs/Kconfig" ++source "fs/aufs/Kconfig" + + endif # MISC_FILESYSTEMS + +diff --git a/fs/Makefile b/fs/Makefile +index af6d047..dba1ce1 100644 +--- a/fs/Makefile ++++ b/fs/Makefile +@@ -124,3 +124,4 @@ obj-$(CONFIG_OCFS2_FS) += ocfs2/ + obj-$(CONFIG_BTRFS_FS) += btrfs/ + obj-$(CONFIG_GFS2_FS) += gfs2/ + obj-$(CONFIG_EXOFS_FS) += exofs/ ++obj-$(CONFIG_AUFS_FS) += aufs/ +diff --git a/include/linux/Kbuild b/include/linux/Kbuild +index 756f831..4b593cb 100644 +--- a/include/linux/Kbuild ++++ b/include/linux/Kbuild +@@ -34,6 +34,7 @@ header-y += atmppp.h + header-y += atmsap.h + header-y += atmsvc.h + header-y += atm_zatm.h ++header-y += aufs_type.h + header-y += auto_fs4.h + header-y += ax25.h + header-y += b1lli.h diff --git a/debian/patches/features/all/aufs2/aufs2-standalone.patch b/debian/patches/features/all/aufs2/aufs2-standalone.patch new file mode 100644 index 000000000..8bf0d36c9 --- /dev/null +++ b/debian/patches/features/all/aufs2/aufs2-standalone.patch @@ -0,0 +1,203 @@ +aufs2 standalone patch for linux-2.6.33 + +diff --git a/fs/namei.c b/fs/namei.c +index 1d12d37..7cb8e5d 100644 +--- a/fs/namei.c ++++ b/fs/namei.c +@@ -349,6 +349,7 @@ int deny_write_access(struct file * file) + + return 0; + } ++EXPORT_SYMBOL_GPL(deny_write_access); + + /** + * path_get - get a reference to a path +@@ -1216,6 +1217,7 @@ struct dentry *lookup_hash(struct nameidata *nd) + return ERR_PTR(err); + return __lookup_hash(&nd->last, nd->path.dentry, nd); + } ++EXPORT_SYMBOL_GPL(lookup_hash); + + int __lookup_one_len(const char *name, struct qstr *this, + struct dentry *base, int len) +@@ -1238,6 +1240,7 @@ int __lookup_one_len(const char *name, struct qstr *this, + this->hash = end_name_hash(hash); + return 0; + } ++EXPORT_SYMBOL_GPL(__lookup_one_len); + + /** + * lookup_one_len - filesystem helper to lookup single pathname component +diff --git a/fs/namespace.c b/fs/namespace.c +index c768f73..0fd78c3 100644 +--- a/fs/namespace.c ++++ b/fs/namespace.c +@@ -39,6 +39,7 @@ + + /* spinlock for vfsmount related operations, inplace of dcache_lock */ + __cacheline_aligned_in_smp DEFINE_SPINLOCK(vfsmount_lock); ++EXPORT_SYMBOL_GPL(vfsmount_lock); + + static int event; + static DEFINE_IDA(mnt_id_ida); +diff --git a/fs/open.c b/fs/open.c +index 040cef7..453b782 100644 +--- a/fs/open.c ++++ b/fs/open.c +@@ -226,6 +226,7 @@ int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs, + mutex_unlock(&dentry->d_inode->i_mutex); + return ret; + } ++EXPORT_SYMBOL_GPL(do_truncate); + + static long do_sys_truncate(const char __user *pathname, loff_t length) + { +diff --git a/fs/splice.c b/fs/splice.c +index b13a9a2..3931ee0 100644 +--- a/fs/splice.c ++++ b/fs/splice.c +@@ -1077,6 +1077,7 @@ long do_splice_from(struct pipe_inode_info *pipe, struct file *out, + + return splice_write(pipe, out, ppos, len, flags); + } ++EXPORT_SYMBOL_GPL(do_splice_from); + + /* + * Attempt to initiate a splice from a file to a pipe. +@@ -1103,6 +1104,7 @@ long do_splice_to(struct file *in, loff_t *ppos, + + return splice_read(in, ppos, pipe, len, flags); + } ++EXPORT_SYMBOL_GPL(do_splice_to); + + /** + * splice_direct_to_actor - splices data directly between two non-pipes +diff --git a/security/commoncap.c b/security/commoncap.c +index f800fdb..ea457bc 100644 +--- a/security/commoncap.c ++++ b/security/commoncap.c +@@ -946,3 +946,4 @@ int cap_file_mmap(struct file *file, unsigned long reqprot, + } + return ret; + } ++EXPORT_SYMBOL_GPL(cap_file_mmap); +diff --git a/security/device_cgroup.c b/security/device_cgroup.c +index 6cf8fd2..008e0d8 100644 +--- a/security/device_cgroup.c ++++ b/security/device_cgroup.c +@@ -514,6 +514,7 @@ found: + + return -EPERM; + } ++EXPORT_SYMBOL_GPL(devcgroup_inode_permission); + + int devcgroup_inode_mknod(int mode, dev_t dev) + { +diff --git a/security/security.c b/security/security.c +index 122b748..a4a3d99 100644 +--- a/security/security.c ++++ b/security/security.c +@@ -404,6 +404,7 @@ int security_path_mkdir(struct path *path, struct dentry *dentry, int mode) + return 0; + return security_ops->path_mkdir(path, dentry, mode); + } ++EXPORT_SYMBOL_GPL(security_path_mkdir); + + int security_path_rmdir(struct path *path, struct dentry *dentry) + { +@@ -411,6 +412,7 @@ int security_path_rmdir(struct path *path, struct dentry *dentry) + return 0; + return security_ops->path_rmdir(path, dentry); + } ++EXPORT_SYMBOL_GPL(security_path_rmdir); + + int security_path_unlink(struct path *path, struct dentry *dentry) + { +@@ -418,6 +420,7 @@ int security_path_unlink(struct path *path, struct dentry *dentry) + return 0; + return security_ops->path_unlink(path, dentry); + } ++EXPORT_SYMBOL_GPL(security_path_unlink); + + int security_path_symlink(struct path *path, struct dentry *dentry, + const char *old_name) +@@ -426,6 +429,7 @@ int security_path_symlink(struct path *path, struct dentry *dentry, + return 0; + return security_ops->path_symlink(path, dentry, old_name); + } ++EXPORT_SYMBOL_GPL(security_path_symlink); + + int security_path_link(struct dentry *old_dentry, struct path *new_dir, + struct dentry *new_dentry) +@@ -434,6 +438,7 @@ int security_path_link(struct dentry *old_dentry, struct path *new_dir, + return 0; + return security_ops->path_link(old_dentry, new_dir, new_dentry); + } ++EXPORT_SYMBOL_GPL(security_path_link); + + int security_path_rename(struct path *old_dir, struct dentry *old_dentry, + struct path *new_dir, struct dentry *new_dentry) +@@ -444,6 +449,7 @@ int security_path_rename(struct path *old_dir, struct dentry *old_dentry, + return security_ops->path_rename(old_dir, old_dentry, new_dir, + new_dentry); + } ++EXPORT_SYMBOL_GPL(security_path_rename); + + int security_path_truncate(struct path *path, loff_t length, + unsigned int time_attrs) +@@ -452,6 +458,7 @@ int security_path_truncate(struct path *path, loff_t length, + return 0; + return security_ops->path_truncate(path, length, time_attrs); + } ++EXPORT_SYMBOL_GPL(security_path_truncate); + + int security_path_chmod(struct dentry *dentry, struct vfsmount *mnt, + mode_t mode) +@@ -460,6 +467,7 @@ int security_path_chmod(struct dentry *dentry, struct vfsmount *mnt, + return 0; + return security_ops->path_chmod(dentry, mnt, mode); + } ++EXPORT_SYMBOL_GPL(security_path_chmod); + + int security_path_chown(struct path *path, uid_t uid, gid_t gid) + { +@@ -467,6 +475,7 @@ int security_path_chown(struct path *path, uid_t uid, gid_t gid) + return 0; + return security_ops->path_chown(path, uid, gid); + } ++EXPORT_SYMBOL_GPL(security_path_chown); + + int security_path_chroot(struct path *path) + { +@@ -543,6 +552,7 @@ int security_inode_readlink(struct dentry *dentry) + return 0; + return security_ops->inode_readlink(dentry); + } ++EXPORT_SYMBOL_GPL(security_inode_readlink); + + int security_inode_follow_link(struct dentry *dentry, struct nameidata *nd) + { +@@ -557,6 +567,7 @@ int security_inode_permission(struct inode *inode, int mask) + return 0; + return security_ops->inode_permission(inode, mask); + } ++EXPORT_SYMBOL_GPL(security_inode_permission); + + int security_inode_setattr(struct dentry *dentry, struct iattr *attr) + { +@@ -657,6 +668,7 @@ int security_file_permission(struct file *file, int mask) + { + return security_ops->file_permission(file, mask); + } ++EXPORT_SYMBOL_GPL(security_file_permission); + + int security_file_alloc(struct file *file) + { +@@ -684,6 +696,7 @@ int security_file_mmap(struct file *file, unsigned long reqprot, + return ret; + return ima_file_mmap(file, prot); + } ++EXPORT_SYMBOL_GPL(security_file_mmap); + + int security_file_mprotect(struct vm_area_struct *vma, unsigned long reqprot, + unsigned long prot) diff --git a/debian/patches/features/all/aufs2/mark-as-staging.patch b/debian/patches/features/all/aufs2/mark-as-staging.patch new file mode 100644 index 000000000..4926e1b70 --- /dev/null +++ b/debian/patches/features/all/aufs2/mark-as-staging.patch @@ -0,0 +1,15 @@ +From: Ben Hutchings +Subject: [PATCH] aufs: mark as staging + +I really don't want to support this. + +--- a/fs/aufs/module.c ++++ b/fs/aufs/module.c +@@ -83,6 +83,7 @@ + MODULE_DESCRIPTION(AUFS_NAME + " -- Advanced multi layered unification filesystem"); + MODULE_VERSION(AUFS_VERSION); ++MODULE_INFO(staging, "Y"); + + /* this module parameter has no meaning when SYSFS is disabled */ + int sysaufs_brs = 1; diff --git a/debian/patches/series/base b/debian/patches/series/base index 936c171fe..6ee0eb270 100644 --- a/debian/patches/series/base +++ b/debian/patches/series/base @@ -20,8 +20,14 @@ + features/all/module-firmware/0028-sep-declare-MODULE_FIRMWARE.patch + features/all/module-firmware/0029-isight-firmware-declare-MODULE_FIRMWARE.patch -# FIXME: 2.6.33 tree # patches from aufs2 repository, with s/EXPORT_SYMBOL/&_GPL/ ++ features/all/aufs2/aufs2-base.patch ++ features/all/aufs2/aufs2-standalone.patch ++ features/all/aufs2/aufs2-kbuild.patch +# content of fs/ and include/ from aufs2 repository ++ features/all/aufs2/aufs2-add.patch +# mark as staging/crap ++ features/all/aufs2/mark-as-staging.patch # content of src/ from speakup package; generated with: # diff -ur --unidirectional-new-file nonexistent src | filterdiff --strip=1 --addoldprefix=a/drivers/staging/speakup/ --addnewprefix=b/drivers/staging/speakup/ From f92b8885538019910753a556d68a58d069693f51 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Sun, 14 Mar 2010 22:55:16 +0000 Subject: [PATCH 69/71] Remove /usr/include/drm from linux-libc-dev; let libdrm-dev provide it again (Closes: #572067) svn path=/dists/trunk/linux-2.6/; revision=15373 --- debian/changelog | 2 ++ debian/rules.real | 2 +- debian/templates/control.libc-dev.in | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/debian/changelog b/debian/changelog index 78c61bcac..2cf907ce2 100644 --- a/debian/changelog +++ b/debian/changelog @@ -2,6 +2,8 @@ linux-2.6 (2.6.33-1~experimental.4) UNRELEASED; urgency=low [ Ben Hutchings ] * Include aufs2, marked as staging (Closes: #573189) + * Remove /usr/include/drm from linux-libc-dev; let libdrm-dev provide it + again (Closes: #572067) -- Ben Hutchings Sat, 13 Mar 2010 23:06:49 +0000 diff --git a/debian/rules.real b/debian/rules.real index 0743b0ea1..78b300053 100644 --- a/debian/rules.real +++ b/debian/rules.real @@ -274,7 +274,7 @@ install-libc-dev_$(ARCH): +$(MAKE_CLEAN) -C $(SOURCE_DIR) O='$(CURDIR)/$(DIR)' headers_check ARCH=$(KERNEL_ARCH) +$(MAKE_CLEAN) -C $(SOURCE_DIR) O='$(CURDIR)/$(DIR)' headers_install ARCH=$(KERNEL_ARCH) INSTALL_HDR_PATH='$(CURDIR)'/$(OUT_DIR) - rm -rf $(OUT_DIR)/include/scsi + rm -rf $(OUT_DIR)/include/drm $(OUT_DIR)/include/scsi find $(OUT_DIR)/include \( -name .install -o -name ..install.cmd \) -execdir rm {} + +$(MAKE_SELF) install-base diff --git a/debian/templates/control.libc-dev.in b/debian/templates/control.libc-dev.in index 6e4a80521..6e3447393 100644 --- a/debian/templates/control.libc-dev.in +++ b/debian/templates/control.libc-dev.in @@ -1,7 +1,7 @@ Package: linux-libc-dev Section: devel Provides: linux-kernel-headers -Replaces: linux-kernel-headers, libdrm-dev (<= 2.4.5-1) +Replaces: linux-kernel-headers Conflicts: linux-kernel-headers Description: Linux support headers for userspace development This package provides userspaces headers from the Linux kernel. These headers From 103df23a00025b79e7363292810b102b2d8fe993 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Mon, 15 Mar 2010 13:44:38 +0000 Subject: [PATCH 70/71] [x86] Enable rtl8192su driver using external firmware svn path=/dists/trunk/linux-2.6/; revision=15377 --- debian/changelog | 1 + debian/config/kernelarch-x86/config | 5 + .../drivers-staging-rtl8192su-disable.patch | 11 - debian/patches/debian/dfsg/files-1 | 2 +- ...u-Remove-Firmware-from-r8192SU_HWImg.patch | 236 ++++++++++++++++++ debian/patches/series/orig-0 | 2 +- 6 files changed, 244 insertions(+), 13 deletions(-) delete mode 100644 debian/patches/debian/dfsg/drivers-staging-rtl8192su-disable.patch create mode 100644 debian/patches/debian/dfsg/rtl8192su-Remove-Firmware-from-r8192SU_HWImg.patch diff --git a/debian/changelog b/debian/changelog index 2cf907ce2..0f8e3f12d 100644 --- a/debian/changelog +++ b/debian/changelog @@ -4,6 +4,7 @@ linux-2.6 (2.6.33-1~experimental.4) UNRELEASED; urgency=low * Include aufs2, marked as staging (Closes: #573189) * Remove /usr/include/drm from linux-libc-dev; let libdrm-dev provide it again (Closes: #572067) + * [x86] Enable rtl8192su driver using external firmware -- Ben Hutchings Sat, 13 Mar 2010 23:06:49 +0000 diff --git a/debian/config/kernelarch-x86/config b/debian/config/kernelarch-x86/config index be3d04b8a..f3a28a05b 100644 --- a/debian/config/kernelarch-x86/config +++ b/debian/config/kernelarch-x86/config @@ -1122,6 +1122,11 @@ CONFIG_RTL8187SE=m ## CONFIG_RTL8192E=m +## +## file: drivers/staging/rtl8192su/Kconfig +## +CONFIG_RTL8192SU=m + ## ## file: drivers/staging/usbip/Kconfig ## diff --git a/debian/patches/debian/dfsg/drivers-staging-rtl8192su-disable.patch b/debian/patches/debian/dfsg/drivers-staging-rtl8192su-disable.patch deleted file mode 100644 index e4fd5b065..000000000 --- a/debian/patches/debian/dfsg/drivers-staging-rtl8192su-disable.patch +++ /dev/null @@ -1,11 +0,0 @@ -diff --git a/drivers/staging/rtl8192su/Kconfig b/drivers/staging/rtl8192su/Kconfig -index 123fa6d..5e081b1 100644 ---- a/drivers/staging/rtl8192su/Kconfig -+++ b/drivers/staging/rtl8192su/Kconfig -@@ -2,5 +2,6 @@ config RTL8192SU - tristate "RealTek RTL8192SU Wireless LAN NIC driver" - depends on PCI && WLAN && USB - depends on WIRELESS_EXT -+ depends on BROKEN - default N - ---help--- diff --git a/debian/patches/debian/dfsg/files-1 b/debian/patches/debian/dfsg/files-1 index c96713c82..9b8d7cbbc 100644 --- a/debian/patches/debian/dfsg/files-1 +++ b/debian/patches/debian/dfsg/files-1 @@ -56,7 +56,7 @@ rm drivers/staging/rt3070/firmware.h rm drivers/staging/rt3090/firmware.h -rm drivers/staging/rtl8192su/r8192SU_HWImg.c +unifdef drivers/staging/rtl8192su/r8192SU_HWImg.c -UREMOVE_DFSG rm drivers/staging/rtl8192u/r819xU_firmware_img.c diff --git a/debian/patches/debian/dfsg/rtl8192su-Remove-Firmware-from-r8192SU_HWImg.patch b/debian/patches/debian/dfsg/rtl8192su-Remove-Firmware-from-r8192SU_HWImg.patch new file mode 100644 index 000000000..d436bea91 --- /dev/null +++ b/debian/patches/debian/dfsg/rtl8192su-Remove-Firmware-from-r8192SU_HWImg.patch @@ -0,0 +1,236 @@ +From: Florian Schilhabel +Date: Fri, 19 Feb 2010 20:10:00 +0100 +Subject: [PATCH] Staging: rtl8192su: Remove Firmware from r8192SU_HWImg.c + +Because the Firmware is loaded from RTL8192SU/rtl8192sfw.bin, +it it save, to remove it from r8192SU_HWImg.c + +Signed-off-by: Florian Schilhabel +Signed-off-by: Greg Kroah-Hartman +[bwh: Use unifdef to remove the firmware itself] + +diff --git a/drivers/staging/rtl8192su/r8192SU_HWImg.c b/drivers/staging/rtl8192su/r8192SU_HWImg.c +index cbb6579..ba8e12c 100644 +--- a/drivers/staging/rtl8192su/r8192SU_HWImg.c ++++ b/drivers/staging/rtl8192su/r8192SU_HWImg.c +@@ -2,6 +2,7 @@ + + #include "r8192SU_HWImg.h" + ++#ifdef REMOVE_DFSG + u8 Rtl8192SUFwImgArray[ImgArrayLength] = { + 0x92,0x81,0x2b,0x90,0x30,0x00,0x00,0x00,0x08,0x74,0x00,0x00,0x88,0x96,0x00,0x00, + 0x30,0x00,0x00,0x00,0x00,0x95,0x00,0x00,0x00,0x00,0x2b,0x00,0x03,0x03,0x23,0x00, +@@ -4277,6 +4278,7 @@ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0xf2,0x30,0xb8,0xff,0xff,0xff,0xff, + }; + ++#endif + u8 Rtl8192SUFwMainArray[MainArrayLength] = { + 0x0, }; + +diff --git a/drivers/staging/rtl8192su/r8192SU_HWImg.h b/drivers/staging/rtl8192su/r8192SU_HWImg.h +index 96b1525..36e84af 100644 +--- a/drivers/staging/rtl8192su/r8192SU_HWImg.h ++++ b/drivers/staging/rtl8192su/r8192SU_HWImg.h +@@ -5,8 +5,6 @@ + + /*Created on 2009/ 3/ 6, 5:29*/ + +-#define ImgArrayLength 68368 +-extern u8 Rtl8192SUFwImgArray[ImgArrayLength]; + #define MainArrayLength 1 + extern u8 Rtl8192SUFwMainArray[MainArrayLength]; + #define DataArrayLength 1 +diff --git a/drivers/staging/rtl8192su/r8192S_firmware.c b/drivers/staging/rtl8192su/r8192S_firmware.c +index ff65bd1..752a3f1 100644 +--- a/drivers/staging/rtl8192su/r8192S_firmware.c ++++ b/drivers/staging/rtl8192su/r8192S_firmware.c +@@ -360,117 +360,58 @@ bool FirmwareDownload92S(struct net_device *dev) + + RT_TRACE(COMP_FIRMWARE, " --->FirmwareDownload92S()\n"); + +- //3// +- //3 //<1> Open Image file, and map file to contineous memory if open file success. +- //3 // or read image file from array. Default load from BIN file +- //3// +- priv->firmware_source = FW_SOURCE_IMG_FILE;// We should decided by Reg. +- +- switch( priv->firmware_source ) ++/* ++* Load the firmware from RTL8192SU/rtl8192sfw.bin ++*/ ++ if(pFirmware->szFwTmpBufferLen == 0) + { +- case FW_SOURCE_IMG_FILE: +- if(pFirmware->szFwTmpBufferLen == 0) +- { +- +- rc = request_firmware(&fw_entry, pFwImageFileName[ulInitStep],&priv->udev->dev);//===>1 +- if(rc < 0 ) { +- RT_TRACE(COMP_ERR, "request firmware fail!\n"); +- goto DownloadFirmware_Fail; +- } +- +- if(fw_entry->size > sizeof(pFirmware->szFwTmpBuffer)) +- { +- RT_TRACE(COMP_ERR, "img file size exceed the container buffer fail!\n"); +- release_firmware(fw_entry); +- goto DownloadFirmware_Fail; +- } ++ rc = request_firmware(&fw_entry, pFwImageFileName[ulInitStep],&priv->udev->dev); ++ if(rc < 0 ) { ++ RT_TRACE(COMP_ERR, "request firmware fail!\n"); ++ goto DownloadFirmware_Fail; ++ } + +- memcpy(pFirmware->szFwTmpBuffer,fw_entry->data,fw_entry->size); +- pFirmware->szFwTmpBufferLen = fw_entry->size; ++ if(fw_entry->size > sizeof(pFirmware->szFwTmpBuffer)) { ++ RT_TRACE(COMP_ERR, "img file size exceed the container buffer fail!\n"); + release_firmware(fw_entry); +- +- pucMappedFile = pFirmware->szFwTmpBuffer; +- file_length = pFirmware->szFwTmpBufferLen; +- +- //Retrieve FW header. +- pFirmware->pFwHeader = (PRT_8192S_FIRMWARE_HDR) pucMappedFile; +- pFwHdr = pFirmware->pFwHeader; +- RT_TRACE(COMP_FIRMWARE,"signature:%x, version:%x, size:%x, imemsize:%x, sram size:%x\n", \ +- pFwHdr->Signature, pFwHdr->Version, pFwHdr->DMEMSize, \ +- pFwHdr->IMG_IMEM_SIZE, pFwHdr->IMG_SRAM_SIZE); +- pFirmware->FirmwareVersion = byte(pFwHdr->Version ,0); +- if ((pFwHdr->IMG_IMEM_SIZE==0) || (pFwHdr->IMG_IMEM_SIZE > sizeof(pFirmware->FwIMEM))) +- { +- RT_TRACE(COMP_ERR, "%s: memory for data image is less than IMEM required\n",\ +- __FUNCTION__); +- goto DownloadFirmware_Fail; +- } else { +- pucMappedFile+=FwHdrSize; +- +- //Retrieve IMEM image. +- memcpy(pFirmware->FwIMEM, pucMappedFile, pFwHdr->IMG_IMEM_SIZE); +- pFirmware->FwIMEMLen = pFwHdr->IMG_IMEM_SIZE; +- } +- +- if (pFwHdr->IMG_SRAM_SIZE > sizeof(pFirmware->FwEMEM)) +- { +- RT_TRACE(COMP_ERR, "%s: memory for data image is less than EMEM required\n",\ +- __FUNCTION__); +- goto DownloadFirmware_Fail; +- } else { +- pucMappedFile += pFirmware->FwIMEMLen; +- +- /* Retriecve EMEM image */ +- memcpy(pFirmware->FwEMEM, pucMappedFile, pFwHdr->IMG_SRAM_SIZE);//===>6 +- pFirmware->FwEMEMLen = pFwHdr->IMG_SRAM_SIZE; +- } +- +- ++ goto DownloadFirmware_Fail; + } +- break; + +- case FW_SOURCE_HEADER_FILE: +-#if 1 +-#define Rtl819XFwImageArray Rtl8192SUFwImgArray +- //2008.11.10 Add by tynli. +- pucMappedFile = Rtl819XFwImageArray; +- ulFileLength = ImgArrayLength; ++ memcpy(pFirmware->szFwTmpBuffer,fw_entry->data,fw_entry->size); ++ pFirmware->szFwTmpBufferLen = fw_entry->size; ++ release_firmware(fw_entry); ++ ++ pucMappedFile = pFirmware->szFwTmpBuffer; ++ file_length = pFirmware->szFwTmpBufferLen; + +- RT_TRACE(COMP_INIT,"Fw download from header.\n"); +- /* Retrieve FW header*/ ++ /* Retrieve FW header. */ + pFirmware->pFwHeader = (PRT_8192S_FIRMWARE_HDR) pucMappedFile; + pFwHdr = pFirmware->pFwHeader; + RT_TRACE(COMP_FIRMWARE,"signature:%x, version:%x, size:%x, imemsize:%x, sram size:%x\n", \ + pFwHdr->Signature, pFwHdr->Version, pFwHdr->DMEMSize, \ + pFwHdr->IMG_IMEM_SIZE, pFwHdr->IMG_SRAM_SIZE); + pFirmware->FirmwareVersion = byte(pFwHdr->Version ,0); +- +- if ((pFwHdr->IMG_IMEM_SIZE==0) || (pFwHdr->IMG_IMEM_SIZE > sizeof(pFirmware->FwIMEM))) +- { +- printk("FirmwareDownload92S(): memory for data image is less than IMEM required\n"); ++ if ((pFwHdr->IMG_IMEM_SIZE==0) || (pFwHdr->IMG_IMEM_SIZE > sizeof(pFirmware->FwIMEM))) { ++ RT_TRACE(COMP_ERR, "%s: memory for data image is less than IMEM required\n",\ ++ __FUNCTION__); + goto DownloadFirmware_Fail; + } else { + pucMappedFile+=FwHdrSize; +- //Retrieve IMEM image. ++ /* Retrieve IMEM image. */ + memcpy(pFirmware->FwIMEM, pucMappedFile, pFwHdr->IMG_IMEM_SIZE); + pFirmware->FwIMEMLen = pFwHdr->IMG_IMEM_SIZE; + } + +- if (pFwHdr->IMG_SRAM_SIZE > sizeof(pFirmware->FwEMEM)) +- { +- printk(" FirmwareDownload92S(): memory for data image is less than EMEM required\n"); +- goto DownloadFirmware_Fail; +- } else { +- pucMappedFile+= pFirmware->FwIMEMLen; +- +- //Retriecve EMEM image. +- memcpy(pFirmware->FwEMEM, pucMappedFile, pFwHdr->IMG_SRAM_SIZE); +- pFirmware->FwEMEMLen = pFwHdr->IMG_SRAM_SIZE; +- } +-#endif +- break; +- default: +- break; ++ if (pFwHdr->IMG_SRAM_SIZE > sizeof(pFirmware->FwEMEM)) { ++ RT_TRACE(COMP_ERR, "%s: memory for data image is less than EMEM required\n",\ ++ __FUNCTION__); ++ goto DownloadFirmware_Fail; ++ } else { ++ pucMappedFile += pFirmware->FwIMEMLen; ++ /* Retriecve EMEM image */ ++ memcpy(pFirmware->FwEMEM, pucMappedFile, pFwHdr->IMG_SRAM_SIZE);//===>6 ++ pFirmware->FwEMEMLen = pFwHdr->IMG_SRAM_SIZE; ++ } + } + + FwStatus = FirmwareGetNextStatus(pFirmware->FWStatus); +diff --git a/drivers/staging/rtl8192su/r8192S_firmware.h b/drivers/staging/rtl8192su/r8192S_firmware.h +index c525380..2c2cf80 100644 +--- a/drivers/staging/rtl8192su/r8192S_firmware.h ++++ b/drivers/staging/rtl8192su/r8192S_firmware.h +@@ -59,12 +59,6 @@ typedef enum _desc_packet_type_e{ + DESC_PACKET_TYPE_NORMAL = 1, + }desc_packet_type_e; + +-typedef enum _firmware_source{ +- FW_SOURCE_IMG_FILE = 0, +- FW_SOURCE_HEADER_FILE = 1, +-}firmware_source_e, *pfirmware_source_e; +- +- + typedef enum _opt_rst_type{ + OPT_SYSTEM_RESET = 0, + OPT_FIRMWARE_RESET = 1, +@@ -185,7 +179,6 @@ typedef enum _FIRMWARE_8192S_STATUS{ + #define RTL8190_MAX_FIRMWARE_CODE_SIZE 64000 //64k + + typedef struct _rt_firmware{ +- firmware_source_e eFWSource; + PRT_8192S_FIRMWARE_HDR pFwHeader; + FIRMWARE_8192S_STATUS FWStatus; + u16 FirmwareVersion; +diff --git a/drivers/staging/rtl8192su/r8192U.h b/drivers/staging/rtl8192su/r8192U.h +index 2a11e01..ba87623 100644 +--- a/drivers/staging/rtl8192su/r8192U.h ++++ b/drivers/staging/rtl8192su/r8192U.h +@@ -1258,7 +1258,6 @@ typedef struct r8192_priv + u8 Rf_Mode; //add for Firmware RF -R/W switch + prt_firmware pFirmware; + rtl819xUsb_loopback_e LoopbackMode; +- firmware_source_e firmware_source; + bool usb_error; + + u16 EEPROMTxPowerDiff; diff --git a/debian/patches/series/orig-0 b/debian/patches/series/orig-0 index 19f74f401..5dcf1099f 100644 --- a/debian/patches/series/orig-0 +++ b/debian/patches/series/orig-0 @@ -5,7 +5,7 @@ + debian/dfsg/drivers-staging-otus-disable.patch + debian/dfsg/drivers-staging-rt2860-disable.patch + debian/dfsg/drivers-staging-rt2870-disable.patch -+ debian/dfsg/drivers-staging-rtl8192su-disable.patch ++ debian/dfsg/rtl8192su-Remove-Firmware-from-r8192SU_HWImg.patch + debian/dfsg/drivers-staging-wlags49_h2-disable.patch + debian/dfsg/drivers-staging-wlags49_h25-disable.patch + debian/dfsg/firmware-cleanup.patch From 330d70aa271b174bf95b9093a7600cdbae0b0e33 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Tue, 16 Mar 2010 01:19:38 +0000 Subject: [PATCH 71/71] Rework rtl8192su patches to avoid the need for a new orig tarball svn path=/dists/trunk/linux-2.6/; revision=15388 --- .../drivers-staging-rtl8192su-disable.patch | 11 + debian/patches/debian/dfsg/files-1 | 2 +- ...u-Remove-Firmware-from-r8192SU_HWImg.patch | 236 ----- ...tl8192su-always-use-request_firmware.patch | 854 ++++++++++++++++++ debian/patches/series/base | 1 + debian/patches/series/orig-0 | 2 +- 6 files changed, 868 insertions(+), 238 deletions(-) create mode 100644 debian/patches/debian/dfsg/drivers-staging-rtl8192su-disable.patch delete mode 100644 debian/patches/debian/dfsg/rtl8192su-Remove-Firmware-from-r8192SU_HWImg.patch create mode 100644 debian/patches/features/all/rtl8192su-always-use-request_firmware.patch diff --git a/debian/patches/debian/dfsg/drivers-staging-rtl8192su-disable.patch b/debian/patches/debian/dfsg/drivers-staging-rtl8192su-disable.patch new file mode 100644 index 000000000..e4fd5b065 --- /dev/null +++ b/debian/patches/debian/dfsg/drivers-staging-rtl8192su-disable.patch @@ -0,0 +1,11 @@ +diff --git a/drivers/staging/rtl8192su/Kconfig b/drivers/staging/rtl8192su/Kconfig +index 123fa6d..5e081b1 100644 +--- a/drivers/staging/rtl8192su/Kconfig ++++ b/drivers/staging/rtl8192su/Kconfig +@@ -2,5 +2,6 @@ config RTL8192SU + tristate "RealTek RTL8192SU Wireless LAN NIC driver" + depends on PCI && WLAN && USB + depends on WIRELESS_EXT ++ depends on BROKEN + default N + ---help--- diff --git a/debian/patches/debian/dfsg/files-1 b/debian/patches/debian/dfsg/files-1 index 9b8d7cbbc..c96713c82 100644 --- a/debian/patches/debian/dfsg/files-1 +++ b/debian/patches/debian/dfsg/files-1 @@ -56,7 +56,7 @@ rm drivers/staging/rt3070/firmware.h rm drivers/staging/rt3090/firmware.h -unifdef drivers/staging/rtl8192su/r8192SU_HWImg.c -UREMOVE_DFSG +rm drivers/staging/rtl8192su/r8192SU_HWImg.c rm drivers/staging/rtl8192u/r819xU_firmware_img.c diff --git a/debian/patches/debian/dfsg/rtl8192su-Remove-Firmware-from-r8192SU_HWImg.patch b/debian/patches/debian/dfsg/rtl8192su-Remove-Firmware-from-r8192SU_HWImg.patch deleted file mode 100644 index d436bea91..000000000 --- a/debian/patches/debian/dfsg/rtl8192su-Remove-Firmware-from-r8192SU_HWImg.patch +++ /dev/null @@ -1,236 +0,0 @@ -From: Florian Schilhabel -Date: Fri, 19 Feb 2010 20:10:00 +0100 -Subject: [PATCH] Staging: rtl8192su: Remove Firmware from r8192SU_HWImg.c - -Because the Firmware is loaded from RTL8192SU/rtl8192sfw.bin, -it it save, to remove it from r8192SU_HWImg.c - -Signed-off-by: Florian Schilhabel -Signed-off-by: Greg Kroah-Hartman -[bwh: Use unifdef to remove the firmware itself] - -diff --git a/drivers/staging/rtl8192su/r8192SU_HWImg.c b/drivers/staging/rtl8192su/r8192SU_HWImg.c -index cbb6579..ba8e12c 100644 ---- a/drivers/staging/rtl8192su/r8192SU_HWImg.c -+++ b/drivers/staging/rtl8192su/r8192SU_HWImg.c -@@ -2,6 +2,7 @@ - - #include "r8192SU_HWImg.h" - -+#ifdef REMOVE_DFSG - u8 Rtl8192SUFwImgArray[ImgArrayLength] = { - 0x92,0x81,0x2b,0x90,0x30,0x00,0x00,0x00,0x08,0x74,0x00,0x00,0x88,0x96,0x00,0x00, - 0x30,0x00,0x00,0x00,0x00,0x95,0x00,0x00,0x00,0x00,0x2b,0x00,0x03,0x03,0x23,0x00, -@@ -4277,6 +4278,7 @@ - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0xf2,0x30,0xb8,0xff,0xff,0xff,0xff, - }; - -+#endif - u8 Rtl8192SUFwMainArray[MainArrayLength] = { - 0x0, }; - -diff --git a/drivers/staging/rtl8192su/r8192SU_HWImg.h b/drivers/staging/rtl8192su/r8192SU_HWImg.h -index 96b1525..36e84af 100644 ---- a/drivers/staging/rtl8192su/r8192SU_HWImg.h -+++ b/drivers/staging/rtl8192su/r8192SU_HWImg.h -@@ -5,8 +5,6 @@ - - /*Created on 2009/ 3/ 6, 5:29*/ - --#define ImgArrayLength 68368 --extern u8 Rtl8192SUFwImgArray[ImgArrayLength]; - #define MainArrayLength 1 - extern u8 Rtl8192SUFwMainArray[MainArrayLength]; - #define DataArrayLength 1 -diff --git a/drivers/staging/rtl8192su/r8192S_firmware.c b/drivers/staging/rtl8192su/r8192S_firmware.c -index ff65bd1..752a3f1 100644 ---- a/drivers/staging/rtl8192su/r8192S_firmware.c -+++ b/drivers/staging/rtl8192su/r8192S_firmware.c -@@ -360,117 +360,58 @@ bool FirmwareDownload92S(struct net_device *dev) - - RT_TRACE(COMP_FIRMWARE, " --->FirmwareDownload92S()\n"); - -- //3// -- //3 //<1> Open Image file, and map file to contineous memory if open file success. -- //3 // or read image file from array. Default load from BIN file -- //3// -- priv->firmware_source = FW_SOURCE_IMG_FILE;// We should decided by Reg. -- -- switch( priv->firmware_source ) -+/* -+* Load the firmware from RTL8192SU/rtl8192sfw.bin -+*/ -+ if(pFirmware->szFwTmpBufferLen == 0) - { -- case FW_SOURCE_IMG_FILE: -- if(pFirmware->szFwTmpBufferLen == 0) -- { -- -- rc = request_firmware(&fw_entry, pFwImageFileName[ulInitStep],&priv->udev->dev);//===>1 -- if(rc < 0 ) { -- RT_TRACE(COMP_ERR, "request firmware fail!\n"); -- goto DownloadFirmware_Fail; -- } -- -- if(fw_entry->size > sizeof(pFirmware->szFwTmpBuffer)) -- { -- RT_TRACE(COMP_ERR, "img file size exceed the container buffer fail!\n"); -- release_firmware(fw_entry); -- goto DownloadFirmware_Fail; -- } -+ rc = request_firmware(&fw_entry, pFwImageFileName[ulInitStep],&priv->udev->dev); -+ if(rc < 0 ) { -+ RT_TRACE(COMP_ERR, "request firmware fail!\n"); -+ goto DownloadFirmware_Fail; -+ } - -- memcpy(pFirmware->szFwTmpBuffer,fw_entry->data,fw_entry->size); -- pFirmware->szFwTmpBufferLen = fw_entry->size; -+ if(fw_entry->size > sizeof(pFirmware->szFwTmpBuffer)) { -+ RT_TRACE(COMP_ERR, "img file size exceed the container buffer fail!\n"); - release_firmware(fw_entry); -- -- pucMappedFile = pFirmware->szFwTmpBuffer; -- file_length = pFirmware->szFwTmpBufferLen; -- -- //Retrieve FW header. -- pFirmware->pFwHeader = (PRT_8192S_FIRMWARE_HDR) pucMappedFile; -- pFwHdr = pFirmware->pFwHeader; -- RT_TRACE(COMP_FIRMWARE,"signature:%x, version:%x, size:%x, imemsize:%x, sram size:%x\n", \ -- pFwHdr->Signature, pFwHdr->Version, pFwHdr->DMEMSize, \ -- pFwHdr->IMG_IMEM_SIZE, pFwHdr->IMG_SRAM_SIZE); -- pFirmware->FirmwareVersion = byte(pFwHdr->Version ,0); -- if ((pFwHdr->IMG_IMEM_SIZE==0) || (pFwHdr->IMG_IMEM_SIZE > sizeof(pFirmware->FwIMEM))) -- { -- RT_TRACE(COMP_ERR, "%s: memory for data image is less than IMEM required\n",\ -- __FUNCTION__); -- goto DownloadFirmware_Fail; -- } else { -- pucMappedFile+=FwHdrSize; -- -- //Retrieve IMEM image. -- memcpy(pFirmware->FwIMEM, pucMappedFile, pFwHdr->IMG_IMEM_SIZE); -- pFirmware->FwIMEMLen = pFwHdr->IMG_IMEM_SIZE; -- } -- -- if (pFwHdr->IMG_SRAM_SIZE > sizeof(pFirmware->FwEMEM)) -- { -- RT_TRACE(COMP_ERR, "%s: memory for data image is less than EMEM required\n",\ -- __FUNCTION__); -- goto DownloadFirmware_Fail; -- } else { -- pucMappedFile += pFirmware->FwIMEMLen; -- -- /* Retriecve EMEM image */ -- memcpy(pFirmware->FwEMEM, pucMappedFile, pFwHdr->IMG_SRAM_SIZE);//===>6 -- pFirmware->FwEMEMLen = pFwHdr->IMG_SRAM_SIZE; -- } -- -- -+ goto DownloadFirmware_Fail; - } -- break; - -- case FW_SOURCE_HEADER_FILE: --#if 1 --#define Rtl819XFwImageArray Rtl8192SUFwImgArray -- //2008.11.10 Add by tynli. -- pucMappedFile = Rtl819XFwImageArray; -- ulFileLength = ImgArrayLength; -+ memcpy(pFirmware->szFwTmpBuffer,fw_entry->data,fw_entry->size); -+ pFirmware->szFwTmpBufferLen = fw_entry->size; -+ release_firmware(fw_entry); -+ -+ pucMappedFile = pFirmware->szFwTmpBuffer; -+ file_length = pFirmware->szFwTmpBufferLen; - -- RT_TRACE(COMP_INIT,"Fw download from header.\n"); -- /* Retrieve FW header*/ -+ /* Retrieve FW header. */ - pFirmware->pFwHeader = (PRT_8192S_FIRMWARE_HDR) pucMappedFile; - pFwHdr = pFirmware->pFwHeader; - RT_TRACE(COMP_FIRMWARE,"signature:%x, version:%x, size:%x, imemsize:%x, sram size:%x\n", \ - pFwHdr->Signature, pFwHdr->Version, pFwHdr->DMEMSize, \ - pFwHdr->IMG_IMEM_SIZE, pFwHdr->IMG_SRAM_SIZE); - pFirmware->FirmwareVersion = byte(pFwHdr->Version ,0); -- -- if ((pFwHdr->IMG_IMEM_SIZE==0) || (pFwHdr->IMG_IMEM_SIZE > sizeof(pFirmware->FwIMEM))) -- { -- printk("FirmwareDownload92S(): memory for data image is less than IMEM required\n"); -+ if ((pFwHdr->IMG_IMEM_SIZE==0) || (pFwHdr->IMG_IMEM_SIZE > sizeof(pFirmware->FwIMEM))) { -+ RT_TRACE(COMP_ERR, "%s: memory for data image is less than IMEM required\n",\ -+ __FUNCTION__); - goto DownloadFirmware_Fail; - } else { - pucMappedFile+=FwHdrSize; -- //Retrieve IMEM image. -+ /* Retrieve IMEM image. */ - memcpy(pFirmware->FwIMEM, pucMappedFile, pFwHdr->IMG_IMEM_SIZE); - pFirmware->FwIMEMLen = pFwHdr->IMG_IMEM_SIZE; - } - -- if (pFwHdr->IMG_SRAM_SIZE > sizeof(pFirmware->FwEMEM)) -- { -- printk(" FirmwareDownload92S(): memory for data image is less than EMEM required\n"); -- goto DownloadFirmware_Fail; -- } else { -- pucMappedFile+= pFirmware->FwIMEMLen; -- -- //Retriecve EMEM image. -- memcpy(pFirmware->FwEMEM, pucMappedFile, pFwHdr->IMG_SRAM_SIZE); -- pFirmware->FwEMEMLen = pFwHdr->IMG_SRAM_SIZE; -- } --#endif -- break; -- default: -- break; -+ if (pFwHdr->IMG_SRAM_SIZE > sizeof(pFirmware->FwEMEM)) { -+ RT_TRACE(COMP_ERR, "%s: memory for data image is less than EMEM required\n",\ -+ __FUNCTION__); -+ goto DownloadFirmware_Fail; -+ } else { -+ pucMappedFile += pFirmware->FwIMEMLen; -+ /* Retriecve EMEM image */ -+ memcpy(pFirmware->FwEMEM, pucMappedFile, pFwHdr->IMG_SRAM_SIZE);//===>6 -+ pFirmware->FwEMEMLen = pFwHdr->IMG_SRAM_SIZE; -+ } - } - - FwStatus = FirmwareGetNextStatus(pFirmware->FWStatus); -diff --git a/drivers/staging/rtl8192su/r8192S_firmware.h b/drivers/staging/rtl8192su/r8192S_firmware.h -index c525380..2c2cf80 100644 ---- a/drivers/staging/rtl8192su/r8192S_firmware.h -+++ b/drivers/staging/rtl8192su/r8192S_firmware.h -@@ -59,12 +59,6 @@ typedef enum _desc_packet_type_e{ - DESC_PACKET_TYPE_NORMAL = 1, - }desc_packet_type_e; - --typedef enum _firmware_source{ -- FW_SOURCE_IMG_FILE = 0, -- FW_SOURCE_HEADER_FILE = 1, --}firmware_source_e, *pfirmware_source_e; -- -- - typedef enum _opt_rst_type{ - OPT_SYSTEM_RESET = 0, - OPT_FIRMWARE_RESET = 1, -@@ -185,7 +179,6 @@ typedef enum _FIRMWARE_8192S_STATUS{ - #define RTL8190_MAX_FIRMWARE_CODE_SIZE 64000 //64k - - typedef struct _rt_firmware{ -- firmware_source_e eFWSource; - PRT_8192S_FIRMWARE_HDR pFwHeader; - FIRMWARE_8192S_STATUS FWStatus; - u16 FirmwareVersion; -diff --git a/drivers/staging/rtl8192su/r8192U.h b/drivers/staging/rtl8192su/r8192U.h -index 2a11e01..ba87623 100644 ---- a/drivers/staging/rtl8192su/r8192U.h -+++ b/drivers/staging/rtl8192su/r8192U.h -@@ -1258,7 +1258,6 @@ typedef struct r8192_priv - u8 Rf_Mode; //add for Firmware RF -R/W switch - prt_firmware pFirmware; - rtl819xUsb_loopback_e LoopbackMode; -- firmware_source_e firmware_source; - bool usb_error; - - u16 EEPROMTxPowerDiff; diff --git a/debian/patches/features/all/rtl8192su-always-use-request_firmware.patch b/debian/patches/features/all/rtl8192su-always-use-request_firmware.patch new file mode 100644 index 000000000..ac8a08284 --- /dev/null +++ b/debian/patches/features/all/rtl8192su-always-use-request_firmware.patch @@ -0,0 +1,854 @@ +From: Florian Schilhabel +Date: Fri, 19 Feb 2010 20:10:00 +0100 +Subject: [PATCH] Staging: rtl8192su: Remove Firmware from r8192SU_HWImg.c + +Because the Firmware is loaded from RTL8192SU/rtl8192sfw.bin, +it it save, to remove it from r8192SU_HWImg.c + +Signed-off-by: Florian Schilhabel +Signed-off-by: Greg Kroah-Hartman +[bwh: Adjust to apply to Debian source] + +--- a/drivers/staging/rtl8192su/Kconfig ++++ b/drivers/staging/rtl8192su/Kconfig +@@ -2,6 +2,5 @@ + tristate "RealTek RTL8192SU Wireless LAN NIC driver" + depends on PCI && WLAN && USB + depends on WIRELESS_EXT +- depends on BROKEN + default N + ---help--- +--- /dev/null ++++ b/drivers/staging/rtl8192su/r8192SU_HWImg.c +@@ -0,0 +1,626 @@ ++/*Created on 2009/ 1/15, 3:10*/ ++ ++#include "r8192SU_HWImg.h" ++ ++u8 Rtl8192SUFwMainArray[MainArrayLength] = { ++0x0, }; ++ ++u8 Rtl8192SUFwDataArray[DataArrayLength] = { ++0x0, }; ++ ++u32 Rtl8192SUPHY_REG_2T2RArray[PHY_REG_2T2RArrayLength] = { ++0x01c,0x07000000, ++0x800,0x00040000, ++0x804,0x00008003, ++0x808,0x0000fc00, ++0x80c,0x0000000a, ++0x810,0x10005088, ++0x814,0x020c3d10, ++0x818,0x00200185, ++0x81c,0x00000000, ++0x820,0x01000000, ++0x824,0x00390004, ++0x828,0x01000000, ++0x82c,0x00390004, ++0x830,0x00000004, ++0x834,0x00690200, ++0x838,0x00000004, ++0x83c,0x00690200, ++0x840,0x00010000, ++0x844,0x00010000, ++0x848,0x00000000, ++0x84c,0x00000000, ++0x850,0x00000000, ++0x854,0x00000000, ++0x858,0x48484848, ++0x85c,0x65a965a9, ++0x860,0x0f7f0130, ++0x864,0x0f7f0130, ++0x868,0x0f7f0130, ++0x86c,0x0f7f0130, ++0x870,0x03000700, ++0x874,0x03000300, ++0x878,0x00020002, ++0x87c,0x004f0201, ++0x880,0xa8300ac1, ++0x884,0x00000058, ++0x888,0x00000008, ++0x88c,0x00000004, ++0x890,0x00000000, ++0x894,0xfffffffe, ++0x898,0x40302010, ++0x89c,0x00706050, ++0x8b0,0x00000000, ++0x8e0,0x00000000, ++0x8e4,0x00000000, ++0xe00,0x30333333, ++0xe04,0x2a2d2e2f, ++0xe08,0x00003232, ++0xe10,0x30333333, ++0xe14,0x2a2d2e2f, ++0xe18,0x30333333, ++0xe1c,0x2a2d2e2f, ++0xe30,0x01007c00, ++0xe34,0x01004800, ++0xe38,0x1000dc1f, ++0xe3c,0x10008c1f, ++0xe40,0x021400a0, ++0xe44,0x281600a0, ++0xe48,0xf8000001, ++0xe4c,0x00002910, ++0xe50,0x01007c00, ++0xe54,0x01004800, ++0xe58,0x1000dc1f, ++0xe5c,0x10008c1f, ++0xe60,0x021400a0, ++0xe64,0x281600a0, ++0xe6c,0x00002910, ++0xe70,0x31ed92fb, ++0xe74,0x361536fb, ++0xe78,0x361536fb, ++0xe7c,0x361536fb, ++0xe80,0x361536fb, ++0xe84,0x000d92fb, ++0xe88,0x000d92fb, ++0xe8c,0x31ed92fb, ++0xed0,0x31ed92fb, ++0xed4,0x31ed92fb, ++0xed8,0x000d92fb, ++0xedc,0x000d92fb, ++0xee0,0x000d92fb, ++0xee4,0x015e5448, ++0xee8,0x21555448, ++0x900,0x00000000, ++0x904,0x00000023, ++0x908,0x00000000, ++0x90c,0x03321333, ++0xa00,0x00d047c8, ++0xa04,0x80ff0008, ++0xa08,0x8ccd8300, ++0xa0c,0x2e62120f, ++0xa10,0x9500bb78, ++0xa14,0x11144028, ++0xa18,0x00881117, ++0xa1c,0x89140f00, ++0xa20,0x1a1b0000, ++0xa24,0x090e1317, ++0xa28,0x00000204, ++0xa2c,0x10d30000, ++0xc00,0x40071d40, ++0xc04,0x00a05633, ++0xc08,0x000000e4, ++0xc0c,0x6c6c6c6c, ++0xc10,0x08800000, ++0xc14,0x40000100, ++0xc18,0x08000000, ++0xc1c,0x40000100, ++0xc20,0x08000000, ++0xc24,0x40000100, ++0xc28,0x08000000, ++0xc2c,0x40000100, ++0xc30,0x6de9ac44, ++0xc34,0x469652cf, ++0xc38,0x49795994, ++0xc3c,0x0a979764, ++0xc40,0x1f7c403f, ++0xc44,0x000100b7, ++0xc48,0xec020000, ++0xc4c,0x007f037f, ++0xc50,0x69543420, ++0xc54,0x433c0094, ++0xc58,0x69543420, ++0xc5c,0x433c0094, ++0xc60,0x69543420, ++0xc64,0x433c0094, ++0xc68,0x69543420, ++0xc6c,0x433c0094, ++0xc70,0x2c7f000d, ++0xc74,0x0186155b, ++0xc78,0x0000001f, ++0xc7c,0x00b91612, ++0xc80,0x40000100, ++0xc84,0x20f60000, ++0xc88,0x20000080, ++0xc8c,0x20200000, ++0xc90,0x40000100, ++0xc94,0x00000000, ++0xc98,0x40000100, ++0xc9c,0x00000000, ++0xca0,0x00492492, ++0xca4,0x00000000, ++0xca8,0x00000000, ++0xcac,0x00000000, ++0xcb0,0x00000000, ++0xcb4,0x00000000, ++0xcb8,0x00000000, ++0xcbc,0x28000000, ++0xcc0,0x00000000, ++0xcc4,0x00000000, ++0xcc8,0x00000000, ++0xccc,0x00000000, ++0xcd0,0x00000000, ++0xcd4,0x00000000, ++0xcd8,0x64b22427, ++0xcdc,0x00766932, ++0xce0,0x00222222, ++0xce4,0x00000000, ++0xce8,0x37644302, ++0xcec,0x2f97d40c, ++0xd00,0x00000750, ++0xd04,0x00000403, ++0xd08,0x0000907f, ++0xd0c,0x00000001, ++0xd10,0xa0633333, ++0xd14,0x33333c63, ++0xd18,0x6a8f5b6b, ++0xd1c,0x00000000, ++0xd20,0x00000000, ++0xd24,0x00000000, ++0xd28,0x00000000, ++0xd2c,0xcc979975, ++0xd30,0x00000000, ++0xd34,0x00000000, ++0xd38,0x00000000, ++0xd3c,0x00027293, ++0xd40,0x00000000, ++0xd44,0x00000000, ++0xd48,0x00000000, ++0xd50,0x6437140a, ++0xd54,0x024dbd02, ++0xd58,0x00000000, ++0xd5c,0x30032064, ++0xd60,0x4653de68, ++0xd64,0x00518a3c, ++0xd68,0x00002101, ++0xf14,0x00000003, ++0xf4c,0x00000000, ++0xf00,0x00000300, ++}; ++ ++u32 Rtl8192SUPHY_REG_1T2RArray[PHY_REG_1T2RArrayLength] = { ++0x0, }; ++ ++u32 Rtl8192SUPHY_ChangeTo_1T1RArray[PHY_ChangeTo_1T1RArrayLength] = { ++0x844,0xffffffff,0x00010000, ++0x804,0x0000000f,0x00000001, ++0x824,0x00f0000f,0x00300004, ++0x82c,0x00f0000f,0x00100002, ++0x870,0x04000000,0x00000001, ++0x864,0x00000400,0x00000000, ++0x878,0x000f000f,0x00000002, ++0xe74,0x0f000000,0x00000002, ++0xe78,0x0f000000,0x00000002, ++0xe7c,0x0f000000,0x00000002, ++0xe80,0x0f000000,0x00000002, ++0x90c,0x000000ff,0x00000011, ++0xc04,0x000000ff,0x00000011, ++0xd04,0x0000000f,0x00000001, ++0x1f4,0xffff0000,0x00007777, ++0x234,0xf8000000,0x0000000a, ++}; ++ ++u32 Rtl8192SUPHY_ChangeTo_1T2RArray[PHY_ChangeTo_1T2RArrayLength] = { ++0x804,0x0000000f,0x00000003, ++0x824,0x00f0000f,0x00300004, ++0x82c,0x00f0000f,0x00300002, ++0x870,0x04000000,0x00000001, ++0x864,0x00000400,0x00000000, ++0x878,0x000f000f,0x00000002, ++0xe74,0x0f000000,0x00000002, ++0xe78,0x0f000000,0x00000002, ++0xe7c,0x0f000000,0x00000002, ++0xe80,0x0f000000,0x00000002, ++0x90c,0x000000ff,0x00000011, ++0xc04,0x000000ff,0x00000033, ++0xd04,0x0000000f,0x00000003, ++0x1f4,0xffff0000,0x00007777, ++0x234,0xf8000000,0x0000000a, ++}; ++ ++u32 Rtl8192SUPHY_ChangeTo_2T2RArray[PHY_ChangeTo_2T2RArrayLength] = { ++0x804,0x0000000f,0x00000003, ++0x824,0x00f0000f,0x00300004, ++0x82c,0x00f0000f,0x00300004, ++0x870,0x04000000,0x00000001, ++0x864,0x00000400,0x00000001, ++0x878,0x000f000f,0x00020002, ++0xe74,0x0f000000,0x00000006, ++0xe78,0x0f000000,0x00000006, ++0xe7c,0x0f000000,0x00000006, ++0xe80,0x0f000000,0x00000006, ++0x90c,0x000000ff,0x00000033, ++0xc04,0x000000ff,0x00000033, ++0xd04,0x0000000f,0x00000003, ++0x1f4,0xffff0000,0x0000ffff, ++0x234,0xf8000000,0x00000013, ++}; ++ ++u32 Rtl8192SUPHY_REG_Array_PG[PHY_REG_Array_PGLength] = { ++0xe00,0xffffffff,0x06090909, ++0xe04,0xffffffff,0x00030406, ++0xe08,0x0000ff00,0x00000000, ++0xe10,0xffffffff,0x0a0c0d0e, ++0xe14,0xffffffff,0x04070809, ++0xe18,0xffffffff,0x0a0c0d0e, ++0xe1c,0xffffffff,0x04070809, ++}; ++ ++u32 Rtl8192SURadioA_1T_Array[RadioA_1T_ArrayLength] = { ++0x000,0x00030159, ++0x001,0x00030250, ++0x002,0x00010000, ++0x010,0x0008000f, ++0x011,0x000231fc, ++0x010,0x000c000f, ++0x011,0x0003f9f8, ++0x010,0x0002000f, ++0x011,0x00020101, ++0x014,0x0001093e, ++0x014,0x0009093e, ++0x015,0x000198f4, ++0x017,0x000f6500, ++0x01a,0x00013056, ++0x01b,0x00060000, ++0x01c,0x00000300, ++0x01e,0x00031059, ++0x021,0x00054000, ++0x022,0x0000083c, ++0x023,0x00001558, ++0x024,0x00000060, ++0x025,0x00022583, ++0x026,0x0000f200, ++0x027,0x000eacf1, ++0x028,0x0009bd54, ++0x029,0x00004582, ++0x02a,0x00000001, ++0x02b,0x00021334, ++0x02a,0x00000000, ++0x02b,0x0000000a, ++0x02a,0x00000001, ++0x02b,0x00000808, ++0x02b,0x00053333, ++0x02c,0x0000000c, ++0x02a,0x00000002, ++0x02b,0x00000808, ++0x02b,0x0005b333, ++0x02c,0x0000000d, ++0x02a,0x00000003, ++0x02b,0x00000808, ++0x02b,0x00063333, ++0x02c,0x0000000d, ++0x02a,0x00000004, ++0x02b,0x00000808, ++0x02b,0x0006b333, ++0x02c,0x0000000d, ++0x02a,0x00000005, ++0x02b,0x00000709, ++0x02b,0x00053333, ++0x02c,0x0000000d, ++0x02a,0x00000006, ++0x02b,0x00000709, ++0x02b,0x0005b333, ++0x02c,0x0000000d, ++0x02a,0x00000007, ++0x02b,0x00000709, ++0x02b,0x00063333, ++0x02c,0x0000000d, ++0x02a,0x00000008, ++0x02b,0x00000709, ++0x02b,0x0006b333, ++0x02c,0x0000000d, ++0x02a,0x00000009, ++0x02b,0x0000060a, ++0x02b,0x00053333, ++0x02c,0x0000000d, ++0x02a,0x0000000a, ++0x02b,0x0000060a, ++0x02b,0x0005b333, ++0x02c,0x0000000d, ++0x02a,0x0000000b, ++0x02b,0x0000060a, ++0x02b,0x00063333, ++0x02c,0x0000000d, ++0x02a,0x0000000c, ++0x02b,0x0000060a, ++0x02b,0x0006b333, ++0x02c,0x0000000d, ++0x02a,0x0000000d, ++0x02b,0x0000050b, ++0x02b,0x00053333, ++0x02c,0x0000000d, ++0x02a,0x0000000e, ++0x02b,0x0000050b, ++0x02b,0x00066623, ++0x02c,0x0000001a, ++0x02a,0x000e4000, ++0x030,0x00020000, ++0x031,0x000b9631, ++0x032,0x0000130d, ++0x033,0x00000187, ++0x013,0x00019e6c, ++0x013,0x00015e94, ++0x000,0x00010159, ++0x018,0x0000f401, ++0x0fe,0x00000000, ++0x01e,0x0003105b, ++0x0fe,0x00000000, ++0x000,0x00030159, ++0x010,0x0004000f, ++0x011,0x000203f9, ++}; ++ ++u32 Rtl8192SURadioB_Array[RadioB_ArrayLength] = { ++0x000,0x00030159, ++0x001,0x00001041, ++0x002,0x00011000, ++0x005,0x00080fc0, ++0x007,0x000fc803, ++0x013,0x00017cb0, ++0x013,0x00011cc0, ++0x013,0x0000dc60, ++0x013,0x00008c60, ++0x013,0x00004450, ++0x013,0x00000020, ++}; ++ ++u32 Rtl8192SURadioA_to1T_Array[RadioA_to1T_ArrayLength] = { ++0x000,0x00000000, ++}; ++ ++u32 Rtl8192SURadioA_to2T_Array[RadioA_to2T_ArrayLength] = { ++0x000,0x00000000, ++}; ++ ++u32 Rtl8192SURadioB_GM_Array[RadioB_GM_ArrayLength] = { ++0x000,0x00030159, ++0x001,0x00001041, ++0x002,0x00011000, ++0x005,0x00080fc0, ++0x007,0x000fc803, ++0x013,0x0000bef0, ++0x013,0x00007e90, ++0x013,0x00003e30, ++}; ++ ++u32 Rtl8192SUMAC_2T_Array[MAC_2T_ArrayLength] = { ++0x020,0x00000035, ++0x048,0x0000000e, ++0x049,0x000000f0, ++0x04a,0x00000077, ++0x04b,0x00000083, ++0x0b5,0x00000021, ++0x0dc,0x000000ff, ++0x0dd,0x000000ff, ++0x0de,0x000000ff, ++0x0df,0x000000ff, ++0x116,0x00000000, ++0x117,0x00000000, ++0x118,0x00000000, ++0x119,0x00000000, ++0x11a,0x00000000, ++0x11b,0x00000000, ++0x11c,0x00000000, ++0x11d,0x00000000, ++0x160,0x0000000b, ++0x161,0x0000000b, ++0x162,0x0000000b, ++0x163,0x0000000b, ++0x164,0x0000000b, ++0x165,0x0000000b, ++0x166,0x0000000b, ++0x167,0x0000000b, ++0x168,0x0000000b, ++0x169,0x0000000b, ++0x16a,0x0000000b, ++0x16b,0x0000000b, ++0x16c,0x0000000b, ++0x16d,0x0000000b, ++0x16e,0x0000000b, ++0x16f,0x0000000b, ++0x170,0x0000000b, ++0x171,0x0000000b, ++0x172,0x0000000b, ++0x173,0x0000000b, ++0x174,0x0000000b, ++0x175,0x0000000b, ++0x176,0x0000000b, ++0x177,0x0000000b, ++0x178,0x0000000b, ++0x179,0x0000000b, ++0x17a,0x0000000b, ++0x17b,0x0000000b, ++0x17c,0x0000000b, ++0x17d,0x0000000b, ++0x17e,0x0000000b, ++0x17f,0x0000000b, ++0x236,0x0000000c, ++0x503,0x00000022, ++0x560,0x00000009, ++}; ++ ++u32 Rtl8192SUMACPHY_Array_PG[MACPHY_Array_PGLength] = { ++0x0, }; ++ ++u32 Rtl8192SUAGCTAB_Array[AGCTAB_ArrayLength] = { ++0xc78,0x7f000001, ++0xc78,0x7f010001, ++0xc78,0x7e020001, ++0xc78,0x7d030001, ++0xc78,0x7c040001, ++0xc78,0x7b050001, ++0xc78,0x7a060001, ++0xc78,0x79070001, ++0xc78,0x78080001, ++0xc78,0x77090001, ++0xc78,0x760a0001, ++0xc78,0x750b0001, ++0xc78,0x740c0001, ++0xc78,0x730d0001, ++0xc78,0x720e0001, ++0xc78,0x710f0001, ++0xc78,0x70100001, ++0xc78,0x6f110001, ++0xc78,0x6f120001, ++0xc78,0x6e130001, ++0xc78,0x6d140001, ++0xc78,0x6d150001, ++0xc78,0x6c160001, ++0xc78,0x6b170001, ++0xc78,0x6a180001, ++0xc78,0x6a190001, ++0xc78,0x691a0001, ++0xc78,0x681b0001, ++0xc78,0x671c0001, ++0xc78,0x661d0001, ++0xc78,0x651e0001, ++0xc78,0x641f0001, ++0xc78,0x63200001, ++0xc78,0x4c210001, ++0xc78,0x4b220001, ++0xc78,0x4a230001, ++0xc78,0x49240001, ++0xc78,0x48250001, ++0xc78,0x47260001, ++0xc78,0x46270001, ++0xc78,0x45280001, ++0xc78,0x44290001, ++0xc78,0x2c2a0001, ++0xc78,0x2b2b0001, ++0xc78,0x2a2c0001, ++0xc78,0x292d0001, ++0xc78,0x282e0001, ++0xc78,0x272f0001, ++0xc78,0x26300001, ++0xc78,0x25310001, ++0xc78,0x24320001, ++0xc78,0x23330001, ++0xc78,0x22340001, ++0xc78,0x09350001, ++0xc78,0x08360001, ++0xc78,0x07370001, ++0xc78,0x06380001, ++0xc78,0x05390001, ++0xc78,0x043a0001, ++0xc78,0x033b0001, ++0xc78,0x023c0001, ++0xc78,0x013d0001, ++0xc78,0x003e0001, ++0xc78,0x003f0001, ++0xc78,0x7f400001, ++0xc78,0x7f410001, ++0xc78,0x7e420001, ++0xc78,0x7d430001, ++0xc78,0x7c440001, ++0xc78,0x7b450001, ++0xc78,0x7a460001, ++0xc78,0x79470001, ++0xc78,0x78480001, ++0xc78,0x77490001, ++0xc78,0x764a0001, ++0xc78,0x754b0001, ++0xc78,0x744c0001, ++0xc78,0x734d0001, ++0xc78,0x724e0001, ++0xc78,0x714f0001, ++0xc78,0x70500001, ++0xc78,0x6f510001, ++0xc78,0x6f520001, ++0xc78,0x6e530001, ++0xc78,0x6d540001, ++0xc78,0x6d550001, ++0xc78,0x6c560001, ++0xc78,0x6b570001, ++0xc78,0x6a580001, ++0xc78,0x6a590001, ++0xc78,0x695a0001, ++0xc78,0x685b0001, ++0xc78,0x675c0001, ++0xc78,0x665d0001, ++0xc78,0x655e0001, ++0xc78,0x645f0001, ++0xc78,0x63600001, ++0xc78,0x4c610001, ++0xc78,0x4b620001, ++0xc78,0x4a630001, ++0xc78,0x49640001, ++0xc78,0x48650001, ++0xc78,0x47660001, ++0xc78,0x46670001, ++0xc78,0x45680001, ++0xc78,0x44690001, ++0xc78,0x2c6a0001, ++0xc78,0x2b6b0001, ++0xc78,0x2a6c0001, ++0xc78,0x296d0001, ++0xc78,0x286e0001, ++0xc78,0x276f0001, ++0xc78,0x26700001, ++0xc78,0x25710001, ++0xc78,0x24720001, ++0xc78,0x23730001, ++0xc78,0x22740001, ++0xc78,0x09750001, ++0xc78,0x08760001, ++0xc78,0x07770001, ++0xc78,0x06780001, ++0xc78,0x05790001, ++0xc78,0x047a0001, ++0xc78,0x037b0001, ++0xc78,0x027c0001, ++0xc78,0x017d0001, ++0xc78,0x007e0001, ++0xc78,0x007f0001, ++0xc78,0x3000001e, ++0xc78,0x3001001e, ++0xc78,0x3002001e, ++0xc78,0x3003001e, ++0xc78,0x3004001e, ++0xc78,0x3405001e, ++0xc78,0x3806001e, ++0xc78,0x3e07001e, ++0xc78,0x3e08001e, ++0xc78,0x4409001e, ++0xc78,0x460a001e, ++0xc78,0x480b001e, ++0xc78,0x480c001e, ++0xc78,0x4e0d001e, ++0xc78,0x560e001e, ++0xc78,0x5a0f001e, ++0xc78,0x5e10001e, ++0xc78,0x6211001e, ++0xc78,0x6c12001e, ++0xc78,0x7213001e, ++0xc78,0x7214001e, ++0xc78,0x7215001e, ++0xc78,0x7216001e, ++0xc78,0x7217001e, ++0xc78,0x7218001e, ++0xc78,0x7219001e, ++0xc78,0x721a001e, ++0xc78,0x721b001e, ++0xc78,0x721c001e, ++0xc78,0x721d001e, ++0xc78,0x721e001e, ++0xc78,0x721f001e, ++}; ++ +diff --git a/drivers/staging/rtl8192su/r8192SU_HWImg.h b/drivers/staging/rtl8192su/r8192SU_HWImg.h +index 96b1525..36e84af 100644 +--- a/drivers/staging/rtl8192su/r8192SU_HWImg.h ++++ b/drivers/staging/rtl8192su/r8192SU_HWImg.h +@@ -5,8 +5,6 @@ + + /*Created on 2009/ 3/ 6, 5:29*/ + +-#define ImgArrayLength 68368 +-extern u8 Rtl8192SUFwImgArray[ImgArrayLength]; + #define MainArrayLength 1 + extern u8 Rtl8192SUFwMainArray[MainArrayLength]; + #define DataArrayLength 1 +diff --git a/drivers/staging/rtl8192su/r8192S_firmware.c b/drivers/staging/rtl8192su/r8192S_firmware.c +index ff65bd1..752a3f1 100644 +--- a/drivers/staging/rtl8192su/r8192S_firmware.c ++++ b/drivers/staging/rtl8192su/r8192S_firmware.c +@@ -360,117 +360,58 @@ bool FirmwareDownload92S(struct net_device *dev) + + RT_TRACE(COMP_FIRMWARE, " --->FirmwareDownload92S()\n"); + +- //3// +- //3 //<1> Open Image file, and map file to contineous memory if open file success. +- //3 // or read image file from array. Default load from BIN file +- //3// +- priv->firmware_source = FW_SOURCE_IMG_FILE;// We should decided by Reg. +- +- switch( priv->firmware_source ) ++/* ++* Load the firmware from RTL8192SU/rtl8192sfw.bin ++*/ ++ if(pFirmware->szFwTmpBufferLen == 0) + { +- case FW_SOURCE_IMG_FILE: +- if(pFirmware->szFwTmpBufferLen == 0) +- { +- +- rc = request_firmware(&fw_entry, pFwImageFileName[ulInitStep],&priv->udev->dev);//===>1 +- if(rc < 0 ) { +- RT_TRACE(COMP_ERR, "request firmware fail!\n"); +- goto DownloadFirmware_Fail; +- } +- +- if(fw_entry->size > sizeof(pFirmware->szFwTmpBuffer)) +- { +- RT_TRACE(COMP_ERR, "img file size exceed the container buffer fail!\n"); +- release_firmware(fw_entry); +- goto DownloadFirmware_Fail; +- } ++ rc = request_firmware(&fw_entry, pFwImageFileName[ulInitStep],&priv->udev->dev); ++ if(rc < 0 ) { ++ RT_TRACE(COMP_ERR, "request firmware fail!\n"); ++ goto DownloadFirmware_Fail; ++ } + +- memcpy(pFirmware->szFwTmpBuffer,fw_entry->data,fw_entry->size); +- pFirmware->szFwTmpBufferLen = fw_entry->size; ++ if(fw_entry->size > sizeof(pFirmware->szFwTmpBuffer)) { ++ RT_TRACE(COMP_ERR, "img file size exceed the container buffer fail!\n"); + release_firmware(fw_entry); +- +- pucMappedFile = pFirmware->szFwTmpBuffer; +- file_length = pFirmware->szFwTmpBufferLen; +- +- //Retrieve FW header. +- pFirmware->pFwHeader = (PRT_8192S_FIRMWARE_HDR) pucMappedFile; +- pFwHdr = pFirmware->pFwHeader; +- RT_TRACE(COMP_FIRMWARE,"signature:%x, version:%x, size:%x, imemsize:%x, sram size:%x\n", \ +- pFwHdr->Signature, pFwHdr->Version, pFwHdr->DMEMSize, \ +- pFwHdr->IMG_IMEM_SIZE, pFwHdr->IMG_SRAM_SIZE); +- pFirmware->FirmwareVersion = byte(pFwHdr->Version ,0); +- if ((pFwHdr->IMG_IMEM_SIZE==0) || (pFwHdr->IMG_IMEM_SIZE > sizeof(pFirmware->FwIMEM))) +- { +- RT_TRACE(COMP_ERR, "%s: memory for data image is less than IMEM required\n",\ +- __FUNCTION__); +- goto DownloadFirmware_Fail; +- } else { +- pucMappedFile+=FwHdrSize; +- +- //Retrieve IMEM image. +- memcpy(pFirmware->FwIMEM, pucMappedFile, pFwHdr->IMG_IMEM_SIZE); +- pFirmware->FwIMEMLen = pFwHdr->IMG_IMEM_SIZE; +- } +- +- if (pFwHdr->IMG_SRAM_SIZE > sizeof(pFirmware->FwEMEM)) +- { +- RT_TRACE(COMP_ERR, "%s: memory for data image is less than EMEM required\n",\ +- __FUNCTION__); +- goto DownloadFirmware_Fail; +- } else { +- pucMappedFile += pFirmware->FwIMEMLen; +- +- /* Retriecve EMEM image */ +- memcpy(pFirmware->FwEMEM, pucMappedFile, pFwHdr->IMG_SRAM_SIZE);//===>6 +- pFirmware->FwEMEMLen = pFwHdr->IMG_SRAM_SIZE; +- } +- +- ++ goto DownloadFirmware_Fail; + } +- break; + +- case FW_SOURCE_HEADER_FILE: +-#if 1 +-#define Rtl819XFwImageArray Rtl8192SUFwImgArray +- //2008.11.10 Add by tynli. +- pucMappedFile = Rtl819XFwImageArray; +- ulFileLength = ImgArrayLength; ++ memcpy(pFirmware->szFwTmpBuffer,fw_entry->data,fw_entry->size); ++ pFirmware->szFwTmpBufferLen = fw_entry->size; ++ release_firmware(fw_entry); ++ ++ pucMappedFile = pFirmware->szFwTmpBuffer; ++ file_length = pFirmware->szFwTmpBufferLen; + +- RT_TRACE(COMP_INIT,"Fw download from header.\n"); +- /* Retrieve FW header*/ ++ /* Retrieve FW header. */ + pFirmware->pFwHeader = (PRT_8192S_FIRMWARE_HDR) pucMappedFile; + pFwHdr = pFirmware->pFwHeader; + RT_TRACE(COMP_FIRMWARE,"signature:%x, version:%x, size:%x, imemsize:%x, sram size:%x\n", \ + pFwHdr->Signature, pFwHdr->Version, pFwHdr->DMEMSize, \ + pFwHdr->IMG_IMEM_SIZE, pFwHdr->IMG_SRAM_SIZE); + pFirmware->FirmwareVersion = byte(pFwHdr->Version ,0); +- +- if ((pFwHdr->IMG_IMEM_SIZE==0) || (pFwHdr->IMG_IMEM_SIZE > sizeof(pFirmware->FwIMEM))) +- { +- printk("FirmwareDownload92S(): memory for data image is less than IMEM required\n"); ++ if ((pFwHdr->IMG_IMEM_SIZE==0) || (pFwHdr->IMG_IMEM_SIZE > sizeof(pFirmware->FwIMEM))) { ++ RT_TRACE(COMP_ERR, "%s: memory for data image is less than IMEM required\n",\ ++ __FUNCTION__); + goto DownloadFirmware_Fail; + } else { + pucMappedFile+=FwHdrSize; +- //Retrieve IMEM image. ++ /* Retrieve IMEM image. */ + memcpy(pFirmware->FwIMEM, pucMappedFile, pFwHdr->IMG_IMEM_SIZE); + pFirmware->FwIMEMLen = pFwHdr->IMG_IMEM_SIZE; + } + +- if (pFwHdr->IMG_SRAM_SIZE > sizeof(pFirmware->FwEMEM)) +- { +- printk(" FirmwareDownload92S(): memory for data image is less than EMEM required\n"); +- goto DownloadFirmware_Fail; +- } else { +- pucMappedFile+= pFirmware->FwIMEMLen; +- +- //Retriecve EMEM image. +- memcpy(pFirmware->FwEMEM, pucMappedFile, pFwHdr->IMG_SRAM_SIZE); +- pFirmware->FwEMEMLen = pFwHdr->IMG_SRAM_SIZE; +- } +-#endif +- break; +- default: +- break; ++ if (pFwHdr->IMG_SRAM_SIZE > sizeof(pFirmware->FwEMEM)) { ++ RT_TRACE(COMP_ERR, "%s: memory for data image is less than EMEM required\n",\ ++ __FUNCTION__); ++ goto DownloadFirmware_Fail; ++ } else { ++ pucMappedFile += pFirmware->FwIMEMLen; ++ /* Retriecve EMEM image */ ++ memcpy(pFirmware->FwEMEM, pucMappedFile, pFwHdr->IMG_SRAM_SIZE);//===>6 ++ pFirmware->FwEMEMLen = pFwHdr->IMG_SRAM_SIZE; ++ } + } + + FwStatus = FirmwareGetNextStatus(pFirmware->FWStatus); +diff --git a/drivers/staging/rtl8192su/r8192S_firmware.h b/drivers/staging/rtl8192su/r8192S_firmware.h +index c525380..2c2cf80 100644 +--- a/drivers/staging/rtl8192su/r8192S_firmware.h ++++ b/drivers/staging/rtl8192su/r8192S_firmware.h +@@ -59,12 +59,6 @@ typedef enum _desc_packet_type_e{ + DESC_PACKET_TYPE_NORMAL = 1, + }desc_packet_type_e; + +-typedef enum _firmware_source{ +- FW_SOURCE_IMG_FILE = 0, +- FW_SOURCE_HEADER_FILE = 1, +-}firmware_source_e, *pfirmware_source_e; +- +- + typedef enum _opt_rst_type{ + OPT_SYSTEM_RESET = 0, + OPT_FIRMWARE_RESET = 1, +@@ -185,7 +179,6 @@ typedef enum _FIRMWARE_8192S_STATUS{ + #define RTL8190_MAX_FIRMWARE_CODE_SIZE 64000 //64k + + typedef struct _rt_firmware{ +- firmware_source_e eFWSource; + PRT_8192S_FIRMWARE_HDR pFwHeader; + FIRMWARE_8192S_STATUS FWStatus; + u16 FirmwareVersion; +diff --git a/drivers/staging/rtl8192su/r8192U.h b/drivers/staging/rtl8192su/r8192U.h +index 2a11e01..ba87623 100644 +--- a/drivers/staging/rtl8192su/r8192U.h ++++ b/drivers/staging/rtl8192su/r8192U.h +@@ -1258,7 +1258,6 @@ typedef struct r8192_priv + u8 Rf_Mode; //add for Firmware RF -R/W switch + prt_firmware pFirmware; + rtl819xUsb_loopback_e LoopbackMode; +- firmware_source_e firmware_source; + bool usb_error; + + u16 EEPROMTxPowerDiff; diff --git a/debian/patches/series/base b/debian/patches/series/base index 6ee0eb270..da97d58fb 100644 --- a/debian/patches/series/base +++ b/debian/patches/series/base @@ -60,3 +60,4 @@ + features/arm/dns323-rev-a1-powerled.patch + features/arm/openrd-base-uart.patch #+ features/all/ath9k-add-support-for-802.11n-bonded-out-AR2427.patch ++ features/all/rtl8192su-always-use-request_firmware.patch diff --git a/debian/patches/series/orig-0 b/debian/patches/series/orig-0 index 5dcf1099f..19f74f401 100644 --- a/debian/patches/series/orig-0 +++ b/debian/patches/series/orig-0 @@ -5,7 +5,7 @@ + debian/dfsg/drivers-staging-otus-disable.patch + debian/dfsg/drivers-staging-rt2860-disable.patch + debian/dfsg/drivers-staging-rt2870-disable.patch -+ debian/dfsg/rtl8192su-Remove-Firmware-from-r8192SU_HWImg.patch ++ debian/dfsg/drivers-staging-rtl8192su-disable.patch + debian/dfsg/drivers-staging-wlags49_h2-disable.patch + debian/dfsg/drivers-staging-wlags49_h25-disable.patch + debian/dfsg/firmware-cleanup.patch