Viewing: fs.h

/* SPDX-License-Identifier: GPL-2.0 */

/*
 * This file is part of Lustre, http://www.lustre.org/
 *
 * Basic library routines.
 */

#ifndef __LIBCFS_LINUX_CFS_FS_H__
#define __LIBCFS_LINUX_CFS_FS_H__

#include <linux/fs.h>
#include <linux/dcache.h>
#include <lustre_compat/linux/time64.h>

#ifndef HAVE_D_MAKE_PERSISTENT
/*
 * Linux commit v6.18-rc5-9-gbacdf1d70bbe2 introduced d_make_persistent() and
 * d_make_discardable() so that filesystems can mark dentries as pinned without
 * leaking unbalanced dget()s. On older kernels we fall back to the equivalent
 * open-coded sequence: d_instantiate() (or d_add() for unhashed dentries) plus
 * an extra dget() to pin, and a matching dput() to unpin. Older kernels still
 * have kill_litter_super() available, which uses d_genocide() to drop these
 * extra references at unmount.
 */
static inline struct dentry *d_make_persistent(struct dentry *dentry,
					       struct inode *inode)
{
	if (d_unhashed(dentry))
		d_add(dentry, inode);
	else
		d_instantiate(dentry, inode);
	dget(dentry);
	return dentry;
}

static inline void d_make_discardable(struct dentry *dentry)
{
	dput(dentry);
}
#endif /* !HAVE_D_MAKE_PERSISTENT */

#ifndef S_DT_SHIFT
#define S_DT_SHIFT		12
#endif

#ifndef S_DT
#define S_DT(type)		(((type) & S_IFMT) >> S_DT_SHIFT)
#endif
#ifndef DTTOIF
#define DTTOIF(dirtype)		((dirtype) << S_DT_SHIFT)
#endif

#ifndef SB_I_CGROUPWB
#define SB_I_CGROUPWB   0
#endif

/* Really belongs in mnt_idmapping.h but it doesn't exist for
 * older kernels. mnt_idmapping.h is always included with fs.h.
 */
#ifndef HAVE_MNT_IDMAP_ARG
#define mnt_idmap       user_namespace
#define nop_mnt_idmap   init_user_ns
#endif

#if !defined(HAVE_VFS_CREATE_DELEGATE)
#if !defined(HAVE_USER_NAMESPACE_ARG) && !defined(HAVE_MNT_IDMAP_ARG)
#define vfs_create(ns, de, mode, di)	\
	vfs_create(d_inode((de)->d_parent), (de), (mode), !!(di))
#else
#define vfs_create(ns, de, mode, di) \
	vfs_create((ns), d_inode((de)->d_parent), (de), (mode), !!(di))
#endif
#endif /* HAVE_VFS_CREATE_DELEGATE */

#ifdef HAVE_VFS_MKDIR_DELEGATE
#define VFS_MKDIR_DELEGATE(id, inode, dentry, mode) \
	vfs_mkdir((id), (inode), (dentry), (mode), NULL)
#else
#define VFS_MKDIR_DELEGATE(id, inode, dentry, mode) \
	vfs_mkdir((id), (inode), (dentry), (mode))
#endif /* HAVE_VFS_MKDIR_DELEGATE */

#ifdef HAVE_IOPS_MKDIR_RETURNS_DENTRY
#define ll_vfs_mkdir(id, inode, dentry, mode)	\
	VFS_MKDIR_DELEGATE((id), (inode), (dentry), (mode))
#else
#define ll_vfs_mkdir(i, inode, dentry, mode) ({				\
	int rc = VFS_MKDIR_DELEGATE((i), (inode), (dentry), (mode));	\
	if (rc) {							\
		dput((dentry));						\
		dentry = ERR_PTR(rc);					\
	}								\
	(dentry);							\
})
#endif /* HAVE_IOPS_MKDIR_RETURNS_DENTRY */

