diff options
| author | Miklos Szeredi <mszeredi@suse.cz> | 2011-11-21 06:11:32 -0500 |
|---|---|---|
| committer | Al Viro <viro@zeniv.linux.org.uk> | 2012-01-06 23:20:12 -0500 |
| commit | 7ada4db88634429f4da690ad1c4eb73c93085f0c (patch) | |
| tree | ed1228f0bfa9d0050d746933595004d7c6e940f9 | |
| parent | 4ed5e82fe77f4147cf386327c9a63a2dd7eff518 (diff) | |
vfs: count unlinked inodes
Add a new counter to the superblock that keeps track of unlinked but
not yet deleted inodes.
Do not WARN_ON if set_nlink is called with zero count, just do a
ratelimited printk. This happens on xfs and probably other
filesystems after an unclean shutdown when the filesystem reads inodes
which already have zero i_nlink. Reported by Christoph Hellwig.
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
Tested-by: Toshiyuki Okajima <toshi.okajima@jp.fujitsu.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
| -rw-r--r-- | fs/inode.c | 85 | ||||
| -rw-r--r-- | include/linux/fs.h | 61 |
2 files changed, 92 insertions, 54 deletions
diff --git a/fs/inode.c b/fs/inode.c index 961355d00e38..87535753ab04 100644 --- a/fs/inode.c +++ b/fs/inode.c | |||
| @@ -26,6 +26,7 @@ | |||
| 26 | #include <linux/ima.h> | 26 | #include <linux/ima.h> |
| 27 | #include <linux/cred.h> | 27 | #include <linux/cred.h> |
| 28 | #include <linux/buffer_head.h> /* for inode_has_buffers */ | 28 | #include <linux/buffer_head.h> /* for inode_has_buffers */ |
| 29 | #include <linux/ratelimit.h> | ||
| 29 | #include "internal.h" | 30 | #include "internal.h" |
| 30 | 31 | ||
| 31 | /* | 32 | /* |
| @@ -242,6 +243,11 @@ void __destroy_inode(struct inode *inode) | |||
| 242 | BUG_ON(inode_has_buffers(inode)); | 243 | BUG_ON(inode_has_buffers(inode)); |
| 243 | security_inode_free(inode); | 244 | security_inode_free(inode); |
| 244 | fsnotify_inode_delete(inode); | 245 | fsnotify_inode_delete(inode); |
| 246 | if (!inode->i_nlink) { | ||
| 247 | WARN_ON(atomic_long_read(&inode->i_sb->s_remove_count) == 0); | ||
| 248 | atomic_long_dec(&inode->i_sb->s_remove_count); | ||
| 249 | } | ||
| 250 | |||
| 245 | #ifdef CONFIG_FS_POSIX_ACL | 251 | #ifdef CONFIG_FS_POSIX_ACL |
| 246 | if (inode->i_acl && inode->i_acl != ACL_NOT_CACHED) | 252 | if (inode->i_acl && inode->i_acl != ACL_NOT_CACHED) |
| 247 | posix_acl_release(inode->i_acl); | 253 | posix_acl_release(inode->i_acl); |
| @@ -268,6 +274,85 @@ static void destroy_inode(struct inode *inode) | |||
| 268 | call_rcu(&inode->i_rcu, i_callback); | 274 | call_rcu(&inode->i_rcu, i_callback); |
| 269 | } | 275 | } |
| 270 | 276 | ||
| 277 | /** | ||
| 278 | * drop_nlink - directly drop an inode's link count | ||
| 279 | * @inode: inode | ||
| 280 | * | ||
| 281 | * This is a low-level filesystem helper to replace any | ||
| 282 | * direct filesystem manipulation of i_nlink. In cases | ||
| 283 | * where we are attempting to track writes to the | ||
| 284 | * filesystem, a decrement to zero means an imminent | ||
| 285 | * write when the file is truncated and actually unlinked | ||
| 286 | * on the filesystem. | ||
| 287 | */ | ||
| 288 | void drop_nlink(struct inode *inode) | ||
| 289 | { | ||
| 290 | WARN_ON(inode->i_nlink == 0); | ||
| 291 | inode->__i_nlink--; | ||
| 292 | if (!inode->i_nlink) | ||
| 293 | atomic_long_inc(&inode->i_sb->s_remove_count); | ||
| 294 | } | ||
| 295 | EXPORT_SYMBOL(drop_nlink); | ||
| 296 | |||
| 297 | /** | ||
| 298 | * clear_nlink - directly zero an inode's link count | ||
| 299 | * @inode: inode | ||
| 300 | * | ||
| 301 | * This is a low-level filesystem helper to replace any | ||
| 302 | * direct filesystem manipulation of i_nlink. See | ||
| 303 | * drop_nlink() for why we care about i_nlink hitting zero. | ||
| 304 | */ | ||
| 305 | void clear_nlink(struct inode *inode) | ||
| 306 | { | ||
| 307 | if (inode->i_nlink) { | ||
| 308 | inode->__i_nlink = 0; | ||
| 309 | atomic_long_inc(&inode->i_sb->s_remove_count); | ||
| 310 | } | ||
| 311 | } | ||
| 312 | EXPORT_SYMBOL(clear_nlink); | ||
| 313 | |||
| 314 | /** | ||
| 315 | * set_nlink - directly set an inode's link count | ||
| 316 | * @inode: inode | ||
| 317 | * @nlink: new nlink (should be non-zero) | ||
| 318 | * | ||
| 319 | * This is a low-level filesystem helper to replace any | ||
| 320 | * direct filesystem manipulation of i_nlink. | ||
| 321 | */ | ||
| 322 | void set_nlink(struct inode *inode, unsigned int nlink) | ||
| 323 | { | ||
| 324 | if (!nlink) { | ||
| 325 | printk_ratelimited(KERN_INFO | ||
| 326 | "set_nlink() clearing i_nlink on %s inode %li\n", | ||
| 327 | inode->i_sb->s_type->name, inode->i_ino); | ||
| 328 | clear_nlink(inode); | ||
| 329 | } else { | ||
| 330 | /* Yes, some filesystems do change nlink from zero to one */ | ||
| 331 | if (inode->i_nlink == 0) | ||
| 332 | atomic_long_dec(&inode->i_sb->s_remove_count); | ||
| 333 | |||
| 334 | inode->__i_nlink = nlink; | ||
| 335 | } | ||
| 336 | } | ||
| 337 | EXPORT_SYMBOL(set_nlink); | ||
| 338 | |||
| 339 | /** | ||
| 340 | * inc_nlink - directly increment an inode's link count | ||
| 341 | * @inode: inode | ||
| 342 | * | ||
| 343 | * This is a low-level filesystem helper to replace any | ||
| 344 | * direct filesystem manipulation of i_nlink. Currently, | ||
| 345 | * it is only here for parity with dec_nlink(). | ||
| 346 | */ | ||
| 347 | void inc_nlink(struct inode *inode) | ||
| 348 | { | ||
| 349 | if (WARN_ON(inode->i_nlink == 0)) | ||
| 350 | atomic_long_dec(&inode->i_sb->s_remove_count); | ||
| 351 | |||
| 352 | inode->__i_nlink++; | ||
| 353 | } | ||
| 354 | EXPORT_SYMBOL(inc_nlink); | ||
| 355 | |||
| 271 | void address_space_init_once(struct address_space *mapping) | 356 | void address_space_init_once(struct address_space *mapping) |
| 272 | { | 357 | { |
| 273 | memset(mapping, 0, sizeof(*mapping)); | 358 | memset(mapping, 0, sizeof(*mapping)); |
diff --git a/include/linux/fs.h b/include/linux/fs.h index 7b8a681b1ef4..8ac40921f5ac 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h | |||
| @@ -1483,6 +1483,9 @@ struct super_block { | |||
| 1483 | 1483 | ||
| 1484 | struct shrinker s_shrink; /* per-sb shrinker handle */ | 1484 | struct shrinker s_shrink; /* per-sb shrinker handle */ |
| 1485 | 1485 | ||
| 1486 | /* Number of inodes with nlink == 0 but still referenced */ | ||
| 1487 | atomic_long_t s_remove_count; | ||
| 1488 | |||
| 1486 | /* Being remounted read-only */ | 1489 | /* Being remounted read-only */ |
| 1487 | int s_readonly_remount; | 1490 | int s_readonly_remount; |
| 1488 | }; | 1491 | }; |
| @@ -1768,31 +1771,10 @@ static inline void mark_inode_dirty_sync(struct inode *inode) | |||
| 1768 | __mark_inode_dirty(inode, I_DIRTY_SYNC); | 1771 | __mark_inode_dirty(inode, I_DIRTY_SYNC); |
| 1769 | } | 1772 | } |
| 1770 | 1773 | ||
| 1771 | /** | 1774 | extern void inc_nlink(struct inode *inode); |
| 1772 | * set_nlink - directly set an inode's link count | 1775 | extern void drop_nlink(struct inode *inode); |
| 1773 | * @inode: inode | 1776 | extern void clear_nlink(struct inode *inode); |
| 1774 | * @nlink: new nlink (should be non-zero) | 1777 | extern void set_nlink(struct inode *inode, unsigned int nlink); |
| 1775 | * | ||
| 1776 | * This is a low-level filesystem helper to replace any | ||
| 1777 | * direct filesystem manipulation of i_nlink. | ||
| 1778 | */ | ||
| 1779 | static inline void set_nlink(struct inode *inode, unsigned int nlink) | ||
| 1780 | { | ||
| 1781 | inode->__i_nlink = nlink; | ||
| 1782 | } | ||
| 1783 | |||
| 1784 | /** | ||
| 1785 | * inc_nlink - directly increment an inode's link count | ||
| 1786 | * @inode: inode | ||
| 1787 | * | ||
| 1788 | * This is a low-level filesystem helper to replace any | ||
| 1789 | * direct filesystem manipulation of i_nlink. Currently, | ||
| 1790 | * it is only here for parity with dec_nlink(). | ||
| 1791 | */ | ||
| 1792 | static inline void inc_nlink(struct inode *inode) | ||
| 1793 | { | ||
| 1794 | inode->__i_nlink++; | ||
| 1795 | } | ||
| 1796 | 1778 | ||
| 1797 | static inline void inode_inc_link_count(struct inode *inode) | 1779 | static inline void inode_inc_link_count(struct inode *inode) |
| 1798 | { | 1780 | { |
| @@ -1800,35 +1782,6 @@ static inline void inode_inc_link_count(struct inode *inode) | |||
| 1800 | mark_inode_dirty(inode); | 1782 | mark_inode_dirty(inode); |
| 1801 | } | 1783 | } |
| 1802 | 1784 | ||
| 1803 | /** | ||
| 1804 | * drop_nlink - directly drop an inode's link count | ||
| 1805 | * @inode: inode | ||
| 1806 | * | ||
| 1807 | * This is a low-level filesystem helper to replace any | ||
| 1808 | * direct filesystem manipulation of i_nlink. In cases | ||
| 1809 | * where we are attempting to track writes to the | ||
| 1810 | * filesystem, a decrement to zero means an imminent | ||
| 1811 | * write when the file is truncated and actually unlinked | ||
| 1812 | * on the filesystem. | ||
| 1813 | */ | ||
| 1814 | static inline void drop_nlink(struct inode *inode) | ||
| 1815 | { | ||
| 1816 | inode->__i_nlink--; | ||
| 1817 | } | ||
| 1818 | |||
| 1819 | /** | ||
| 1820 | * clear_nlink - directly zero an inode's link count | ||
| 1821 | * @inode: inode | ||
| 1822 | * | ||
| 1823 | * This is a low-level filesystem helper to replace any | ||
| 1824 | * direct filesystem manipulation of i_nlink. See | ||
| 1825 | * drop_nlink() for why we care about i_nlink hitting zero. | ||
| 1826 | */ | ||
| 1827 | static inline void clear_nlink(struct inode *inode) | ||
| 1828 | { | ||
| 1829 | inode->__i_nlink = 0; | ||
| 1830 | } | ||
| 1831 | |||
| 1832 | static inline void inode_dec_link_count(struct inode *inode) | 1785 | static inline void inode_dec_link_count(struct inode *inode) |
| 1833 | { | 1786 | { |
| 1834 | drop_nlink(inode); | 1787 | drop_nlink(inode); |
