Newer
Older
* Copyright (C) 2002, 2007 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
#include <linux/compiler.h>
#include <linux/kernel.h>
#include <linux/rxrpc.h>
#include <net/net_namespace.h>
#include <net/af_rxrpc.h>
#include "afs.h"
#include "afs_vl.h"
#define AFS_CELL_MAX_ADDRS 15
struct afs_call;
struct afs_mount_params {
bool rwpath; /* T if the parent should be considered R/W */
bool force; /* T to force cell type */
bool autocell; /* T if set auto mount operation */
afs_voltype_t type; /* type of volume requested */
int volnamesz; /* size of volume name */
const char *volname; /* name of volume to mount */
struct afs_net *net; /* Network namespace in effect */
struct afs_cell *cell; /* cell in which to find volume */
struct afs_volume *volume; /* volume record */
struct key *key; /* key to use for secure mounting */
};
struct afs_iget_data {
struct afs_fid fid;
struct afs_volume *volume; /* volume on which resides */
};
AFS_CALL_CL_REQUESTING, /* Client: Request is being sent */
AFS_CALL_CL_AWAIT_REPLY, /* Client: Awaiting reply */
AFS_CALL_CL_PROC_REPLY, /* Client: rxrpc call complete; processing reply */
AFS_CALL_SV_AWAIT_OP_ID, /* Server: Awaiting op ID */
AFS_CALL_SV_AWAIT_REQUEST, /* Server: Awaiting request data */
AFS_CALL_SV_REPLYING, /* Server: Replying */
AFS_CALL_SV_AWAIT_ACK, /* Server: Awaiting final ACK */
AFS_CALL_COMPLETE, /* Completed or failed */
/*
* List of server addresses.
*/
struct afs_addr_list {
struct rcu_head rcu; /* Must be first */
refcount_t usage;
u32 version; /* Version */
unsigned short nr_addrs;
unsigned short index; /* Address currently in use */
unsigned short nr_ipv4; /* Number of IPv4 addresses */
unsigned long probed; /* Mask of servers that have been probed */
unsigned long yfs; /* Mask of servers that are YFS */
/*
* a record of an in-progress RxRPC call
*/
struct afs_call {
const struct afs_call_type *type; /* type of call */
wait_queue_head_t waitq; /* processes awaiting completion */
struct work_struct async_work; /* async I/O processor */
struct work_struct work; /* actual work processor */
struct rxrpc_call *rxcall; /* RxRPC call handle */
struct key *key; /* security for this call */
struct afs_net *net; /* The network namespace */
struct afs_server *cm_server; /* Server affected by incoming CM call */
struct afs_cb_interest *cbi; /* Callback interest for server used */
void *request; /* request data (first part) */
struct address_space *mapping; /* Pages being written from */
void *buffer; /* reply receive buffer */
void *reply[4]; /* Where to put the reply */
pgoff_t first; /* first page in mapping to deal with */
pgoff_t last; /* last page in mapping to deal with */
size_t offset; /* offset into received data store */
int error; /* error code */
u32 abort_code; /* Remote abort ID or 0 */
unsigned request_size; /* size of request data */
unsigned reply_max; /* maximum size of reply */
unsigned first_offset; /* offset into mapping[first] */
unsigned int cb_break; /* cb_break + cb_s_break before the call */
union {
unsigned last_to; /* amount of mapping[last] */
unsigned count2; /* count used in unmarshalling */
};
unsigned char unmarshall; /* unmarshalling phase */
bool incoming; /* T if incoming call */
bool send_pages; /* T if data from mapping should be sent */
bool need_attention; /* T if RxRPC poked us */
bool ret_reply0; /* T if should return reply[0] on success */
bool upgrade; /* T to request service upgrade */
u16 service_id; /* Actual service ID (after upgrade) */
u32 operation_ID; /* operation ID for an incoming call */
u32 count; /* count for use in unmarshalling */
__be32 tmp; /* place to extract temporary data */
afs_dataversion_t store_version; /* updated version expected from store */
};
struct afs_call_type {
unsigned int op; /* Really enum afs_fs_operation */
/* deliver request or reply data to an call
* - returning an error will cause the call to be aborted
*/
int (*deliver)(struct afs_call *call);
/* clean up a call */
void (*destructor)(struct afs_call *call);
/* Work function */
void (*work)(struct work_struct *work);
/*
* Key available for writeback on a file.
*/
struct afs_wb_key {
refcount_t usage;
struct key *key;
struct list_head vnode_link; /* Link in vnode->wb_keys */
};
/*
* AFS open file information record. Pointed to by file->private_data.
*/
struct afs_file {
struct key *key; /* The key this file was opened with */
struct afs_wb_key *wb; /* Writeback key record for this file */
};
static inline struct key *afs_file_key(struct file *file)
{
struct afs_file *af = file->private_data;
return af->key;
}
/*
* Record of an outstanding read operation on a vnode.
*/
struct afs_read {
loff_t pos; /* Where to start reading */
loff_t len; /* How much we're asking for */
loff_t actual_len; /* How much we're actually getting */
loff_t remain; /* Amount remaining */
atomic_t usage;
unsigned int index; /* Which page we're reading into */
unsigned int nr_pages;
void (*page_done)(struct afs_call *, struct afs_read *);
struct page *pages[];
};
/*
* AFS superblock private data
* - there's one superblock per volume
*/
struct afs_super_info {
struct afs_net *net; /* Network namespace */
struct afs_cell *cell; /* The cell in which the volume resides */
struct afs_volume *volume; /* volume record */
bool dyn_root; /* True if dynamic root */
static inline struct afs_super_info *AFS_FS_S(struct super_block *sb)
{
return sb->s_fs_info;
extern struct file_system_type afs_fs_type;
* AFS network namespace record.
*/
struct afs_net {
struct afs_uuid uuid;
bool live; /* F if this namespace is being removed */
/* AF_RXRPC I/O stuff */
struct socket *socket;
struct afs_call *spare_incoming_call;
struct work_struct charge_preallocation_work;
struct mutex socket_mutex;
atomic_t nr_outstanding_calls;
atomic_t nr_superblocks;
/* Cell database */
struct afs_cell *ws_cell;
struct work_struct cells_manager;
struct timer_list cells_timer;
atomic_t cells_outstanding;
seqlock_t cells_lock;
struct list_head proc_cells;
/* Known servers. Theoretically each fileserver can only be in one
* cell, but in practice, people create aliases and subsets and there's
* no easy way to distinguish them.
*/
seqlock_t fs_lock; /* For fs_servers */
struct rb_root fs_servers; /* afs_server (by server UUID or address) */
struct list_head fs_updates; /* afs_server (by update_at) */
struct hlist_head fs_proc; /* procfs servers list */
struct hlist_head fs_addresses4; /* afs_server (by lowest IPv4 addr) */
struct hlist_head fs_addresses6; /* afs_server (by lowest IPv6 addr) */
seqlock_t fs_addr_lock; /* For fs_addresses[46] */
struct work_struct fs_manager;
struct timer_list fs_timer;
/* File locking renewal management */
struct mutex lock_manager_mutex;
/* Misc */
struct proc_dir_entry *proc_afs; /* /proc/net/afs directory */
};
extern struct afs_net __afs_net;// Dummy AFS network namespace; TODO: replace with real netns
enum afs_cell_state {
AFS_CELL_UNSET,
AFS_CELL_ACTIVATING,
AFS_CELL_ACTIVE,
AFS_CELL_DEACTIVATING,
AFS_CELL_INACTIVE,
AFS_CELL_FAILED,
};
* AFS cell record.
*
* This is a tricky concept to get right as it is possible to create aliases
* simply by pointing AFSDB/SRV records for two names at the same set of VL
* servers; it is also possible to do things like setting up two sets of VL
* servers, one of which provides a superset of the volumes provided by the
* other (for internal/external division, for example).
*
* Cells only exist in the sense that (a) a cell's name maps to a set of VL
* servers and (b) a cell's name is used by the client to select the key to use
* for authentication and encryption. The cell name is not typically used in
* the protocol.
*
* There is no easy way to determine if two cells are aliases or one is a
* subset of another.
*/
struct afs_cell {
union {
struct rcu_head rcu;
struct rb_node net_node; /* Node in net->cells */
};
struct afs_net *net;
struct key *anonymous_key; /* anonymous user key for this cell */
struct work_struct manager; /* Manager for init/deinit/dns */
struct list_head proc_link; /* /proc cell list link */
#ifdef CONFIG_AFS_FSCACHE
struct fscache_cookie *cache; /* caching cookie */
time64_t dns_expiry; /* Time AFSDB/SRV record expires */
time64_t last_inactive; /* Time of last drop of usage count */
atomic_t usage;
unsigned long flags;
#define AFS_CELL_FL_NOT_READY 0 /* The cell record is not ready for use */
#define AFS_CELL_FL_NO_GC 1 /* The cell was added manually, don't auto-gc */
#define AFS_CELL_FL_NOT_FOUND 2 /* Permanent DNS error */
#define AFS_CELL_FL_DNS_FAIL 3 /* Failed to access DNS */
#define AFS_CELL_FL_NO_LOOKUP_YET 4 /* Not completed first DNS lookup yet */
enum afs_cell_state state;
short error;
/* Active fileserver interaction state. */
struct list_head proc_volumes; /* procfs volume list */
rwlock_t proc_lock;
/* VL server list. */
rwlock_t vl_addrs_lock; /* Lock on vl_addrs */
struct afs_addr_list __rcu *vl_addrs; /* List of VL servers */
u8 name_len; /* Length of name */
char name[64 + 1]; /* Cell name, case-flattened and NUL-padded */
};
/*
* Cached VLDB entry.
*
* This is pointed to by cell->vldb_entries, indexed by name.
struct afs_vldb_entry {
afs_volid_t vid[3]; /* Volume IDs for R/W, R/O and Bak volumes */
unsigned long flags;
#define AFS_VLDB_HAS_RW 0 /* - R/W volume exists */
#define AFS_VLDB_HAS_RO 1 /* - R/O volume exists */
#define AFS_VLDB_HAS_BAK 2 /* - Backup volume exists */
#define AFS_VLDB_QUERY_VALID 3 /* - Record is valid */
#define AFS_VLDB_QUERY_ERROR 4 /* - VL server returned error */
uuid_t fs_server[AFS_NMAXNSERVERS];
u8 fs_mask[AFS_NMAXNSERVERS];
#define AFS_VOL_VTM_RW 0x01 /* R/W version of the volume is available (on this server) */
#define AFS_VOL_VTM_RO 0x02 /* R/O version of the volume is available (on this server) */
#define AFS_VOL_VTM_BAK 0x04 /* backup version of the volume is available (on this server) */
short error;
u8 nr_servers; /* Number of server records */
u8 name_len;
u8 name[AFS_MAXVOLNAME + 1]; /* NUL-padded volume name */
};
/*
* Record of fileserver with which we're actively communicating.
*/
struct afs_server {
struct rcu_head rcu;
union {
uuid_t uuid; /* Server ID */
struct afs_uuid _uuid;
};
struct afs_addr_list __rcu *addresses;
struct rb_node uuid_rb; /* Link in net->servers */
struct hlist_node addr4_link; /* Link in net->fs_addresses4 */
struct hlist_node addr6_link; /* Link in net->fs_addresses6 */
struct hlist_node proc_link; /* Link in net->fs_proc */
struct afs_server *gc_next; /* Next server in manager's list */
time64_t put_time; /* Time at which last put */
time64_t update_at; /* Time at which to next update the record */
#define AFS_SERVER_FL_NEW 0 /* New server, don't inc cb_s_break */
#define AFS_SERVER_FL_NOT_READY 1 /* The record is not ready for use */
#define AFS_SERVER_FL_NOT_FOUND 2 /* VL server says no such server */
#define AFS_SERVER_FL_VL_FAIL 3 /* Failed to access VL server */
#define AFS_SERVER_FL_UPDATING 4
#define AFS_SERVER_FL_PROBED 5 /* The fileserver has been probed */
#define AFS_SERVER_FL_PROBING 6 /* Fileserver is being probed */
atomic_t usage;
u32 addr_version; /* Address list version */
/* file service access */
rwlock_t fs_lock; /* access lock */
/* callback promise management */
struct list_head cb_interests; /* List of superblocks using this server */
unsigned cb_s_break; /* Break-everything counter. */
rwlock_t cb_break_lock; /* Volume finding lock */
};
/*
* Interest by a superblock on a server.
*/
struct afs_cb_interest {
struct list_head cb_link; /* Link in server->cb_interests */
struct afs_server *server; /* Server on which this interest resides */
struct super_block *sb; /* Superblock on which inodes reside */
afs_volid_t vid; /* Volume ID to match */
refcount_t usage;
};
/*
* Replaceable server list.
*/
struct afs_server_entry {
struct afs_server *server;
struct afs_cb_interest *cb_interest;
};
struct afs_server_list {
refcount_t usage;
unsigned short nr_servers;
unsigned short index; /* Server currently in use */
unsigned short vnovol_mask; /* Servers to be skipped due to VNOVOL */
unsigned int seq; /* Set to ->servers_seq when installed */
struct afs_server_entry servers[];
};
/*
* Live AFS volume management.
*/
struct afs_volume {
afs_volid_t vid; /* volume ID */
atomic_t usage;
time64_t update_at; /* Time at which to next update */
struct afs_cell *cell; /* Cell to which belongs (pins ref) */
struct list_head proc_link; /* Link in cell->vl_proc */
unsigned long flags;
#define AFS_VOLUME_NEEDS_UPDATE 0 /* - T if an update needs performing */
#define AFS_VOLUME_UPDATING 1 /* - T if an update is in progress */
#define AFS_VOLUME_WAIT 2 /* - T if users must wait for update */
#define AFS_VOLUME_DELETED 3 /* - T if volume appears deleted */
#define AFS_VOLUME_OFFLINE 4 /* - T if volume offline notice given */
#define AFS_VOLUME_BUSY 5 /* - T if volume busy notice given */
#ifdef CONFIG_AFS_FSCACHE
struct fscache_cookie *cache; /* caching cookie */
struct afs_server_list *servers; /* List of servers on which volume resides */
rwlock_t servers_lock; /* Lock for ->servers */
unsigned int servers_seq; /* Incremented each time ->servers changes */
afs_voltype_t type; /* type of volume */
short error;
char type_force; /* force volume type (suppress R/O -> R/W) */
u8 name_len;
u8 name[AFS_MAXVOLNAME + 1]; /* NUL-padded volume name */
enum afs_lock_state {
AFS_VNODE_LOCK_NONE, /* The vnode has no lock on the server */
AFS_VNODE_LOCK_WAITING_FOR_CB, /* We're waiting for the server to break the callback */
AFS_VNODE_LOCK_SETTING, /* We're asking the server for a lock */
AFS_VNODE_LOCK_GRANTED, /* We have a lock on the server */
AFS_VNODE_LOCK_EXTENDING, /* We're extending a lock on the server */
AFS_VNODE_LOCK_NEED_UNLOCK, /* We need to unlock on the server */
AFS_VNODE_LOCK_UNLOCKING, /* We're telling the server to unlock */
};
* AFS inode private data.
*
* Note that afs_alloc_inode() *must* reset anything that could incorrectly
* leak from one inode to another.
Loading
Loading full blame...