aboutsummaryrefslogtreecommitdiff
path: root/ubuntu
diff options
context:
space:
mode:
authorAndy Whitcroft <apw@canonical.com>2011-01-06 16:14:12 +0000
committerJohn Rigby <john.rigby@linaro.org>2011-09-23 08:47:56 -0600
commit944c2da8b73334c989bf900ed7b09d486844e59a (patch)
tree3246bcc6398d0e33c349aba8162d6117bad68ab6 /ubuntu
parentb4054c5bfbe8a36cda456fdd260b12210fc94a64 (diff)
UBUNTU: ubuntu: AUFS -- update to c5021514085a5d96364e096dbd34cadb2251abfd
commit c5021514085a5d96364e096dbd34cadb2251abfd Author: J. R. Okajima <hooanon05@yahoo.co.jp> Date: Thu Dec 16 01:29:04 2010 +0900 aufs: bugfix, missign test for branch management In aufs_lookup(), the parent dir MAY be removed logically by branch management. Signed-off-by: J. R. Okajima <hooanon05@yahoo.co.jp> commit 5df24d5e0dc992ab991d0113703b9c90416ce527 Author: J. R. Okajima <hooanon05@yahoo.co.jp> Date: Wed Dec 15 22:55:09 2010 +0900 aufs: debugging, stop dcsub in sysrq handler Signed-off-by: J. R. Okajima <hooanon05@yahoo.co.jp> commit 3f141020200c0e39c41c039eb261f65db0b3f18e Author: J. R. Okajima <hooanon05@yahoo.co.jp> Date: Wed Dec 15 22:50:15 2010 +0900 aufs: tiny, revised simply Signed-off-by: J. R. Okajima <hooanon05@yahoo.co.jp> commit 8f46271b6cd7521da44a087dcbf3d783f4af24c7 Author: J. R. Okajima <hooanon05@yahoo.co.jp> Date: Wed Dec 15 22:18:33 2010 +0900 aufs: debugging, false positive around NOPLMW Signed-off-by: J. R. Okajima <hooanon05@yahoo.co.jp> commit 788f93f121fcafecaca33dafb824495db02edfe7 Author: J. R. Okajima <hooanon05@yahoo.co.jp> Date: Wed Dec 15 21:19:26 2010 +0900 aufs: tiny, just an indentation Signed-off-by: J. R. Okajima <hooanon05@yahoo.co.jp> commit 9a8dc61df4b4b722f9a9ef8a568cfcb78a4eb0aa Author: J. R. Okajima <hooanon05@yahoo.co.jp> Date: Wed Dec 15 21:19:09 2010 +0900 aufs: minor optimization, skip file-refresh for root Signed-off-by: J. R. Okajima <hooanon05@yahoo.co.jp> commit 9784a821611537ad9d0d4593ba775bb816ace3e9 Author: J. R. Okajima <hooanon05@yahoo.co.jp> Date: Mon Dec 13 17:13:59 2010 +0900 aufs: possible bugfix, protect branch from deleting in nfsd fh_to_dentry() Signed-off-by: J. R. Okajima <hooanon05@yahoo.co.jp> commit 8c017b90207d3e0914f53f7e15ff9fb30d33ffac Author: J. R. Okajima <hooanon05@yahoo.co.jp> Date: Mon Dec 13 17:00:20 2010 +0900 aufs: possible bugfix, br_count in async rmdir There is a missing decrement br_count for 'br' member in struct au_whtmp_rmdir in an error path. Introduce a larger and bigger but more generic and simple solution. Signed-off-by: J. R. Okajima <hooanon05@yahoo.co.jp> commit 29c19e545f53894ca89a9525685572b9c99f34c3 Author: J. R. Okajima <hooanon05@yahoo.co.jp> Date: Sun Dec 12 10:25:26 2010 +0900 aufs: move missing declaration Signed-off-by: J. R. Okajima <hooanon05@yahoo.co.jp> commit 0de8fbc346a9bc5cf314ea82063a65c08ca9e41b Author: J. R. Okajima <hooanon05@yahoo.co.jp> Date: Fri Dec 10 13:25:09 2010 +0900 aufs: possible bugfix, walk in dcache limited to aufs In some cases, au_dcsub_pages_rev() should not handle out of aufs or broken (but still cached) aufs dentry. Signed-off-by: J. R. Okajima <hooanon05@yahoo.co.jp> commit 52f9727243bf644db05168e6c77d2f063bcc01ba Author: J. R. Okajima <hooanon05@yahoo.co.jp> Date: Fri Dec 10 13:20:06 2010 +0900 aufs: d_instantiate in link(2) Historically there was(were?) filesystem which calls d_drop() after the success of link(2). In order to support such filesystem, old aufs1 follows it if h_dentry is dropped without d_instantiate(). Recently I looked whether there still exists such filesystem or not, and could not find. So aufs_link() uncondionally calls d_instantiate() after success of vfs_link() for branch fs. But, as a fallback, d_drop() call with a d_unhashed() test are left. Signed-off-by: J. R. Okajima <hooanon05@yahoo.co.jp> commit 6b0be66a68b95ca0bab3068133c8730882a38385 Author: J. R. Okajima <hooanon05@yahoo.co.jp> Date: Fri Dec 10 02:29:50 2010 +0900 aufs: bugfix, lock subclass in copying-up a dir hierarchy Signed-off-by: J. R. Okajima <hooanon05@yahoo.co.jp> commit e1d13b721d930c72217df0a9b6e8a87e51ed1810 Author: J. R. Okajima <hooanon05@yahoo.co.jp> Date: Fri Dec 10 02:27:55 2010 +0900 aufs: bugfix, restore the internal array after special copyup When copyup a file which exists on the lower readonly branch and already removed logically, au_do_cpup_wh() operates the internal array in dinfo before copyup. After that, regardless an error happened in copyup, restore the internal array. Signed-off-by: J. R. Okajima <hooanon05@yahoo.co.jp> commit d539fca6887a013c6fbd1b579898aa78ba7c65c9 Author: J. R. Okajima <hooanon05@yahoo.co.jp> Date: Thu Dec 9 02:19:42 2010 +0900 aufs: minor, make inode bad before unlock If an error happens in settting a new inode, we call iget_failed() and make it "bad inode." Since someone else is wating for the inode is unlocked, call iget_failed() before unlock it. Signed-off-by: J. R. Okajima <hooanon05@yahoo.co.jp> commit b69574acb527171af24eddb51ac414664d70ddc4 Author: J. R. Okajima <hooanon05@yahoo.co.jp> Date: Thu Dec 9 02:17:00 2010 +0900 aufs: bugfix, assign inode number for hardlink If the cached inode doesn't match the dentry in operation, never combine them (instatiate). Find another inode number. Basically the known inode number is stored in XINO file. But UDBA or branch management easily break it. Signed-off-by: J. R. Okajima <hooanon05@yahoo.co.jp> commit efa578c51e3132442f8cd65e6efe4e344969449f Author: J. R. Okajima <hooanon05@yahoo.co.jp> Date: Wed Dec 8 02:28:32 2010 +0900 aufs: tiny, a comment Signed-off-by: J. R. Okajima <hooanon05@yahoo.co.jp> commit ff7babf5257fa57b341eb7230817a9ec0b45767c Author: J. R. Okajima <hooanon05@yahoo.co.jp> Date: Wed Dec 8 02:28:16 2010 +0900 aufs: debug by lockdep_depth() Signed-off-by: J. R. Okajima <hooanon05@yahoo.co.jp> commit f44393848b3d0ab046de672752d4c23cf14c6b62 Author: J. R. Okajima <hooanon05@yahoo.co.jp> Date: Wed Dec 8 02:27:04 2010 +0900 aufs: minor, sysrq+A prints all Signed-off-by: J. R. Okajima <hooanon05@yahoo.co.jp> commit 8fa5bfe552fdab2c900309f73f8a4174f705282d Author: J. R. Okajima <hooanon05@yahoo.co.jp> Date: Wed Dec 8 02:26:03 2010 +0900 aufs: limit of rdcache MAX_SEC_IN_JIFFIES is less meaningful and hard to handle. Introduce a new reasonable upper limit AUFS_RDCACHE_MAX. Signed-off-by: J. R. Okajima <hooanon05@yahoo.co.jp> commit f85351d0360f40a2595c99f1182ddf1de0eed8a1 Author: J. R. Okajima <hooanon05@yahoo.co.jp> Date: Wed Dec 8 02:24:40 2010 +0900 aufs: limit of MFS seconds MAX_SEC_IN_JIFFIES is less meaningful and hard to handle. Introduce a new reasonable upper limit AUFS_MFS_MAX_SEC. Signed-off-by: J. R. Okajima <hooanon05@yahoo.co.jp> commit b64f629ab85e8d0641704fea2f2787d53713afd9 Author: J. R. Okajima <hooanon05@yahoo.co.jp> Date: Wed Dec 8 02:21:00 2010 +0900 aufs: tiny, revise error messages Signed-off-by: J. R. Okajima <hooanon05@yahoo.co.jp> commit 3e17bf45f4ab40d6516c9de073417942661cd31f Author: J. R. Okajima <hooanon05@yahoo.co.jp> Date: Tue Dec 7 01:19:32 2010 +0900 aufs: bugfix, hfsnotify for multiple aufs 2/2 Implement new operations, ->fin_br(), ->init_br() and ->reset_br(). Signed-off-by: J. R. Okajima <hooanon05@yahoo.co.jp> commit fec63cfd00c69fe89ecc60fdf22e610b836e0785 Author: J. R. Okajima <hooanon05@yahoo.co.jp> Date: Tue Dec 7 01:18:47 2010 +0900 aufs: bugfix, hfsnotify for multiple aufs 1/2 Since fsnotify doesn't allow registering a same fsnotify_ops to the same fsnotify_group, aufs should make them per branch. Theoritically it is enough to make them per aufs super_block, but users MAY move branch into the same filesystem where other branch exists. To support such case, make them per branch. Introduce new operations, ->fin_br(), ->init_br() and ->reset_br(). Reported-by: Joonwoo Park <joonwpark81@gmail.com> Signed-off-by: J. R. Okajima <hooanon05@yahoo.co.jp> commit 3da80541bb8d42a8f3cd2e2caf04b3037a0040bf Author: J. R. Okajima <hooanon05@yahoo.co.jp> Date: Mon Dec 6 23:53:49 2010 +0900 aufs: tiny, revise the parameter for hinotify - convert au_hnotify to au_hinode, remove h_inode from au_hn_alloc() and ->alloc(). - convert au_hnotify to au_hinode, ->free(). Signed-off-by: J. R. Okajima <hooanon05@yahoo.co.jp> commit b632f916658d019669d393975bdc66644b333269 Author: J. R. Okajima <hooanon05@yahoo.co.jp> Date: Fri Dec 10 13:29:13 2010 +0900 aufs: debugging dinfo New debug function to verify the correctness of dinfo. Signed-off-by: J. R. Okajima <hooanon05@yahoo.co.jp> commit 1341643c5de13471e781f9c0bcd8d987023494b6 Author: J. R. Okajima <hooanon05@yahoo.co.jp> Date: Mon Dec 6 23:41:42 2010 +0900 aufs: bugfix, return value of au_do_refresh_d() Intialize it as success (0). Add some debug messgages. Signed-off-by: J. R. Okajima <hooanon05@yahoo.co.jp> commit a4935871b43ea40fa73a67f228da6ef8c3dd0b14 Author: J. R. Okajima <hooanon05@yahoo.co.jp> Date: Wed Dec 8 02:27:39 2010 +0900 aufs stdalone: export debug_locks Signed-off-by: J. R. Okajima <hooanon05@yahoo.co.jp> commit 09853aaa34cca5eeedb9277591668258de081813 Author: J. R. Okajima <hooanon05@yahoo.co.jp> Date: Tue Dec 7 21:53:59 2010 +0900 aufs: support for 2.6.34, protect f_mode By introducing FMODE_RANDOM, file->f_mode may be modified out of aufs. Signed-off-by: J. R. Okajima <hooanon05@yahoo.co.jp> commit f1617ce6112b85ed5a686be5e0cb8f48794ea2c4 Author: J. R. Okajima <hooanon05@yahoo.co.jp> Date: Thu Dec 2 03:48:57 2010 +0900 aufs: revise how to build Reported-by: wanyanqing <udknight@gmail.com> Reported-by: Alex Vogt <elias@linexa.de> Signed-off-by: J. R. Okajima <hooanon05@yahoo.co.jp> commit 543820e74625523e263faad047928266dc672cfd Author: J. R. Okajima <hooanon05@yahoo.co.jp> Date: Tue Nov 30 15:39:35 2010 +0900 aufs: tiny, remove unnecesary var Signed-off-by: J. R. Okajima <hooanon05@yahoo.co.jp> commit 38fe8516196e35e6fab39a49f650dd5dd24deb63 Author: J. R. Okajima <hooanon05@yahoo.co.jp> Date: Tue Nov 30 06:27:32 2010 +0900 aufs: refreshing, replace functions for remount time (This is a part of a patch series "new strategy for refreshing") In remounting (branch management), refresh all dentries and inodes regardless their status (unhashed, unlinked, etc). Signed-off-by: J. R. Okajima <hooanon05@yahoo.co.jp> commit f822af6506e20cd2bd328dfc678ffbcf31c6f910 Author: J. R. Okajima <hooanon05@yahoo.co.jp> Date: Tue Nov 30 06:25:27 2010 +0900 aufs: refreshing, new functions for remount time (This is a part of a patch series "new strategy for refreshing") Introduce new functions do_refresh, au_do_refresh_d, au_refresh_d, and au_refresh_i which will replace current functions. Since they are large and to keep single commit simple, this commit just define these functions. The behaviour won't change. Signed-off-by: J. R. Okajima <hooanon05@yahoo.co.jp> commit 85a3a786f9fb483aea021caf66d71a930a327974 Author: J. R. Okajima <hooanon05@yahoo.co.jp> Date: Sat Nov 27 14:32:52 2010 +0900 aufs: refreshing, replace old function by new one (This is a part of a patch series "new strategy for refreshing") Replace au_refresh_hinode() by au_refresh_dentry() which was committed previously. Signed-off-by: J. R. Okajima <hooanon05@yahoo.co.jp> commit 872472221dc4771c29010fb89609ffc4ec31d9f9 Author: J. R. Okajima <hooanon05@yahoo.co.jp> Date: Sat Nov 27 03:32:18 2010 +0900 aufs: refreshing, new functions to refresh dentry (This is a part of a patch series "new strategy for refreshing") Introduce new functions au_do_hide, au_hide_children, au_hide, au_refresh_by_dinfo, and au_refresh_dentry which will replace current au_refresh_hdentry. Since they are large and to keep single commit simple, this commit just define these functions. The behaviour won't change. Signed-off-by: J. R. Okajima <hooanon05@yahoo.co.jp> commit 92dcda8894818f43b7a627d4a3062996552306b3 Author: J. R. Okajima <hooanon05@yahoo.co.jp> Date: Fri Nov 26 22:10:47 2010 +0900 aufs: refreshing, refine au_do_refresh_hdentry (This is a part of a patch series "new strategy for refreshing") Now dinfo sets -1 to dbstart and dbend to represent invalid. Currently its return value is ignored. It will be used in later commits. Signed-off-by: J. R. Okajima <hooanon05@yahoo.co.jp> commit db0c0d602004fe2884225624af19e9ac97d8b19c Author: J. R. Okajima <hooanon05@yahoo.co.jp> Date: Fri Nov 26 16:59:17 2010 +0900 aufs: refreshing, stop updating iigen in test_inode_busy() (This is a part of a patch series "new strategy for refreshing") In order to force refreshing in the later au_remount_refresh(). Signed-off-by: J. R. Okajima <hooanon05@yahoo.co.jp> commit 48c759bfc43e795092bf0c0f31c6a8047cc6c9b1 Author: J. R. Okajima <hooanon05@yahoo.co.jp> Date: Fri Nov 26 03:19:02 2010 +0900 aufs: refreshing, consolidate REFRESH macros (This is a part of a patch series "new strategy for refreshing") At remounting (branch management), aufs refreshes some internal arrays. In this refreshing, objects for a dir and non-dir are separatedly handled for performance. This commit forces always refreshing both. And rename a macro AuSi_FAILED_REFRESH_DIRS to AuSiFAILED_REFRESH_DIR. Signed-off-by: J. R. Okajima <hooanon05@yahoo.co.jp> commit 40058d7c0ee7d8f449f5eef9ed178335303924a5 Author: J. R. Okajima <hooanon05@yahoo.co.jp> Date: Thu Nov 25 02:40:13 2010 +0900 aufs: new strategy for refreshing, refresh negative dentries (This is a part of a patch series "new strategy for refreshing") In branch management at remount, refresh negative dentries too, since they may hold a refrence to an object in the deleting branch. Also they may be in freeing, so call dget_locked() instead of simple dget(). The permission of the branch who has the negative dentry may be changed to readonly, so confirm it in au_pin_and_icpup(). Signed-off-by: J. R. Okajima <hooanon05@yahoo.co.jp> commit 97f1369508bf1e71935363adc85c5fd52695a915 Author: J. R. Okajima <hooanon05@yahoo.co.jp> Date: Sun Nov 28 11:24:12 2010 +0900 aufs: keep dinfo valid by temp dinfo To decide creating a new whiteout is necessary or not, aufs tries finding whiteout on the lower branches. In this lookup, use another dinfo temporary to keep the original dinfo. Signed-off-by: J. R. Okajima <hooanon05@yahoo.co.jp> commit 381ba01af8e781512742858854a510ebb7667b1f Author: J. R. Okajima <hooanon05@yahoo.co.jp> Date: Fri Nov 26 00:52:57 2010 +0900 aufs: temporary dinfo Introduce some functions to handle dinfo which will be used to make a temporary dinfo. The existing interfaces (di_init() and di_fin()) are not changed. Signed-off-by: J. R. Okajima <hooanon05@yahoo.co.jp> commit ca7dc2240a3b787761d31dc096fe95f3beb9a18a Author: J. R. Okajima <hooanon05@yahoo.co.jp> Date: Fri Nov 26 21:59:45 2010 +0900 aufs: store br_id in dinfo In order to identify the index of branch at refreshing, store br_id in dinfo. Signed-off-by: J. R. Okajima <hooanon05@yahoo.co.jp> commit 447344925adad5f89950e409d3de501e7431468e Author: J. R. Okajima <hooanon05@yahoo.co.jp> Date: Sun Nov 28 22:47:25 2010 +0900 aufs: bugfix, write to a removed file more than once In file write, the file may be already removed and au_ready_to_write() supports such case. But the write to the removed file, eg, the file had been already handled by au_ready_to_write(), then the function doesn't detect it and a bug appear. - when the file is removed, au_cpup_dirs() is unnecessary. - when the file is removevd and already handled by au_ready_to_write(), just re-open without copyup. Signed-off-by: J. R. Okajima <hooanon05@yahoo.co.jp> commit 24dddc56d3cab8671e30ad2213436b405ca715bc Author: J. R. Okajima <hooanon05@yahoo.co.jp> Date: Fri Nov 26 16:55:26 2010 +0900 aufs: split au_refresh_hinode_self() Extract a part of au_refresh_hinode_self() and create a new function au_ii_refresh(). The 'do_attr' parameter of au_refresh_hinode_self() becomes unnecessary. Signed-off-by: J. R. Okajima <hooanon05@yahoo.co.jp> commit d954281d7bd5f2523804290b120fd8a8bc7bb7fe Author: J. R. Okajima <hooanon05@yahoo.co.jp> Date: Fri Nov 26 15:46:32 2010 +0900 aufs: refine au_update_ibrange() Now iinfo sets -1 to ibstart and ibend to represent invalid. Signed-off-by: J. R. Okajima <hooanon05@yahoo.co.jp> commit bbc392af26ace27fc5e41e68f9437ad57ec2b85e Author: J. R. Okajima <hooanon05@yahoo.co.jp> Date: Fri Nov 26 01:45:43 2010 +0900 aufs: keep dinfo valid Keep dinfo valid even if an error happened. Signed-off-by: J. R. Okajima <hooanon05@yahoo.co.jp> commit 49b3e86c8b8337fc7db9093ec98906de4cd4acb3 Author: J. R. Okajima <hooanon05@yahoo.co.jp> Date: Thu Nov 25 17:00:04 2010 +0900 aufs: use a generic warpper dbrange_test() Call au_dbrange_test() near au_digen_test() call. Signed-off-by: J. R. Okajima <hooanon05@yahoo.co.jp> commit e3d0c8ea457f3192caacaaeb83a01e9befb5176c Author: J. R. Okajima <hooanon05@yahoo.co.jp> Date: Thu Nov 25 16:59:11 2010 +0900 aufs: use a generic warpper [di]i_gen_test() Replace some direct test codes by au_[di]igen_test(). Signed-off-by: J. R. Okajima <hooanon05@yahoo.co.jp> commit 6680a2cc71b37511097df27149ae072034e89491 Author: J. R. Okajima <hooanon05@yahoo.co.jp> Date: Tue Nov 30 13:35:07 2010 +0900 aufs: bugfix, missing unlock in an error path File revalidating in au_reval_and_lock_fdi(). Signed-off-by: J. R. Okajima <hooanon05@yahoo.co.jp> commit f1abf5b5d55ffeae0d3850a62853c99c02286228 Author: J. R. Okajima <hooanon05@yahoo.co.jp> Date: Mon Nov 29 03:22:07 2010 +0900 aufs: possible bugfix, the generation of dentry 3/3 Test the generation of a dentry in the beginning of many operations. Signed-off-by: J. R. Okajima <hooanon05@yahoo.co.jp> commit 69e55ee7c6f87380df71b37dca94f6023407e1c2 Author: J. R. Okajima <hooanon05@yahoo.co.jp> Date: Mon Nov 29 03:21:36 2010 +0900 aufs: possible bugfix, the generation of dentry 2/3 Introduce AuLock_GEN flag to test the generation of a dentry in the beginning of many operations. Signed-off-by: J. R. Okajima <hooanon05@yahoo.co.jp> commit 8755a096f8cc12a00b5f4826ac6cf8a3f5014535 Author: J. R. Okajima <hooanon05@yahoo.co.jp> Date: Thu Nov 25 01:25:57 2010 +0900 aufs: possible bugfix, the generation of dentry 1/3 Introduce new functions au_[di]igen_test() and au_dbrange_test(). Signed-off-by: J. R. Okajima <hooanon05@yahoo.co.jp> commit 49bfb76c10c75603561fcd6e9d79d5ccf000e7ce Author: J. R. Okajima <hooanon05@yahoo.co.jp> Date: Sun Nov 28 23:33:50 2010 +0900 aufs: possible bugfix, test valid dentry 2/2 Test the validity of a dentry in the beginning of many operations. Signed-off-by: J. R. Okajima <hooanon05@yahoo.co.jp> commit 2ecf50571003219f9d7ab257420c570764332469 Author: J. R. Okajima <hooanon05@yahoo.co.jp> Date: Sun Nov 28 23:05:57 2010 +0900 aufs: possible bugfix, test valid dentry 1/2 Introduce some functions to test the validity of a dentry. Signed-off-by: J. R. Okajima <hooanon05@yahoo.co.jp> commit 952cec591bffdb1d470286eeea4ae27ed196bf94 Author: J. R. Okajima <hooanon05@yahoo.co.jp> Date: Sun Nov 28 22:51:06 2010 +0900 aufs: tiny, debug code for i_mode To detect setting type unmatching h_inode to iinfo, initialize i_mode. Signed-off-by: J. R. Okajima <hooanon05@yahoo.co.jp> commit c00655e4c8f66871decf0d79a2d3b4c1fb6207d7 Author: J. R. Okajima <hooanon05@yahoo.co.jp> Date: Thu Nov 25 00:00:44 2010 +0900 aufs: tiny, comment around d_drop Signed-off-by: J. R. Okajima <hooanon05@yahoo.co.jp> commit 426ed6061a419cb1c7a5e1504052a50c5198d3a7 Author: J. R. Okajima <hooanon05@yahoo.co.jp> Date: Wed Nov 24 23:59:08 2010 +0900 aufs: possible bugfix, keep dentry of renamed target valid Basically the renamed target is removed, but it may be still referenced and alive. Call d_drop in aufs and keep its dinfo valid. Signed-off-by: J. R. Okajima <hooanon05@yahoo.co.jp> commit 6f00617abf56f74429ab06751df6519b957fc325 Author: J. R. Okajima <hooanon05@yahoo.co.jp> Date: Sat Nov 27 22:06:48 2010 +0900 aufs: possible bugfix, decrement the link count of non-dir rename target Fix a missing drop_nlink() for the non-dir rename target. Signed-off-by: J. R. Okajima <hooanon05@yahoo.co.jp> commit b8ee2bd5b62c5dece464571a83f4142181a67a72 Author: J. R. Okajima <hooanon05@yahoo.co.jp> Date: Fri Nov 26 17:28:15 2010 +0900 aufs: set S_DEAD to i_flags in aufs The S_DEAD flag is set in VFS, but we need to do it by ourselves because a race condition may happen with aufs remount/branch-mgmt operation. Set the flag within the aufs lock region. Signed-off-by: J. R. Okajima <hooanon05@yahoo.co.jp> commit 68fd4a243e4b9bbf397040c68ccc0f11da12c304 Author: J. R. Okajima <hooanon05@yahoo.co.jp> Date: Wed Nov 24 23:58:35 2010 +0900 aufs: minor optimization, d_drop after failure of adding an entry After the failure of creating an entry, the aufs dentry private data may still refer the dentry in the branch fs's or may have invalid info. Discard it by d_drop() in error case. Signed-off-by: J. R. Okajima <hooanon05@yahoo.co.jp> commit 6f7ebf0d44bacda459a8ae6235c59f47c9715808 Author: J. R. Okajima <hooanon05@yahoo.co.jp> Date: Wed Nov 24 15:57:22 2010 +0900 aufs: possible bugfix, d_drop() job for hnotify Current d_drop() calls may have unexpected side effects. In order to force re-lookup, aufs should use di_gen instead of testing unhashed. When the test (in d_revalidate) fails, make it obsoleted. Signed-off-by: J. R. Okajima <hooanon05@yahoo.co.jp> commit ade2eb21fc942caa1c48bd931b5b8e2411eaadde Author: J. R. Okajima <hooanon05@yahoo.co.jp> Date: Thu Nov 25 02:52:39 2010 +0900 aufs: tiny, remove an empty line Signed-off-by: J. R. Okajima <hooanon05@yahoo.co.jp> commit 16514eeea2d4b3ddcdd01b6cf54c8ae60cdc9bdf Author: J. R. Okajima <hooanon05@yahoo.co.jp> Date: Wed Nov 24 15:09:23 2010 +0900 aufs: tiny, use a wrapper for fs private data Signed-off-by: J. R. Okajima <hooanon05@yahoo.co.jp> commit 8823675f5fd00ef30d6fea5f6779b45b3eb3bfd1 Author: J. R. Okajima <hooanon05@yahoo.co.jp> Date: Sat Nov 27 04:05:07 2010 +0900 aufs: possible bugfix, test d_fsdata in revalidating The passed dentry may not be created correctly, error case in previous lookup. Signed-off-by: J. R. Okajima <hooanon05@yahoo.co.jp> commit 33d73de5ae0c44312ce6fbce59819cf04b9de9fa Author: J. R. Okajima <hooanon05@yahoo.co.jp> Date: Wed Nov 24 13:22:02 2010 +0900 aufs: possible bugfix, release all before au_nwt_done() In racing unmount process, iput() after au_nwt_done() MAY cause a problem. Signed-off-by: J. R. Okajima <hooanon05@yahoo.co.jp> Signed-off-by: Andy Whitcroft <apw@canonical.com>
Diffstat (limited to 'ubuntu')
-rw-r--r--ubuntu/aufs/BOM2
-rw-r--r--ubuntu/aufs/Makefile1
-rw-r--r--ubuntu/aufs/branch.c40
-rw-r--r--ubuntu/aufs/branch.h5
-rw-r--r--ubuntu/aufs/cpup.c18
-rw-r--r--ubuntu/aufs/dcsub.c22
-rw-r--r--ubuntu/aufs/dcsub.h37
-rw-r--r--ubuntu/aufs/debug.c53
-rw-r--r--ubuntu/aufs/debug.h3
-rw-r--r--ubuntu/aufs/dentry.c444
-rw-r--r--ubuntu/aufs/dentry.h14
-rw-r--r--ubuntu/aufs/dinfo.c159
-rw-r--r--ubuntu/aufs/dir.c10
-rw-r--r--ubuntu/aufs/export.c56
-rw-r--r--ubuntu/aufs/f_op.c9
-rw-r--r--ubuntu/aufs/file.c83
-rw-r--r--ubuntu/aufs/hfsnotify.c63
-rw-r--r--ubuntu/aufs/hnotify.c80
-rw-r--r--ubuntu/aufs/i_op.c92
-rw-r--r--ubuntu/aufs/i_op_add.c88
-rw-r--r--ubuntu/aufs/i_op_del.c89
-rw-r--r--ubuntu/aufs/i_op_ren.c103
-rw-r--r--ubuntu/aufs/iinfo.c38
-rw-r--r--ubuntu/aufs/inode.c86
-rw-r--r--ubuntu/aufs/inode.h46
-rw-r--r--ubuntu/aufs/opts.c46
-rw-r--r--ubuntu/aufs/opts.h7
-rw-r--r--ubuntu/aufs/plink.c6
-rw-r--r--ubuntu/aufs/rdu.c7
-rw-r--r--ubuntu/aufs/sbinfo.c49
-rw-r--r--ubuntu/aufs/super.c239
-rw-r--r--ubuntu/aufs/super.h3
-rw-r--r--ubuntu/aufs/sysrq.c44
-rw-r--r--ubuntu/aufs/vfsub.h7
-rw-r--r--ubuntu/aufs/wbr_policy.c3
-rw-r--r--ubuntu/aufs/whout.c12
-rw-r--r--ubuntu/aufs/wkq.c4
-rw-r--r--ubuntu/aufs/xino.c2
-rw-r--r--ubuntu/include/linux/aufs_type.h6
39 files changed, 1441 insertions, 635 deletions
diff --git a/ubuntu/aufs/BOM b/ubuntu/aufs/BOM
index efa81f9de29..bdad0cd19c5 100644
--- a/ubuntu/aufs/BOM
+++ b/ubuntu/aufs/BOM
@@ -1,2 +1,2 @@
URL: http://git.c3sl.ufpr.br/pub/scm/aufs/aufs2-standalone.git
-COMMIT: 097bf62d6f49619359d34bf17f242df38562489a
+COMMIT: c5021514085a5d96364e096dbd34cadb2251abfd
diff --git a/ubuntu/aufs/Makefile b/ubuntu/aufs/Makefile
index 3d6b50f84ba..46615fe113e 100644
--- a/ubuntu/aufs/Makefile
+++ b/ubuntu/aufs/Makefile
@@ -1,3 +1,4 @@
+
include ${src}/magic.mk
ifeq (${CONFIG_AUFS_FS},m)
include ${src}/conf.mk
diff --git a/ubuntu/aufs/branch.c b/ubuntu/aufs/branch.c
index 4687a35d43f..25c523de95e 100644
--- a/ubuntu/aufs/branch.c
+++ b/ubuntu/aufs/branch.c
@@ -33,6 +33,8 @@ static void au_br_do_free(struct au_branch *br)
struct au_wbr *wbr;
struct au_dykey **key;
+ au_hnotify_fin_br(br);
+
if (br->br_xino.xi_file)
fput(br->br_xino.xi_file);
mutex_destroy(&br->br_xino.xi_nondir_mtx);
@@ -124,13 +126,17 @@ static struct au_branch *au_br_alloc(struct super_block *sb, int new_nbranch,
if (unlikely(!add_branch))
goto out;
+ err = au_hnotify_init_br(add_branch, perm);
+ if (unlikely(err))
+ goto out_br;
+
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;
+ goto out_hnotify;
}
err = au_sbr_realloc(au_sbi(sb), new_nbranch);
@@ -143,6 +149,8 @@ static struct au_branch *au_br_alloc(struct super_block *sb, int new_nbranch,
kfree(add_branch->br_wbr);
+out_hnotify:
+ au_hnotify_fin_br(add_branch);
out_br:
kfree(add_branch);
out:
@@ -548,11 +556,18 @@ static int test_dentry_busy(struct dentry *root, aufs_bindex_t bindex,
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)
+ if (!au_digen_test(d, sigen)) {
di_read_lock_child(d, AuLock_IR);
- else {
+ if (unlikely(au_dbrange_test(d))) {
+ di_read_unlock(d, AuLock_IR);
+ continue;
+ }
+ } else {
di_write_lock_child(d);
+ if (unlikely(au_dbrange_test(d))) {
+ di_write_unlock(d);
+ continue;
+ }
err = au_reval_dpath(d, sigen);
if (!err)
di_downgrade_lock(d, AuLock_IR);
@@ -562,14 +577,18 @@ static int test_dentry_busy(struct dentry *root, aufs_bindex_t bindex,
}
}
+ /* AuDbgDentry(d); */
+ inode = d->d_inode;
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)) {
+ && ((inode && !S_ISDIR(inode->i_mode))
+ || bstart == bend)) {
err = -EBUSY;
AuVerbose(verbose, "busy %.*s\n", AuDLNPair(d));
+ AuDbgDentry(d);
}
di_read_unlock(d, AuLock_IR);
}
@@ -606,7 +625,8 @@ static int test_inode_busy(struct super_block *sb, aufs_bindex_t bindex,
ii_read_lock_child(i);
else {
ii_write_lock_child(i);
- err = au_refresh_hinode_self(i, /*do_attr*/1);
+ err = au_refresh_hinode_self(i);
+ au_iigen_dec(i);
if (!err)
ii_downgrade_lock(i);
else {
@@ -830,7 +850,7 @@ static void au_warn_ima(void)
{
#ifdef CONFIG_IMA
/* since it doesn't support mark_files_ro() */
- AuWarn1("RW -> RO makes IMA to produce wrong message");
+ AuWarn1("RW -> RO makes IMA to produce wrong message\n");
#endif
}
@@ -893,7 +913,6 @@ static int au_br_mod_files_ro(struct super_block *sb, aufs_bindex_t bindex)
unsigned long long ull, max;
aufs_bindex_t br_id;
struct file *file, *hf, **array;
- struct dentry *dentry;
struct inode *inode;
struct au_hfile *hfile;
@@ -906,8 +925,6 @@ static int au_br_mod_files_ro(struct super_block *sb, aufs_bindex_t bindex)
br_id = au_sbr_id(sb, bindex);
for (ull = 0; ull < max; ull++) {
file = array[ull];
- dentry = file->f_dentry;
- inode = dentry->d_inode;
/* AuDbg("%.*s\n", AuDLNPair(file->f_dentry)); */
fi_read_lock(file);
@@ -919,6 +936,7 @@ static int au_br_mod_files_ro(struct super_block *sb, aufs_bindex_t bindex)
goto out_array;
}
+ inode = file->f_dentry->d_inode;
hfile = &au_fi(file)->fi_htop;
hf = hfile->hf_file;
if (!S_ISREG(inode->i_mode)
@@ -951,7 +969,9 @@ static int au_br_mod_files_ro(struct super_block *sb, aufs_bindex_t bindex)
hfile = &au_fi(file)->fi_htop;
hf = hfile->hf_file;
/* fi_read_unlock(file); */
+ spin_lock(&hf->f_lock);
hf->f_mode &= ~FMODE_WRITE;
+ spin_unlock(&hf->f_lock);
if (!file_check_writeable(hf)) {
file_release_write(hf);
mnt_drop_write(hf->f_vfsmnt);
diff --git a/ubuntu/aufs/branch.h b/ubuntu/aufs/branch.h
index ddbfbb81008..a273e60a597 100644
--- a/ubuntu/aufs/branch.h
+++ b/ubuntu/aufs/branch.h
@@ -81,6 +81,11 @@ struct au_branch {
blkcnt_t br_xino_upper; /* watermark in blocks */
atomic_t br_xino_running;
+#ifdef CONFIG_AUFS_HFSNOTIFY
+ struct fsnotify_group *br_hfsn_group;
+ struct fsnotify_ops br_hfsn_ops;
+#endif
+
#ifdef CONFIG_SYSFS
/* an entry under sysfs per mount-point */
char br_name[8];
diff --git a/ubuntu/aufs/cpup.c b/ubuntu/aufs/cpup.c
index 962fd507147..3f667dd6acc 100644
--- a/ubuntu/aufs/cpup.c
+++ b/ubuntu/aufs/cpup.c
@@ -576,8 +576,9 @@ static int au_cpup_single(struct dentry *dentry, aufs_bindex_t 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);
+ AuIOErr("hi%lu(i%lu) exists on b%d "
+ "but plink is disabled\n",
+ dst_inode->i_ino, inode->i_ino, bdst);
goto out;
}
@@ -591,7 +592,8 @@ static int au_cpup_single(struct dentry *dentry, aufs_bindex_t bdst,
if (unlikely(!h_src->d_inode)) {
err = -EIO;
AuIOErr("i%lu exists on a upper branch "
- "but plink is broken\n", inode->i_ino);
+ "but not pseudo-linked\n",
+ inode->i_ino);
dput(h_src);
goto out;
}
@@ -816,13 +818,15 @@ static int au_do_cpup_wh(struct dentry *dentry, aufs_bindex_t bdst,
h_d_dst = hdp[0 + bdst].hd_dentry;
dinfo->di_bstart = bdst;
hdp[0 + bdst].hd_dentry = wh_dentry;
- h_d_start = hdp[0 + bstart].hd_dentry;
- if (file)
+ if (file) {
+ h_d_start = hdp[0 + bstart].hd_dentry;
hdp[0 + bstart].hd_dentry = au_hf_top(file)->f_dentry;
+ }
err = au_cpup_single(dentry, bdst, bstart, len, !AuCpup_DTIME,
/*h_parent*/NULL);
- if (!err && file) {
- err = au_reopen_nondir(file);
+ if (file) {
+ if (!err)
+ err = au_reopen_nondir(file);
hdp[0 + bstart].hd_dentry = h_d_start;
}
hdp[0 + bdst].hd_dentry = h_d_dst;
diff --git a/ubuntu/aufs/dcsub.c b/ubuntu/aufs/dcsub.c
index d5ab3525791..d9755f77859 100644
--- a/ubuntu/aufs/dcsub.c
+++ b/ubuntu/aufs/dcsub.c
@@ -98,7 +98,8 @@ static int au_dpages_append(struct au_dcsub_pages *dpages,
dpages->ndpage++;
}
- dpage->dentries[dpage->ndentry++] = dget(dentry);
+ /* d_count can be zero */
+ dpage->dentries[dpage->ndentry++] = dget_locked(dentry);
return 0; /* success */
out:
@@ -120,8 +121,7 @@ repeat:
resume:
if (this_parent->d_sb == sb
&& !IS_ROOT(this_parent)
- && atomic_read(&this_parent->d_count)
- && this_parent->d_inode
+ && au_di(this_parent)
&& (!test || test(this_parent, arg))) {
err = au_dpages_append(dpages, this_parent, GFP_ATOMIC);
if (unlikely(err))
@@ -133,14 +133,12 @@ resume:
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)
+ && au_di(dentry)
&& (!test || test(dentry, arg))) {
err = au_dpages_append(dpages, dentry, GFP_ATOMIC);
if (unlikely(err))
@@ -185,6 +183,18 @@ out:
return err;
}
+static inline int au_dcsub_dpages_aufs(struct dentry *dentry, void *arg)
+{
+ return au_di(dentry) && dentry->d_sb == arg;
+}
+
+int au_dcsub_pages_rev_aufs(struct au_dcsub_pages *dpages,
+ struct dentry *dentry, int do_include)
+{
+ return au_dcsub_pages_rev(dpages, dentry, do_include,
+ au_dcsub_dpages_aufs, dentry->d_sb);
+}
+
int au_test_subdir(struct dentry *d1, struct dentry *d2)
{
struct path path[2] = {
diff --git a/ubuntu/aufs/dcsub.h b/ubuntu/aufs/dcsub.h
index be25a134621..13b4fb2ca84 100644
--- a/ubuntu/aufs/dcsub.h
+++ b/ubuntu/aufs/dcsub.h
@@ -26,6 +26,7 @@
#ifdef __KERNEL__
#include <linux/dcache.h>
+#include <linux/fs.h>
#include <linux/types.h>
struct dentry;
@@ -50,6 +51,8 @@ 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);
+int au_dcsub_pages_rev_aufs(struct au_dcsub_pages *dpages,
+ struct dentry *dentry, int do_include);
int au_test_subdir(struct dentry *d1, struct dentry *d2);
/* ---------------------------------------------------------------------- */
@@ -59,5 +62,39 @@ static inline int au_d_removed(struct dentry *d)
return !IS_ROOT(d) && d_unhashed(d);
}
+static inline int au_d_hashed_positive(struct dentry *d)
+{
+ int err;
+ struct inode *inode = d->d_inode;
+ err = 0;
+ if (unlikely(d_unhashed(d) || !inode || !inode->i_nlink))
+ err = -ENOENT;
+ return err;
+}
+
+static inline int au_d_alive(struct dentry *d)
+{
+ int err;
+ struct inode *inode;
+ err = 0;
+ if (!IS_ROOT(d))
+ err = au_d_hashed_positive(d);
+ else {
+ inode = d->d_inode;
+ if (unlikely(au_d_removed(d) || !inode || !inode->i_nlink))
+ err = -ENOENT;
+ }
+ return err;
+}
+
+static inline int au_alive_dir(struct dentry *d)
+{
+ int err;
+ err = au_d_alive(d);
+ if (unlikely(err || IS_DEADDIR(d->d_inode)))
+ err = -ENOENT;
+ return err;
+}
+
#endif /* __KERNEL__ */
#endif /* __AUFS_DCSUB_H__ */
diff --git a/ubuntu/aufs/debug.c b/ubuntu/aufs/debug.c
index ec8dc079edc..fd3ebd8481d 100644
--- a/ubuntu/aufs/debug.c
+++ b/ubuntu/aufs/debug.c
@@ -335,24 +335,63 @@ void au_dbg_iattr(struct iattr *ia)
/* ---------------------------------------------------------------------- */
+void __au_dbg_verify_dinode(struct dentry *dentry, const char *func, int line)
+{
+ struct inode *h_inode, *inode = dentry->d_inode;
+ struct dentry *h_dentry;
+ aufs_bindex_t bindex, bend, bi;
+
+ if (!inode /* || au_di(dentry)->di_lsc == AuLsc_DI_TMP */)
+ return;
+
+ bend = au_dbend(dentry);
+ bi = au_ibend(inode);
+ if (bi < bend)
+ bend = bi;
+ bindex = au_dbstart(dentry);
+ bi = au_ibstart(inode);
+ if (bi > bindex)
+ bindex = bi;
+
+ for (; bindex <= bend; bindex++) {
+ h_dentry = au_h_dptr(dentry, bindex);
+ if (!h_dentry)
+ continue;
+ h_inode = au_h_iptr(inode, bindex);
+ if (unlikely(h_inode != h_dentry->d_inode)) {
+ int old = au_debug_test();
+ if (!old)
+ au_debug(1);
+ AuDbg("b%d, %s:%d\n", bindex, func, line);
+ AuDbgDentry(dentry);
+ AuDbgInode(inode);
+ if (!old)
+ au_debug(0);
+ BUG();
+ }
+ }
+}
+
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);
+ AuDebugOn(!S_ISDIR(dentry->d_inode->i_mode));
+ AuDebugOn(IS_ROOT(dentry));
+ AuDebugOn(au_digen_test(parent, sigen));
dput(parent);
}
void au_dbg_verify_nondir_parent(struct dentry *dentry, unsigned int sigen)
{
struct dentry *parent;
+ struct inode *inode;
parent = dget_parent(dentry);
- AuDebugOn(S_ISDIR(dentry->d_inode->i_mode)
- || au_digen(parent) != sigen);
+ inode = dentry->d_inode;
+ AuDebugOn(inode && S_ISDIR(dentry->d_inode->i_mode));
+ AuDebugOn(au_digen_test(parent, sigen));
dput(parent);
}
@@ -365,13 +404,13 @@ void au_dbg_verify_gen(struct dentry *parent, unsigned int sigen)
err = au_dpages_init(&dpages, GFP_NOFS);
AuDebugOn(err);
- err = au_dcsub_pages_rev(&dpages, parent, /*do_include*/1, NULL, NULL);
+ err = au_dcsub_pages_rev_aufs(&dpages, parent, /*do_include*/1);
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);
+ AuDebugOn(au_digen_test(dentries[j], sigen));
}
au_dpages_free(&dpages);
}
diff --git a/ubuntu/aufs/debug.h b/ubuntu/aufs/debug.h
index c6b2626dee7..cfe4413181b 100644
--- a/ubuntu/aufs/debug.h
+++ b/ubuntu/aufs/debug.h
@@ -132,6 +132,8 @@ void au_dbg_sleep_jiffy(int jiffy);
struct iattr;
void au_dbg_iattr(struct iattr *ia);
+#define au_dbg_verify_dinode(d) __au_dbg_verify_dinode(d, __func__, __LINE__)
+void __au_dbg_verify_dinode(struct dentry *dentry, const char *func, int line);
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);
@@ -196,6 +198,7 @@ void au_debug_sbinfo_init(struct au_sbinfo *sbinfo);
AuInfo("%s\n", sym); \
} while (0)
#else
+AuStubVoid(au_dbg_verify_dinode, struct dentry *dentry)
AuStubVoid(au_dbg_verify_dir_parent, struct dentry *dentry, unsigned int sigen)
AuStubVoid(au_dbg_verify_nondir_parent, struct dentry *dentry,
unsigned int sigen)
diff --git a/ubuntu/aufs/dentry.c b/ubuntu/aufs/dentry.c
index 2743e26f5ee..8daf4a36aad 100644
--- a/ubuntu/aufs/dentry.c
+++ b/ubuntu/aufs/dentry.c
@@ -267,9 +267,11 @@ int au_lkup_dentry(struct dentry *dentry, aufs_bindex_t bstart, mode_t type,
}
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 */
+ && au_dbstart(dentry) < 0)) {
err = -EIO;
+ AuIOErr("both of real entry and whiteout found, %.*s, err %d\n",
+ AuDLNPair(dentry), err);
+ }
out_parent:
dput(parent);
@@ -320,8 +322,8 @@ int au_lkup_neg(struct dentry *dentry, aufs_bindex_t bindex)
goto out;
if (unlikely(h_dentry->d_inode)) {
err = -EIO;
- AuIOErr("b%d %.*s should be negative.\n",
- bindex, AuDLNPair(h_dentry));
+ AuIOErr("%.*s should be negative on b%d.\n",
+ AuDLNPair(h_dentry), bindex);
dput(h_dentry);
goto out;
}
@@ -437,32 +439,30 @@ int au_h_verify(struct dentry *h_dentry, unsigned int udba, struct inode *h_dir,
/* ---------------------------------------------------------------------- */
-static void au_do_refresh_hdentry(struct au_hdentry *p, struct au_dinfo *dinfo,
- struct dentry *parent)
+static int au_do_refresh_hdentry(struct dentry *dentry, struct dentry *parent)
{
- struct dentry *h_d, *h_dp;
- struct au_hdentry tmp, *q;
- struct super_block *sb;
+ int err;
aufs_bindex_t new_bindex, bindex, bend, bwh, bdiropq;
+ struct au_hdentry tmp, *p, *q;
+ struct au_dinfo *dinfo;
+ struct super_block *sb;
- AuRwMustWriteLock(&dinfo->di_rwsem);
+ DiMustWriteLock(dentry);
+ sb = dentry->d_sb;
+ dinfo = au_di(dentry);
bend = dinfo->di_bend;
bwh = dinfo->di_bwh;
bdiropq = dinfo->di_bdiropq;
+ p = dinfo->di_hdentry + dinfo->di_bstart;
for (bindex = dinfo->di_bstart; bindex <= bend; bindex++, p++) {
- h_d = p->hd_dentry;
- if (!h_d)
+ if (!p->hd_dentry)
continue;
- h_dp = dget_parent(h_d);
- if (h_dp == au_h_dptr(parent, bindex)) {
- dput(h_dp);
+ new_bindex = au_br_index(sb, p->hd_id);
+ if (new_bindex == bindex)
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)
@@ -484,7 +484,6 @@ static void au_do_refresh_hdentry(struct au_hdentry *p, struct au_dinfo *dinfo,
}
}
- sb = parent->d_sb;
dinfo->di_bwh = -1;
if (bwh >= 0 && bwh <= au_sbend(sb) && au_sbr_whable(sb, bwh))
dinfo->di_bwh = bwh;
@@ -495,6 +494,9 @@ static void au_do_refresh_hdentry(struct au_hdentry *p, struct au_dinfo *dinfo,
&& au_sbr_whable(sb, bdiropq))
dinfo->di_bdiropq = bdiropq;
+ err = -EIO;
+ dinfo->di_bstart = -1;
+ dinfo->di_bend = -1;
bend = au_dbend(parent);
p = dinfo->di_hdentry;
for (bindex = 0; bindex <= bend; bindex++, p++)
@@ -503,61 +505,318 @@ static void au_do_refresh_hdentry(struct au_hdentry *p, struct au_dinfo *dinfo,
break;
}
- p = dinfo->di_hdentry + bend;
- for (bindex = bend; bindex >= 0; bindex--, p--)
- if (p->hd_dentry) {
- dinfo->di_bend = bindex;
- break;
+ if (dinfo->di_bstart >= 0) {
+ p = dinfo->di_hdentry + bend;
+ for (bindex = bend; bindex >= 0; bindex--, p--)
+ if (p->hd_dentry) {
+ dinfo->di_bend = bindex;
+ err = 0;
+ break;
+ }
+ }
+
+ return err;
+}
+
+static void au_do_hide(struct dentry *dentry)
+{
+ struct inode *inode;
+
+ inode = dentry->d_inode;
+ if (inode) {
+ if (!S_ISDIR(inode->i_mode)) {
+ if (inode->i_nlink && !d_unhashed(dentry))
+ drop_nlink(inode);
+ } else {
+ clear_nlink(inode);
+ /* stop next lookup */
+ inode->i_flags |= S_DEAD;
}
+ smp_mb(); /* necessary? */
+ }
+ d_drop(dentry);
+}
+
+static int au_hide_children(struct dentry *parent)
+{
+ int err, i, j, ndentry;
+ struct au_dcsub_pages dpages;
+ struct au_dpage *dpage;
+ struct dentry *dentry;
+
+ err = au_dpages_init(&dpages, GFP_NOFS);
+ if (unlikely(err))
+ goto out;
+ err = au_dcsub_pages(&dpages, parent, NULL, NULL);
+ if (unlikely(err))
+ goto out_dpages;
+
+ /* in reverse order */
+ for (i = dpages.ndpage - 1; i >= 0; i--) {
+ dpage = dpages.dpages + i;
+ ndentry = dpage->ndentry;
+ for (j = ndentry - 1; j >= 0; j--) {
+ dentry = dpage->dentries[j];
+ if (dentry != parent)
+ au_do_hide(dentry);
+ }
+ }
+
+out_dpages:
+ au_dpages_free(&dpages);
+out:
+ return err;
+}
+
+static void au_hide(struct dentry *dentry)
+{
+ int err;
+ struct inode *inode;
+
+ AuDbgDentry(dentry);
+ inode = dentry->d_inode;
+ if (inode && S_ISDIR(inode->i_mode)) {
+ /* shrink_dcache_parent(dentry); */
+ err = au_hide_children(dentry);
+ if (unlikely(err))
+ AuIOErr("%.*s, failed hiding children, ignored %d\n",
+ AuDLNPair(dentry), err);
+ }
+ au_do_hide(dentry);
}
/*
- * returns the number of found lower positive dentries,
- * otherwise an error.
+ * By adding a dirty branch, a cached dentry may be affected in various ways.
+ *
+ * a dirty branch is added
+ * - on the top of layers
+ * - in the middle of layers
+ * - to the bottom of layers
+ *
+ * on the added branch there exists
+ * - a whiteout
+ * - a diropq
+ * - a same named entry
+ * + exist
+ * * negative --> positive
+ * * positive --> positive
+ * - type is unchanged
+ * - type is changed
+ * + doesn't exist
+ * * negative --> negative
+ * * positive --> negative (rejected by au_br_del() for non-dir case)
+ * - none
*/
-int au_refresh_hdentry(struct dentry *dentry, mode_t type)
+static int au_refresh_by_dinfo(struct dentry *dentry, struct au_dinfo *dinfo,
+ struct au_dinfo *tmp)
{
- int npositive, err;
+ int err;
+ aufs_bindex_t bindex, bend;
+ struct {
+ struct dentry *dentry;
+ struct inode *inode;
+ mode_t mode;
+ } orig_h, tmp_h;
+ struct au_hdentry *hd;
+ struct inode *inode, *h_inode;
+ struct dentry *h_dentry;
+
+ err = 0;
+ AuDebugOn(dinfo->di_bstart < 0);
+ orig_h.dentry = dinfo->di_hdentry[dinfo->di_bstart].hd_dentry;
+ orig_h.inode = orig_h.dentry->d_inode;
+ orig_h.mode = 0;
+ if (orig_h.inode)
+ orig_h.mode = orig_h.inode->i_mode & S_IFMT;
+ memset(&tmp_h, 0, sizeof(tmp_h));
+ if (tmp->di_bstart >= 0) {
+ tmp_h.dentry = tmp->di_hdentry[tmp->di_bstart].hd_dentry;
+ tmp_h.inode = tmp_h.dentry->d_inode;
+ if (tmp_h.inode)
+ tmp_h.mode = tmp_h.inode->i_mode & S_IFMT;
+ }
+
+ inode = dentry->d_inode;
+ if (!orig_h.inode) {
+ AuDbg("nagative originally\n");
+ if (inode) {
+ au_hide(dentry);
+ goto out;
+ }
+ AuDebugOn(inode);
+ AuDebugOn(dinfo->di_bstart != dinfo->di_bend);
+ AuDebugOn(dinfo->di_bdiropq != -1);
+
+ if (!tmp_h.inode) {
+ AuDbg("negative --> negative\n");
+ /* should have only one negative lower */
+ if (tmp->di_bstart >= 0
+ && tmp->di_bstart < dinfo->di_bstart) {
+ AuDebugOn(tmp->di_bstart != tmp->di_bend);
+ AuDebugOn(dinfo->di_bstart != dinfo->di_bend);
+ au_set_h_dptr(dentry, dinfo->di_bstart, NULL);
+ au_di_cp(dinfo, tmp);
+ hd = tmp->di_hdentry + tmp->di_bstart;
+ au_set_h_dptr(dentry, tmp->di_bstart,
+ dget(hd->hd_dentry));
+ }
+ au_dbg_verify_dinode(dentry);
+ } else {
+ AuDbg("negative --> positive\n");
+ /*
+ * similar to the behaviour of creating with bypassing
+ * aufs.
+ * unhash it in order to force an error in the
+ * succeeding create operation.
+ * we should not set S_DEAD here.
+ */
+ d_drop(dentry);
+ /* au_di_swap(tmp, dinfo); */
+ au_dbg_verify_dinode(dentry);
+ }
+ } else {
+ AuDbg("positive originally\n");
+ /* inode may be NULL */
+ AuDebugOn(inode && (inode->i_mode & S_IFMT) != orig_h.mode);
+ if (!tmp_h.inode) {
+ AuDbg("positive --> negative\n");
+ /* or bypassing aufs */
+ au_hide(dentry);
+ if (tmp->di_bwh >= 0 && tmp->di_bwh <= dinfo->di_bstart)
+ dinfo->di_bwh = tmp->di_bwh;
+ if (inode)
+ err = au_refresh_hinode_self(inode);
+ au_dbg_verify_dinode(dentry);
+ } else if (orig_h.mode == tmp_h.mode) {
+ AuDbg("positive --> positive, same type\n");
+ if (!S_ISDIR(orig_h.mode)
+ && dinfo->di_bstart > tmp->di_bstart) {
+ /*
+ * similar to the behaviour of removing and
+ * creating.
+ */
+ au_hide(dentry);
+ if (inode)
+ err = au_refresh_hinode_self(inode);
+ au_dbg_verify_dinode(dentry);
+ } else {
+ /* fill empty slots */
+ if (dinfo->di_bstart > tmp->di_bstart)
+ dinfo->di_bstart = tmp->di_bstart;
+ if (dinfo->di_bend < tmp->di_bend)
+ dinfo->di_bend = tmp->di_bend;
+ dinfo->di_bwh = tmp->di_bwh;
+ dinfo->di_bdiropq = tmp->di_bdiropq;
+ hd = tmp->di_hdentry;
+ bend = dinfo->di_bend;
+ for (bindex = tmp->di_bstart; bindex <= bend;
+ bindex++) {
+ if (au_h_dptr(dentry, bindex))
+ continue;
+ h_dentry = hd[bindex].hd_dentry;
+ if (!h_dentry)
+ continue;
+ h_inode = h_dentry->d_inode;
+ AuDebugOn(!h_inode);
+ AuDebugOn(orig_h.mode
+ != (h_inode->i_mode
+ & S_IFMT));
+ au_set_h_dptr(dentry, bindex,
+ dget(h_dentry));
+ }
+ err = au_refresh_hinode(inode, dentry);
+ au_dbg_verify_dinode(dentry);
+ }
+ } else {
+ AuDbg("positive --> positive, different type\n");
+ /* similar to the behaviour of removing and creating */
+ au_hide(dentry);
+ if (inode)
+ err = au_refresh_hinode_self(inode);
+ au_dbg_verify_dinode(dentry);
+ }
+ }
+
+out:
+ return err;
+}
+
+int au_refresh_dentry(struct dentry *dentry, struct dentry *parent)
+{
+ int err, ebrange;
unsigned int sigen;
- aufs_bindex_t bstart;
- struct au_dinfo *dinfo;
+ struct au_dinfo *dinfo, *tmp;
struct super_block *sb;
- struct dentry *parent;
+ struct inode *inode;
DiMustWriteLock(dentry);
+ AuDebugOn(IS_ROOT(dentry));
+ AuDebugOn(!parent->d_inode);
sb = dentry->d_sb;
- AuDebugOn(IS_ROOT(dentry));
+ inode = dentry->d_inode;
sigen = au_sigen(sb);
- parent = dget_parent(dentry);
- AuDebugOn(au_digen(parent) != sigen
- || au_iigen(parent->d_inode) != sigen);
+ err = au_digen_test(parent, sigen);
+ if (unlikely(err))
+ goto out;
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);
+ ebrange = au_dbrange_test(dentry);
+ if (!ebrange)
+ ebrange = au_do_refresh_hdentry(dentry, parent);
- npositive = 0;
- bstart = au_dbstart(parent);
- if (type != S_IFDIR && dinfo->di_bstart == bstart)
- goto out_dgen; /* success */
+ if (d_unhashed(dentry) || ebrange) {
+ AuDebugOn(au_dbstart(dentry) < 0 && au_dbend(dentry) >= 0);
+ if (inode)
+ err = au_refresh_hinode_self(inode);
+ au_dbg_verify_dinode(dentry);
+ if (!err)
+ goto out_dgen; /* success */
+ goto out;
+ }
- npositive = au_lkup_dentry(dentry, bstart, type, /*nd*/NULL);
- if (npositive < 0)
+ /* temporary dinfo */
+ AuDbgDentry(dentry);
+ err = -ENOMEM;
+ tmp = au_di_alloc(sb, AuLsc_DI_TMP);
+ if (unlikely(!tmp))
+ goto out;
+ au_di_swap(tmp, dinfo);
+ /* returns the number of positive dentries */
+ /*
+ * if current working dir is removed, it returns an error.
+ * but the dentry is legal.
+ */
+ err = au_lkup_dentry(dentry, /*bstart*/0, /*type*/0, /*nd*/NULL);
+ AuDbgDentry(dentry);
+ au_di_swap(tmp, dinfo);
+ if (err == -ENOENT)
+ err = 0;
+ if (err >= 0) {
+ /* compare/refresh by dinfo */
+ AuDbgDentry(dentry);
+ err = au_refresh_by_dinfo(dentry, dinfo, tmp);
+ au_dbg_verify_dinode(dentry);
+ AuTraceErr(err);
+ }
+ au_rw_write_unlock(&tmp->di_rwsem);
+ au_di_free(tmp);
+ if (unlikely(err))
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;
+ if (unlikely(err && !(dentry->d_flags & DCACHE_NFSFS_RENAMED))) {
+ AuIOErr("failed refreshing %.*s, %d\n",
+ AuDLNPair(dentry), err);
+ AuDbgDentry(dentry);
+ }
+ AuTraceErr(err);
+ return err;
}
static noinline_for_stack
@@ -706,29 +965,23 @@ static int h_d_revalidate(struct dentry *dentry, struct inode *inode,
return err;
}
+/* todo: consolidate with do_refresh() and au_reval_for_attr() */
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)
+ if (!au_digen_test(dentry, 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);
+ AuDebugOn(au_digen_test(parent, 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);
-
+ err = au_refresh_dentry(dentry, parent);
di_read_unlock(parent, AuLock_IR);
dput(parent);
+ AuTraceErr(err);
return err;
}
@@ -738,36 +991,35 @@ int au_reval_dpath(struct dentry *dentry, unsigned int sigen)
struct dentry *d, *parent;
struct inode *inode;
- if (!au_ftest_si(au_sbi(dentry->d_sb), FAILED_REFRESH_DIRS))
+ if (!au_ftest_si(au_sbi(dentry->d_sb), FAILED_REFRESH_DIR))
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) {
+ while (au_digen_test(dentry, sigen)) {
d = dentry;
while (1) {
dput(parent);
parent = dget_parent(d);
- if (au_digen(parent) == sigen
- && au_iigen(parent->d_inode) == sigen)
+ if (!au_digen_test(parent, sigen))
break;
d = parent;
}
inode = d->d_inode;
if (d != dentry)
- di_write_lock_child(d);
+ di_write_lock_child2(d);
/* someone might update our dentry while we were sleeping */
- if (au_digen(d) != sigen || au_iigen(d->d_inode) != sigen) {
+ if (au_digen_test(d, sigen)) {
+ /*
+ * todo: consolidate with simple_reval_dpath(),
+ * do_refresh() and au_reval_for_attr().
+ */
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);
+ err = au_refresh_dentry(d, parent);
di_read_unlock(parent, AuLock_IR);
}
@@ -792,6 +1044,10 @@ static int aufs_d_revalidate(struct dentry *dentry, struct nameidata *nd)
struct super_block *sb;
struct inode *inode;
+ valid = 0;
+ if (unlikely(!au_di(dentry)))
+ goto out;
+
valid = 1;
sb = dentry->d_sb;
inode = dentry->d_inode;
@@ -803,38 +1059,48 @@ static int aufs_d_revalidate(struct dentry *dentry, struct nameidata *nd)
err = aufs_read_lock(dentry, AuLock_FLUSH | AuLock_DW | AuLock_NOPLM);
if (unlikely(err)) {
valid = err;
+ AuTraceErr(err);
goto out;
}
- 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;
+ if (unlikely(au_dbrange_test(dentry))) {
+ err = -EINVAL;
+ AuTraceErr(err);
+ goto out_dgrade;
}
- if (inode && au_iigen(inode) != sigen) {
+
+ sigen = au_sigen(sb);
+ if (au_digen_test(dentry, sigen)) {
AuDebugOn(IS_ROOT(dentry));
- err = au_refresh_hinode(inode, dentry);
- if (unlikely(err))
+ err = au_reval_dpath(dentry, sigen);
+ if (unlikely(err)) {
+ AuTraceErr(err);
goto out_dgrade;
+ }
}
di_downgrade_lock(dentry, AuLock_IR);
err = -EINVAL;
+ if (inode && (IS_DEADDIR(inode) || !inode->i_nlink))
+ goto out_inval;
+
do_udba = !au_opt_test(au_mntflags(sb), UDBA_NONE);
if (do_udba && inode) {
aufs_bindex_t bstart = au_ibstart(inode);
+ struct inode *h_inode;
- if (bstart >= 0
- && au_test_higen(inode, au_h_iptr(inode, bstart)))
- goto out_inval;
+ if (bstart >= 0) {
+ h_inode = au_h_iptr(inode, bstart);
+ if (h_inode && au_test_higen(inode, h_inode))
+ goto out_inval;
+ }
}
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 */
+ if (unlikely(!err && do_udba && au_dbstart(dentry) < 0)) {
err = -EIO;
+ AuDbg("both of real entry and whiteout found, %.*s, err %d\n",
+ AuDLNPair(dentry), err);
+ }
goto out_inval;
out_dgrade:
@@ -844,14 +1110,16 @@ out_inval:
AuTraceErr(err);
valid = !err;
out:
- if (!valid)
+ if (!valid) {
AuDbg("%.*s invalid, %d\n", AuDLNPair(dentry), valid);
+ d_drop(dentry);
+ }
return valid;
}
static void aufs_d_release(struct dentry *dentry)
{
- if (dentry->d_fsdata) {
+ if (au_di(dentry)) {
au_di_fin(dentry);
au_hn_di_reinit(dentry);
}
diff --git a/ubuntu/aufs/dentry.h b/ubuntu/aufs/dentry.h
index 2f2bb81db56..4865f5e0903 100644
--- a/ubuntu/aufs/dentry.h
+++ b/ubuntu/aufs/dentry.h
@@ -29,10 +29,9 @@
#include <linux/aufs_type.h>
#include "rwsem.h"
-/* make a single member structure for future use */
-/* todo: remove this structure */
struct au_hdentry {
struct dentry *hd_dentry;
+ aufs_bindex_t hd_id;
};
struct au_dinfo {
@@ -58,11 +57,15 @@ int au_h_verify(struct dentry *h_dentry, unsigned int udba, struct inode *h_dir,
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_refresh_dentry(struct dentry *dentry, struct dentry *parent);
int au_reval_dpath(struct dentry *dentry, unsigned int sigen);
/* dinfo.c */
void au_di_init_once(void *_di);
+struct au_dinfo *au_di_alloc(struct super_block *sb, unsigned int lsc);
+void au_di_free(struct au_dinfo *dinfo);
+void au_di_swap(struct au_dinfo *a, struct au_dinfo *b);
+void au_di_cp(struct au_dinfo *dst, struct au_dinfo *src);
int au_di_init(struct dentry *dentry);
void au_di_fin(struct dentry *dentry);
int au_di_realloc(struct au_dinfo *dinfo, int nbr);
@@ -82,6 +85,8 @@ aufs_bindex_t au_dbtaildir(struct dentry *dentry);
void au_set_h_dptr(struct dentry *dentry, aufs_bindex_t bindex,
struct dentry *h_dentry);
+int au_digen_test(struct dentry *dentry, unsigned int sigen);
+int au_dbrange_test(struct dentry *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);
@@ -104,7 +109,8 @@ enum {
AuLsc_DI_CHILD3, /* copyup dirs */
AuLsc_DI_PARENT,
AuLsc_DI_PARENT2,
- AuLsc_DI_PARENT3
+ AuLsc_DI_PARENT3,
+ AuLsc_DI_TMP /* temp for replacing dinfo */
};
/*
diff --git a/ubuntu/aufs/dinfo.c b/ubuntu/aufs/dinfo.c
index 4a638dc92b5..fff8cdd2771 100644
--- a/ubuntu/aufs/dinfo.c
+++ b/ubuntu/aufs/dinfo.c
@@ -31,60 +31,118 @@ void au_di_init_once(void *_dinfo)
au_rw_class(&dinfo->di_rwsem, &aufs_di);
}
-int au_di_init(struct dentry *dentry)
+struct au_dinfo *au_di_alloc(struct super_block *sb, unsigned int lsc)
{
struct au_dinfo *dinfo;
- struct super_block *sb;
- int nbr;
+ int nbr, i;
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_write_lock_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 */
+ if (dinfo->di_hdentry) {
+ au_rw_write_lock_nested(&dinfo->di_rwsem, lsc);
+ dinfo->di_bstart = -1;
+ dinfo->di_bend = -1;
+ dinfo->di_bwh = -1;
+ dinfo->di_bdiropq = -1;
+ for (i = 0; i < nbr; i++)
+ dinfo->di_hdentry[i].hd_id = -1;
+ goto out;
+ }
-out_dinfo:
au_cache_free_dinfo(dinfo);
+ dinfo = NULL;
+
out:
- return -ENOMEM;
+ return dinfo;
}
-void au_di_fin(struct dentry *dentry)
+void au_di_free(struct au_dinfo *dinfo)
{
- struct au_dinfo *di;
struct au_hdentry *p;
aufs_bindex_t bend, bindex;
/* dentry may not be revalidated */
- di = dentry->d_fsdata;
- bindex = di->di_bstart;
+ bindex = dinfo->di_bstart;
if (bindex >= 0) {
- bend = di->di_bend;
- p = di->di_hdentry + bindex;
+ bend = dinfo->di_bend;
+ p = dinfo->di_hdentry + bindex;
while (bindex++ <= bend)
au_hdput(p++);
}
- kfree(di->di_hdentry);
- AuRwDestroy(&di->di_rwsem);
- au_cache_free_dinfo(di);
+ kfree(dinfo->di_hdentry);
+ au_cache_free_dinfo(dinfo);
+}
+
+void au_di_swap(struct au_dinfo *a, struct au_dinfo *b)
+{
+ struct au_hdentry *p;
+ aufs_bindex_t bi;
+
+ AuRwMustWriteLock(&a->di_rwsem);
+ AuRwMustWriteLock(&b->di_rwsem);
+
+#define DiSwap(v, name) \
+ do { \
+ v = a->di_##name; \
+ a->di_##name = b->di_##name; \
+ b->di_##name = v; \
+ } while (0)
+
+ DiSwap(p, hdentry);
+ DiSwap(bi, bstart);
+ DiSwap(bi, bend);
+ DiSwap(bi, bwh);
+ DiSwap(bi, bdiropq);
+ /* smp_mb(); */
+
+#undef DiSwap
+}
+
+void au_di_cp(struct au_dinfo *dst, struct au_dinfo *src)
+{
+ AuRwMustWriteLock(&dst->di_rwsem);
+ AuRwMustWriteLock(&src->di_rwsem);
+
+ dst->di_bstart = src->di_bstart;
+ dst->di_bend = src->di_bend;
+ dst->di_bwh = src->di_bwh;
+ dst->di_bdiropq = src->di_bdiropq;
+ /* smp_mb(); */
+}
+
+int au_di_init(struct dentry *dentry)
+{
+ int err;
+ struct super_block *sb;
+ struct au_dinfo *dinfo;
+
+ err = 0;
+ sb = dentry->d_sb;
+ dinfo = au_di_alloc(sb, AuLsc_DI_CHILD);
+ if (dinfo) {
+ atomic_set(&dinfo->di_generation, au_sigen(sb));
+ /* smp_mb(); */ /* atomic_set */
+ dentry->d_op = &aufs_dop;
+ dentry->d_fsdata = dinfo;
+ } else
+ err = -ENOMEM;
+
+ return err;
+}
+
+void au_di_fin(struct dentry *dentry)
+{
+ struct au_dinfo *dinfo;
+
+ dinfo = au_di(dentry);
+ AuRwDestroy(&dinfo->di_rwsem);
+ au_di_free(dinfo);
}
int au_di_realloc(struct au_dinfo *dinfo, int nbr)
@@ -175,10 +233,13 @@ void di_read_lock(struct dentry *d, int flags, unsigned int lsc)
void di_read_unlock(struct dentry *d, int flags)
{
if (d->d_inode) {
- if (au_ftest_lock(flags, IW))
+ if (au_ftest_lock(flags, IW)) {
+ au_dbg_verify_dinode(d);
ii_write_unlock(d->d_inode);
- else if (au_ftest_lock(flags, IR))
+ } else if (au_ftest_lock(flags, IR)) {
+ au_dbg_verify_dinode(d);
ii_read_unlock(d->d_inode);
+ }
}
au_rw_read_unlock(&au_di(d)->di_rwsem);
}
@@ -199,6 +260,7 @@ void di_write_lock(struct dentry *d, unsigned int lsc)
void di_write_unlock(struct dentry *d)
{
+ au_dbg_verify_dinode(d);
if (d->d_inode)
ii_write_unlock(d->d_inode);
au_rw_write_unlock(&au_di(d)->di_rwsem);
@@ -295,11 +357,46 @@ 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;
+ struct au_branch *br;
DiMustWriteLock(dentry);
au_hdput(hd);
hd->hd_dentry = h_dentry;
+ if (h_dentry) {
+ br = au_sbr(dentry->d_sb, bindex);
+ hd->hd_id = br->br_id;
+ }
+}
+
+int au_dbrange_test(struct dentry *dentry)
+{
+ int err;
+ aufs_bindex_t bstart, bend;
+
+ err = 0;
+ bstart = au_dbstart(dentry);
+ bend = au_dbend(dentry);
+ if (bstart >= 0)
+ AuDebugOn(bend < 0 && bstart > bend);
+ else {
+ err = -EIO;
+ AuDebugOn(bend >= 0);
+ }
+
+ return err;
+}
+
+int au_digen_test(struct dentry *dentry, unsigned int sigen)
+{
+ int err;
+
+ err = 0;
+ if (unlikely(au_digen(dentry) != sigen
+ || au_iigen_test(dentry->d_inode, sigen)))
+ err = -EIO;
+
+ return err;
}
void au_update_digen(struct dentry *dentry)
diff --git a/ubuntu/aufs/dir.c b/ubuntu/aufs/dir.c
index d97ec02e0eb..f2d9750c42f 100644
--- a/ubuntu/aufs/dir.c
+++ b/ubuntu/aufs/dir.c
@@ -145,8 +145,11 @@ static int do_open_dir(struct file *file, int flags)
FiMustWriteLock(file);
- err = 0;
dentry = file->f_dentry;
+ err = au_alive_dir(dentry);
+ if (unlikely(err))
+ goto out;
+
file->f_version = dentry->d_inode->i_version;
bindex = au_dbstart(dentry);
au_set_fbstart(file, bindex);
@@ -176,6 +179,7 @@ static int do_open_dir(struct file *file, int flags)
au_set_fbstart(file, -1);
au_set_fbend_dir(file, -1);
+out:
return err;
}
@@ -388,7 +392,9 @@ static int aufs_readdir(struct file *file, void *dirent, filldir_t filldir)
err = au_reval_and_lock_fdi(file, reopen_dir, /*wlock*/1);
if (unlikely(err))
goto out;
- err = au_vdir_init(file);
+ err = au_alive_dir(dentry);
+ if (!err)
+ err = au_vdir_init(file);
di_downgrade_lock(dentry, AuLock_IR);
if (unlikely(err))
goto out_unlock;
diff --git a/ubuntu/aufs/export.c b/ubuntu/aufs/export.c
index 05a9a75c65f..b638ba60098 100644
--- a/ubuntu/aufs/export.c
+++ b/ubuntu/aufs/export.c
@@ -236,7 +236,7 @@ static struct dentry *decode_by_ino(struct super_block *sb, ino_t ino,
}
spin_unlock(&dcache_lock);
}
- if (unlikely(dentry && sigen != au_digen(dentry))) {
+ if (unlikely(dentry && au_digen_test(dentry, sigen))) {
dput(dentry);
dentry = ERR_PTR(-ESTALE);
}
@@ -292,28 +292,32 @@ static struct vfsmount *au_mnt_get(struct super_block *sb)
struct au_nfsd_si_lock {
unsigned int sigen;
- aufs_bindex_t br_id;
+ aufs_bindex_t bindex, 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)
+static int si_nfsd_read_lock(struct super_block *sb,
+ struct au_nfsd_si_lock *nsi_lock)
{
+ int err;
aufs_bindex_t bindex;
si_read_lock(sb, AuLock_FLUSH);
/* branch id may be wrapped around */
+ err = 0;
bindex = au_br_index(sb, nsi_lock->br_id);
if (bindex >= 0 && nsi_lock->sigen + AUFS_BRANCH_MAX > au_sigen(sb))
goto out; /* success */
+ err = -ESTALE;
+ bindex = -1;
if (!nsi_lock->force_lock)
si_read_unlock(sb);
- bindex = -1;
out:
- return bindex;
+ nsi_lock->bindex = bindex;
+ return err;
}
struct find_name_by_ino {
@@ -470,9 +474,8 @@ out:
}
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 *decode_by_path(struct super_block *sb, 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;
@@ -482,8 +485,7 @@ struct dentry *decode_by_path(struct super_block *sb, aufs_bindex_t bindex,
int err;
struct path path;
- br = au_sbr(sb, bindex);
- /* au_br_get(br); */
+ br = au_sbr(sb, nsi_lock->bindex);
h_mnt = br->br_mnt;
h_sb = h_mnt->mnt_sb;
/* todo: call lower fh_to_dentry()? fh_to_parent()? */
@@ -511,7 +513,7 @@ struct dentry *decode_by_path(struct super_block *sb, aufs_bindex_t bindex,
root = sb->s_root;
path.mnt = h_mnt;
di_read_lock_parent(root, !AuLock_IR);
- path.dentry = au_h_dptr(root, bindex);
+ path.dentry = au_h_dptr(root, nsi_lock->bindex);
di_read_unlock(root, !AuLock_IR);
p = au_build_path(h_parent, &path, pathname, PAGE_SIZE, sb);
dentry = (void *)p;
@@ -547,7 +549,6 @@ out_pathname:
out_h_parent:
dput(h_parent);
out:
- /* au_br_put(br); */
AuTraceErrPtr(dentry);
return dentry;
}
@@ -560,8 +561,8 @@ aufs_fh_to_dentry(struct super_block *sb, struct fid *fid, int fh_len,
{
struct dentry *dentry;
__u32 *fh = fid->raw;
+ struct au_branch *br;
ino_t ino, dir_ino;
- aufs_bindex_t bindex;
struct au_nfsd_si_lock nsi_lock = {
.force_lock = 0
};
@@ -574,8 +575,8 @@ aufs_fh_to_dentry(struct super_block *sb, struct fid *fid, int fh_len,
nsi_lock.br_id = fh[Fh_br_id];
/* branch id may be wrapped around */
- bindex = si_nfsd_read_lock(sb, &nsi_lock);
- if (unlikely(bindex < 0))
+ br = NULL;
+ if (unlikely(si_nfsd_read_lock(sb, &nsi_lock)))
goto out;
nsi_lock.force_lock = 1;
@@ -593,6 +594,8 @@ aufs_fh_to_dentry(struct super_block *sb, struct fid *fid, int fh_len,
goto accept;
/* is the parent dir cached? */
+ br = au_sbr(sb, nsi_lock.bindex);
+ atomic_inc(&br->br_count);
dentry = decode_by_dir_ino(sb, ino, dir_ino, &nsi_lock);
if (IS_ERR(dentry))
goto out_unlock;
@@ -600,7 +603,7 @@ aufs_fh_to_dentry(struct super_block *sb, struct fid *fid, int fh_len,
goto accept;
/* lookup path */
- dentry = decode_by_path(sb, bindex, ino, fh, fh_len, &nsi_lock);
+ dentry = decode_by_path(sb, ino, fh, fh_len, &nsi_lock);
if (IS_ERR(dentry))
goto out_unlock;
if (unlikely(!dentry))
@@ -608,12 +611,15 @@ aufs_fh_to_dentry(struct super_block *sb, struct fid *fid, int fh_len,
goto out_unlock;
accept:
- if (dentry->d_inode->i_generation == fh[Fh_igen])
+ if (!au_digen_test(dentry, au_sigen(sb))
+ && dentry->d_inode->i_generation == fh[Fh_igen])
goto out_unlock; /* success */
dput(dentry);
dentry = ERR_PTR(-ESTALE);
out_unlock:
+ if (br)
+ atomic_dec(&br->br_count);
si_read_unlock(sb);
out:
AuTraceErrPtr(dentry);
@@ -670,19 +676,21 @@ static int aufs_encode_fh(struct dentry *dentry, __u32 *fh, int *max_len,
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);
+ err = aufs_read_lock(dentry, AuLock_FLUSH | AuLock_IR | AuLock_GEN);
+ if (unlikely(err))
+ goto out;
+
inode = dentry->d_inode;
AuDebugOn(!inode);
+ sb = dentry->d_sb;
#ifdef CONFIG_AUFS_DEBUG
if (unlikely(!au_opt_test(au_mntflags(sb), XINO)))
AuWarn1("NFS-exporting requires xino\n");
#endif
-
+ err = -EIO;
+ parent = dget_parent(dentry);
+ di_read_lock_parent(parent, !AuLock_IR);
bend = au_dbtaildir(parent);
for (bindex = au_dbstart(parent); bindex <= bend; bindex++) {
h_parent = au_h_dptr(parent, bindex);
diff --git a/ubuntu/aufs/f_op.c b/ubuntu/aufs/f_op.c
index 829a67e3c2d..ff0f44bd201 100644
--- a/ubuntu/aufs/f_op.c
+++ b/ubuntu/aufs/f_op.c
@@ -37,8 +37,11 @@ int au_do_open_nondir(struct file *file, int flags)
FiMustWriteLock(file);
- err = 0;
dentry = file->f_dentry;
+ err = au_d_alive(dentry);
+ if (unlikely(err))
+ goto out;
+
finfo = au_fi(file);
memset(&finfo->fi_htop, 0, sizeof(finfo->fi_htop));
finfo->fi_hvmop = NULL;
@@ -53,6 +56,8 @@ int au_do_open_nondir(struct file *file, int flags)
/* todo: necessary? */
/* file->f_ra = h_file->f_ra; */
}
+
+out:
return err;
}
@@ -376,7 +381,7 @@ 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))
+ if (au_fi(file) && au_test_aufs(file->f_dentry->d_sb))
return file;
return NULL;
}
diff --git a/ubuntu/aufs/file.c b/ubuntu/aufs/file.c
index 15e38ce31c6..2ba0c000f16 100644
--- a/ubuntu/aufs/file.c
+++ b/ubuntu/aufs/file.c
@@ -65,7 +65,7 @@ struct file *au_h_open(struct dentry *dentry, aufs_bindex_t bindex, int flags,
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;
+ goto out;
/* drop flags for writing */
if (au_test_ro(sb, bindex, dentry->d_inode))
@@ -202,14 +202,20 @@ 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 inode *inode, *h_inode;
+ struct dentry *dentry, *h_dentry, *hi_wh;
dentry = file->f_dentry;
au_update_dbstart(dentry);
inode = dentry->d_inode;
+ h_inode = NULL;
+ if (au_dbstart(dentry) <= bcpup && au_dbend(dentry) >= bcpup) {
+ h_dentry = au_h_dptr(dentry, bcpup);
+ if (h_dentry)
+ h_inode = h_dentry->d_inode;
+ }
hi_wh = au_hi_wh(inode, bcpup);
- if (!hi_wh)
+ if (!hi_wh && !h_inode)
err = au_sio_cpup_wh(dentry, bcpup, len, file);
else
/* already copied-up after unlink */
@@ -229,7 +235,7 @@ static int au_ready_to_write_wh(struct file *file, loff_t len,
int au_ready_to_write(struct file *file, loff_t len, struct au_pin *pin)
{
int err;
- aufs_bindex_t bstart, bcpup;
+ aufs_bindex_t bstart, bcpup, dbstart;
struct dentry *dentry, *parent, *h_dentry;
struct inode *h_inode, *inode;
struct super_block *sb;
@@ -246,7 +252,7 @@ int au_ready_to_write(struct file *file, loff_t len, struct au_pin *pin)
goto out;
}
- /* need to cpup */
+ /* need to cpup or reopen */
parent = dget_parent(dentry);
di_write_lock_parent(parent);
err = AuWbrCopyup(au_sbi(sb), dentry);
@@ -255,7 +261,7 @@ int au_ready_to_write(struct file *file, loff_t len, struct au_pin *pin)
goto out_dgrade;
err = 0;
- if (!au_h_dptr(parent, bcpup)) {
+ if (!d_unhashed(dentry) && !au_h_dptr(parent, bcpup)) {
err = au_cpup_dirs(dentry, bcpup);
if (unlikely(err))
goto out_dgrade;
@@ -268,25 +274,43 @@ int au_ready_to_write(struct file *file, loff_t len, struct au_pin *pin)
h_dentry = au_hf_top(file)->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 */) {
+ dbstart = au_dbstart(dentry);
+ if (dbstart <= bcpup) {
+ h_dentry = au_h_dptr(dentry, bcpup);
+ AuDebugOn(!h_dentry);
+ h_inode = h_dentry->d_inode;
+ AuDebugOn(!h_inode);
+ bstart = bcpup;
+ }
+
+ if (dbstart <= bcpup /* just reopen */
+ || !d_unhashed(dentry) /* copyup and reopen */
+ ) {
+ 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 {
+ di_downgrade_lock(parent, AuLock_IR);
+ if (dbstart > 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);
+ } else { /* copyup as wh and reopen */
+ /*
+ * since writable hfsplus branch is not supported,
+ * h_open_pre/post() are unnecessary.
+ */
+ mutex_lock_nested(&h_inode->i_mutex, AuLsc_I_CHILD);
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);
}
- mutex_unlock(&h_inode->i_mutex);
- au_h_open_post(dentry, bstart, h_file);
if (!err) {
au_pin_set_parent_lflag(pin, /*lflag*/0);
@@ -351,7 +375,7 @@ static int au_file_refresh_by_inode(struct file *file, int *need_reopen)
sb = dentry->d_sb;
inode = dentry->d_inode;
bstart = au_ibstart(inode);
- if (bstart == finfo->fi_btop)
+ if (bstart == finfo->fi_btop || IS_ROOT(dentry))
goto out;
parent = dget_parent(dentry);
@@ -549,16 +573,13 @@ 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(inode)) {
+ if (au_digen_test(dentry, sigen)) {
err = au_reval_dpath(dentry, sigen);
- if (unlikely(err < 0))
- goto out;
- AuDebugOn(au_digen(dentry) != sigen
- || au_iigen(inode) != sigen);
+ AuDebugOn(!err && au_digen_test(dentry, sigen));
}
- err = refresh_file(file, reopen);
+ if (!err)
+ err = refresh_file(file, reopen);
if (!err) {
if (!wlock) {
di_downgrade_lock(dentry, AuLock_IR);
diff --git a/ubuntu/aufs/hfsnotify.c b/ubuntu/aufs/hfsnotify.c
index 621b5380704..eaed1f12395 100644
--- a/ubuntu/aufs/hfsnotify.c
+++ b/ubuntu/aufs/hfsnotify.c
@@ -25,7 +25,6 @@
/* FS_IN_IGNORED is unnecessary */
static const __u32 AuHfsnMask = (FS_MOVED_TO | FS_MOVED_FROM | FS_DELETE
| FS_CREATE | FS_EVENT_ON_CHILD);
-static struct fsnotify_group *au_hfsn_group;
static DECLARE_WAIT_QUEUE_HEAD(au_hfsn_wq);
static void au_hfsn_free_mark(struct fsnotify_mark *mark)
@@ -38,10 +37,18 @@ static void au_hfsn_free_mark(struct fsnotify_mark *mark)
wake_up_all(&au_hfsn_wq);
}
-static int au_hfsn_alloc(struct au_hnotify *hn, struct inode *h_inode)
+static int au_hfsn_alloc(struct au_hinode *hinode)
{
+ struct au_hnotify *hn;
+ struct super_block *sb;
+ struct au_branch *br;
struct fsnotify_mark *mark;
+ aufs_bindex_t bindex;
+ hn = hinode->hi_notify;
+ sb = hn->hn_aufs_inode->i_sb;
+ bindex = au_br_index(sb, hinode->hi_id);
+ br = au_sbr(sb, bindex);
hn->hn_mark_dead = 0;
mark = &hn->hn_mark;
fsnotify_init_mark(mark, au_hfsn_free_mark);
@@ -50,14 +57,16 @@ static int au_hfsn_alloc(struct au_hnotify *hn, struct inode *h_inode)
* by udba rename or rmdir, aufs assign a new inode to the known
* h_inode, so specify 1 to allow dups.
*/
- return fsnotify_add_mark(mark, au_hfsn_group, h_inode, /*mnt*/NULL,
- /*allow_dups*/1);
+ return fsnotify_add_mark(mark, br->br_hfsn_group, hinode->hi_inode,
+ /*mnt*/NULL, /*allow_dups*/1);
}
-static void au_hfsn_free(struct au_hnotify *hn)
+static void au_hfsn_free(struct au_hinode *hinode)
{
+ struct au_hnotify *hn;
struct fsnotify_mark *mark;
+ hn = hinode->hi_notify;
mark = &hn->hn_mark;
fsnotify_destroy_mark(mark);
fsnotify_put_mark(mark);
@@ -167,6 +176,7 @@ out:
return err;
}
+/* isn't it waste to ask every registered 'group'? */
/* copied from linux/fs/notify/inotify/inotify_fsnotiry.c */
/* it should be exported to modules */
static bool au_hfsn_should_send_event(struct fsnotify_group *group,
@@ -186,31 +196,52 @@ static struct fsnotify_ops au_hfsn_ops = {
/* ---------------------------------------------------------------------- */
-static int __init au_hfsn_init(void)
+static void au_hfsn_fin_br(struct au_branch *br)
+{
+ if (br->br_hfsn_group)
+ fsnotify_put_group(br->br_hfsn_group);
+}
+
+static int au_hfsn_init_br(struct au_branch *br, int perm)
+{
+ br->br_hfsn_group = NULL;
+ br->br_hfsn_ops = au_hfsn_ops;
+ return 0;
+}
+
+static int au_hfsn_reset_br(unsigned int udba, struct au_branch *br, int perm)
{
int err;
err = 0;
- au_hfsn_group = fsnotify_alloc_group(&au_hfsn_ops);
- if (IS_ERR(au_hfsn_group)) {
- err = PTR_ERR(au_hfsn_group);
+ if (udba != AuOpt_UDBA_HNOTIFY
+ || !au_br_hnotifyable(perm)) {
+ au_hfsn_fin_br(br);
+ br->br_hfsn_group = NULL;
+ goto out;
+ }
+
+ if (br->br_hfsn_group)
+ goto out;
+
+ br->br_hfsn_group = fsnotify_alloc_group(&br->br_hfsn_ops);
+ if (IS_ERR(br->br_hfsn_group)) {
+ err = PTR_ERR(br->br_hfsn_group);
pr_err("fsnotify_alloc_group() failed, %d\n", err);
+ br->br_hfsn_group = NULL;
}
+out:
AuTraceErr(err);
return err;
}
-static void au_hfsn_fin(void)
-{
- fsnotify_put_group(au_hfsn_group);
-}
-
const struct au_hnotify_op au_hnotify_op = {
.ctl = au_hfsn_ctl,
.alloc = au_hfsn_alloc,
.free = au_hfsn_free,
- .fin = au_hfsn_fin,
- .init = au_hfsn_init
+ .reset_br = au_hfsn_reset_br,
+ .fin_br = au_hfsn_fin_br,
+ .init_br = au_hfsn_init_br
};
diff --git a/ubuntu/aufs/hnotify.c b/ubuntu/aufs/hnotify.c
index 535a5ceeec9..68279f9fa04 100644
--- a/ubuntu/aufs/hnotify.c
+++ b/ubuntu/aufs/hnotify.c
@@ -22,8 +22,7 @@
#include "aufs.h"
-int au_hn_alloc(struct au_hinode *hinode, struct inode *inode,
- struct inode *h_inode)
+int au_hn_alloc(struct au_hinode *hinode, struct inode *inode)
{
int err;
struct au_hnotify *hn;
@@ -32,10 +31,11 @@ int au_hn_alloc(struct au_hinode *hinode, struct inode *inode,
hn = au_cache_alloc_hnotify();
if (hn) {
hn->hn_aufs_inode = inode;
- err = au_hnotify_op.alloc(hn, h_inode);
- if (!err)
- hinode->hi_notify = hn;
- else {
+ hinode->hi_notify = hn;
+ err = au_hnotify_op.alloc(hinode);
+ AuTraceErr(err);
+ if (unlikely(err)) {
+ hinode->hi_notify = NULL;
au_cache_free_hnotify(hn);
/*
* The upper dir was removed by udba, but the same named
@@ -48,6 +48,7 @@ int au_hn_alloc(struct au_hinode *hinode, struct inode *inode,
}
}
+ AuTraceErr(err);
return err;
}
@@ -57,7 +58,7 @@ void au_hn_free(struct au_hinode *hinode)
hn = hinode->hi_notify;
if (hn) {
- au_hnotify_op.free(hn);
+ au_hnotify_op.free(hinode);
au_cache_free_hnotify(hn);
hinode->hi_notify = NULL;
}
@@ -170,7 +171,6 @@ static int hn_gen_tree(struct dentry *dentry)
if (IS_ROOT(d))
continue;
- d_drop(d);
au_digen_dec(d);
if (d->d_inode)
/* todo: reset children xino?
@@ -216,15 +216,12 @@ static int hn_gen_by_inode(char *name, unsigned int nlen, struct inode *inode,
&& 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);
+ au_fset_si(au_sbi(inode->i_sb), FAILED_REFRESH_DIR);
d = d_find_alias(inode);
if (!d) {
au_iigen_dec(inode);
@@ -257,12 +254,11 @@ static int hn_gen_by_name(struct dentry *dentry, const unsigned int isdir)
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);
+ au_fset_si(au_sbi(dentry->d_sb), FAILED_REFRESH_DIR);
if (inode)
err = hn_gen_tree(dentry);
}
@@ -376,12 +372,12 @@ static struct dentry *lookup_wlock_by_name(char *name, unsigned int nlen,
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);
+ if (au_di(d))
+ au_digen_dec(d);
+ else
+ continue;
+ if (!atomic_read(&d->d_count))
continue;
- }
dentry = dget(d);
break;
@@ -498,7 +494,7 @@ static void au_hn_bh(void *_args)
args.h_nlen = a->h_child_nlen;
err = hn_job(&args);
if (dentry) {
- if (dentry->d_fsdata)
+ if (au_di(dentry))
di_write_unlock(dentry);
dput(dentry);
}
@@ -520,12 +516,11 @@ static void au_hn_bh(void *_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);
+ si_write_unlock(sb);
+ au_nwt_done(&sbinfo->si_nowait);
kfree(a);
}
@@ -634,6 +629,38 @@ out:
return err;
}
+/* ---------------------------------------------------------------------- */
+
+int au_hnotify_reset_br(unsigned int udba, struct au_branch *br, int perm)
+{
+ int err;
+
+ AuDebugOn(!(udba & AuOptMask_UDBA));
+
+ err = 0;
+ if (au_hnotify_op.reset_br)
+ err = au_hnotify_op.reset_br(udba, br, perm);
+
+ return err;
+}
+
+int au_hnotify_init_br(struct au_branch *br, int perm)
+{
+ int err;
+
+ err = 0;
+ if (au_hnotify_op.init_br)
+ err = au_hnotify_op.init_br(br, perm);
+
+ return err;
+}
+
+void au_hnotify_fin_br(struct au_branch *br)
+{
+ if (au_hnotify_op.fin_br)
+ au_hnotify_op.fin_br(br);
+}
+
static void au_hn_destroy_cache(void)
{
kmem_cache_destroy(au_cachep[AuCache_HNOTIFY]);
@@ -647,7 +674,9 @@ int __init au_hnotify_init(void)
err = -ENOMEM;
au_cachep[AuCache_HNOTIFY] = AuCache(au_hnotify);
if (au_cachep[AuCache_HNOTIFY]) {
- err = au_hnotify_op.init();
+ err = 0;
+ if (au_hnotify_op.init)
+ err = au_hnotify_op.init();
if (unlikely(err))
au_hn_destroy_cache();
}
@@ -657,7 +686,8 @@ int __init au_hnotify_init(void)
void au_hnotify_fin(void)
{
- au_hnotify_op.fin();
+ if (au_hnotify_op.fin)
+ au_hnotify_op.fin();
/* cf. au_cache_fin() */
if (au_cachep[AuCache_HNOTIFY])
au_hn_destroy_cache();
diff --git a/ubuntu/aufs/i_op.c b/ubuntu/aufs/i_op.c
index bbda6e4a2f2..dddcaca16a9 100644
--- a/ubuntu/aufs/i_op.c
+++ b/ubuntu/aufs/i_op.c
@@ -95,6 +95,11 @@ static int aufs_permission(struct inode *inode, int mask)
sb = inode->i_sb;
si_read_lock(sb, AuLock_FLUSH);
ii_read_lock_child(inode);
+#if 0
+ err = au_iigen_test(inode, au_sigen(sb));
+ if (unlikely(err))
+ goto out;
+#endif
if (!isdir || write_mask) {
err = au_busy_or_stale();
@@ -170,11 +175,18 @@ static struct dentry *aufs_lookup(struct inode *dir, struct dentry *dentry,
if (unlikely(err))
goto out_si;
+ npositive = 0; /* suppress a warning */
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);
+ err = au_alive_dir(parent);
+ if (!err)
+ err = au_digen_test(parent, au_sigen(sb));
+ if (!err) {
+ npositive = au_lkup_dentry(dentry, au_dbstart(parent),
+ /*type*/0, nd);
+ err = npositive;
+ }
di_read_unlock(parent, AuLock_IR);
- err = npositive;
ret = ERR_PTR(err);
if (unlikely(err < 0))
goto out_unlock;
@@ -211,10 +223,9 @@ static int au_wr_dir_cpup(struct dentry *dentry, struct dentry *parent,
struct dentry *h_parent;
struct inode *h_dir;
- if (add_entry) {
- au_update_dbstart(dentry);
+ if (add_entry)
IMustLock(parent->d_inode);
- } else
+ else
di_write_lock_parent(parent);
err = 0;
@@ -231,8 +242,11 @@ static int au_wr_dir_cpup(struct dentry *dentry, struct dentry *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);
+
+ AuDbg("bcpup %d\n", bcpup);
+ if (!err) {
+ if (!dentry->d_inode)
+ au_set_h_dptr(dentry, bstart, NULL);
au_update_dbrange(dentry, /*do_put_zero*/0);
}
}
@@ -242,6 +256,7 @@ static int au_wr_dir_cpup(struct dentry *dentry, struct dentry *parent,
if (!err)
err = bcpup; /* success */
+ AuTraceErr(err);
return err;
}
@@ -296,15 +311,22 @@ int au_wr_dir(struct dentry *dentry, struct dentry *src_dentry,
bcpup = args->force_btgt;
AuDebugOn(au_test_ro(sb, bcpup, dentry->d_inode));
}
+
AuDbg("bstart %d, bcpup %d\n", bstart, bcpup);
err = bcpup;
if (bcpup == bstart)
goto out; /* success */
- else if (bstart < bcpup)
- au_update_dbrange(dentry, /*do_put_zero*/1);
/* copyup the new parent into the branch we process */
err = au_wr_dir_cpup(dentry, parent, add_entry, bcpup, bstart);
+ if (err >= 0) {
+ if (!dentry->d_inode) {
+ au_set_h_dptr(dentry, bstart, NULL);
+ au_set_dbstart(dentry, bcpup);
+ au_set_dbend(dentry, bcpup);
+ }
+ AuDebugOn(add_entry && !au_h_dptr(dentry, bcpup));
+ }
out:
dput(parent);
@@ -455,6 +477,7 @@ int au_pin(struct au_pin *pin, struct dentry *dentry, aufs_bindex_t bindex,
* unhashed.
* for ->setattr(), ia->ia_file is passed from ftruncate only.
*/
+/* todo: consolidate with do_refresh() and simple_reval_dpath() */
static int au_reval_for_attr(struct dentry *dentry, unsigned int sigen)
{
int err;
@@ -463,13 +486,10 @@ static int au_reval_for_attr(struct dentry *dentry, unsigned int sigen)
err = 0;
inode = dentry->d_inode;
- if (au_digen(dentry) != sigen || au_iigen(inode) != sigen) {
+ if (au_digen_test(dentry, 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);
+ err = au_refresh_dentry(dentry, parent);
di_read_unlock(parent, AuLock_IR);
dput(parent);
}
@@ -515,7 +535,7 @@ static int au_pin_and_icpup(struct dentry *dentry, struct iattr *ia,
au_fset_wrdir(wr_dir_args.flags, ISDIR);
/* plink or hi_wh() case */
ibstart = au_ibstart(inode);
- if (bstart != ibstart)
+ if (bstart != ibstart && !au_test_ro(inode->i_sb, ibstart, inode))
wr_dir_args.force_btgt = ibstart;
err = au_wr_dir(dentry, /*src_dentry*/NULL, &wr_dir_args);
if (unlikely(err < 0))
@@ -692,6 +712,8 @@ static int aufs_setattr(struct dentry *dentry, struct iattr *ia)
out_unlock:
mutex_unlock(&a->h_inode->i_mutex);
au_unpin(&a->pin);
+ if (unlikely(err))
+ au_update_dbstart(dentry);
out_dentry:
di_write_unlock(dentry);
if (file) {
@@ -753,12 +775,18 @@ static int aufs_getattr(struct vfsmount *mnt __maybe_unused,
/* support fstat(2) */
if (!au_d_removed(dentry) && !udba_none) {
unsigned int sigen = au_sigen(sb);
- if (au_digen(dentry) == sigen && au_iigen(inode) == sigen)
+ err = au_digen_test(dentry, sigen);
+ if (!err) {
di_read_lock_child(dentry, AuLock_IR);
- else {
+ err = au_dbrange_test(dentry);
+ if (unlikely(err))
+ goto out_unlock;
+ } else {
AuDebugOn(IS_ROOT(dentry));
di_write_lock_child(dentry);
- err = au_reval_for_attr(dentry, sigen);
+ err = au_dbrange_test(dentry);
+ if (!err)
+ err = au_reval_for_attr(dentry, sigen);
di_downgrade_lock(dentry, AuLock_IR);
if (unlikely(err))
goto out_unlock;
@@ -839,10 +867,15 @@ 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);
+ err = aufs_read_lock(dentry, AuLock_IR | AuLock_GEN);
+ if (unlikely(err))
+ goto out;
+ err = au_d_hashed_positive(dentry);
+ if (!err)
+ err = h_readlink(dentry, au_dbstart(dentry), buf, bufsiz);
aufs_read_unlock(dentry, AuLock_IR);
+out:
return err;
}
@@ -860,11 +893,17 @@ static void *aufs_follow_link(struct dentry *dentry, struct nameidata *nd)
if (unlikely(!buf.k))
goto out;
- aufs_read_lock(dentry, AuLock_IR);
- old_fs = get_fs();
- set_fs(KERNEL_DS);
- err = h_readlink(dentry, au_dbstart(dentry), buf.u, PATH_MAX);
- set_fs(old_fs);
+ err = aufs_read_lock(dentry, AuLock_IR | AuLock_GEN);
+ if (unlikely(err))
+ goto out_name;
+
+ err = au_d_hashed_positive(dentry);
+ if (!err) {
+ old_fs = get_fs();
+ set_fs(KERNEL_DS);
+ err = h_readlink(dentry, au_dbstart(dentry), buf.u, PATH_MAX);
+ set_fs(old_fs);
+ }
aufs_read_unlock(dentry, AuLock_IR);
if (err >= 0) {
@@ -873,8 +912,9 @@ static void *aufs_follow_link(struct dentry *dentry, struct nameidata *nd)
nd_set_link(nd, buf.k);
return NULL; /* success */
}
- __putname(buf.k);
+out_name:
+ __putname(buf.k);
out:
path_put(&nd->path);
AuTraceErr(err);
diff --git a/ubuntu/aufs/i_op_add.c b/ubuntu/aufs/i_op_add.c
index 18635718325..cd11360361d 100644
--- a/ubuntu/aufs/i_op_add.c
+++ b/ubuntu/aufs/i_op_add.c
@@ -81,6 +81,18 @@ out:
return err;
}
+static int au_d_may_add(struct dentry *dentry)
+{
+ int err;
+
+ err = 0;
+ if (unlikely(d_unhashed(dentry)))
+ err = -ENOENT;
+ if (unlikely(dentry->d_inode))
+ err = -EEXIST;
+ return err;
+}
+
/*
* simple tests for the adding inode operations.
* following the checks in vfs, plus the parent-child relationship.
@@ -236,13 +248,18 @@ static int add_simple(struct inode *dir, struct dentry *dentry,
IMustLock(dir);
parent = dentry->d_parent; /* dir inode is locked */
- aufs_read_lock(dentry, AuLock_DW);
+ err = aufs_read_lock(dentry, AuLock_DW | AuLock_GEN);
+ if (unlikely(err))
+ goto out;
+ err = au_d_may_add(dentry);
+ if (unlikely(err))
+ goto out_unlock;
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;
+ goto out_parent;
bstart = au_dbstart(dentry);
h_path.dentry = au_h_dptr(dentry, bstart);
@@ -275,19 +292,20 @@ static int add_simple(struct inode *dir, struct dentry *dentry,
err = -EIO;
}
au_dtime_revert(&dt);
- d_drop(dentry);
}
au_unpin(&pin);
dput(wh_dentry);
-out:
+out_parent:
+ di_write_unlock(parent);
+out_unlock:
if (unlikely(err)) {
au_update_dbstart(dentry);
d_drop(dentry);
}
- di_write_unlock(parent);
aufs_read_unlock(dentry, AuLock_DW);
+out:
return err;
}
@@ -456,19 +474,22 @@ int aufs_link(struct dentry *src_dentry, struct inode *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 */
- err = aufs_read_and_write_lock2(dentry, src_dentry, AuLock_NOPLM);
+ err = aufs_read_and_write_lock2(dentry, src_dentry,
+ AuLock_NOPLM | AuLock_GEN);
if (unlikely(err))
goto out_kfree;
+ err = au_d_hashed_positive(src_dentry);
+ if (unlikely(err))
+ goto out_unlock;
+ err = au_d_may_add(dentry);
+ if (unlikely(err))
+ goto out_unlock;
a->src_parent = dget_parent(src_dentry);
wr_dir_args.force_btgt = au_dbstart(src_dentry);
@@ -479,7 +500,7 @@ int aufs_link(struct dentry *src_dentry, struct inode *dir,
&wr_dir_args);
err = PTR_ERR(wh_dentry);
if (IS_ERR(wh_dentry))
- goto out_unlock;
+ goto out_parent;
err = 0;
sb = dentry->d_sb;
@@ -539,34 +560,32 @@ int aufs_link(struct dentry *src_dentry, struct inode *dir,
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
+ d_instantiate(dentry, au_igrab(inode));
+ if (d_unhashed(a->h_path.dentry))
/* 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);
+ if (unlikely(rerr)) {
+ AuIOErr("%.*s reverting failed(%d, %d)\n",
+ AuDLNPair(dentry), err, rerr);
+ err = -EIO;
+ }
au_dtime_revert(&dt);
out_unpin:
au_unpin(&a->pin);
out_wh:
dput(wh_dentry);
+out_parent:
+ di_write_unlock(a->parent);
+ dput(a->src_parent);
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);
out_kfree:
kfree(a);
@@ -599,14 +618,20 @@ int aufs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
if (unlikely(!a))
goto out;
- aufs_read_lock(dentry, AuLock_DW);
+ err = aufs_read_lock(dentry, AuLock_DW | AuLock_GEN);
+ if (unlikely(err))
+ goto out_free;
+ err = au_d_may_add(dentry);
+ if (unlikely(err))
+ goto out_unlock;
+
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;
+ goto out_parent;
sb = dentry->d_sb;
bindex = au_dbstart(dentry);
@@ -614,7 +639,7 @@ int aufs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
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;
+ goto out_unpin;
/* make the dir opaque */
diropq = 0;
@@ -634,7 +659,7 @@ int aufs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
err = epilog(dir, bindex, wh_dentry, dentry);
if (!err) {
inc_nlink(dir);
- goto out_unlock; /* success */
+ goto out_unpin; /* success */
}
/* revert */
@@ -658,18 +683,19 @@ out_dir:
AuDLNPair(dentry), err, rerr);
err = -EIO;
}
- d_drop(dentry);
au_dtime_revert(&a->dt);
-out_unlock:
+out_unpin:
au_unpin(&a->pin);
dput(wh_dentry);
-out_free:
+out_parent:
+ di_write_unlock(parent);
+out_unlock:
if (unlikely(err)) {
au_update_dbstart(dentry);
d_drop(dentry);
}
- di_write_unlock(parent);
aufs_read_unlock(dentry, AuLock_DW);
+out_free:
kfree(a);
out:
return err;
diff --git a/ubuntu/aufs/i_op_del.c b/ubuntu/aufs/i_op_del.c
index 5b31bbd8876..1019bf91aea 100644
--- a/ubuntu/aufs/i_op_del.c
+++ b/ubuntu/aufs/i_op_del.c
@@ -59,24 +59,20 @@ int au_wr_dir_need_wh(struct dentry *dentry, int isdir, aufs_bindex_t *bcpup)
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);
+ struct au_dinfo *dinfo, *tmp;
+
+ need_wh = -ENOMEM;
+ dinfo = au_di(dentry);
+ tmp = au_di_alloc(sb, AuLsc_DI_TMP);
+ if (tmp) {
+ au_di_cp(tmp, dinfo);
+ au_di_swap(tmp, dinfo);
+ /* returns the number of positive dentries */
+ need_wh = au_lkup_dentry(dentry, bstart + 1, /*type*/0,
+ /*nd*/NULL);
+ au_di_swap(tmp, dinfo);
+ au_rw_write_unlock(&tmp->di_rwsem);
+ au_di_free(tmp);
}
}
AuDbg("need_wh %d\n", need_wh);
@@ -268,10 +264,6 @@ static void epilog(struct inode *dir, struct dentry *dentry,
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++;
@@ -315,22 +307,28 @@ int aufs_unlink(struct inode *dir, struct dentry *dentry)
struct dentry *parent, *wh_dentry;
IMustLock(dir);
+
+ err = aufs_read_lock(dentry, AuLock_DW | AuLock_GEN);
+ if (unlikely(err))
+ goto out;
+ err = au_d_hashed_positive(dentry);
+ if (unlikely(err))
+ goto out_unlock;
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);
+ err = -EISDIR;
+ if (unlikely(S_ISDIR(inode->i_mode)))
+ goto out_unlock; /* possible? */
bstart = au_dbstart(dentry);
bwh = au_dbwh(dentry);
bindex = -1;
+ parent = dentry->d_parent; /* dir inode is locked */
+ di_write_lock_parent(parent);
wh_dentry = lock_hdir_create_wh(dentry, /*isdir*/0, &bindex, &dt, &pin);
err = PTR_ERR(wh_dentry);
if (IS_ERR(wh_dentry))
- goto out;
+ goto out_parent;
h_path.mnt = au_sbr_mnt(dentry->d_sb, bstart);
h_path.dentry = au_h_dptr(dentry, bstart);
@@ -356,7 +354,7 @@ int aufs_unlink(struct inode *dir, struct dentry *dentry)
} else
/* todo: this timestamp may be reverted later */
inode->i_ctime = h_dir->i_ctime;
- goto out_unlock; /* success */
+ goto out_unpin; /* success */
}
/* revert */
@@ -368,13 +366,15 @@ int aufs_unlink(struct inode *dir, struct dentry *dentry)
err = rerr;
}
-out_unlock:
+out_unpin:
au_unpin(&pin);
dput(wh_dentry);
dput(h_path.dentry);
-out:
+out_parent:
di_write_unlock(parent);
+out_unlock:
aufs_read_unlock(dentry, AuLock_DW);
+out:
return err;
}
@@ -389,13 +389,22 @@ int aufs_rmdir(struct inode *dir, struct dentry *dentry)
struct au_whtmp_rmdir *args;
IMustLock(dir);
- inode = dentry->d_inode;
- err = -ENOENT; /* possible? */
- if (unlikely(!inode))
+
+ err = aufs_read_lock(dentry, AuLock_DW | AuLock_FLUSH | AuLock_GEN);
+ if (unlikely(err))
goto out;
+
+ /* VFS already unhashes it */
+ inode = dentry->d_inode;
+ err = -ENOENT;
+ if (unlikely(!inode || !inode->i_nlink
+ || IS_DEADDIR(inode)))
+ goto out_unlock;
IMustLock(inode);
+ err = -ENOTDIR;
+ if (unlikely(!S_ISDIR(inode->i_mode)))
+ goto out_unlock; /* possible? */
- aufs_read_lock(dentry, AuLock_DW | AuLock_FLUSH);
err = -ENOMEM;
args = au_whtmp_rmdir_alloc(dir->i_sb, GFP_NOFS);
if (unlikely(!args))
@@ -405,7 +414,7 @@ int aufs_rmdir(struct inode *dir, struct dentry *dentry)
di_write_lock_parent(parent);
err = au_test_empty(dentry, &args->whlist);
if (unlikely(err))
- goto out_args;
+ goto out_parent;
bstart = au_dbstart(dentry);
bwh = au_dbwh(dentry);
@@ -413,7 +422,7 @@ int aufs_rmdir(struct inode *dir, struct dentry *dentry)
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;
+ goto out_parent;
h_dentry = au_h_dptr(dentry, bstart);
dget(h_dentry);
@@ -434,7 +443,7 @@ int aufs_rmdir(struct inode *dir, struct dentry *dentry)
}
if (!err) {
- clear_nlink(inode);
+ vfsub_dead_dir(inode);
au_set_dbdiropq(dentry, -1);
epilog(dir, dentry, bindex);
@@ -460,7 +469,7 @@ out_unpin:
au_unpin(&pin);
dput(wh_dentry);
dput(h_dentry);
-out_args:
+out_parent:
di_write_unlock(parent);
if (args)
au_whtmp_rmdir_free(args);
diff --git a/ubuntu/aufs/i_op_ren.c b/ubuntu/aufs/i_op_ren.c
index 89efe679fea..e1d23928cf7 100644
--- a/ubuntu/aufs/i_op_ren.c
+++ b/ubuntu/aufs/i_op_ren.c
@@ -79,7 +79,7 @@ struct au_ren_args {
struct au_hinode *src_hinode;
struct path h_path;
struct au_nhash whlist;
- aufs_bindex_t btgt;
+ aufs_bindex_t btgt, src_bwh, src_bdiropq;
unsigned int flags;
@@ -110,6 +110,7 @@ static void au_ren_rev_diropq(int err, struct au_ren_args *a)
au_hn_imtx_lock_nested(a->src_hinode, AuLsc_I_CHILD);
rerr = au_diropq_remove(a->src_dentry, a->btgt);
au_hn_imtx_unlock(a->src_hinode);
+ au_set_dbdiropq(a->src_dentry, a->src_bdiropq);
if (rerr)
RevertFailure("remove diropq %.*s", AuDLNPair(a->src_dentry));
}
@@ -180,31 +181,10 @@ static void au_ren_rev_whsrc(int err, struct au_ren_args *a)
a->h_path.dentry = a->src_wh_dentry;
rerr = au_wh_unlink_dentry(a->src_h_dir, &a->h_path, a->src_dentry);
+ au_set_dbwh(a->src_dentry, a->src_bwh);
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
/* ---------------------------------------------------------------------- */
@@ -254,6 +234,9 @@ static int au_ren_or_cpup(struct au_ren_args *a)
au_set_dbstart(d, a->src_bstart);
}
}
+ if (!err && a->h_dst)
+ /* it will be set to dinfo later */
+ dget(a->h_dst);
return err;
}
@@ -292,6 +275,7 @@ static int au_ren_diropq(struct au_ren_args *a)
struct dentry *diropq;
err = 0;
+ a->src_bdiropq = au_dbdiropq(a->src_dentry);
a->src_hinode = au_hi(a->src_inode, a->btgt);
au_hn_imtx_lock_nested(a->src_hinode, AuLsc_I_CHILD);
diropq = au_diropq_create(a->src_dentry, a->btgt);
@@ -320,6 +304,8 @@ static int do_rename(struct au_ren_args *a)
/* create whiteout for src_dentry */
if (au_ftest_ren(a->flags, WHSRC)) {
+ a->src_bwh = au_dbwh(a->src_dentry);
+ AuDebugOn(a->src_bwh >= 0);
a->src_wh_dentry
= au_wh_create(a->src_dentry, a->btgt, a->src_h_parent);
err = PTR_ERR(a->src_wh_dentry);
@@ -425,6 +411,7 @@ out_rename:
au_ren_rev_rename(err, a);
else
au_ren_rev_cpup(err, a);
+ dput(a->h_dst);
out_whtmp:
if (a->thargs)
au_ren_rev_whtmp(err, a);
@@ -434,7 +421,6 @@ out_whdst:
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);
@@ -685,11 +671,8 @@ static void au_ren_refresh_dir(struct au_ren_args *a)
/* 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);
@@ -711,6 +694,31 @@ static void au_ren_refresh(struct au_ren_args *a)
struct inode *i, *h_i;
struct super_block *sb;
+ d = a->dst_dentry;
+ d_drop(d);
+ if (a->h_dst)
+ /* already dget-ed by au_ren_or_cpup() */
+ au_set_h_dptr(d, a->btgt, a->h_dst);
+
+ i = a->dst_inode;
+ if (i) {
+ if (!au_ftest_ren(a->flags, ISDIR))
+ vfsub_drop_nlink(i);
+ else {
+ vfsub_dead_dir(i);
+ au_cpup_attr_timesizes(i);
+ }
+ au_update_dbrange(d, /*do_put_zero*/1);
+ } else {
+ bend = a->btgt;
+ for (bindex = au_dbstart(d); bindex < bend; bindex++)
+ au_set_h_dptr(d, bindex, NULL);
+ bend = au_dbend(d);
+ for (bindex = a->btgt + 1; bindex <= bend; bindex++)
+ au_set_h_dptr(d, bindex, NULL);
+ au_update_dbrange(d, /*do_put_zero*/0);
+ }
+
d = a->src_dentry;
au_set_dbwh(d, -1);
bend = au_dbend(d);
@@ -866,7 +874,7 @@ int aufs_rename(struct inode *_src_dir, struct dentry *_src_dentry,
}
err = -ENOTDIR;
- flags = AuLock_FLUSH | AuLock_NOPLM;
+ flags = AuLock_FLUSH | AuLock_NOPLM | AuLock_GEN;
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)))
@@ -879,13 +887,33 @@ int aufs_rename(struct inode *_src_dir, struct dentry *_src_dentry,
if (unlikely(err))
goto out_free;
+ err = au_d_hashed_positive(a->src_dentry);
+ if (unlikely(err))
+ goto out_unlock;
+ err = -ENOENT;
+ if (a->dst_inode) {
+ /*
+ * If it is a dir, VFS unhash dst_dentry before this
+ * function. It means we cannot rely upon d_unhashed().
+ */
+ if (unlikely(!a->dst_inode->i_nlink))
+ goto out_unlock;
+ if (!S_ISDIR(a->dst_inode->i_mode)) {
+ err = au_d_hashed_positive(a->dst_dentry);
+ if (unlikely(err))
+ goto out_unlock;
+ } else if (unlikely(IS_DEADDIR(a->dst_inode)))
+ goto out_unlock;
+ } else if (unlikely(d_unhashed(a->dst_dentry)))
+ goto out_unlock;
+
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;
+ goto out_parent;
a->br = au_sbr(a->dst_dentry->d_sb, a->btgt);
a->h_path.mnt = a->br->br_mnt;
@@ -959,17 +987,24 @@ 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 && a->dst_inode && a->dst_bstart != a->btgt) {
+ AuDbg("bstart %d, btgt %d\n", a->dst_bstart, a->btgt);
+ au_set_h_dptr(a->dst_dentry, a->btgt, NULL);
+ au_set_dbstart(a->dst_dentry, a->dst_bstart);
}
+out_parent:
if (!err)
d_move(a->src_dentry, a->dst_dentry);
+ else {
+ au_update_dbstart(a->dst_dentry);
+ if (!a->dst_inode)
+ d_drop(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);
+out_unlock:
aufs_read_and_write_unlock2(a->dst_dentry, a->src_dentry);
out_free:
iput(a->dst_inode);
diff --git a/ubuntu/aufs/iinfo.c b/ubuntu/aufs/iinfo.c
index 6bccfdf18e4..571b21d25fc 100644
--- a/ubuntu/aufs/iinfo.c
+++ b/ubuntu/aufs/iinfo.c
@@ -75,6 +75,9 @@ void au_set_h_iptr(struct inode *inode, aufs_bindex_t bindex,
struct super_block *sb = inode->i_sb;
struct au_branch *br;
+ AuDebugOn(inode->i_mode
+ && (h_inode->i_mode & S_IFMT)
+ != (inode->i_mode & S_IFMT));
if (bindex == iinfo->ii_bstart)
au_cpup_igen(inode, h_inode);
br = au_sbr(sb, bindex);
@@ -88,7 +91,7 @@ void au_set_h_iptr(struct inode *inode, aufs_bindex_t bindex,
if (au_ftest_hi(flags, HNOTIFY)
&& au_br_hnotifyable(br->br_perm)) {
- err = au_hn_alloc(hinode, inode, h_inode);
+ err = au_hn_alloc(hinode, inode);
if (unlikely(err))
AuIOErr1("au_hn_alloc() %d\n", err);
}
@@ -117,16 +120,15 @@ void au_update_iigen(struct inode *inode)
void au_update_ibrange(struct inode *inode, int do_put_zero)
{
struct au_iinfo *iinfo;
+ aufs_bindex_t bindex, bend;
iinfo = au_ii(inode);
- if (!iinfo || iinfo->ii_bstart < 0)
+ if (!iinfo)
return;
IiMustWriteLock(inode);
- if (do_put_zero) {
- aufs_bindex_t bindex;
-
+ if (do_put_zero && iinfo->ii_bstart >= 0) {
for (bindex = iinfo->ii_bstart; bindex <= iinfo->ii_bend;
bindex++) {
struct inode *h_i;
@@ -138,20 +140,20 @@ void au_update_ibrange(struct inode *inode, int do_put_zero)
}
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)
+ iinfo->ii_bend = -1;
+ bend = au_sbend(inode->i_sb);
+ for (bindex = 0; bindex <= bend; bindex++)
+ if (iinfo->ii_hinode[0 + bindex].hi_inode) {
+ iinfo->ii_bstart = bindex;
break;
- AuDebugOn(iinfo->ii_bstart > iinfo->ii_bend || iinfo->ii_bend < 0);
+ }
+ if (iinfo->ii_bstart >= 0)
+ for (bindex = bend; bindex >= iinfo->ii_bstart; bindex--)
+ if (iinfo->ii_hinode[0 + bindex].hi_inode) {
+ iinfo->ii_bend = bindex;
+ break;
+ }
+ AuDebugOn(iinfo->ii_bstart > iinfo->ii_bend);
}
/* ---------------------------------------------------------------------- */
diff --git a/ubuntu/aufs/inode.c b/ubuntu/aufs/inode.c
index fe4ee9bd626..9fe4d50e20f 100644
--- a/ubuntu/aufs/inode.c
+++ b/ubuntu/aufs/inode.c
@@ -39,37 +39,39 @@ static void au_refresh_hinode_attr(struct inode *inode, int do_version)
inode->i_version++;
}
-int au_refresh_hinode_self(struct inode *inode, int do_attr)
+static int au_ii_refresh(struct inode *inode, int *update)
{
int err, e;
+ umode_t type;
aufs_bindex_t bindex, new_bindex;
- unsigned char update;
- struct au_hinode *p, *q, tmp;
struct super_block *sb;
struct au_iinfo *iinfo;
+ struct au_hinode *p, *q, tmp;
IiMustWriteLock(inode);
- update = 0;
+ *update = 0;
sb = inode->i_sb;
+ type = inode->i_mode & S_IFMT;
iinfo = au_ii(inode);
err = au_ii_realloc(iinfo, au_sbend(sb) + 1);
if (unlikely(err))
goto out;
+ AuDebugOn(iinfo->ii_bstart < 0);
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;
+ AuDebugOn(type != (p->hi_inode->i_mode & S_IFMT));
new_bindex = au_br_index(sb, p->hi_id);
if (new_bindex == bindex)
continue;
if (new_bindex < 0) {
- update = 1;
+ *update = 1;
au_hiput(p);
p->hi_inode = NULL;
continue;
@@ -93,30 +95,43 @@ int au_refresh_hinode_self(struct inode *inode, int do_attr)
e = au_dy_irefresh(inode);
if (unlikely(e && !err))
err = e;
- if (do_attr)
- au_refresh_hinode_attr(inode, update && S_ISDIR(inode->i_mode));
out:
+ AuTraceErr(err);
+ return err;
+}
+
+int au_refresh_hinode_self(struct inode *inode)
+{
+ int err, update;
+
+ err = au_ii_refresh(inode, &update);
+ if (!err)
+ au_refresh_hinode_attr(inode, update && S_ISDIR(inode->i_mode));
+
+ AuTraceErr(err);
return err;
}
int au_refresh_hinode(struct inode *inode, struct dentry *dentry)
{
- int err, e;
+ int err, e, update;
unsigned int flags;
+ umode_t mode;
aufs_bindex_t bindex, bend;
- unsigned char isdir, update;
+ unsigned char isdir;
struct au_hinode *p;
struct au_iinfo *iinfo;
- err = au_refresh_hinode_self(inode, /*do_attr*/0);
+ err = au_ii_refresh(inode, &update);
if (unlikely(err))
goto out;
update = 0;
iinfo = au_ii(inode);
p = iinfo->ii_hinode + iinfo->ii_bstart;
- isdir = S_ISDIR(inode->i_mode);
+ mode = (inode->i_mode & S_IFMT);
+ isdir = S_ISDIR(mode);
flags = au_hi_flags(inode, isdir);
bend = au_dbend(dentry);
for (bindex = au_dbstart(dentry); bindex <= bend; bindex++) {
@@ -127,6 +142,7 @@ int au_refresh_hinode(struct inode *inode, struct dentry *dentry)
if (!h_d || !h_d->d_inode)
continue;
+ AuDebugOn(mode != (h_d->d_inode->i_mode & S_IFMT));
if (iinfo->ii_bstart <= bindex && bindex <= iinfo->ii_bend) {
h_i = au_h_iptr(inode, bindex);
if (h_i) {
@@ -147,7 +163,8 @@ int au_refresh_hinode(struct inode *inode, struct dentry *dentry)
e = au_dy_irefresh(inode);
if (unlikely(e && !err))
err = e;
- au_refresh_hinode_attr(inode, update && isdir);
+ if (!err)
+ au_refresh_hinode_attr(inode, update && isdir);
out:
AuTraceErr(err);
@@ -227,15 +244,18 @@ out:
return err;
}
-/* successful returns with iinfo write_locked */
-static int reval_inode(struct inode *inode, struct dentry *dentry, int *matched)
+/*
+ * successful returns with iinfo write_locked
+ * minus: errno
+ * zero: success, matched
+ * plus: no error, but unmatched
+ */
+static int reval_inode(struct inode *inode, struct dentry *dentry)
{
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.
@@ -245,16 +265,15 @@ static int reval_inode(struct inode *inode, struct dentry *dentry, int *matched)
if (unlikely(inode->i_ino == parent_ino(dentry)))
goto out;
- err = 0;
+ err = 1;
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))
+ if (au_iigen_test(inode, au_digen(dentry)))
err = au_refresh_hinode(inode, dentry);
break;
}
@@ -307,7 +326,7 @@ struct inode *au_new_inode(struct dentry *dentry, int must_new)
struct super_block *sb;
struct mutex *mtx;
ino_t h_ino, ino;
- int err, match;
+ int err;
aufs_bindex_t bstart;
sb = dentry->d_sb;
@@ -355,23 +374,33 @@ new_ino:
goto out; /* success */
}
- ii_write_unlock(inode);
+ /*
+ * iget_failed() calls iput(), but we need to call
+ * ii_write_unlock() after iget_failed(). so dirty hack for
+ * i_count.
+ */
+ atomic_inc(&inode->i_count);
iget_failed(inode);
- goto out_err;
- } else if (!must_new) {
+ ii_write_unlock(inode);
+ au_xino_write(sb, bstart, h_ino, /*ino*/0);
+ /* ignore this error */
+ goto out_iput;
+ } else if (!must_new && !IS_DEADDIR(inode) && inode->i_nlink) {
/*
* horrible race condition between lookup, readdir and copyup
* (or something).
*/
if (mtx)
mutex_unlock(mtx);
- err = reval_inode(inode, dentry, &match);
+ err = reval_inode(inode, dentry);
+ if (unlikely(err < 0)) {
+ mtx = NULL;
+ goto out_iput;
+ }
+
if (!err) {
mtx = NULL;
goto out; /* success */
- } else if (match) {
- mtx = NULL;
- goto out_iput;
} else if (mtx)
mutex_lock(mtx);
}
@@ -392,7 +421,6 @@ new_ino:
out_iput:
iput(inode);
-out_err:
inode = ERR_PTR(err);
out:
if (mtx)
diff --git a/ubuntu/aufs/inode.h b/ubuntu/aufs/inode.h
index ecb91be37d2..9f004a03d93 100644
--- a/ubuntu/aufs/inode.h
+++ b/ubuntu/aufs/inode.h
@@ -109,7 +109,7 @@ static inline struct au_iinfo *au_ii(struct inode *inode)
/* inode.c */
struct inode *au_igrab(struct inode *inode);
-int au_refresh_hinode_self(struct inode *inode, int do_attr);
+int au_refresh_hinode_self(struct inode *inode);
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);
@@ -305,6 +305,13 @@ AuSimpleUnlockRwsemFuncs(ii, struct inode *i, &au_ii(i)->ii_rwsem);
/* ---------------------------------------------------------------------- */
+static inline void au_icntnr_init(struct au_icntnr *c)
+{
+#ifdef CONFIG_AUFS_DEBUG
+ c->vfs_inode.i_mode = 0;
+#endif
+}
+
static inline unsigned int au_iigen(struct inode *inode)
{
return atomic_read(&au_ii(inode)->ii_generation);
@@ -324,9 +331,18 @@ static inline int au_test_higen(struct inode *inode, struct inode *h_inode)
static inline void au_iigen_dec(struct inode *inode)
{
-#ifdef CONFIG_AUFS_HNOTIFY
atomic_dec(&au_ii(inode)->ii_generation);
-#endif
+}
+
+static inline int au_iigen_test(struct inode *inode, unsigned int sigen)
+{
+ int err;
+
+ err = 0;
+ if (unlikely(inode && au_iigen(inode) != sigen))
+ err = -EIO;
+
+ return err;
}
/* ---------------------------------------------------------------------- */
@@ -436,24 +452,31 @@ static inline void au_pin_set_parent(struct au_pin *pin, struct dentry *parent)
/* ---------------------------------------------------------------------- */
+struct au_branch;
#ifdef CONFIG_AUFS_HNOTIFY
struct au_hnotify_op {
void (*ctl)(struct au_hinode *hinode, int do_set);
- int (*alloc)(struct au_hnotify *hn, struct inode *h_inode);
- void (*free)(struct au_hnotify *hn);
+ int (*alloc)(struct au_hinode *hinode);
+ void (*free)(struct au_hinode *hinode);
void (*fin)(void);
int (*init)(void);
+
+ int (*reset_br)(unsigned int udba, struct au_branch *br, int perm);
+ void (*fin_br)(struct au_branch *br);
+ int (*init_br)(struct au_branch *br, int perm);
};
/* hnotify.c */
-int au_hn_alloc(struct au_hinode *hinode, struct inode *inode,
- struct inode *h_inode);
+int au_hn_alloc(struct au_hinode *hinode, struct inode *inode);
void au_hn_free(struct au_hinode *hinode);
void au_hn_ctl(struct au_hinode *hinode, int do_set);
void au_hn_reset(struct inode *inode, unsigned int flags);
int au_hnotify(struct inode *h_dir, struct au_hnotify *hnotify, u32 mask,
struct qstr *h_child_qstr, struct inode *h_child_inode);
+int au_hnotify_reset_br(unsigned int udba, struct au_branch *br, int perm);
+int au_hnotify_init_br(struct au_branch *br, int perm);
+void au_hnotify_fin_br(struct au_branch *br);
int __init au_hnotify_init(void);
void au_hnotify_fin(void);
@@ -469,8 +492,7 @@ void au_hn_init(struct au_hinode *hinode)
#else
static inline
int au_hn_alloc(struct au_hinode *hinode __maybe_unused,
- struct inode *inode __maybe_unused,
- struct inode *h_inode __maybe_unused)
+ struct inode *inode __maybe_unused)
{
return -EOPNOTSUPP;
}
@@ -480,6 +502,12 @@ AuStubVoid(au_hn_ctl, struct au_hinode *hinode __maybe_unused,
int do_set __maybe_unused)
AuStubVoid(au_hn_reset, struct inode *inode __maybe_unused,
unsigned int flags __maybe_unused)
+AuStubInt0(au_hnotify_reset_br, unsigned int udba __maybe_unused,
+ struct au_branch *br __maybe_unused,
+ int perm __maybe_unused)
+AuStubInt0(au_hnotify_init_br, struct au_branch *br __maybe_unused,
+ int perm __maybe_unused)
+AuStubVoid(au_hnotify_fin_br, struct au_branch *br __maybe_unused)
AuStubInt0(__init au_hnotify_init, void)
AuStubVoid(au_hnotify_fin, void)
AuStubVoid(au_hn_init, struct au_hinode *hinode __maybe_unused)
diff --git a/ubuntu/aufs/opts.c b/ubuntu/aufs/opts.c
index bdb2712f628..b41f5a1944c 100644
--- a/ubuntu/aufs/opts.c
+++ b/ubuntu/aufs/opts.c
@@ -299,7 +299,7 @@ static int au_wbr_mfs_sec(substring_t *arg, char *str,
int n, err;
err = 0;
- if (!match_int(arg, &n) && 0 <= n && n <= MAX_SEC_IN_JIFFIES)
+ if (!match_int(arg, &n) && 0 <= n && n <= AUFS_MFS_MAX_SEC)
create->mfs_second = n;
else {
pr_err("bad integer in %s\n", str);
@@ -334,7 +334,7 @@ au_wbr_create_val(char *str, struct au_opt_wbr_create *create)
/*FALLTHROUGH*/
case AuWbrCreate_MFS:
case AuWbrCreate_PMFS:
- create->mfs_second = AUFS_MFS_SECOND_DEF;
+ create->mfs_second = AUFS_MFS_DEF_SEC;
break;
case AuWbrCreate_MFSV:
case AuWbrCreate_PMFSV:
@@ -929,9 +929,16 @@ int au_opts_parse(struct super_block *sb, char *str, struct au_opts *opts)
break;
case Opt_rdcache:
- if (unlikely(match_int(&a->args[0], &opt->rdcache)
- || opt->rdcache > MAX_SEC_IN_JIFFIES))
+ if (unlikely(match_int(&a->args[0], &n))) {
+ pr_err("bad integer in %s\n", opt_str);
+ break;
+ }
+ if (unlikely(n > AUFS_RDCACHE_MAX)) {
+ pr_err("rdcache must be smaller than %d\n",
+ AUFS_RDCACHE_MAX);
break;
+ }
+ opt->rdcache = n;
err = 0;
opt->type = token;
break;
@@ -1265,8 +1272,7 @@ static int au_opt_br(struct super_block *sb, struct au_opt *opt,
au_ftest_opts(opts->flags, REMOUNT));
if (!err) {
err = 1;
- au_fset_opts(opts->flags, REFRESH_DIR);
- au_fset_opts(opts->flags, REFRESH_NONDIR);
+ au_fset_opts(opts->flags, REFRESH);
}
break;
@@ -1277,8 +1283,7 @@ static int au_opt_br(struct super_block *sb, struct au_opt *opt,
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);
+ au_fset_opts(opts->flags, REFRESH);
}
break;
@@ -1289,10 +1294,8 @@ static int au_opt_br(struct super_block *sb, struct au_opt *opt,
&do_refresh);
if (!err) {
err = 1;
- if (do_refresh) {
- au_fset_opts(opts->flags, REFRESH_DIR);
- au_fset_opts(opts->flags, REFRESH_NONDIR);
- }
+ if (do_refresh)
+ au_fset_opts(opts->flags, REFRESH);
}
break;
}
@@ -1451,10 +1454,11 @@ int au_opts_mount(struct super_block *sb, struct au_opts *opts)
{
int err;
unsigned int tmp;
- aufs_bindex_t bend;
+ aufs_bindex_t bindex, bend;
struct au_opt *opt;
struct au_opt_xino *opt_xino, xino;
struct au_sbinfo *sbinfo;
+ struct au_branch *br;
SiMustWriteLock(sb);
@@ -1515,8 +1519,18 @@ int au_opts_mount(struct super_block *sb, struct au_opts *opts)
}
/* restore udba */
+ tmp &= AuOptMask_UDBA;
sbinfo->si_mntflags &= ~AuOptMask_UDBA;
- sbinfo->si_mntflags |= (tmp & AuOptMask_UDBA);
+ sbinfo->si_mntflags |= tmp;
+ bend = au_sbend(sb);
+ for (bindex = 0; bindex <= bend; bindex++) {
+ br = au_sbr(sb, bindex);
+ err = au_hnotify_reset_br(tmp, br, br->br_perm);
+ if (unlikely(err))
+ AuIOErr("hnotify failed on br %d, %d, ignored\n",
+ bindex, err);
+ /* go on even if err */
+ }
if (au_opt_test(tmp, UDBA_HNOTIFY)) {
struct inode *dir = sb->s_root->d_inode;
au_hn_reset(dir, au_hi_flags(dir, /*isdir*/1) & ~AuHi_XINO);
@@ -1565,9 +1579,9 @@ int au_opts_remount(struct super_block *sb, struct au_opts *opts)
}
/* will be handled by the caller */
- if (!au_ftest_opts(opts->flags, REFRESH_DIR)
+ if (!au_ftest_opts(opts->flags, REFRESH)
&& (opts->given_udba || au_opt_test(sbinfo->si_mntflags, XINO)))
- au_fset_opts(opts->flags, REFRESH_DIR);
+ au_fset_opts(opts->flags, REFRESH);
AuDbg("status 0x%x\n", opts->flags);
return err;
diff --git a/ubuntu/aufs/opts.h b/ubuntu/aufs/opts.h
index 03ce3351c49..e788621447d 100644
--- a/ubuntu/aufs/opts.h
+++ b/ubuntu/aufs/opts.h
@@ -170,10 +170,9 @@ struct au_opt {
/* 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 AuOpts_REFRESH_DYAOP (1 << 4)
+#define AuOpts_REFRESH (1 << 1)
+#define AuOpts_TRUNC_XIB (1 << 2)
+#define AuOpts_REFRESH_DYAOP (1 << 3)
#define au_ftest_opts(flags, name) ((flags) & AuOpts_##name)
#define au_fset_opts(flags, name) \
do { (flags) |= AuOpts_##name; } while (0)
diff --git a/ubuntu/aufs/plink.c b/ubuntu/aufs/plink.c
index dd7eb1e49f9..d3995bcf5a5 100644
--- a/ubuntu/aufs/plink.c
+++ b/ubuntu/aufs/plink.c
@@ -67,10 +67,8 @@ int au_plink_maint(struct super_block *sb, int flags)
goto out;
if (au_ftest_lock(flags, NOPLMW)) {
- /*
- * todo: debug by lockdep, if there is no i_mutex lock in VFS,
- * we don't need to wait.
- */
+ /* if there is no i_mutex lock in VFS, we don't need to wait */
+ /* AuDebugOn(!lockdep_depth(current)); */
while (sbi->si_plink_maint_pid) {
si_read_unlock(sb);
/* gave up wake_up_bit() */
diff --git a/ubuntu/aufs/rdu.c b/ubuntu/aufs/rdu.c
index fedbc384a1a..627232894e0 100644
--- a/ubuntu/aufs/rdu.c
+++ b/ubuntu/aufs/rdu.c
@@ -162,14 +162,14 @@ static int au_rdu(struct file *file, struct aufs_rdu *rdu)
if (unlikely(err))
goto out;
#endif
- err = -ENOENT;
- if (unlikely(IS_DEADDIR(inode)))
- goto out_mtx;
arg.sb = inode->i_sb;
err = si_read_lock(arg.sb, AuLock_FLUSH | AuLock_NOPLM);
if (unlikely(err))
goto out_mtx;
+ err = au_alive_dir(dentry);
+ if (unlikely(err))
+ goto out_si;
/* todo: reval? */
fi_read_lock(file);
@@ -215,6 +215,7 @@ static int au_rdu(struct file *file, struct aufs_rdu *rdu)
out_unlock:
fi_read_unlock(file);
+out_si:
si_read_unlock(arg.sb);
out_mtx:
mutex_unlock(&inode->i_mutex);
diff --git a/ubuntu/aufs/sbinfo.c b/ubuntu/aufs/sbinfo.c
index 1eefcb816b3..42783dcd873 100644
--- a/ubuntu/aufs/sbinfo.c
+++ b/ubuntu/aufs/sbinfo.c
@@ -87,7 +87,6 @@ int au_si_alloc(struct super_block *sb)
INIT_RADIX_TREE(&sbinfo->au_si_pid.tree, GFP_ATOMIC | __GFP_NOFAIL);
atomic_long_set(&sbinfo->si_ninodes, 0);
-
atomic_long_set(&sbinfo->si_nfiles, 0);
sbinfo->si_bend = -1;
@@ -221,15 +220,26 @@ int si_write_lock(struct super_block *sb, int flags)
int aufs_read_lock(struct dentry *dentry, int flags)
{
int err;
+ struct super_block *sb;
+
+ sb = dentry->d_sb;
+ err = si_read_lock(sb, flags);
+ if (unlikely(err))
+ goto out;
+
+ if (au_ftest_lock(flags, DW))
+ di_write_lock_child(dentry);
+ else
+ di_read_lock_child(dentry, flags);
- err = si_read_lock(dentry->d_sb, flags);
- if (!err) {
- if (au_ftest_lock(flags, DW))
- di_write_lock_child(dentry);
- else
- di_read_lock_child(dentry, flags);
+ if (au_ftest_lock(flags, GEN)) {
+ err = au_digen_test(dentry, au_sigen(sb));
+ AuDebugOn(!err && au_dbrange_test(dentry));
+ if (unlikely(err))
+ aufs_read_unlock(dentry, flags);
}
+out:
return err;
}
@@ -257,10 +267,29 @@ void aufs_write_unlock(struct dentry *dentry)
int aufs_read_and_write_lock2(struct dentry *d1, struct dentry *d2, int flags)
{
int err;
+ unsigned int sigen;
+ struct super_block *sb;
+
+ sb = d1->d_sb;
+ err = si_read_lock(sb, flags);
+ if (unlikely(err))
+ goto out;
- err = si_read_lock(d1->d_sb, flags);
- if (!err)
- di_write_lock2_child(d1, d2, au_ftest_lock(flags, DIR));
+ di_write_lock2_child(d1, d2, au_ftest_lock(flags, DIR));
+
+ if (au_ftest_lock(flags, GEN)) {
+ sigen = au_sigen(sb);
+ err = au_digen_test(d1, sigen);
+ AuDebugOn(!err && au_dbrange_test(d1));
+ if (!err) {
+ err = au_digen_test(d2, sigen);
+ AuDebugOn(!err && au_dbrange_test(d2));
+ }
+ if (unlikely(err))
+ aufs_read_and_write_unlock2(d1, d2);
+ }
+
+out:
return err;
}
diff --git a/ubuntu/aufs/super.c b/ubuntu/aufs/super.c
index 7aba5f24309..008702ddecb 100644
--- a/ubuntu/aufs/super.c
+++ b/ubuntu/aufs/super.c
@@ -38,6 +38,7 @@ static struct inode *aufs_alloc_inode(struct super_block *sb __maybe_unused)
c = au_cache_alloc_icntnr();
if (c) {
+ au_icntnr_init(c);
c->vfs_inode.i_version = 1; /* sigen(sb); */
c->iinfo.ii_hinode = NULL;
return &c->vfs_inode;
@@ -196,7 +197,7 @@ out:
/* 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;
+ int err;
unsigned int mnt_flags, v;
struct super_block *sb;
struct au_sbinfo *sbinfo;
@@ -254,8 +255,8 @@ static int aufs_show_options(struct seq_file *m, struct vfsmount *mnt)
AuUInt(DIRWH, dirwh, sbinfo->si_dirwh);
- n = jiffies_to_msecs(sbinfo->si_rdcache) / MSEC_PER_SEC;
- AuUInt(RDCACHE, rdcache, n);
+ v = jiffies_to_msecs(sbinfo->si_rdcache) / MSEC_PER_SEC;
+ AuUInt(RDCACHE, rdcache, v);
AuUInt(RDBLK, rdblk, sbinfo->si_rdblk);
AuUInt(RDHASH, rdhash, sbinfo->si_rdhash);
@@ -476,92 +477,84 @@ void au_iarray_free(struct inode **a, unsigned long long max)
/*
* refresh dentry and inode at remount time.
*/
-static int do_refresh(struct dentry *dentry, mode_t type,
- unsigned int dir_flags)
+/* todo: consolidate with simple_reval_dpath() and au_reval_for_attr() */
+static int au_do_refresh(struct dentry *dentry, unsigned int dir_flags,
+ struct dentry *parent)
{
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_hn_reset(inode, dir_flags);
- }
- if (unlikely(err))
- pr_err("unrecoverable error %d, %.*s\n",
- err, AuDLNPair(dentry));
-
+ err = au_refresh_dentry(dentry, parent);
+ if (!err && dir_flags)
+ au_hn_reset(dentry->d_inode, dir_flags);
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)
+static int au_do_refresh_d(struct dentry *dentry, unsigned int sigen,
+ struct au_sbinfo *sbinfo,
+ const unsigned int dir_flags)
{
- return S_ISDIR(dentry->d_inode->i_mode);
+ int err;
+ struct dentry *parent;
+ struct inode *inode;
+
+ err = 0;
+ parent = dget_parent(dentry);
+ if (!au_digen_test(parent, sigen) && au_digen_test(dentry, sigen)) {
+ inode = dentry->d_inode;
+ if (inode) {
+ if (!S_ISDIR(inode->i_mode))
+ err = au_do_refresh(dentry, /*dir_flags*/0,
+ parent);
+ else {
+ err = au_do_refresh(dentry, dir_flags, parent);
+ if (unlikely(err))
+ au_fset_si(sbinfo, FAILED_REFRESH_DIR);
+ }
+ } else
+ err = au_do_refresh(dentry, /*dir_flags*/0, parent);
+ AuDbgDentry(dentry);
+ }
+ dput(parent);
+
+ AuTraceErr(err);
+ return err;
}
-/* gave up consolidating with refresh_nondir() */
-static int refresh_dir(struct dentry *root, unsigned int sigen)
+static int au_refresh_d(struct super_block *sb)
{
int err, i, j, ndentry, e;
+ unsigned int sigen;
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 */
- }
- }
+ struct dentry **dentries, *d;
+ struct au_sbinfo *sbinfo;
+ struct dentry *root = sb->s_root;
+ const unsigned int dir_flags = au_hi_flags(root->d_inode, /*isdir*/1);
- e = au_dpages_init(&dpages, GFP_NOFS);
- if (unlikely(e)) {
- if (!err)
- err = e;
+ err = au_dpages_init(&dpages, GFP_NOFS);
+ if (unlikely(err))
goto out;
- }
- e = au_dcsub_pages(&dpages, root, test_dir, NULL);
- if (unlikely(e)) {
- if (!err)
- err = e;
+ err = au_dcsub_pages(&dpages, root, NULL, NULL);
+ if (unlikely(err))
goto out_dpages;
- }
- for (i = 0; !e && i < dpages.ndpage; i++) {
+ sigen = au_sigen(sb);
+ sbinfo = au_sbi(sb);
+ for (i = 0; i < dpages.ndpage; i++) {
dpage = dpages.dpages + i;
dentries = dpage->dentries;
ndentry = dpage->ndentry;
- for (j = 0; !e && j < ndentry; j++) {
- struct dentry *d;
-
+ for (j = 0; j < ndentry; j++) {
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 */
- }
+ e = au_do_refresh_d(d, sigen, sbinfo, dir_flags);
+ if (unlikely(e && !err))
+ err = e;
+ /* go on even err */
}
}
@@ -571,113 +564,82 @@ out:
return err;
}
-static int test_nondir(struct dentry *dentry, void *arg __maybe_unused)
+static int au_refresh_i(struct super_block *sb)
{
- return !S_ISDIR(dentry->d_inode->i_mode);
-}
+ int err, e;
+ unsigned int sigen;
+ unsigned long long max, ull;
+ struct inode *inode, **array;
-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;
+ array = au_iarray_alloc(sb, &max);
+ err = PTR_ERR(array);
+ if (IS_ERR(array))
+ goto out;
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) {
+ sigen = au_sigen(sb);
+ for (ull = 0; ull < max; ull++) {
+ inode = array[ull];
+ if (au_iigen(inode) != sigen) {
ii_write_lock_child(inode);
- e = au_refresh_hinode_self(inode, /*do_attr*/1);
+ e = au_refresh_hinode_self(inode);
ii_write_unlock(inode);
if (unlikely(e)) {
- AuDbg("e %d, i%lu\n", e, inode->i_ino);
+ pr_err("error %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;
+ au_iarray_free(array, max);
- 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)
+static void au_remount_refresh(struct super_block *sb)
{
- int err;
- unsigned int sigen;
- struct au_sbinfo *sbinfo;
+ int err, e;
+ unsigned int udba;
+ aufs_bindex_t bindex, bend;
struct dentry *root;
struct inode *inode;
+ struct au_branch *br;
au_sigen_inc(sb);
- sigen = au_sigen(sb);
- sbinfo = au_sbi(sb);
- au_fclr_si(sbinfo, FAILED_REFRESH_DIRS);
+ au_fclr_si(au_sbi(sb), FAILED_REFRESH_DIR);
root = sb->s_root;
DiMustNoWaiters(root);
inode = root->d_inode;
IiMustNoWaiters(inode);
- au_hn_reset(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);
+ udba = au_opt_udba(sb);
+ bend = au_sbend(sb);
+ for (bindex = 0; bindex <= bend; bindex++) {
+ br = au_sbr(sb, bindex);
+ err = au_hnotify_reset_br(udba, br, br->br_perm);
if (unlikely(err))
- pr_warning("Refreshing non-directories failed, ignored"
- "(%d)\n", err);
+ AuIOErr("hnotify failed on br %d, %d, ignored\n",
+ bindex, err);
+ /* go on even if err */
}
+ au_hn_reset(inode, au_hi_flags(inode, /*isdir*/1));
+ di_write_unlock(root);
+ err = au_refresh_d(sb);
+ e = au_refresh_i(sb);
+ if (unlikely(e && !err))
+ err = e;
/* aufs_write_lock() calls ..._child() */
di_write_lock_child(root);
- au_cpup_attr_all(root->d_inode, /*force*/1);
+
+ au_cpup_attr_all(inode, /*force*/1);
+
+ if (unlikely(err))
+ AuIOErr("refresh failed, ignored, %d\n", err);
}
/* stop extra interpretation of errno in mount(8), and strange error messages */
@@ -742,9 +704,8 @@ static int aufs_remount_fs(struct super_block *sb, int *flags, char *data)
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);
+ if (au_ftest_opts(opts.flags, REFRESH))
+ au_remount_refresh(sb);
if (au_ftest_opts(opts.flags, REFRESH_DYAOP)) {
mntflags = au_mntflags(sb);
@@ -932,7 +893,7 @@ static void aufs_kill_sb(struct super_block *sb)
sbinfo->si_wbr_create_ops->fin(sb);
if (au_opt_test(sbinfo->si_mntflags, UDBA_HNOTIFY)) {
au_opt_set_udba(sbinfo->si_mntflags, UDBA_NONE);
- au_remount_refresh(sb, /*flags*/0);
+ au_remount_refresh(sb);
}
if (au_opt_test(sbinfo->si_mntflags, PLINK))
au_plink_put(sb, /*verbose*/1);
diff --git a/ubuntu/aufs/super.h b/ubuntu/aufs/super.h
index 0cc087beadb..1930ce71a66 100644
--- a/ubuntu/aufs/super.h
+++ b/ubuntu/aufs/super.h
@@ -179,7 +179,7 @@ struct au_sbinfo {
* 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_FAILED_REFRESH_DIR 1
static inline unsigned char au_do_ftest_si(struct au_sbinfo *sbi,
unsigned int flag)
{
@@ -212,6 +212,7 @@ static inline unsigned char au_do_ftest_si(struct au_sbinfo *sbi,
#define AuLock_DIR (1 << 4) /* target is a dir */
#define AuLock_NOPLM (1 << 5) /* return err in plm mode */
#define AuLock_NOPLMW (1 << 6) /* wait for plm mode ends */
+#define AuLock_GEN (1 << 7) /* test digen/iigen */
#define au_ftest_lock(flags, name) ((flags) & AuLock_##name)
#define au_fset_lock(flags, name) \
do { (flags) |= AuLock_##name; } while (0)
diff --git a/ubuntu/aufs/sysrq.c b/ubuntu/aufs/sysrq.c
index c18829b97eb..452fe3a25fc 100644
--- a/ubuntu/aufs/sysrq.c
+++ b/ubuntu/aufs/sysrq.c
@@ -24,6 +24,7 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
/* #include <linux/sysrq.h> */
+#include <linux/writeback.h>
#include "aufs.h"
/* ---------------------------------------------------------------------- */
@@ -42,18 +43,45 @@ static void sysrq_sb(struct super_block *sb)
printk(KERN_WARNING "si=%lx\n", sysaufs_si_id(sbinfo));
printk(KERN_WARNING AUFS_NAME ": superblock\n");
au_dpri_sb(sb);
+
+#if 0
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);
+#endif
+
#if 0
- struct inode *i;
- printk(KERN_WARNING AUFS_NAME ": isolated inode\n");
- spin_lock(&inode_lock);
- list_for_each_entry(i, &sb->s_inodes, i_sb_list)
- if (list_empty(&i->i_dentry))
- au_dpri_inode(i);
- spin_unlock(&inode_lock);
+ do {
+ int err, i, j, ndentry;
+ struct au_dcsub_pages dpages;
+ struct au_dpage *dpage;
+
+ err = au_dpages_init(&dpages, GFP_ATOMIC);
+ if (unlikely(err))
+ break;
+ err = au_dcsub_pages(&dpages, sb->s_root, NULL, NULL);
+ if (!err)
+ for (i = 0; i < dpages.ndpage; i++) {
+ dpage = dpages.dpages + i;
+ ndentry = dpage->ndentry;
+ for (j = 0; j < ndentry; j++)
+ au_dpri_dentry(dpage->dentries[j]);
+ }
+ au_dpages_free(&dpages);
+ } while (0);
+#endif
+
+#if 1
+ {
+ struct inode *i;
+ printk(KERN_WARNING AUFS_NAME ": isolated inode\n");
+ spin_lock(&inode_lock);
+ list_for_each_entry(i, &sb->s_inodes, i_sb_list)
+ if (1 || list_empty(&i->i_dentry))
+ au_dpri_inode(i);
+ spin_unlock(&inode_lock);
+ }
#endif
printk(KERN_WARNING AUFS_NAME ": files\n");
lg_global_lock(files_lglock);
@@ -80,10 +108,12 @@ static void au_sysrq(int key __maybe_unused)
{
struct au_sbinfo *sbinfo;
+ lockdep_off();
spin_lock(&au_sbilist.spin);
list_for_each_entry(sbinfo, &au_sbilist.head, si_list)
sysrq_sb(sbinfo->si_sb);
spin_unlock(&au_sbilist.spin);
+ lockdep_on();
}
static struct sysrq_key_op au_sysrq_op = {
diff --git a/ubuntu/aufs/vfsub.h b/ubuntu/aufs/vfsub.h
index 4b44827c428..9a9f2669b34 100644
--- a/ubuntu/aufs/vfsub.h
+++ b/ubuntu/aufs/vfsub.h
@@ -91,6 +91,13 @@ static inline void vfsub_drop_nlink(struct inode *inode)
drop_nlink(inode);
}
+static inline void vfsub_dead_dir(struct inode *inode)
+{
+ AuDebugOn(!S_ISDIR(inode->i_mode));
+ inode->i_flags |= S_DEAD;
+ clear_nlink(inode);
+}
+
/* ---------------------------------------------------------------------- */
int vfsub_update_h_iattr(struct path *h_path, int *did);
diff --git a/ubuntu/aufs/wbr_policy.c b/ubuntu/aufs/wbr_policy.c
index bb57ae520fc..9e4f1e48b4e 100644
--- a/ubuntu/aufs/wbr_policy.c
+++ b/ubuntu/aufs/wbr_policy.c
@@ -232,8 +232,7 @@ static int au_wbr_nonopq(struct dentry *dentry, aufs_bindex_t bindex)
if (unlikely(err))
goto out;
parent = dget_parent(dentry);
- err = au_dcsub_pages_rev(&dpages, parent, /*do_include*/0, /*test*/NULL,
- /*arg*/NULL);
+ err = au_dcsub_pages_rev_aufs(&dpages, parent, /*do_include*/0);
if (unlikely(err))
goto out_free;
diff --git a/ubuntu/aufs/whout.c b/ubuntu/aufs/whout.c
index 284b8cc7c35..bdc989bb9d2 100644
--- a/ubuntu/aufs/whout.c
+++ b/ubuntu/aufs/whout.c
@@ -123,6 +123,7 @@ struct dentry *au_whtmp_lkup(struct dentry *h_parent, struct au_branch *br,
int i;
char defname[NAME_MAX - AUFS_MAX_NAMELEN + DNAME_INLINE_LEN_MIN + 1],
*name, *p;
+ /* strict atomic_t is unnecessary here */
static unsigned short cnt;
struct qstr qs;
@@ -607,8 +608,8 @@ 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);
+ au_nwt_done(&au_sbi(a->sb)->si_nowait);
kfree(arg);
if (unlikely(err))
AuIOErr("err %d\n", err);
@@ -901,6 +902,7 @@ struct au_whtmp_rmdir *au_whtmp_rmdir_alloc(struct super_block *sb, gfp_t gfp)
}
whtmp->dir = NULL;
+ whtmp->br = NULL;
whtmp->wh_dentry = NULL;
/* no estimation for dir size */
rdhash = au_sbi(sb)->si_rdhash;
@@ -918,6 +920,8 @@ out:
void au_whtmp_rmdir_free(struct au_whtmp_rmdir *whtmp)
{
+ if (whtmp->br)
+ atomic_dec(&whtmp->br->br_count);
dput(whtmp->wh_dentry);
iput(whtmp->dir);
au_nhash_wh_free(&whtmp->whlist);
@@ -969,7 +973,6 @@ int au_whtmp_rmdir(struct inode *dir, aufs_bindex_t bindex,
h_tmp.dentry = wh_dentry;
h_tmp.mnt = br->br_mnt;
err = vfsub_rmdir(h_dir, &h_tmp);
- /* d_drop(h_dentry); */
}
if (!err) {
@@ -1029,10 +1032,9 @@ static void call_rmdir_whtmp(void *args)
out:
/* mutex_unlock(&a->dir->i_mutex); */
- atomic_dec(&a->br->br_count);
- au_nwt_done(&au_sbi(sb)->si_nowait);
- si_read_unlock(sb);
au_whtmp_rmdir_free(a);
+ si_read_unlock(sb);
+ au_nwt_done(&au_sbi(sb)->si_nowait);
if (unlikely(err))
AuIOErr("err %d\n", err);
}
diff --git a/ubuntu/aufs/wkq.c b/ubuntu/aufs/wkq.c
index 9739d3a1377..c2a31f99211 100644
--- a/ubuntu/aufs/wkq.c
+++ b/ubuntu/aufs/wkq.c
@@ -160,6 +160,10 @@ int au_wkq_do_wait(unsigned int flags, au_wkq_func_t func, void *args)
}
+/*
+ * Note: dget/dput() in func for aufs dentries are not supported. It will be a
+ * problem in a concurrent umounting.
+ */
int au_wkq_nowait(au_wkq_func_t func, void *args, struct super_block *sb)
{
int err;
diff --git a/ubuntu/aufs/xino.c b/ubuntu/aufs/xino.c
index 84e745a1310..7c21a4aa00c 100644
--- a/ubuntu/aufs/xino.c
+++ b/ubuntu/aufs/xino.c
@@ -320,8 +320,8 @@ static void xino_do_trunc(void *_args)
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);
+ au_nwt_done(&au_sbi(sb)->si_nowait);
kfree(args);
}
diff --git a/ubuntu/include/linux/aufs_type.h b/ubuntu/include/linux/aufs_type.h
index c9e2845a13c..6a67e6788e0 100644
--- a/ubuntu/include/linux/aufs_type.h
+++ b/ubuntu/include/linux/aufs_type.h
@@ -24,7 +24,7 @@
#include <linux/limits.h>
#include <linux/types.h>
-#define AUFS_VERSION "2.1-standalone.tree-37-rcN-20101122"
+#define AUFS_VERSION "2.1-standalone.tree-37-rcN-20101220"
/* todo? move this to linux-2.6.19/include/magic.h */
#define AUFS_SUPER_MAGIC ('a' << 24 | 'u' << 16 | 'f' << 8 | 's')
@@ -73,11 +73,13 @@ typedef __s16 aufs_bindex_t;
#define AUFS_XINO_TRUNC_STEP 4 /* blocks */
#define AUFS_DIRWH_DEF 3
#define AUFS_RDCACHE_DEF 10 /* seconds */
+#define AUFS_RDCACHE_MAX 3600 /* seconds */
#define AUFS_RDBLK_DEF 512 /* bytes */
#define AUFS_RDHASH_DEF 32
#define AUFS_WKQ_NAME AUFS_NAME "d"
#define AUFS_WKQ_PRE_NAME AUFS_WKQ_NAME "_pre"
-#define AUFS_MFS_SECOND_DEF 30 /* seconds */
+#define AUFS_MFS_DEF_SEC 30 /* seconds */
+#define AUFS_MFS_MAX_SEC 3600 /* seconds */
#define AUFS_PLINK_WARN 100 /* number of plinks */
/* pseudo-link maintenace under /proc */