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); |