forked from luck/tmp_suning_uos_patched
a528d35e8b
Add a system call to make extended file information available, including file creation and some attribute flags where available through the underlying filesystem. The getattr inode operation is altered to take two additional arguments: a u32 request_mask and an unsigned int flags that indicate the synchronisation mode. This change is propagated to the vfs_getattr*() function. Functions like vfs_stat() are now inline wrappers around new functions vfs_statx() and vfs_statx_fd() to reduce stack usage. ======== OVERVIEW ======== The idea was initially proposed as a set of xattrs that could be retrieved with getxattr(), but the general preference proved to be for a new syscall with an extended stat structure. A number of requests were gathered for features to be included. The following have been included: (1) Make the fields a consistent size on all arches and make them large. (2) Spare space, request flags and information flags are provided for future expansion. (3) Better support for the y2038 problem [Arnd Bergmann] (tv_sec is an __s64). (4) Creation time: The SMB protocol carries the creation time, which could be exported by Samba, which will in turn help CIFS make use of FS-Cache as that can be used for coherency data (stx_btime). This is also specified in NFSv4 as a recommended attribute and could be exported by NFSD [Steve French]. (5) Lightweight stat: Ask for just those details of interest, and allow a netfs (such as NFS) to approximate anything not of interest, possibly without going to the server [Trond Myklebust, Ulrich Drepper, Andreas Dilger] (AT_STATX_DONT_SYNC). (6) Heavyweight stat: Force a netfs to go to the server, even if it thinks its cached attributes are up to date [Trond Myklebust] (AT_STATX_FORCE_SYNC). And the following have been left out for future extension: (7) Data version number: Could be used by userspace NFS servers [Aneesh Kumar]. Can also be used to modify fill_post_wcc() in NFSD which retrieves i_version directly, but has just called vfs_getattr(). It could get it from the kstat struct if it used vfs_xgetattr() instead. (There's disagreement on the exact semantics of a single field, since not all filesystems do this the same way). (8) BSD stat compatibility: Including more fields from the BSD stat such as creation time (st_btime) and inode generation number (st_gen) [Jeremy Allison, Bernd Schubert]. (9) Inode generation number: Useful for FUSE and userspace NFS servers [Bernd Schubert]. (This was asked for but later deemed unnecessary with the open-by-handle capability available and caused disagreement as to whether it's a security hole or not). (10) Extra coherency data may be useful in making backups [Andreas Dilger]. (No particular data were offered, but things like last backup timestamp, the data version number and the DOS archive bit would come into this category). (11) Allow the filesystem to indicate what it can/cannot provide: A filesystem can now say it doesn't support a standard stat feature if that isn't available, so if, for instance, inode numbers or UIDs don't exist or are fabricated locally... (This requires a separate system call - I have an fsinfo() call idea for this). (12) Store a 16-byte volume ID in the superblock that can be returned in struct xstat [Steve French]. (Deferred to fsinfo). (13) Include granularity fields in the time data to indicate the granularity of each of the times (NFSv4 time_delta) [Steve French]. (Deferred to fsinfo). (14) FS_IOC_GETFLAGS value. These could be translated to BSD's st_flags. Note that the Linux IOC flags are a mess and filesystems such as Ext4 define flags that aren't in linux/fs.h, so translation in the kernel may be a necessity (or, possibly, we provide the filesystem type too). (Some attributes are made available in stx_attributes, but the general feeling was that the IOC flags were to ext[234]-specific and shouldn't be exposed through statx this way). (15) Mask of features available on file (eg: ACLs, seclabel) [Brad Boyer, Michael Kerrisk]. (Deferred, probably to fsinfo. Finding out if there's an ACL or seclabal might require extra filesystem operations). (16) Femtosecond-resolution timestamps [Dave Chinner]. (A __reserved field has been left in the statx_timestamp struct for this - if there proves to be a need). (17) A set multiple attributes syscall to go with this. =============== NEW SYSTEM CALL =============== The new system call is: int ret = statx(int dfd, const char *filename, unsigned int flags, unsigned int mask, struct statx *buffer); The dfd, filename and flags parameters indicate the file to query, in a similar way to fstatat(). There is no equivalent of lstat() as that can be emulated with statx() by passing AT_SYMLINK_NOFOLLOW in flags. There is also no equivalent of fstat() as that can be emulated by passing a NULL filename to statx() with the fd of interest in dfd. Whether or not statx() synchronises the attributes with the backing store can be controlled by OR'ing a value into the flags argument (this typically only affects network filesystems): (1) AT_STATX_SYNC_AS_STAT tells statx() to behave as stat() does in this respect. (2) AT_STATX_FORCE_SYNC will require a network filesystem to synchronise its attributes with the server - which might require data writeback to occur to get the timestamps correct. (3) AT_STATX_DONT_SYNC will suppress synchronisation with the server in a network filesystem. The resulting values should be considered approximate. mask is a bitmask indicating the fields in struct statx that are of interest to the caller. The user should set this to STATX_BASIC_STATS to get the basic set returned by stat(). It should be noted that asking for more information may entail extra I/O operations. buffer points to the destination for the data. This must be 256 bytes in size. ====================== MAIN ATTRIBUTES RECORD ====================== The following structures are defined in which to return the main attribute set: struct statx_timestamp { __s64 tv_sec; __s32 tv_nsec; __s32 __reserved; }; struct statx { __u32 stx_mask; __u32 stx_blksize; __u64 stx_attributes; __u32 stx_nlink; __u32 stx_uid; __u32 stx_gid; __u16 stx_mode; __u16 __spare0[1]; __u64 stx_ino; __u64 stx_size; __u64 stx_blocks; __u64 __spare1[1]; struct statx_timestamp stx_atime; struct statx_timestamp stx_btime; struct statx_timestamp stx_ctime; struct statx_timestamp stx_mtime; __u32 stx_rdev_major; __u32 stx_rdev_minor; __u32 stx_dev_major; __u32 stx_dev_minor; __u64 __spare2[14]; }; The defined bits in request_mask and stx_mask are: STATX_TYPE Want/got stx_mode & S_IFMT STATX_MODE Want/got stx_mode & ~S_IFMT STATX_NLINK Want/got stx_nlink STATX_UID Want/got stx_uid STATX_GID Want/got stx_gid STATX_ATIME Want/got stx_atime{,_ns} STATX_MTIME Want/got stx_mtime{,_ns} STATX_CTIME Want/got stx_ctime{,_ns} STATX_INO Want/got stx_ino STATX_SIZE Want/got stx_size STATX_BLOCKS Want/got stx_blocks STATX_BASIC_STATS [The stuff in the normal stat struct] STATX_BTIME Want/got stx_btime{,_ns} STATX_ALL [All currently available stuff] stx_btime is the file creation time, stx_mask is a bitmask indicating the data provided and __spares*[] are where as-yet undefined fields can be placed. Time fields are structures with separate seconds and nanoseconds fields plus a reserved field in case we want to add even finer resolution. Note that times will be negative if before 1970; in such a case, the nanosecond fields will also be negative if not zero. The bits defined in the stx_attributes field convey information about a file, how it is accessed, where it is and what it does. The following attributes map to FS_*_FL flags and are the same numerical value: STATX_ATTR_COMPRESSED File is compressed by the fs STATX_ATTR_IMMUTABLE File is marked immutable STATX_ATTR_APPEND File is append-only STATX_ATTR_NODUMP File is not to be dumped STATX_ATTR_ENCRYPTED File requires key to decrypt in fs Within the kernel, the supported flags are listed by: KSTAT_ATTR_FS_IOC_FLAGS [Are any other IOC flags of sufficient general interest to be exposed through this interface?] New flags include: STATX_ATTR_AUTOMOUNT Object is an automount trigger These are for the use of GUI tools that might want to mark files specially, depending on what they are. Fields in struct statx come in a number of classes: (0) stx_dev_*, stx_blksize. These are local system information and are always available. (1) stx_mode, stx_nlinks, stx_uid, stx_gid, stx_[amc]time, stx_ino, stx_size, stx_blocks. These will be returned whether the caller asks for them or not. The corresponding bits in stx_mask will be set to indicate whether they actually have valid values. If the caller didn't ask for them, then they may be approximated. For example, NFS won't waste any time updating them from the server, unless as a byproduct of updating something requested. If the values don't actually exist for the underlying object (such as UID or GID on a DOS file), then the bit won't be set in the stx_mask, even if the caller asked for the value. In such a case, the returned value will be a fabrication. Note that there are instances where the type might not be valid, for instance Windows reparse points. (2) stx_rdev_*. This will be set only if stx_mode indicates we're looking at a blockdev or a chardev, otherwise will be 0. (3) stx_btime. Similar to (1), except this will be set to 0 if it doesn't exist. ======= TESTING ======= The following test program can be used to test the statx system call: samples/statx/test-statx.c Just compile and run, passing it paths to the files you want to examine. The file is built automatically if CONFIG_SAMPLES is enabled. Here's some example output. Firstly, an NFS directory that crosses to another FSID. Note that the AUTOMOUNT attribute is set because transiting this directory will cause d_automount to be invoked by the VFS. [root@andromeda ~]# /tmp/test-statx -A /warthog/data statx(/warthog/data) = 0 results=7ff Size: 4096 Blocks: 8 IO Block: 1048576 directory Device: 00:26 Inode: 1703937 Links: 125 Access: (3777/drwxrwxrwx) Uid: 0 Gid: 4041 Access: 2016-11-24 09:02:12.219699527+0000 Modify: 2016-11-17 10:44:36.225653653+0000 Change: 2016-11-17 10:44:36.225653653+0000 Attributes: 0000000000001000 (-------- -------- -------- -------- -------- -------- ---m---- --------) Secondly, the result of automounting on that directory. [root@andromeda ~]# /tmp/test-statx /warthog/data statx(/warthog/data) = 0 results=7ff Size: 4096 Blocks: 8 IO Block: 1048576 directory Device: 00:27 Inode: 2 Links: 125 Access: (3777/drwxrwxrwx) Uid: 0 Gid: 4041 Access: 2016-11-24 09:02:12.219699527+0000 Modify: 2016-11-17 10:44:36.225653653+0000 Change: 2016-11-17 10:44:36.225653653+0000 Signed-off-by: David Howells <dhowells@redhat.com> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
589 lines
16 KiB
C
589 lines
16 KiB
C
/*
|
|
* (C) 2001 Clemson University and The University of Chicago
|
|
*
|
|
* See COPYING in top-level directory.
|
|
*/
|
|
|
|
/*
|
|
* The ORANGEFS Linux kernel support allows ORANGEFS volumes to be mounted and
|
|
* accessed through the Linux VFS (i.e. using standard I/O system calls).
|
|
* This support is only needed on clients that wish to mount the file system.
|
|
*
|
|
*/
|
|
|
|
/*
|
|
* Declarations and macros for the ORANGEFS Linux kernel support.
|
|
*/
|
|
|
|
#ifndef __ORANGEFSKERNEL_H
|
|
#define __ORANGEFSKERNEL_H
|
|
|
|
#include <linux/kernel.h>
|
|
#include <linux/moduleparam.h>
|
|
#include <linux/statfs.h>
|
|
#include <linux/backing-dev.h>
|
|
#include <linux/device.h>
|
|
#include <linux/mpage.h>
|
|
#include <linux/namei.h>
|
|
#include <linux/errno.h>
|
|
#include <linux/init.h>
|
|
#include <linux/module.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/types.h>
|
|
#include <linux/fs.h>
|
|
#include <linux/vmalloc.h>
|
|
|
|
#include <linux/aio.h>
|
|
#include <linux/posix_acl.h>
|
|
#include <linux/posix_acl_xattr.h>
|
|
#include <linux/compat.h>
|
|
#include <linux/mount.h>
|
|
#include <linux/uaccess.h>
|
|
#include <linux/atomic.h>
|
|
#include <linux/uio.h>
|
|
#include <linux/sched.h>
|
|
#include <linux/mm.h>
|
|
#include <linux/wait.h>
|
|
#include <linux/dcache.h>
|
|
#include <linux/pagemap.h>
|
|
#include <linux/poll.h>
|
|
#include <linux/rwsem.h>
|
|
#include <linux/xattr.h>
|
|
#include <linux/exportfs.h>
|
|
|
|
#include <asm/unaligned.h>
|
|
|
|
#include "orangefs-dev-proto.h"
|
|
|
|
#ifdef ORANGEFS_KERNEL_DEBUG
|
|
#define ORANGEFS_DEFAULT_OP_TIMEOUT_SECS 10
|
|
#else
|
|
#define ORANGEFS_DEFAULT_OP_TIMEOUT_SECS 20
|
|
#endif
|
|
|
|
#define ORANGEFS_BUFMAP_WAIT_TIMEOUT_SECS 30
|
|
|
|
#define ORANGEFS_DEFAULT_SLOT_TIMEOUT_SECS 900 /* 15 minutes */
|
|
|
|
#define ORANGEFS_REQDEVICE_NAME "pvfs2-req"
|
|
|
|
#define ORANGEFS_DEVREQ_MAGIC 0x20030529
|
|
#define ORANGEFS_LINK_MAX 0x000000FF
|
|
#define ORANGEFS_PURGE_RETRY_COUNT 0x00000005
|
|
#define ORANGEFS_MAX_NUM_OPTIONS 0x00000004
|
|
#define ORANGEFS_MAX_MOUNT_OPT_LEN 0x00000080
|
|
#define ORANGEFS_MAX_FSKEY_LEN 64
|
|
|
|
#define MAX_DEV_REQ_UPSIZE (2 * sizeof(__s32) + \
|
|
sizeof(__u64) + sizeof(struct orangefs_upcall_s))
|
|
#define MAX_DEV_REQ_DOWNSIZE (2 * sizeof(__s32) + \
|
|
sizeof(__u64) + sizeof(struct orangefs_downcall_s))
|
|
|
|
/*
|
|
* valid orangefs kernel operation states
|
|
*
|
|
* unknown - op was just initialized
|
|
* waiting - op is on request_list (upward bound)
|
|
* inprogr - op is in progress (waiting for downcall)
|
|
* serviced - op has matching downcall; ok
|
|
* purged - op has to start a timer since client-core
|
|
* exited uncleanly before servicing op
|
|
* given up - submitter has given up waiting for it
|
|
*/
|
|
enum orangefs_vfs_op_states {
|
|
OP_VFS_STATE_UNKNOWN = 0,
|
|
OP_VFS_STATE_WAITING = 1,
|
|
OP_VFS_STATE_INPROGR = 2,
|
|
OP_VFS_STATE_SERVICED = 4,
|
|
OP_VFS_STATE_PURGED = 8,
|
|
OP_VFS_STATE_GIVEN_UP = 16,
|
|
};
|
|
|
|
/*
|
|
* orangefs kernel memory related flags
|
|
*/
|
|
|
|
#if ((defined ORANGEFS_KERNEL_DEBUG) && (defined CONFIG_DEBUG_SLAB))
|
|
#define ORANGEFS_CACHE_CREATE_FLAGS SLAB_RED_ZONE
|
|
#else
|
|
#define ORANGEFS_CACHE_CREATE_FLAGS 0
|
|
#endif /* ((defined ORANGEFS_KERNEL_DEBUG) && (defined CONFIG_DEBUG_SLAB)) */
|
|
|
|
extern int orangefs_init_acl(struct inode *inode, struct inode *dir);
|
|
extern const struct xattr_handler *orangefs_xattr_handlers[];
|
|
|
|
extern struct posix_acl *orangefs_get_acl(struct inode *inode, int type);
|
|
extern int orangefs_set_acl(struct inode *inode, struct posix_acl *acl, int type);
|
|
|
|
/*
|
|
* Redefine xtvec structure so that we could move helper functions out of
|
|
* the define
|
|
*/
|
|
struct xtvec {
|
|
__kernel_off_t xtv_off; /* must be off_t */
|
|
__kernel_size_t xtv_len; /* must be size_t */
|
|
};
|
|
|
|
/*
|
|
* orangefs data structures
|
|
*/
|
|
struct orangefs_kernel_op_s {
|
|
enum orangefs_vfs_op_states op_state;
|
|
__u64 tag;
|
|
|
|
/*
|
|
* Set uses_shared_memory to non zero if this operation uses
|
|
* shared memory. If true, then a retry on the op must also
|
|
* get a new shared memory buffer and re-populate it.
|
|
* Cancels don't care - it only matters for service_operation()
|
|
* retry logics and cancels don't go through it anymore. It
|
|
* safely stays non-zero when we use it as slot_to_free.
|
|
*/
|
|
union {
|
|
int uses_shared_memory;
|
|
int slot_to_free;
|
|
};
|
|
|
|
struct orangefs_upcall_s upcall;
|
|
struct orangefs_downcall_s downcall;
|
|
|
|
struct completion waitq;
|
|
spinlock_t lock;
|
|
|
|
int attempts;
|
|
|
|
struct list_head list;
|
|
};
|
|
|
|
#define set_op_state_waiting(op) ((op)->op_state = OP_VFS_STATE_WAITING)
|
|
#define set_op_state_inprogress(op) ((op)->op_state = OP_VFS_STATE_INPROGR)
|
|
#define set_op_state_given_up(op) ((op)->op_state = OP_VFS_STATE_GIVEN_UP)
|
|
static inline void set_op_state_serviced(struct orangefs_kernel_op_s *op)
|
|
{
|
|
op->op_state = OP_VFS_STATE_SERVICED;
|
|
complete(&op->waitq);
|
|
}
|
|
|
|
#define op_state_waiting(op) ((op)->op_state & OP_VFS_STATE_WAITING)
|
|
#define op_state_in_progress(op) ((op)->op_state & OP_VFS_STATE_INPROGR)
|
|
#define op_state_serviced(op) ((op)->op_state & OP_VFS_STATE_SERVICED)
|
|
#define op_state_purged(op) ((op)->op_state & OP_VFS_STATE_PURGED)
|
|
#define op_state_given_up(op) ((op)->op_state & OP_VFS_STATE_GIVEN_UP)
|
|
#define op_is_cancel(op) ((op)->upcall.type == ORANGEFS_VFS_OP_CANCEL)
|
|
|
|
void op_release(struct orangefs_kernel_op_s *op);
|
|
|
|
extern void orangefs_bufmap_put(int);
|
|
static inline void put_cancel(struct orangefs_kernel_op_s *op)
|
|
{
|
|
orangefs_bufmap_put(op->slot_to_free);
|
|
op_release(op);
|
|
}
|
|
|
|
static inline void set_op_state_purged(struct orangefs_kernel_op_s *op)
|
|
{
|
|
spin_lock(&op->lock);
|
|
if (unlikely(op_is_cancel(op))) {
|
|
list_del_init(&op->list);
|
|
spin_unlock(&op->lock);
|
|
put_cancel(op);
|
|
} else {
|
|
op->op_state |= OP_VFS_STATE_PURGED;
|
|
complete(&op->waitq);
|
|
spin_unlock(&op->lock);
|
|
}
|
|
}
|
|
|
|
/* per inode private orangefs info */
|
|
struct orangefs_inode_s {
|
|
struct orangefs_object_kref refn;
|
|
char link_target[ORANGEFS_NAME_MAX];
|
|
__s64 blksize;
|
|
/*
|
|
* Reading/Writing Extended attributes need to acquire the appropriate
|
|
* reader/writer semaphore on the orangefs_inode_s structure.
|
|
*/
|
|
struct rw_semaphore xattr_sem;
|
|
|
|
struct inode vfs_inode;
|
|
sector_t last_failed_block_index_read;
|
|
|
|
/*
|
|
* State of in-memory attributes not yet flushed to disk associated
|
|
* with this object
|
|
*/
|
|
unsigned long pinode_flags;
|
|
|
|
unsigned long getattr_time;
|
|
};
|
|
|
|
#define P_ATIME_FLAG 0
|
|
#define P_MTIME_FLAG 1
|
|
#define P_CTIME_FLAG 2
|
|
#define P_MODE_FLAG 3
|
|
|
|
#define ClearAtimeFlag(pinode) clear_bit(P_ATIME_FLAG, &(pinode)->pinode_flags)
|
|
#define SetAtimeFlag(pinode) set_bit(P_ATIME_FLAG, &(pinode)->pinode_flags)
|
|
#define AtimeFlag(pinode) test_bit(P_ATIME_FLAG, &(pinode)->pinode_flags)
|
|
|
|
#define ClearMtimeFlag(pinode) clear_bit(P_MTIME_FLAG, &(pinode)->pinode_flags)
|
|
#define SetMtimeFlag(pinode) set_bit(P_MTIME_FLAG, &(pinode)->pinode_flags)
|
|
#define MtimeFlag(pinode) test_bit(P_MTIME_FLAG, &(pinode)->pinode_flags)
|
|
|
|
#define ClearCtimeFlag(pinode) clear_bit(P_CTIME_FLAG, &(pinode)->pinode_flags)
|
|
#define SetCtimeFlag(pinode) set_bit(P_CTIME_FLAG, &(pinode)->pinode_flags)
|
|
#define CtimeFlag(pinode) test_bit(P_CTIME_FLAG, &(pinode)->pinode_flags)
|
|
|
|
#define ClearModeFlag(pinode) clear_bit(P_MODE_FLAG, &(pinode)->pinode_flags)
|
|
#define SetModeFlag(pinode) set_bit(P_MODE_FLAG, &(pinode)->pinode_flags)
|
|
#define ModeFlag(pinode) test_bit(P_MODE_FLAG, &(pinode)->pinode_flags)
|
|
|
|
/* per superblock private orangefs info */
|
|
struct orangefs_sb_info_s {
|
|
struct orangefs_khandle root_khandle;
|
|
__s32 fs_id;
|
|
int id;
|
|
int flags;
|
|
#define ORANGEFS_OPT_INTR 0x01
|
|
#define ORANGEFS_OPT_LOCAL_LOCK 0x02
|
|
char devname[ORANGEFS_MAX_SERVER_ADDR_LEN];
|
|
struct super_block *sb;
|
|
int mount_pending;
|
|
struct list_head list;
|
|
};
|
|
|
|
/*
|
|
* structure that holds the state of any async I/O operation issued
|
|
* through the VFS. Needed especially to handle cancellation requests
|
|
* or even completion notification so that the VFS client-side daemon
|
|
* can free up its vfs_request slots.
|
|
*/
|
|
struct orangefs_kiocb_s {
|
|
/* the pointer to the task that initiated the AIO */
|
|
struct task_struct *tsk;
|
|
|
|
/* pointer to the kiocb that kicked this operation */
|
|
struct kiocb *kiocb;
|
|
|
|
/* buffer index that was used for the I/O */
|
|
struct orangefs_bufmap *bufmap;
|
|
int buffer_index;
|
|
|
|
/* orangefs kernel operation type */
|
|
struct orangefs_kernel_op_s *op;
|
|
|
|
/* The user space buffers from/to which I/O is being staged */
|
|
struct iovec *iov;
|
|
|
|
/* number of elements in the iovector */
|
|
unsigned long nr_segs;
|
|
|
|
/* set to indicate the type of the operation */
|
|
int rw;
|
|
|
|
/* file offset */
|
|
loff_t offset;
|
|
|
|
/* and the count in bytes */
|
|
size_t bytes_to_be_copied;
|
|
|
|
ssize_t bytes_copied;
|
|
int needs_cleanup;
|
|
};
|
|
|
|
struct orangefs_stats {
|
|
unsigned long cache_hits;
|
|
unsigned long cache_misses;
|
|
unsigned long reads;
|
|
unsigned long writes;
|
|
};
|
|
|
|
extern struct orangefs_stats orangefs_stats;
|
|
|
|
/*
|
|
* NOTE: See Documentation/filesystems/porting for information
|
|
* on implementing FOO_I and properly accessing fs private data
|
|
*/
|
|
static inline struct orangefs_inode_s *ORANGEFS_I(struct inode *inode)
|
|
{
|
|
return container_of(inode, struct orangefs_inode_s, vfs_inode);
|
|
}
|
|
|
|
static inline struct orangefs_sb_info_s *ORANGEFS_SB(struct super_block *sb)
|
|
{
|
|
return (struct orangefs_sb_info_s *) sb->s_fs_info;
|
|
}
|
|
|
|
/* ino_t descends from "unsigned long", 8 bytes, 64 bits. */
|
|
static inline ino_t orangefs_khandle_to_ino(struct orangefs_khandle *khandle)
|
|
{
|
|
union {
|
|
unsigned char u[8];
|
|
__u64 ino;
|
|
} ihandle;
|
|
|
|
ihandle.u[0] = khandle->u[0] ^ khandle->u[4];
|
|
ihandle.u[1] = khandle->u[1] ^ khandle->u[5];
|
|
ihandle.u[2] = khandle->u[2] ^ khandle->u[6];
|
|
ihandle.u[3] = khandle->u[3] ^ khandle->u[7];
|
|
ihandle.u[4] = khandle->u[12] ^ khandle->u[8];
|
|
ihandle.u[5] = khandle->u[13] ^ khandle->u[9];
|
|
ihandle.u[6] = khandle->u[14] ^ khandle->u[10];
|
|
ihandle.u[7] = khandle->u[15] ^ khandle->u[11];
|
|
|
|
return ihandle.ino;
|
|
}
|
|
|
|
static inline struct orangefs_khandle *get_khandle_from_ino(struct inode *inode)
|
|
{
|
|
return &(ORANGEFS_I(inode)->refn.khandle);
|
|
}
|
|
|
|
static inline __s32 get_fsid_from_ino(struct inode *inode)
|
|
{
|
|
return ORANGEFS_I(inode)->refn.fs_id;
|
|
}
|
|
|
|
static inline ino_t get_ino_from_khandle(struct inode *inode)
|
|
{
|
|
struct orangefs_khandle *khandle;
|
|
ino_t ino;
|
|
|
|
khandle = get_khandle_from_ino(inode);
|
|
ino = orangefs_khandle_to_ino(khandle);
|
|
return ino;
|
|
}
|
|
|
|
static inline ino_t get_parent_ino_from_dentry(struct dentry *dentry)
|
|
{
|
|
return get_ino_from_khandle(dentry->d_parent->d_inode);
|
|
}
|
|
|
|
static inline int is_root_handle(struct inode *inode)
|
|
{
|
|
gossip_debug(GOSSIP_DCACHE_DEBUG,
|
|
"%s: root handle: %pU, this handle: %pU:\n",
|
|
__func__,
|
|
&ORANGEFS_SB(inode->i_sb)->root_khandle,
|
|
get_khandle_from_ino(inode));
|
|
|
|
if (ORANGEFS_khandle_cmp(&(ORANGEFS_SB(inode->i_sb)->root_khandle),
|
|
get_khandle_from_ino(inode)))
|
|
return 0;
|
|
else
|
|
return 1;
|
|
}
|
|
|
|
static inline int match_handle(struct orangefs_khandle resp_handle,
|
|
struct inode *inode)
|
|
{
|
|
gossip_debug(GOSSIP_DCACHE_DEBUG,
|
|
"%s: one handle: %pU, another handle:%pU:\n",
|
|
__func__,
|
|
&resp_handle,
|
|
get_khandle_from_ino(inode));
|
|
|
|
if (ORANGEFS_khandle_cmp(&resp_handle, get_khandle_from_ino(inode)))
|
|
return 0;
|
|
else
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* defined in orangefs-cache.c
|
|
*/
|
|
int op_cache_initialize(void);
|
|
int op_cache_finalize(void);
|
|
struct orangefs_kernel_op_s *op_alloc(__s32 type);
|
|
void orangefs_new_tag(struct orangefs_kernel_op_s *op);
|
|
char *get_opname_string(struct orangefs_kernel_op_s *new_op);
|
|
|
|
int orangefs_inode_cache_initialize(void);
|
|
int orangefs_inode_cache_finalize(void);
|
|
|
|
/*
|
|
* defined in orangefs-mod.c
|
|
*/
|
|
void purge_inprogress_ops(void);
|
|
|
|
/*
|
|
* defined in waitqueue.c
|
|
*/
|
|
void purge_waiting_ops(void);
|
|
|
|
/*
|
|
* defined in super.c
|
|
*/
|
|
extern uint64_t orangefs_features;
|
|
|
|
struct dentry *orangefs_mount(struct file_system_type *fst,
|
|
int flags,
|
|
const char *devname,
|
|
void *data);
|
|
|
|
void orangefs_kill_sb(struct super_block *sb);
|
|
int orangefs_remount(struct orangefs_sb_info_s *);
|
|
|
|
int fsid_key_table_initialize(void);
|
|
void fsid_key_table_finalize(void);
|
|
|
|
/*
|
|
* defined in inode.c
|
|
*/
|
|
__u32 convert_to_orangefs_mask(unsigned long lite_mask);
|
|
struct inode *orangefs_new_inode(struct super_block *sb,
|
|
struct inode *dir,
|
|
int mode,
|
|
dev_t dev,
|
|
struct orangefs_object_kref *ref);
|
|
|
|
int orangefs_setattr(struct dentry *dentry, struct iattr *iattr);
|
|
|
|
int orangefs_getattr(const struct path *path, struct kstat *stat,
|
|
u32 request_mask, unsigned int flags);
|
|
|
|
int orangefs_permission(struct inode *inode, int mask);
|
|
|
|
/*
|
|
* defined in xattr.c
|
|
*/
|
|
int orangefs_setxattr(struct dentry *dentry,
|
|
const char *name,
|
|
const void *value,
|
|
size_t size,
|
|
int flags);
|
|
|
|
ssize_t orangefs_getxattr(struct dentry *dentry,
|
|
const char *name,
|
|
void *buffer,
|
|
size_t size);
|
|
|
|
ssize_t orangefs_listxattr(struct dentry *dentry, char *buffer, size_t size);
|
|
|
|
/*
|
|
* defined in namei.c
|
|
*/
|
|
struct inode *orangefs_iget(struct super_block *sb,
|
|
struct orangefs_object_kref *ref);
|
|
|
|
ssize_t orangefs_inode_read(struct inode *inode,
|
|
struct iov_iter *iter,
|
|
loff_t *offset,
|
|
loff_t readahead_size);
|
|
|
|
/*
|
|
* defined in devorangefs-req.c
|
|
*/
|
|
extern uint32_t orangefs_userspace_version;
|
|
|
|
int orangefs_dev_init(void);
|
|
void orangefs_dev_cleanup(void);
|
|
int is_daemon_in_service(void);
|
|
bool __is_daemon_in_service(void);
|
|
|
|
/*
|
|
* defined in orangefs-utils.c
|
|
*/
|
|
__s32 fsid_of_op(struct orangefs_kernel_op_s *op);
|
|
|
|
int orangefs_flush_inode(struct inode *inode);
|
|
|
|
ssize_t orangefs_inode_getxattr(struct inode *inode,
|
|
const char *name,
|
|
void *buffer,
|
|
size_t size);
|
|
|
|
int orangefs_inode_setxattr(struct inode *inode,
|
|
const char *name,
|
|
const void *value,
|
|
size_t size,
|
|
int flags);
|
|
|
|
int orangefs_inode_getattr(struct inode *inode, int new, int bypass);
|
|
|
|
int orangefs_inode_check_changed(struct inode *inode);
|
|
|
|
int orangefs_inode_setattr(struct inode *inode, struct iattr *iattr);
|
|
|
|
void orangefs_make_bad_inode(struct inode *inode);
|
|
|
|
int orangefs_unmount_sb(struct super_block *sb);
|
|
|
|
bool orangefs_cancel_op_in_progress(struct orangefs_kernel_op_s *op);
|
|
|
|
int orangefs_normalize_to_errno(__s32 error_code);
|
|
|
|
extern struct mutex orangefs_request_mutex;
|
|
extern int op_timeout_secs;
|
|
extern int slot_timeout_secs;
|
|
extern int orangefs_dcache_timeout_msecs;
|
|
extern int orangefs_getattr_timeout_msecs;
|
|
extern struct list_head orangefs_superblocks;
|
|
extern spinlock_t orangefs_superblocks_lock;
|
|
extern struct list_head orangefs_request_list;
|
|
extern spinlock_t orangefs_request_list_lock;
|
|
extern wait_queue_head_t orangefs_request_list_waitq;
|
|
extern struct list_head *orangefs_htable_ops_in_progress;
|
|
extern spinlock_t orangefs_htable_ops_in_progress_lock;
|
|
extern int hash_table_size;
|
|
|
|
extern const struct address_space_operations orangefs_address_operations;
|
|
extern const struct inode_operations orangefs_file_inode_operations;
|
|
extern const struct file_operations orangefs_file_operations;
|
|
extern const struct inode_operations orangefs_symlink_inode_operations;
|
|
extern const struct inode_operations orangefs_dir_inode_operations;
|
|
extern const struct file_operations orangefs_dir_operations;
|
|
extern const struct dentry_operations orangefs_dentry_operations;
|
|
extern const struct file_operations orangefs_devreq_file_operations;
|
|
|
|
extern wait_queue_head_t orangefs_bufmap_init_waitq;
|
|
|
|
/*
|
|
* misc convenience macros
|
|
*/
|
|
|
|
#define ORANGEFS_OP_INTERRUPTIBLE 1 /* service_operation() is interruptible */
|
|
#define ORANGEFS_OP_PRIORITY 2 /* service_operation() is high priority */
|
|
#define ORANGEFS_OP_CANCELLATION 4 /* this is a cancellation */
|
|
#define ORANGEFS_OP_NO_MUTEX 8 /* don't acquire request_mutex */
|
|
#define ORANGEFS_OP_ASYNC 16 /* Queue it, but don't wait */
|
|
|
|
int service_operation(struct orangefs_kernel_op_s *op,
|
|
const char *op_name,
|
|
int flags);
|
|
|
|
#define get_interruptible_flag(inode) \
|
|
((ORANGEFS_SB(inode->i_sb)->flags & ORANGEFS_OPT_INTR) ? \
|
|
ORANGEFS_OP_INTERRUPTIBLE : 0)
|
|
|
|
#define fill_default_sys_attrs(sys_attr, type, mode) \
|
|
do { \
|
|
sys_attr.owner = from_kuid(&init_user_ns, current_fsuid()); \
|
|
sys_attr.group = from_kgid(&init_user_ns, current_fsgid()); \
|
|
sys_attr.perms = ORANGEFS_util_translate_mode(mode); \
|
|
sys_attr.mtime = 0; \
|
|
sys_attr.atime = 0; \
|
|
sys_attr.ctime = 0; \
|
|
sys_attr.mask = ORANGEFS_ATTR_SYS_ALL_SETABLE; \
|
|
} while (0)
|
|
|
|
static inline void orangefs_i_size_write(struct inode *inode, loff_t i_size)
|
|
{
|
|
#if BITS_PER_LONG == 32 && defined(CONFIG_SMP)
|
|
inode_lock(inode);
|
|
#endif
|
|
i_size_write(inode, i_size);
|
|
#if BITS_PER_LONG == 32 && defined(CONFIG_SMP)
|
|
inode_unlock(inode);
|
|
#endif
|
|
}
|
|
|
|
static inline void orangefs_set_timeout(struct dentry *dentry)
|
|
{
|
|
unsigned long time = jiffies + orangefs_dcache_timeout_msecs*HZ/1000;
|
|
|
|
dentry->d_fsdata = (void *) time;
|
|
}
|
|
|
|
#endif /* __ORANGEFSKERNEL_H */
|