#ifndef ATTR_CTIME_SET /* added in v6.17-rc7-14-gafc5b36e29 */
#define ATTR_CTIME_SET (1 << 28) /* safe for at least v4.18..v6.17 */
#endif

static inline int ll_vfs_getattr(struct path *path, struct kstat *st,
				 u32 request_mask, unsigned int flags)
{
#ifdef AT_GETATTR_NOSEC /* added in v6.7-rc1-1-g8a924db2d7b5 */
	if (flags & AT_GETATTR_NOSEC)
		return vfs_getattr_nosec(path, st, request_mask, flags);
#endif /* AT_GETATTR_NOSEC */

	return vfs_getattr(path, st, request_mask, flags);
}

#ifndef HAVE_INODE_JUST_DROP
static inline int inode_just_drop(struct inode *inode)
{
	return generic_delete_inode(inode);
}

static inline int inode_generic_drop(struct inode *inode)
{
	return generic_drop_inode(inode);
}
#endif

#ifndef HAVE_ILOOKUP5_NOWAIT_ISNEW
#define ilookup5_nowait(sb, hash, fn, data, isnew) \
	ilookup5_nowait((sb), (hash), (fn), (data))
#endif

#ifndef F_GETLK64
#define F_GETLK64	12	/*  using 'struct flock64' */
#define F_SETLK64	13
#define F_SETLKW64	14
#endif

#ifndef HAVE_INODE_GET_CTIME
#define inode_get_ctime(i)		((i)->i_ctime)
#define inode_set_ctime_to_ts(i, ts)	((i)->i_ctime = ts)
#define inode_set_ctime_current(i) \
	inode_set_ctime_to_ts((i), current_time((i)))

static inline struct timespec64 inode_set_ctime(struct inode *inode,
						time64_t sec, long nsec)
{
	struct timespec64 ts = { .tv_sec  = sec,
				 .tv_nsec = nsec };

	return inode_set_ctime_to_ts(inode, ts);
}
#endif /* !HAVE_INODE_GET_CTIME */

#ifndef HAVE_INODE_GET_MTIME_SEC

#define inode_get_ctime_sec(i)		(inode_get_ctime((i)).tv_sec)

#define inode_get_atime(i)		((i)->i_atime)
#define inode_get_atime_sec(i)		((i)->i_atime.tv_sec)
#define inode_set_atime_to_ts(i, ts)	((i)->i_atime = ts)

static inline struct timespec64 inode_set_atime(struct inode *inode,
						time64_t sec, long nsec)
{
	struct timespec64 ts = { .tv_sec  = sec,
				 .tv_nsec = nsec };
	return inode_set_atime_to_ts(inode, ts);
}

#define inode_get_mtime(i)		((i)->i_mtime)
#define inode_get_mtime_sec(i)		((i)->i_mtime.tv_sec)
#define inode_set_mtime_to_ts(i, ts)	((i)->i_mtime = ts)

static inline struct timespec64 inode_set_mtime(struct inode *inode,
						time64_t sec, long nsec)
{
	struct timespec64 ts = { .tv_sec  = sec,
				 .tv_nsec = nsec };
	return inode_set_mtime_to_ts(inode, ts);
}
#endif  /* !HAVE_INODE_GET_MTIME_SEC */

/* Inode timestamp helpers returning nanoseconds since epoch */
static inline s64 inode_get_atime_ns(struct inode *inode)
{
	struct timespec64 ts;

	ts = inode_get_atime(inode);
	return timespec64_to_ns(&ts);
}

static inline s64 inode_get_mtime_ns(struct inode *inode)
{
	struct timespec64 ts;

	ts = inode_get_mtime(inode);
	return timespec64_to_ns(&ts);
}

static inline s64 inode_get_ctime_ns(struct inode *inode)
{
	struct timespec64 ts;

	ts = inode_get_ctime(inode);
	return timespec64_to_ns(&ts);
}

#endif /* __LIBCFS_LINUX_CFS_FS_H__ */