linux/fs/ocfs2/stack_user.c

// SPDX-License-Identifier: GPL-2.0-only
/*
 * stack_user.c
 *
 * Code which interfaces ocfs2 with fs/dlm and a userspace stack.
 *
 * Copyright (C) 2007 Oracle.  All rights reserved.
 */

#include <linux/module.h>
#include <linux/fs.h>
#include <linux/filelock.h>
#include <linux/miscdevice.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/reboot.h>
#include <linux/sched.h>
#include <linux/uaccess.h>

#include "stackglue.h"

#include <linux/dlm_plock.h>

/*
 * The control protocol starts with a handshake.  Until the handshake
 * is complete, the control device will fail all write(2)s.
 *
 * The handshake is simple.  First, the client reads until EOF.  Each line
 * of output is a supported protocol tag.  All protocol tags are a single
 * character followed by a two hex digit version number.  Currently the
 * only things supported is T01, for "Text-base version 0x01".  Next, the
 * client writes the version they would like to use, including the newline.
 * Thus, the protocol tag is 'T01\n'.  If the version tag written is
 * unknown, -EINVAL is returned.  Once the negotiation is complete, the
 * client can start sending messages.
 *
 * The T01 protocol has three messages.  First is the "SETN" message.
 * It has the following syntax:
 *
 *  SETN<space><8-char-hex-nodenum><newline>
 *
 * This is 14 characters.
 *
 * The "SETN" message must be the first message following the protocol.
 * It tells ocfs2_control the local node number.
 *
 * Next comes the "SETV" message.  It has the following syntax:
 *
 *  SETV<space><2-char-hex-major><space><2-char-hex-minor><newline>
 *
 * This is 11 characters.
 *
 * The "SETV" message sets the filesystem locking protocol version as
 * negotiated by the client.  The client negotiates based on the maximum
 * version advertised in /sys/fs/ocfs2/max_locking_protocol.  The major
 * number from the "SETV" message must match
 * ocfs2_user_plugin.sp_max_proto.pv_major, and the minor number
 * must be less than or equal to ...sp_max_version.pv_minor.
 *
 * Once this information has been set, mounts will be allowed.  From this
 * point on, the "DOWN" message can be sent for node down notification.
 * It has the following syntax:
 *
 *  DOWN<space><32-char-cap-hex-uuid><space><8-char-hex-nodenum><newline>
 *
 * eg:
 *
 *  DOWN 632A924FDD844190BDA93C0DF6B94899 00000001\n
 *
 * This is 47 characters.
 */

/*
 * Whether or not the client has done the handshake.
 * For now, we have just one protocol version.
 */
#define OCFS2_CONTROL_PROTO
#define OCFS2_CONTROL_PROTO_LEN

/* Handshake states */
#define OCFS2_CONTROL_HANDSHAKE_INVALID
#define OCFS2_CONTROL_HANDSHAKE_READ
#define OCFS2_CONTROL_HANDSHAKE_PROTOCOL
#define OCFS2_CONTROL_HANDSHAKE_VALID

/* Messages */
#define OCFS2_CONTROL_MESSAGE_OP_LEN
#define OCFS2_CONTROL_MESSAGE_SETNODE_OP
#define OCFS2_CONTROL_MESSAGE_SETNODE_TOTAL_LEN
#define OCFS2_CONTROL_MESSAGE_SETVERSION_OP
#define OCFS2_CONTROL_MESSAGE_SETVERSION_TOTAL_LEN
#define OCFS2_CONTROL_MESSAGE_DOWN_OP
#define OCFS2_CONTROL_MESSAGE_DOWN_TOTAL_LEN
#define OCFS2_TEXT_UUID_LEN
#define OCFS2_CONTROL_MESSAGE_VERNUM_LEN
#define OCFS2_CONTROL_MESSAGE_NODENUM_LEN
#define VERSION_LOCK

enum ocfs2_connection_type {};

/*
 * ocfs2_live_connection is refcounted because the filesystem and
 * miscdevice sides can detach in different order.  Let's just be safe.
 */
struct ocfs2_live_connection {};

struct ocfs2_control_private {};

/* SETN<space><8-char-hex-nodenum><newline> */
struct ocfs2_control_message_setn {};

/* SETV<space><2-char-hex-major><space><2-char-hex-minor><newline> */
struct ocfs2_control_message_setv {};

/* DOWN<space><32-char-cap-hex-uuid><space><8-char-hex-nodenum><newline> */
struct ocfs2_control_message_down {};

ocfs2_control_message;

static struct ocfs2_stack_plugin ocfs2_user_plugin;

static atomic_t ocfs2_control_opened;
static int ocfs2_control_this_node =;
static struct ocfs2_protocol_version running_proto;

static LIST_HEAD(ocfs2_live_connection_list);
static LIST_HEAD(ocfs2_control_private_list);
static DEFINE_MUTEX(ocfs2_control_lock);

static inline void ocfs2_control_set_handshake_state(struct file *file,
						     int state)
{}

static inline int ocfs2_control_get_handshake_state(struct file *file)
{}

static struct ocfs2_live_connection *ocfs2_connection_find(const char *name)
{}

/*
 * ocfs2_live_connection structures are created underneath the ocfs2
 * mount path.  Since the VFS prevents multiple calls to
 * fill_super(), we can't get dupes here.
 */
static int ocfs2_live_connection_attach(struct ocfs2_cluster_connection *conn,
				     struct ocfs2_live_connection *c)
{}

/*
 * This function disconnects the cluster connection from ocfs2_control.
 * Afterwards, userspace can't affect the cluster connection.
 */
static void ocfs2_live_connection_drop(struct ocfs2_live_connection *c)
{}

