Commit 08e0e7c8 authored by David Howells's avatar David Howells Committed by David S. Miller

[AF_RXRPC]: Make the in-kernel AFS filesystem use AF_RXRPC.

Make the in-kernel AFS filesystem use AF_RXRPC instead of the old RxRPC code.
Signed-off-by: default avatarDavid Howells <dhowells@redhat.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 651350d1
......@@ -2019,7 +2019,7 @@ config CODA_FS_OLD_API
config AFS_FS
tristate "Andrew File System support (AFS) (EXPERIMENTAL)"
depends on INET && EXPERIMENTAL
select RXRPC
select AF_RXRPC
help
If you say Y here, you will get an experimental Andrew File System
driver. It currently only supports unsecured read-only AFS access.
......@@ -2028,6 +2028,17 @@ config AFS_FS
If unsure, say N.
config AFS_DEBUG
bool "AFS dynamic debugging"
depends on AFS_FS
help
Say Y here to make runtime controllable debugging messages appear.
See <file:Documentation/filesystems/afs.txt> for more information.
If unsure, say N.
config RXRPC
tristate
......
......@@ -10,12 +10,11 @@ kafs-objs := \
file.o \
fsclient.o \
inode.o \
kafsasyncd.o \
kafstimod.o \
main.o \
misc.o \
mntpt.o \
proc.o \
rxrpc.o \
server.o \
super.o \
vlclient.o \
......
/* AFS types
/* AFS common types
*
* Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
* 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
......@@ -9,10 +9,10 @@
* 2 of the License, or (at your option) any later version.
*/
#ifndef AFS_TYPES_H
#define AFS_TYPES_H
#ifndef AFS_H
#define AFS_H
#include <rxrpc/types.h>
#include <linux/in.h>
typedef unsigned afs_volid_t;
typedef unsigned afs_vnodeid_t;
......@@ -31,9 +31,6 @@ typedef enum {
AFS_FTYPE_SYMLINK = 3,
} afs_file_type_t;
struct afs_cell;
struct afs_vnode;
/*
* AFS file identifier
*/
......@@ -54,14 +51,13 @@ typedef enum {
} afs_callback_type_t;
struct afs_callback {
struct afs_server *server; /* server that made the promise */
struct afs_fid fid; /* file identifier */
unsigned version; /* callback version */
unsigned expiry; /* time at which expires */
afs_callback_type_t type; /* type of callback */
};
#define AFSCBMAX 50
#define AFSCBMAX 50 /* maximum callbacks transferred per bulk op */
/*
* AFS volume information
......@@ -70,7 +66,7 @@ struct afs_volume_info {
afs_volid_t vid; /* volume ID */
afs_voltype_t type; /* type of this volume */
afs_volid_t type_vids[5]; /* volume ID's for possible types for this vol */
/* list of fileservers serving this volume */
size_t nservers; /* number of entries used in servers[] */
struct {
......@@ -88,7 +84,7 @@ struct afs_file_status {
afs_file_type_t type; /* file type */
unsigned nlink; /* link count */
size_t size; /* file size */
afs_dataversion_t version; /* current data version */
afs_dataversion_t data_version; /* current data version */
unsigned author; /* author ID */
unsigned owner; /* owner ID */
unsigned caller_access; /* access rights for authenticated caller */
......@@ -106,4 +102,4 @@ struct afs_volsync {
time_t creation; /* volume creation time */
};
#endif /* AFS_TYPES_H */
#endif /* AFS_H */
/* mount parameters
/* AFS Cache Manager definitions
*
* Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
* Copyright (C) 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
......@@ -9,15 +9,20 @@
* 2 of the License, or (at your option) any later version.
*/
#ifndef AFS_MOUNT_H
#define AFS_MOUNT_H
#ifndef AFS_CM_H
#define AFS_CM_H
struct afs_mountdata {
const char *volume; /* name of volume */
const char *cell; /* name of cell containing volume */
const char *cache; /* name of cache block device */
size_t nservers; /* number of server addresses listed */
uint32_t servers[10]; /* IP addresses of servers in this cell */
#define AFS_CM_PORT 7001 /* AFS file server port */
#define CM_SERVICE 1 /* AFS File Service ID */
enum AFS_CM_Operations {
CBCallBack = 204, /* break callback promises */
CBInitCallBackState = 205, /* initialise callback state */
CBProbe = 206, /* probe client */
CBGetLock = 207, /* get contents of CM lock table */
CBGetCE = 208, /* get cache file description */
CBGetXStatsVersion = 209, /* get version of extended statistics */
CBGetXStats = 210, /* get contents of extended statistics data */
};
#endif /* AFS_MOUNT_H */
#endif /* AFS_FS_H */
/* AFS abort/error codes
/* AFS File Service definitions
*
* Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
* Copyright (C) 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
......@@ -9,15 +9,22 @@
* 2 of the License, or (at your option) any later version.
*/
#ifndef AFS_ERRORS_H
#define AFS_ERRORS_H
#ifndef AFS_FS_H
#define AFS_FS_H
#include "types.h"
#define AFS_FS_PORT 7000 /* AFS file server port */
#define FS_SERVICE 1 /* AFS File Service ID */
/*
* file server abort codes
*/
typedef enum {
enum AFS_FS_Operations {
FSFETCHSTATUS = 132, /* AFS Fetch file status */
FSFETCHDATA = 130, /* AFS Fetch file data */
FSGIVEUPCALLBACKS = 147, /* AFS Discard callback promises */
FSGETVOLUMEINFO = 148, /* AFS Get root volume information */
FSGETROOTVOLUME = 151, /* AFS Get root volume name */
FSLOOKUP = 161 /* AFS lookup file in directory */
};
enum AFS_FS_Errors {
VSALVAGE = 101, /* volume needs salvaging */
VNOVNODE = 102, /* no such file/dir (vnode) */
VNOVOL = 103, /* no such volume or volume unavailable */
......@@ -29,8 +36,6 @@ typedef enum {
VOVERQUOTA = 109, /* volume's maximum quota exceeded */
VBUSY = 110, /* volume is temporarily unavailable */
VMOVED = 111, /* volume moved to new server - ask this FS where */
} afs_rxfs_abort_t;
extern int afs_abort_to_error(int);
};
#endif /* AFS_ERRORS_H */
#endif /* AFS_FS_H */
/* Volume Location Service client interface
/* AFS Volume Location Service client interface
*
* Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
* 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
......@@ -9,10 +9,19 @@
* 2 of the License, or (at your option) any later version.
*/
#ifndef AFS_VLCLIENT_H
#define AFS_VLCLIENT_H
#ifndef AFS_VL_H
#define AFS_VL_H
#include "types.h"
#include "afs.h"
#define AFS_VL_PORT 7003 /* volume location service port */
#define VL_SERVICE 52 /* RxRPC service ID for the Volume Location service */
enum AFSVL_Operations {
VLGETENTRYBYID = 503, /* AFS Get Cache Entry By ID operation ID */
VLGETENTRYBYNAME = 504, /* AFS Get Cache Entry By Name operation ID */
VLPROBE = 514, /* AFS Probe Volume Location Service operation ID */
};
enum AFSVL_Errors {
AFSVL_IDEXIST = 363520, /* Volume Id entry exists in vl database */
......@@ -40,14 +49,16 @@ enum AFSVL_Errors {
AFSVL_BADVOLOPER = 363542, /* Bad volume operation code */
AFSVL_BADRELLOCKTYPE = 363543, /* Bad release lock type */
AFSVL_RERELEASE = 363544, /* Status report: last release was aborted */
AFSVL_BADSERVERFLAG = 363545, /* Invalid replication site server ag */
AFSVL_BADSERVERFLAG = 363545, /* Invalid replication site server °ag */
AFSVL_PERM = 363546, /* No permission access */
AFSVL_NOMEM = 363547, /* malloc/realloc failed to alloc enough memory */
};
/* maps to "struct vldbentry" in vvl-spec.pdf */
/*
* maps to "struct vldbentry" in vvl-spec.pdf
*/
struct afs_vldbentry {
char name[65]; /* name of volume (including NUL char) */
char name[65]; /* name of volume (with NUL char) */
afs_voltype_t type; /* volume type */
unsigned num_servers; /* num servers that hold instances of this vol */
unsigned clone_id; /* cloning ID */
......@@ -70,16 +81,4 @@ struct afs_vldbentry {
} servers[8];
};
extern int afs_rxvl_get_entry_by_name(struct afs_server *, const char *,
unsigned, struct afs_cache_vlocation *);
extern int afs_rxvl_get_entry_by_id(struct afs_server *, afs_volid_t,
afs_voltype_t,
struct afs_cache_vlocation *);
extern int afs_rxvl_get_entry_by_id_async(struct afs_async_op *,
afs_volid_t, afs_voltype_t);
extern int afs_rxvl_get_entry_by_id_async2(struct afs_async_op *,
struct afs_cache_vlocation *);
#endif /* AFS_VLCLIENT_H */
#endif /* AFS_VL_H */
/* AFS caching stuff
*
* Copyright (C) 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.
*/
#ifdef AFS_CACHING_SUPPORT
static cachefs_match_val_t afs_cell_cache_match(void *target,
const void *entry);
static void afs_cell_cache_update(void *source, void *entry);
struct cachefs_index_def afs_cache_cell_index_def = {
.name = "cell_ix",
.data_size = sizeof(struct afs_cache_cell),
.keys[0] = { CACHEFS_INDEX_KEYS_ASCIIZ, 64 },
.match = afs_cell_cache_match,
.update = afs_cell_cache_update,
};
#endif
/*
* match a cell record obtained from the cache
*/
#ifdef AFS_CACHING_SUPPORT
static cachefs_match_val_t afs_cell_cache_match(void *target,
const void *entry)
{
const struct afs_cache_cell *ccell = entry;
struct afs_cell *cell = target;
_enter("{%s},{%s}", ccell->name, cell->name);
if (strncmp(ccell->name, cell->name, sizeof(ccell->name)) == 0) {
_leave(" = SUCCESS");
return CACHEFS_MATCH_SUCCESS;
}
_leave(" = FAILED");
return CACHEFS_MATCH_FAILED;
}
#endif
/*
* update a cell record in the cache
*/
#ifdef AFS_CACHING_SUPPORT
static void afs_cell_cache_update(void *source, void *entry)
{
struct afs_cache_cell *ccell = entry;
struct afs_cell *cell = source;
_enter("%p,%p", source, entry);
strncpy(ccell->name, cell->name, sizeof(ccell->name));
memcpy(ccell->vl_servers,
cell->vl_addrs,
min(sizeof(ccell->vl_servers), sizeof(cell->vl_addrs)));
}
#endif
#ifdef AFS_CACHING_SUPPORT
static cachefs_match_val_t afs_vlocation_cache_match(void *target,
const void *entry);
static void afs_vlocation_cache_update(void *source, void *entry);
struct cachefs_index_def afs_vlocation_cache_index_def = {
.name = "vldb",
.data_size = sizeof(struct afs_cache_vlocation),
.keys[0] = { CACHEFS_INDEX_KEYS_ASCIIZ, 64 },
.match = afs_vlocation_cache_match,
.update = afs_vlocation_cache_update,
};
#endif
/*
* match a VLDB record stored in the cache
* - may also load target from entry
*/
#ifdef AFS_CACHING_SUPPORT
static cachefs_match_val_t afs_vlocation_cache_match(void *target,
const void *entry)
{
const struct afs_cache_vlocation *vldb = entry;
struct afs_vlocation *vlocation = target;
_enter("{%s},{%s}", vlocation->vldb.name, vldb->name);
if (strncmp(vlocation->vldb.name, vldb->name, sizeof(vldb->name)) == 0
) {
if (!vlocation->valid ||
vlocation->vldb.rtime == vldb->rtime
) {
vlocation->vldb = *vldb;
vlocation->valid = 1;
_leave(" = SUCCESS [c->m]");
return CACHEFS_MATCH_SUCCESS;
} else if (memcmp(&vlocation->vldb, vldb, sizeof(*vldb)) != 0) {
/* delete if VIDs for this name differ */
if (memcmp(&vlocation->vldb.vid,
&vldb->vid,
sizeof(vldb->vid)) != 0) {
_leave(" = DELETE");
return CACHEFS_MATCH_SUCCESS_DELETE;
}
_leave(" = UPDATE");
return CACHEFS_MATCH_SUCCESS_UPDATE;
} else {
_leave(" = SUCCESS");
return CACHEFS_MATCH_SUCCESS;
}
}
_leave(" = FAILED");
return CACHEFS_MATCH_FAILED;
}
#endif
/*
* update a VLDB record stored in the cache
*/
#ifdef AFS_CACHING_SUPPORT
static void afs_vlocation_cache_update(void *source, void *entry)
{
struct afs_cache_vlocation *vldb = entry;
struct afs_vlocation *vlocation = source;
_enter("");
*vldb = vlocation->vldb;
}
#endif
#ifdef AFS_CACHING_SUPPORT
static cachefs_match_val_t afs_volume_cache_match(void *target,
const void *entry);
static void afs_volume_cache_update(void *source, void *entry);
struct cachefs_index_def afs_volume_cache_index_def = {
.name = "volume",
.data_size = sizeof(struct afs_cache_vhash),
.keys[0] = { CACHEFS_INDEX_KEYS_BIN, 1 },
.keys[1] = { CACHEFS_INDEX_KEYS_BIN, 1 },
.match = afs_volume_cache_match,
.update = afs_volume_cache_update,
};
#endif
/*
* match a volume hash record stored in the cache
*/
#ifdef AFS_CACHING_SUPPORT
static cachefs_match_val_t afs_volume_cache_match(void *target,
const void *entry)
{
const struct afs_cache_vhash *vhash = entry;
struct afs_volume *volume = target;
_enter("{%u},{%u}", volume->type, vhash->vtype);
if (volume->type == vhash->vtype) {
_leave(" = SUCCESS");
return CACHEFS_MATCH_SUCCESS;
}
_leave(" = FAILED");
return CACHEFS_MATCH_FAILED;
}
#endif
/*
* update a volume hash record stored in the cache
*/
#ifdef AFS_CACHING_SUPPORT
static void afs_volume_cache_update(void *source, void *entry)
{
struct afs_cache_vhash *vhash = entry;
struct afs_volume *volume = source;
_enter("");
vhash->vtype = volume->type;
}
#endif
#ifdef AFS_CACHING_SUPPORT
static cachefs_match_val_t afs_vnode_cache_match(void *target,
const void *entry);
static void afs_vnode_cache_update(void *source, void *entry);
struct cachefs_index_def afs_vnode_cache_index_def = {
.name = "vnode",
.data_size = sizeof(struct afs_cache_vnode),
.keys[0] = { CACHEFS_INDEX_KEYS_BIN, 4 },
.match = afs_vnode_cache_match,
.update = afs_vnode_cache_update,
};
#endif
/*
* match a vnode record stored in the cache
*/
#ifdef AFS_CACHING_SUPPORT
static cachefs_match_val_t afs_vnode_cache_match(void *target,
const void *entry)
{
const struct afs_cache_vnode *cvnode = entry;
struct afs_vnode *vnode = target;
_enter("{%x,%x,%Lx},{%x,%x,%Lx}",
vnode->fid.vnode,
vnode->fid.unique,
vnode->status.version,
cvnode->vnode_id,
cvnode->vnode_unique,
cvnode->data_version);
if (vnode->fid.vnode != cvnode->vnode_id) {
_leave(" = FAILED");
return CACHEFS_MATCH_FAILED;
}
if (vnode->fid.unique != cvnode->vnode_unique ||
vnode->status.version != cvnode->data_version) {
_leave(" = DELETE");
return CACHEFS_MATCH_SUCCESS_DELETE;
}
_leave(" = SUCCESS");
return CACHEFS_MATCH_SUCCESS;
}
#endif
/*
* update a vnode record stored in the cache
*/
#ifdef AFS_CACHING_SUPPORT
static void afs_vnode_cache_update(void *source, void *entry)
{
struct afs_cache_vnode *cvnode = entry;
struct afs_vnode *vnode = source;
_enter("");
cvnode->vnode_id = vnode->fid.vnode;
cvnode->vnode_unique = vnode->fid.unique;
cvnode->data_version = vnode->status.version;
}
#endif
This diff is collapsed.
This diff is collapsed.
/* AFS cell record
*
* Copyright (C) 2002 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.
*/
#ifndef AFS_CELL_H
#define AFS_CELL_H
#include "types.h"
#include "cache.h"
#define AFS_CELL_MAX_ADDRS 15
extern volatile int afs_cells_being_purged; /* T when cells are being purged by rmmod */
/*
* entry in the cached cell catalogue
*/
struct afs_cache_cell {
char name[64]; /* cell name (padded with NULs) */
struct in_addr vl_servers[15]; /* cached cell VL servers */
};
/*
* AFS cell record
*/
struct afs_cell {
atomic_t usage;
struct list_head link; /* main cell list link */
struct list_head proc_link; /* /proc cell list link */
struct proc_dir_entry *proc_dir; /* /proc dir for this cell */
#ifdef AFS_CACHING_SUPPORT
struct cachefs_cookie *cache; /* caching cookie */
#endif
/* server record management */
rwlock_t sv_lock; /* active server list lock */
struct list_head sv_list; /* active server list */
struct list_head sv_graveyard; /* inactive server list */
spinlock_t sv_gylock; /* inactive server list lock */
/* volume location record management */
struct rw_semaphore vl_sem; /* volume management serialisation semaphore */
struct list_head vl_list; /* cell's active VL record list */
struct list_head vl_graveyard; /* cell's inactive VL record list */
spinlock_t vl_gylock; /* graveyard lock */
unsigned short vl_naddrs; /* number of VL servers in addr list */
unsigned short vl_curr_svix; /* current server index */
struct in_addr vl_addrs[AFS_CELL_MAX_ADDRS]; /* cell VL server addresses */
char name[0]; /* cell name - must go last */
};
extern int afs_cell_init(char *);
extern int afs_cell_create(const char *, char *, struct afs_cell **);
extern int afs_cell_lookup(const char *, unsigned, struct afs_cell **);
#define afs_get_cell(C) do { atomic_inc(&(C)->usage); } while(0)
extern struct afs_cell *afs_get_cell_maybe(struct afs_cell **);
extern void afs_put_cell(struct afs_cell *);
extern void afs_cell_purge(void);
#endif /* AFS_CELL_H */
This diff is collapsed.
/* AFS Cache Manager Service declarations
*
* Copyright (C) 2002 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.
*/
#ifndef AFS_CMSERVICE_H
#define AFS_CMSERVICE_H
#include <rxrpc/transport.h>
#include "types.h"
/* cache manager start/stop */
extern int afscm_start(void);
extern void afscm_stop(void);
/* cache manager server functions */
extern int SRXAFSCM_InitCallBackState(struct afs_server *);
extern int SRXAFSCM_CallBack(struct afs_server *, size_t,
struct afs_callback[]);
extern int SRXAFSCM_Probe(struct afs_server *);
#endif /* AFS_CMSERVICE_H */
This diff is collapsed.
/* file.c: AFS filesystem file handling
/* AFS filesystem file handling
*
* Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
* 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
......@@ -15,9 +15,6 @@
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/pagemap.h>
#include "volume.h"
#include "vnode.h"
#include <rxrpc/call.h>
#include "internal.h"
#if 0
......@@ -80,12 +77,10 @@ static void afs_file_readpage_write_complete(void *cookie_data,
*/
static int afs_file_readpage(struct file *file, struct page *page)
{
struct afs_rxfs_fetch_descriptor desc;
#ifdef AFS_CACHING_SUPPORT
struct cachefs_page *pageio;
#endif
struct afs_vnode *vnode;
struct inode *inode;
size_t len;
off_t offset;
int ret;
inode = page->mapping->host;
......@@ -97,14 +92,10 @@ static int afs_file_readpage(struct file *file, struct page *page)
BUG_ON(!PageLocked(page));
ret = -ESTALE;
if (vnode->flags & AFS_VNODE_DELETED)
if (test_bit(AFS_VNODE_DELETED, &vnode->flags))
goto error;
#ifdef AFS_CACHING_SUPPORT
ret = cachefs_page_get_private(page, &pageio, GFP_NOIO);
if (ret < 0)
goto error;
/* is it cached? */
ret = cachefs_read_or_alloc_page(vnode->cache,
page,
......@@ -128,26 +119,19 @@ static int afs_file_readpage(struct file *file, struct page *page)
case -ENOBUFS:
case -ENODATA:
default:
desc.fid = vnode->fid;
desc.offset = page->index << PAGE_CACHE_SHIFT;
desc.size = min((size_t) (inode->i_size - desc.offset),
(size_t) PAGE_SIZE);
desc.buffer = kmap(page);
clear_page(desc.buffer);
offset = page->index << PAGE_CACHE_SHIFT;
len = min_t(size_t, i_size_read(inode) - offset, PAGE_SIZE);
/* read the contents of the file from the server into the
* page */
ret = afs_vnode_fetch_data(vnode, &desc);
kunmap(page);
ret = afs_vnode_fetch_data(vnode, offset, len, page);
if (ret < 0) {
if (ret==-ENOENT) {
if (ret == -ENOENT) {
_debug("got NOENT from server"
" - marking file deleted and stale");
vnode->flags |= AFS_VNODE_DELETED;
set_bit(AFS_VNODE_DELETED, &vnode->flags);
ret = -ESTALE;
}
#ifdef AFS_CACHING_SUPPORT
cachefs_uncache_page(vnode->cache, page);
#endif
......@@ -174,10 +158,9 @@ static int afs_file_readpage(struct file *file, struct page *page)
_leave(" = 0");
return 0;
error:
error:
SetPageError(page);
unlock_page(page);
_leave(" = %d", ret);
return ret;
}
......
This diff is collapsed.
/* AFS File Server client stub declarations
*
* Copyright (C) 2002 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.
*/
#ifndef AFS_FSCLIENT_H
#define AFS_FSCLIENT_H
#include "server.h"
extern int afs_rxfs_get_volume_info(struct afs_server *,
const char *,
struct afs_volume_info *);
extern int afs_rxfs_fetch_file_status(struct afs_server *,
struct afs_vnode *,
struct afs_volsync *);
struct afs_rxfs_fetch_descriptor {
struct afs_fid fid; /* file ID to fetch */
size_t size; /* total number of bytes to fetch */
off_t offset; /* offset in file to start from */
void *buffer; /* read buffer */
size_t actual; /* actual size sent back by server */
};
extern int afs_rxfs_fetch_file_data(struct afs_server *,
struct afs_vnode *,
struct afs_rxfs_fetch_descriptor *,
struct afs_volsync *);
extern int afs_rxfs_give_up_callback(struct afs_server *,
struct afs_vnode *);
/* this doesn't appear to work in OpenAFS server */
extern int afs_rxfs_lookup(struct afs_server *,
struct afs_vnode *,
const char *,
struct afs_vnode *,
struct afs_volsync *);
/* this is apparently mis-implemented in OpenAFS server */
extern int afs_rxfs_get_root_volume(struct afs_server *,
char *,
size_t *);
#endif /* AFS_FSCLIENT_H */
......@@ -19,9 +19,6 @@
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/pagemap.h>
#include "volume.h"
#include "vnode.h"
#include "super.h"
#include "internal.h"
struct afs_iget_data {
......@@ -40,7 +37,7 @@ static int afs_inode_map_status(struct afs_vnode *vnode)
vnode->status.type,
vnode->status.nlink,
vnode->status.size,
vnode->status.version,
vnode->status.data_version,
vnode->status.mode);
switch (vnode->status.type) {
......@@ -78,7 +75,7 @@ static int afs_inode_map_status(struct afs_vnode *vnode)
if (vnode->status.type == AFS_FTYPE_SYMLINK) {
afs_mntpt_check_symlink(vnode);
if (vnode->flags & AFS_VNODE_MOUNTPOINT) {
if (test_bit(AFS_VNODE_MOUNTPOINT, &vnode->flags)) {
inode->i_mode = S_IFDIR | vnode->status.mode;
inode->i_op = &afs_mntpt_inode_operations;
inode->i_fop = &afs_mntpt_file_operations;
......@@ -88,25 +85,6 @@ static int afs_inode_map_status(struct afs_vnode *vnode)
return 0;
}
/*
* attempt to fetch the status of an inode, coelescing multiple simultaneous
* fetches
*/
static int afs_inode_fetch_status(struct inode *inode)
{
struct afs_vnode *vnode;
int ret;
vnode = AFS_FS_I(inode);
ret = afs_vnode_fetch_status(vnode);
if (ret == 0)
ret = afs_inode_map_status(vnode);
return ret;
}
/*
* iget5() comparator
*/
......@@ -137,8 +115,7 @@ static int afs_iget5_set(struct inode *inode, void *opaque)
/*
* inode retrieval
*/
inline int afs_iget(struct super_block *sb, struct afs_fid *fid,
struct inode **_inode)
inline struct inode *afs_iget(struct super_block *sb, struct afs_fid *fid)
{
struct afs_iget_data data = { .fid = *fid };
struct afs_super_info *as;
......@@ -155,20 +132,18 @@ inline int afs_iget(struct super_block *sb, struct afs_fid *fid,
&data);
if (!inode) {
_leave(" = -ENOMEM");
return -ENOMEM;
return ERR_PTR(-ENOMEM);
}
_debug("GOT INODE %p { vl=%x vn=%x, u=%x }",
inode, fid->vid, fid->vnode, fid->unique);
vnode = AFS_FS_I(inode);
/* deal with an existing inode */
if (!(inode->i_state & I_NEW)) {
ret = afs_vnode_fetch_status(vnode);
if (ret == 0)
*_inode = inode;
else
iput(inode);
_leave(" = %d", ret);
return ret;
_leave(" = %p", inode);
return inode;
}
#ifdef AFS_CACHING_SUPPORT
......@@ -181,21 +156,19 @@ inline int afs_iget(struct super_block *sb, struct afs_fid *fid,
#endif
/* okay... it's a new inode */
inode->i_flags |= S_NOATIME;
vnode->flags |= AFS_VNODE_CHANGED;
ret = afs_inode_fetch_status(inode);
if (ret<0)
set_bit(AFS_VNODE_CB_BROKEN, &vnode->flags);
ret = afs_vnode_fetch_status(vnode);
if (ret < 0)
goto bad_inode;
ret = afs_inode_map_status(vnode);
if (ret < 0)
goto bad_inode;
/* success */
inode->i_flags |= S_NOATIME;
unlock_new_inode(inode);
*_inode = inode;
_leave(" = 0 [CB { v=%u x=%lu t=%u }]",
vnode->cb_version,
vnode->cb_timeout.timo_jif,
vnode->cb_type);
return 0;
_leave(" = %p [CB { v=%u t=%u }]", inode, vnode->cb_version, vnode->cb_type);
return inode;
/* failure */
bad_inode:
......@@ -204,7 +177,7 @@ inline int afs_iget(struct super_block *sb, struct afs_fid *fid,
iput(inode);
_leave(" = %d [bad]", ret);
return ret;
return ERR_PTR(ret);
}
/*
......@@ -213,36 +186,13 @@ inline int afs_iget(struct super_block *sb, struct afs_fid *fid,
int afs_inode_getattr(struct vfsmount *mnt, struct dentry *dentry,
struct kstat *stat)
{
struct afs_vnode *vnode;
struct inode *inode;
int ret;
inode = dentry->d_inode;
_enter("{ ino=%lu v=%lu }", inode->i_ino, inode->i_version);
vnode = AFS_FS_I(inode);
ret = afs_inode_fetch_status(inode);
if (ret == -ENOENT) {
_leave(" = %d [%d %p]",
ret, atomic_read(&dentry->d_count), dentry->d_inode);
return ret;
} else if (ret < 0) {
make_bad_inode(inode);
_leave(" = %d", ret);
return ret;
}
/* transfer attributes from the inode structure to the stat
* structure */
generic_fillattr(inode, stat);
_leave(" = 0 CB { v=%u x=%u t=%u }",
vnode->cb_version,
vnode->cb_expiry,
vnode->cb_type);
return 0;
}
......@@ -260,12 +210,23 @@ void afs_clear_inode(struct inode *inode)
vnode->fid.vnode,
vnode->cb_version,
vnode->cb_expiry,
vnode->cb_type
);
vnode->cb_type);
BUG_ON(inode->i_ino != vnode->fid.vnode);
_debug("CLEAR INODE %p", inode);
ASSERTCMP(inode->i_ino, ==, vnode->fid.vnode);
afs_give_up_callback(vnode);
if (vnode->server) {
spin_lock(&vnode->server->fs_lock);
rb_erase(&vnode->server_rb, &vnode->server->fs_vnodes);
spin_unlock(&vnode->server->fs_lock);
afs_put_server(vnode->server);
vnode->server = NULL;
}
afs_vnode_give_up_callback(vnode);
ASSERT(!vnode->cb_promised);
#ifdef AFS_CACHING_SUPPORT
cachefs_relinquish_cookie(vnode->cache, 0);
......
This diff is collapsed.
/* AFS asynchronous operation daemon
*
* Copyright (C) 2002 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.
*
*
* The AFS async daemon is used to the following:
* - probe "dead" servers to see whether they've come back to life yet.
* - probe "live" servers that we haven't talked to for a while to see if they are better
* candidates for serving than what we're currently using
* - poll volume location servers to keep up to date volume location lists
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/completion.h>
#include <linux/freezer.h>
#include "cell.h"
#include "server.h"
#include "volume.h"
#include "kafsasyncd.h"
#include "kafstimod.h"
#include <rxrpc/call.h>
#include <asm/errno.h>
#include "internal.h"
static DECLARE_COMPLETION(kafsasyncd_alive);
static DECLARE_COMPLETION(kafsasyncd_dead);
static DECLARE_WAIT_QUEUE_HEAD(kafsasyncd_sleepq);
static struct task_struct *kafsasyncd_task;
static int kafsasyncd_die;
static int kafsasyncd(void *arg);
static LIST_HEAD(kafsasyncd_async_attnq);
static LIST_HEAD(kafsasyncd_async_busyq);
static DEFINE_SPINLOCK(kafsasyncd_async_lock);
static void kafsasyncd_null_call_attn_func(struct rxrpc_call *call)
{
}
static void kafsasyncd_null_call_error_func(struct rxrpc_call *call)
{
}
/*
* start the async daemon
*/
int afs_kafsasyncd_start(void)
{
int ret;
ret = kernel_thread(kafsasyncd, NULL, 0);
if (ret < 0)
return ret;
wait_for_completion(&kafsasyncd_alive);
return ret;
}
/*
* stop the async daemon
*/
void afs_kafsasyncd_stop(void)
{
/* get rid of my daemon */
kafsasyncd_die = 1;
wake_up(&kafsasyncd_sleepq);
wait_for_completion(&kafsasyncd_dead);
}
/*
* probing daemon
*/
static int kafsasyncd(void *arg)
{
struct afs_async_op *op;
int die;
DECLARE_WAITQUEUE(myself, current);
kafsasyncd_task = current;
printk("kAFS: Started kafsasyncd %d\n", current->pid);
daemonize("kafsasyncd");
complete(&kafsasyncd_alive);
/* loop around looking for things to attend to */
do {
set_current_state(TASK_INTERRUPTIBLE);
add_wait_queue(&kafsasyncd_sleepq, &myself);
for (;;) {
if (!list_empty(&kafsasyncd_async_attnq) ||
signal_pending(current) ||
kafsasyncd_die)
break;
schedule();
set_current_state(TASK_INTERRUPTIBLE);
}
remove_wait_queue(&kafsasyncd_sleepq, &myself);
set_current_state(TASK_RUNNING);
try_to_freeze();
/* discard pending signals */
afs_discard_my_signals();
die = kafsasyncd_die;
/* deal with the next asynchronous operation requiring
* attention */
if (!list_empty(&kafsasyncd_async_attnq)) {
struct afs_async_op *op;
_debug("@@@ Begin Asynchronous Operation");
op = NULL;
spin_lock(&kafsasyncd_async_lock);
if (!list_empty(&kafsasyncd_async_attnq)) {
op = list_entry(kafsasyncd_async_attnq.next,
struct afs_async_op, link);
list_move_tail(&op->link,
&kafsasyncd_async_busyq);
}
spin_unlock(&kafsasyncd_async_lock);
_debug("@@@ Operation %p {%p}\n",
op, op ? op->ops : NULL);
if (op)
op->ops->attend(op);
_debug("@@@ End Asynchronous Operation");
}
} while(!die);
/* need to kill all outstanding asynchronous operations before
* exiting */
kafsasyncd_task = NULL;
spin_lock(&kafsasyncd_async_lock);
/* fold the busy and attention queues together */
list_splice_init(&kafsasyncd_async_busyq,
&kafsasyncd_async_attnq);
/* dequeue kafsasyncd from all their wait queues */
list_for_each_entry(op, &kafsasyncd_async_attnq, link) {
op->call->app_attn_func = kafsasyncd_null_call_attn_func;
op->call->app_error_func = kafsasyncd_null_call_error_func;
remove_wait_queue(&op->call->waitq, &op->waiter);
}
spin_unlock(&kafsasyncd_async_lock);
/* abort all the operations */
while (!list_empty(&kafsasyncd_async_attnq)) {
op = list_entry(kafsasyncd_async_attnq.next, struct afs_async_op, link);
list_del_init(&op->link);
rxrpc_call_abort(op->call, -EIO);
rxrpc_put_call(op->call);
op->call = NULL;
op->ops->discard(op);
}
/* and that's all */
_leave("");
complete_and_exit(&kafsasyncd_dead, 0);
}
/*
* begin an operation
* - place operation on busy queue
*/
void afs_kafsasyncd_begin_op(struct afs_async_op *op)
{
_enter("");
spin_lock(&kafsasyncd_async_lock);
init_waitqueue_entry(&op->waiter, kafsasyncd_task);
add_wait_queue(&op->call->waitq, &op->waiter);
list_move_tail(&op->link, &kafsasyncd_async_busyq);
spin_unlock(&kafsasyncd_async_lock);
_leave("");
}
/*
* request attention for an operation
* - move to attention queue
*/
void afs_kafsasyncd_attend_op(struct afs_async_op *op)
{
_enter("");
spin_lock(&kafsasyncd_async_lock);
list_move_tail(&op->link, &kafsasyncd_async_attnq);
spin_unlock(&kafsasyncd_async_lock);
wake_up(&kafsasyncd_sleepq);
_leave("");
}
/*
* terminate an operation
* - remove from either queue
*/
void afs_kafsasyncd_terminate_op(struct afs_async_op *op)
{
_enter("");
spin_lock(&kafsasyncd_async_lock);
if (!list_empty(&op->link)) {
list_del_init(&op->link);
remove_wait_queue(&op->call->waitq, &op->waiter);
}
spin_unlock(&kafsasyncd_async_lock);
wake_up(&kafsasyncd_sleepq);
_leave("");
}
/* AFS asynchronous operation daemon
*
* Copyright (C) 2002 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.
*/
#ifndef AFS_KAFSASYNCD_H
#define AFS_KAFSASYNCD_H
#include "types.h"
struct afs_async_op;
struct afs_async_op_ops {
void (*attend)(struct afs_async_op *);
void (*discard)(struct afs_async_op *);
};
/*
* asynchronous operation record
*/
struct afs_async_op {
struct list_head link;
struct afs_server *server; /* server being contacted */
struct rxrpc_call *call; /* RxRPC call performing op */
wait_queue_t waiter; /* wait queue for kafsasyncd */
const struct afs_async_op_ops *ops; /* operations */
};
static inline void afs_async_op_init(struct afs_async_op *op,
const struct afs_async_op_ops *ops)
{
INIT_LIST_HEAD(&op->link);
op->call = NULL;
op->ops = ops;
}
extern int afs_kafsasyncd_start(void);
extern void afs_kafsasyncd_stop(void);
extern void afs_kafsasyncd_begin_op(struct afs_async_op *);
extern void afs_kafsasyncd_attend_op(struct afs_async_op *);
extern void afs_kafsasyncd_terminate_op(struct afs_async_op *);
#endif /* AFS_KAFSASYNCD_H */
/* AFS timeout daemon
*
* Copyright (C) 2002 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/module.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/completion.h>
#include <linux/freezer.h>
#include "cell.h"
#include "volume.h"
#include "kafstimod.h"
#include <asm/errno.h>
#include "internal.h"
static DECLARE_COMPLETION(kafstimod_alive);
static DECLARE_COMPLETION(kafstimod_dead);
static DECLARE_WAIT_QUEUE_HEAD(kafstimod_sleepq);
static int kafstimod_die;
static LIST_HEAD(kafstimod_list);
static DEFINE_SPINLOCK(kafstimod_lock);
static int kafstimod(void *arg);
/*
* start the timeout daemon
*/
int afs_kafstimod_start(void)
{
int ret;
ret = kernel_thread(kafstimod, NULL, 0);
if (ret < 0)
return ret;
wait_for_completion(&kafstimod_alive);
return ret;
}
/*
* stop the timeout daemon
*/
void afs_kafstimod_stop(void)
{
/* get rid of my daemon */
kafstimod_die = 1;
wake_up(&kafstimod_sleepq);
wait_for_completion(&kafstimod_dead);
}
/*
* timeout processing daemon
*/
static int kafstimod(void *arg)
{
struct afs_timer *timer;
DECLARE_WAITQUEUE(myself, current);
printk("kAFS: Started kafstimod %d\n", current->pid);
daemonize("kafstimod");
complete(&kafstimod_alive);
/* loop around looking for things to attend to */
loop:
set_current_state(TASK_INTERRUPTIBLE);
add_wait_queue(&kafstimod_sleepq, &myself);
for (;;) {
unsigned long jif;
signed long timeout;
/* deal with the server being asked to die */
if (kafstimod_die) {
remove_wait_queue(&kafstimod_sleepq, &myself);
_leave("");
complete_and_exit(&kafstimod_dead, 0);
}
try_to_freeze();
/* discard pending signals */
afs_discard_my_signals();
/* work out the time to elapse before the next event */
spin_lock(&kafstimod_lock);
if (list_empty(&kafstimod_list)) {
timeout = MAX_SCHEDULE_TIMEOUT;
} else {
timer = list_entry(kafstimod_list.next,
struct afs_timer, link);
timeout = timer->timo_jif;
jif = jiffies;
if (time_before_eq((unsigned long) timeout, jif))
goto immediate;
timeout = (long) timeout - (long) jiffies;
}
spin_unlock(&kafstimod_lock);
schedule_timeout(timeout);
set_current_state(TASK_INTERRUPTIBLE);
}
/* the thing on the front of the queue needs processing
* - we come here with the lock held and timer pointing to the expired
* entry
*/
immediate:
remove_wait_queue(&kafstimod_sleepq, &myself);
set_current_state(TASK_RUNNING);
_debug("@@@ Begin Timeout of %p", timer);
/* dequeue the timer */
list_del_init(&timer->link);
spin_unlock(&kafstimod_lock);
/* call the timeout function */
timer->ops->timed_out(timer);
_debug("@@@ End Timeout");
goto loop;
}
/*
* (re-)queue a timer
*/
void afs_kafstimod_add_timer(struct afs_timer *timer, unsigned long timeout)
{
struct afs_timer *ptimer;
struct list_head *_p;
_enter("%p,%lu", timer, timeout);
spin_lock(&kafstimod_lock);
list_del(&timer->link);
/* the timer was deferred or reset - put it back in the queue at the
* right place */
timer->timo_jif = jiffies + timeout;
list_for_each(_p, &kafstimod_list) {
ptimer = list_entry(_p, struct afs_timer, link);
if (time_before(timer->timo_jif, ptimer->timo_jif))
break;
}
list_add_tail(&timer->link, _p); /* insert before stopping point */
spin_unlock(&kafstimod_lock);
wake_up(&kafstimod_sleepq);
_leave("");
}
/*
* dequeue a timer
* - returns 0 if the timer was deleted or -ENOENT if it wasn't queued
*/
int afs_kafstimod_del_timer(struct afs_timer *timer)
{
int ret = 0;
_enter("%p", timer);
spin_lock(&kafstimod_lock);
if (list_empty(&timer->link))
ret = -ENOENT;
else
list_del_init(&timer->link);
spin_unlock(&kafstimod_lock);
wake_up(&kafstimod_sleepq);
_leave(" = %d", ret);
return ret;
}
This diff is collapsed.
This diff is collapsed.
/* miscellaneous bits
*
* Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
* 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
......@@ -12,18 +12,19 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/errno.h>
#include "errors.h"
#include "internal.h"
#include "afs_fs.h"
/*
* convert an AFS abort code to a Linux error number
*/
int afs_abort_to_error(int abortcode)
int afs_abort_to_error(u32 abort_code)
{
switch (abortcode) {
switch (abort_code) {
case 13: return -EACCES;
case VSALVAGE: return -EIO;
case VNOVNODE: return -ENOENT;
case VNOVOL: return -ENXIO;
case VNOVOL: return -ENOMEDIUM;
case VVOLEXISTS: return -EEXIST;
case VNOSERVICE: return -EIO;
case VOFFLINE: return -ENOENT;
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment