|
@@ -26,6 +26,7 @@
|
|
|
#include <linux/ima.h>
|
|
|
#include <linux/cred.h>
|
|
|
#include <linux/buffer_head.h> /* for inode_has_buffers */
|
|
|
+#include <linux/ratelimit.h>
|
|
|
#include "internal.h"
|
|
|
|
|
|
/*
|
|
@@ -242,6 +243,11 @@ void __destroy_inode(struct inode *inode)
|
|
|
BUG_ON(inode_has_buffers(inode));
|
|
|
security_inode_free(inode);
|
|
|
fsnotify_inode_delete(inode);
|
|
|
+ if (!inode->i_nlink) {
|
|
|
+ WARN_ON(atomic_long_read(&inode->i_sb->s_remove_count) == 0);
|
|
|
+ atomic_long_dec(&inode->i_sb->s_remove_count);
|
|
|
+ }
|
|
|
+
|
|
|
#ifdef CONFIG_FS_POSIX_ACL
|
|
|
if (inode->i_acl && inode->i_acl != ACL_NOT_CACHED)
|
|
|
posix_acl_release(inode->i_acl);
|
|
@@ -268,6 +274,85 @@ static void destroy_inode(struct inode *inode)
|
|
|
call_rcu(&inode->i_rcu, i_callback);
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * drop_nlink - directly drop an inode's link count
|
|
|
+ * @inode: inode
|
|
|
+ *
|
|
|
+ * This is a low-level filesystem helper to replace any
|
|
|
+ * direct filesystem manipulation of i_nlink. In cases
|
|
|
+ * where we are attempting to track writes to the
|
|
|
+ * filesystem, a decrement to zero means an imminent
|
|
|
+ * write when the file is truncated and actually unlinked
|
|
|
+ * on the filesystem.
|
|
|
+ */
|
|
|
+void drop_nlink(struct inode *inode)
|
|
|
+{
|
|
|
+ WARN_ON(inode->i_nlink == 0);
|
|
|
+ inode->__i_nlink--;
|
|
|
+ if (!inode->i_nlink)
|
|
|
+ atomic_long_inc(&inode->i_sb->s_remove_count);
|
|
|
+}
|
|
|
+EXPORT_SYMBOL(drop_nlink);
|
|
|
+
|
|
|
+/**
|
|
|
+ * clear_nlink - directly zero an inode's link count
|
|
|
+ * @inode: inode
|
|
|
+ *
|
|
|
+ * This is a low-level filesystem helper to replace any
|
|
|
+ * direct filesystem manipulation of i_nlink. See
|
|
|
+ * drop_nlink() for why we care about i_nlink hitting zero.
|
|
|
+ */
|
|
|
+void clear_nlink(struct inode *inode)
|
|
|
+{
|
|
|
+ if (inode->i_nlink) {
|
|
|
+ inode->__i_nlink = 0;
|
|
|
+ atomic_long_inc(&inode->i_sb->s_remove_count);
|
|
|
+ }
|
|
|
+}
|
|
|
+EXPORT_SYMBOL(clear_nlink);
|
|
|
+
|
|
|
+/**
|
|
|
+ * set_nlink - directly set an inode's link count
|
|
|
+ * @inode: inode
|
|
|
+ * @nlink: new nlink (should be non-zero)
|
|
|
+ *
|
|
|
+ * This is a low-level filesystem helper to replace any
|
|
|
+ * direct filesystem manipulation of i_nlink.
|
|
|
+ */
|
|
|
+void set_nlink(struct inode *inode, unsigned int nlink)
|
|
|
+{
|
|
|
+ if (!nlink) {
|
|
|
+ printk_ratelimited(KERN_INFO
|
|
|
+ "set_nlink() clearing i_nlink on %s inode %li\n",
|
|
|
+ inode->i_sb->s_type->name, inode->i_ino);
|
|
|
+ clear_nlink(inode);
|
|
|
+ } else {
|
|
|
+ /* Yes, some filesystems do change nlink from zero to one */
|
|
|
+ if (inode->i_nlink == 0)
|
|
|
+ atomic_long_dec(&inode->i_sb->s_remove_count);
|
|
|
+
|
|
|
+ inode->__i_nlink = nlink;
|
|
|
+ }
|
|
|
+}
|
|
|
+EXPORT_SYMBOL(set_nlink);
|
|
|
+
|
|
|
+/**
|
|
|
+ * inc_nlink - directly increment an inode's link count
|
|
|
+ * @inode: inode
|
|
|
+ *
|
|
|
+ * This is a low-level filesystem helper to replace any
|
|
|
+ * direct filesystem manipulation of i_nlink. Currently,
|
|
|
+ * it is only here for parity with dec_nlink().
|
|
|
+ */
|
|
|
+void inc_nlink(struct inode *inode)
|
|
|
+{
|
|
|
+ if (WARN_ON(inode->i_nlink == 0))
|
|
|
+ atomic_long_dec(&inode->i_sb->s_remove_count);
|
|
|
+
|
|
|
+ inode->__i_nlink++;
|
|
|
+}
|
|
|
+EXPORT_SYMBOL(inc_nlink);
|
|
|
+
|
|
|
void address_space_init_once(struct address_space *mapping)
|
|
|
{
|
|
|
memset(mapping, 0, sizeof(*mapping));
|