static int ocfs2_control_cfu(void *target, size_t target_len,
			     const char __user *buf, size_t count)
{}

static ssize_t ocfs2_control_validate_protocol(struct file *file,
					       const char __user *buf,
					       size_t count)
{}

static void ocfs2_control_send_down(const char *uuid,
				    int nodenum)
{}

/*
 * Called whenever configuration elements are sent to /dev/ocfs2_control.
 * If all configuration elements are present, try to set the global
 * values.  If there is a problem, return an error.  Skip any missing
 * elements, and only bump ocfs2_control_opened when we have all elements
 * and are successful.
 */
static int ocfs2_control_install_private(struct file *file)
{}

static int ocfs2_control_get_this_node(void)
{}

static int ocfs2_control_do_setnode_msg(struct file *file,
					struct ocfs2_control_message_setn *msg)
{}

static int ocfs2_control_do_setversion_msg(struct file *file,
					   struct ocfs2_control_message_setv *msg)
{}

static int ocfs2_control_do_down_msg(struct file *file,
				     struct ocfs2_control_message_down *msg)
{}

static ssize_t ocfs2_control_message(struct file *file,
				     const char __user *buf,
				     size_t count)
{}

static ssize_t ocfs2_control_write(struct file *file,
				   const char __user *buf,
				   size_t count,
				   loff_t *ppos)
{}

/*
 * This is a naive version.  If we ever have a new protocol, we'll expand
 * it.  Probably using seq_file.
 */
static ssize_t ocfs2_control_read(struct file *file,
				  char __user *buf,
				  size_t count,
				  loff_t *ppos)
{}

static int ocfs2_control_release(struct inode *inode, struct file *file)
{}

static int ocfs2_control_open(struct inode *inode, struct file *file)
{}

static const struct file_operations ocfs2_control_fops =;

static struct miscdevice ocfs2_control_device =;

static int ocfs2_control_init(void)
{}

static void ocfs2_control_exit(void)
{}

static void fsdlm_lock_ast_wrapper(void *astarg)
{}

static void fsdlm_blocking_ast_wrapper(void *astarg, int level)
{}

static int user_dlm_lock(struct ocfs2_cluster_connection *conn,
			 int mode,
			 struct ocfs2_dlm_lksb *lksb,
			 u32 flags,
			 void *name,
			 unsigned int namelen)
{}

static int user_dlm_unlock(struct ocfs2_cluster_connection *conn,
			   struct ocfs2_dlm_lksb *lksb,
			   u32 flags)
{}

static int user_dlm_lock_status(struct ocfs2_dlm_lksb *lksb)
{}

static int user_dlm_lvb_valid(struct ocfs2_dlm_lksb *lksb)
{}

static void *user_dlm_lvb(struct ocfs2_dlm_lksb *lksb)
{}

static void user_dlm_dump_lksb(struct ocfs2_dlm_lksb *lksb)
{}

static int user_plock(struct ocfs2_cluster_connection *conn,
		      u64 ino,
		      struct file *file,
		      int cmd,
		      struct file_lock *fl)
{}

/*
 * Compare a requested locking protocol version against the current one.
 *
 * If the major numbers are different, they are incompatible.
 * If the current minor is greater than the request, they are incompatible.
 * If the current minor is less than or equal to the request, they are
 * compatible, and the requester should run at the current minor version.
 */
static int fs_protocol_compare(struct ocfs2_protocol_version *existing,
			       struct ocfs2_protocol_version *request)
{}

static void lvb_to_version(char *lvb, struct ocfs2_protocol_version *ver)
{}

static void version_to_lvb(struct ocfs2_protocol_version *ver, char *lvb)
{}

static void sync_wait_cb(void *arg)
{}

static int sync_unlock(struct ocfs2_cluster_connection *conn,
		struct dlm_lksb *lksb, char *name)
{}

static int sync_lock(struct ocfs2_cluster_connection *conn,
		int mode, uint32_t flags,
		struct dlm_lksb *lksb, char *name)
{}


static int version_lock(struct ocfs2_cluster_connection *conn, int mode,
		int flags)
{}

static int version_unlock(struct ocfs2_cluster_connection *conn)
{}

/* get_protocol_version()
 *
 * To exchange ocfs2 versioning, we use the LVB of the version dlm lock.
 * The algorithm is:
 * 1. Attempt to take the lock in EX mode (non-blocking).
 * 2. If successful (which means it is the first mount), write the
 *    version number and downconvert to PR lock.
 * 3. If unsuccessful (returns -EAGAIN), read the version from the LVB after
 *    taking the PR lock.
 */

static int get_protocol_version(struct ocfs2_cluster_connection *conn)
{}

static void user_recover_prep(void *arg)
{}

static void user_recover_slot(void *arg, struct dlm_slot *slot)
{}

static void user_recover_done(void *arg, struct dlm_slot *slots,
		int num_slots, int our_slot,
		uint32_t generation)
{}

static const struct dlm_lockspace_ops ocfs2_ls_ops =;

static int user_cluster_disconnect(struct ocfs2_cluster_connection *conn)
{}

static int user_cluster_connect(struct ocfs2_cluster_connection *conn)
{}


static int user_cluster_this_node(struct ocfs2_cluster_connection *conn,
				  unsigned int *this_node)
{}

static const struct ocfs2_stack_operations ocfs2_user_plugin_ops =;

static struct ocfs2_stack_plugin ocfs2_user_plugin =;


static int __init ocfs2_user_plugin_init(void)
{}

static void __exit ocfs2_user_plugin_exit(void)
{}

MODULE_AUTHOR();
MODULE_DESCRIPTION();
MODULE_LICENSE();
module_init();
module_exit(ocfs2_user_plugin_exit);