Move xfs_bumplink and xfs_droplink to libxfs.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
));
}
-static void
-droplink(
- struct xfs_trans *tp,
- struct xfs_inode *ip)
-{
- struct inode *inode = VFS_I(ip);
-
- libxfs_trans_ichgtime(tp, ip, XFS_ICHGTIME_CHG);
-
- if (inode->i_nlink != XFS_NLINK_PINNED)
- drop_nlink(VFS_I(ip));
-
- libxfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
-}
-
static int
remove_child(
struct xfs_mount *mp,
if (S_ISDIR(VFS_I(ip)->i_mode)) {
/* drop ip's dotdot link to dp */
- droplink(tp, dp);
+ error = -libxfs_droplink(tp, dp);
+ if (error)
+ goto out_trans;
} else {
libxfs_trans_log_inode(tp, dp, XFS_ILOG_CORE);
}
/* drop dp's link to ip */
- droplink(tp, ip);
+ error = -libxfs_droplink(tp, ip);
+ if (error)
+ goto out_trans;
error = -libxfs_dir_removename(tp, dp, &xname, ip->i_ino, resblks);
if (error)
struct xfs_inode *, int);
extern int libxfs_iflush_int (struct xfs_inode *, struct xfs_buf *);
-void libxfs_bumplink(struct xfs_trans *tp, struct xfs_inode *ip);
-
int libxfs_icreate(struct xfs_trans *tp, xfs_ino_t ino,
const struct xfs_icreate_args *args, struct xfs_inode **ipp);
#include "xfs_da_btree.h"
#include "xfs_dir2_priv.h"
-/*
- * Increment the link count on an inode & log the change.
- */
-void
-libxfs_bumplink(
- struct xfs_trans *tp,
- struct xfs_inode *ip)
-{
- struct inode *inode = VFS_I(ip);
-
- xfs_trans_ichgtime(tp, ip, XFS_ICHGTIME_CHG);
-
- if (inode->i_nlink != XFS_NLINK_PINNED)
- inc_nlink(inode);
-
- xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
-}
-
/*
* Initialise a newly allocated inode and return the in-core inode to the
* caller locked exclusively.
#define xfs_buf_relse libxfs_buf_relse
#define xfs_buf_unlock libxfs_buf_unlock
#define xfs_buftarg_drain libxfs_buftarg_drain
+#define xfs_bumplink libxfs_bumplink
#define xfs_bunmapi libxfs_bunmapi
#define xfs_bwrite libxfs_bwrite
#define xfs_calc_dquots_per_chunk libxfs_calc_dquots_per_chunk
enum ce { CE_DEBUG, CE_CONT, CE_NOTE, CE_WARN, CE_ALERT, CE_PANIC };
#define xfs_info(mp,fmt,args...) cmn_err(CE_CONT, _(fmt), ## args)
+#define xfs_info_ratelimited(mp,fmt,args...) cmn_err(CE_CONT, _(fmt), ## args)
#define xfs_notice(mp,fmt,args...) cmn_err(CE_NOTE, _(fmt), ## args)
#define xfs_warn(mp,fmt,args...) cmn_err((mp) ? CE_WARN : CE_WARN, _(fmt), ## args)
#define xfs_err(mp,fmt,args...) cmn_err(CE_ALERT, _(fmt), ## args)
return xfs_iunlink_remove_inode(tp, pag, agibp, ip);
}
+
+/*
+ * Decrement the link count on an inode & log the change. If this causes the
+ * link count to go to zero, move the inode to AGI unlinked list so that it can
+ * be freed when the last active reference goes away via xfs_inactive().
+ */
+int
+xfs_droplink(
+ struct xfs_trans *tp,
+ struct xfs_inode *ip)
+{
+ struct inode *inode = VFS_I(ip);
+
+ xfs_trans_ichgtime(tp, ip, XFS_ICHGTIME_CHG);
+
+ if (inode->i_nlink == 0) {
+ xfs_info_ratelimited(tp->t_mountp,
+ "Inode 0x%llx link count dropped below zero. Pinning link count.",
+ ip->i_ino);
+ set_nlink(inode, XFS_NLINK_PINNED);
+ }
+ if (inode->i_nlink != XFS_NLINK_PINNED)
+ drop_nlink(inode);
+
+ xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
+
+ if (inode->i_nlink)
+ return 0;
+
+ return xfs_iunlink(tp, ip);
+}
+
+/*
+ * Increment the link count on an inode & log the change.
+ */
+void
+xfs_bumplink(
+ struct xfs_trans *tp,
+ struct xfs_inode *ip)
+{
+ struct inode *inode = VFS_I(ip);
+
+ xfs_trans_ichgtime(tp, ip, XFS_ICHGTIME_CHG);
+
+ if (inode->i_nlink == XFS_NLINK_PINNED - 1)
+ xfs_info_ratelimited(tp->t_mountp,
+ "Inode 0x%llx link count exceeded maximum. Pinning link count.",
+ ip->i_ino);
+ if (inode->i_nlink != XFS_NLINK_PINNED)
+ inc_nlink(inode);
+
+ xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
+}
int xfs_iunlink(struct xfs_trans *tp, struct xfs_inode *ip);
int xfs_iunlink_remove(struct xfs_trans *tp, struct xfs_perag *pag,
struct xfs_inode *ip);
+int xfs_droplink(struct xfs_trans *tp, struct xfs_inode *ip);
+void xfs_bumplink(struct xfs_trans *tp, struct xfs_inode *ip);
#endif /* __XFS_INODE_UTIL_H__ */