Commit 19e8a2f8 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'afs-dh' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs

Pull AFS updates from Al Viro:
 "The AFS series posted by dhowells depended upon lookup_one_len()
  rework; now that prereq is in the mainline, that series had been
  rebased on top of it and got some exposure and testing..."

* 'afs-dh' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs:
  afs: Do better accretion of small writes on newly created content
  afs: Add stats for data transfer operations
  afs: Trace protocol errors
  afs: Locally edit directory data for mkdir/create/unlink/...
  afs: Adjust the directory XDR structures
  afs: Split the directory content defs into a header
  afs: Fix directory handling
  afs: Split the dynroot stuff out and give it its own ops tables
  afs: Keep track of invalid-before version for dentry coherency
  afs: Rearrange status mapping
  afs: Make it possible to get the data version in readpage
  afs: Init inode before accessing cache
  afs: Introduce a statistics proc file
  afs: Dump bad status record
  afs: Implement @cell substitution handling
  afs: Implement @sys substitution handling
  afs: Prospectively look up extra files when doing a single lookup
  afs: Don't over-increment the cell usage count when pinning it
  afs: Fix checker warnings
  vfs: Remove the const from dir_context::actor
parents 5d136594 5a813276
......@@ -11,7 +11,7 @@ Contents:
- Proc filesystem.
- The cell database.
- Security.
- Examples.
- The @sys substitution.
========
......@@ -230,3 +230,29 @@ If a file is opened with a particular key and then the file descriptor is
passed to a process that doesn't have that key (perhaps over an AF_UNIX
socket), then the operations on the file will be made with key that was used to
open the file.
=====================
THE @SYS SUBSTITUTION
=====================
The list of up to 16 @sys substitutions for the current network namespace can
be configured by writing a list to /proc/fs/afs/sysname:
[root@andromeda ~]# echo foo amd64_linux_26 >/proc/fs/afs/sysname
or cleared entirely by writing an empty list:
[root@andromeda ~]# echo >/proc/fs/afs/sysname
The current list for current network namespace can be retrieved by:
[root@andromeda ~]# cat /proc/fs/afs/sysname
foo
amd64_linux_26
When @sys is being substituted for, each element of the list is tried in the
order given.
By default, the list will contain one item that conforms to the pattern
"<arch>_linux_26", amd64 being the name for x86_64.
......@@ -12,6 +12,8 @@ kafs-objs := \
cell.o \
cmservice.o \
dir.o \
dir_edit.o \
dynroot.o \
file.o \
flock.o \
fsclient.o \
......
......@@ -243,9 +243,9 @@ void afs_merge_fs_addr4(struct afs_addr_list *alist, __be32 xdr, u16 port)
xport == a->sin6_port)
return;
if (xdr == a->sin6_addr.s6_addr32[3] &&
xport < a->sin6_port)
(u16 __force)xport < (u16 __force)a->sin6_port)
break;
if (xdr < a->sin6_addr.s6_addr32[3])
if ((u32 __force)xdr < (u32 __force)a->sin6_addr.s6_addr32[3])
break;
}
......@@ -280,7 +280,7 @@ void afs_merge_fs_addr6(struct afs_addr_list *alist, __be32 *xdr, u16 port)
xport == a->sin6_port)
return;
if (diff == 0 &&
xport < a->sin6_port)
(u16 __force)xport < (u16 __force)a->sin6_port)
break;
if (diff < 0)
break;
......
......@@ -67,10 +67,14 @@ typedef enum {
} afs_callback_type_t;
struct afs_callback {
struct afs_fid fid; /* file identifier */
unsigned version; /* callback version */
unsigned expiry; /* time at which expires */
afs_callback_type_t type; /* type of callback */
unsigned version; /* Callback version */
unsigned expiry; /* Time at which expires */
afs_callback_type_t type; /* Type of callback */
};
struct afs_callback_break {
struct afs_fid fid; /* File identifier */
struct afs_callback cb; /* Callback details */
};
#define AFSCBMAX 50 /* maximum callbacks transferred per bulk op */
......@@ -123,21 +127,20 @@ typedef u32 afs_access_t;
* AFS file status information
*/
struct afs_file_status {
unsigned if_version; /* interface version */
#define AFS_FSTATUS_VERSION 1
u64 size; /* file size */
afs_dataversion_t data_version; /* current data version */
time_t mtime_client; /* last time client changed data */
time_t mtime_server; /* last time server changed data */
unsigned abort_code; /* Abort if bulk-fetching this failed */
afs_file_type_t type; /* file type */
unsigned nlink; /* link count */
u64 size; /* file size */
afs_dataversion_t data_version; /* current data version */
u32 author; /* author ID */
kuid_t owner; /* owner ID */
kgid_t group; /* group ID */
u32 owner; /* owner ID */
u32 group; /* group ID */
afs_access_t caller_access; /* access rights for authenticated caller */
afs_access_t anon_access; /* access rights for unauthenticated caller */
umode_t mode; /* UNIX mode */
time_t mtime_client; /* last time client changed data */
time_t mtime_server; /* last time server changed data */
s32 lock_count; /* file lock count (0=UNLK -1=WRLCK +ve=#RDLCK */
};
......
......@@ -31,10 +31,12 @@ enum AFS_FS_Operations {
FSGETVOLUMEINFO = 148, /* AFS Get information about a volume */
FSGETVOLUMESTATUS = 149, /* AFS Get volume status information */
FSGETROOTVOLUME = 151, /* AFS Get root volume name */
FSBULKSTATUS = 155, /* AFS Fetch multiple file statuses */
FSSETLOCK = 156, /* AFS Request a file lock */
FSEXTENDLOCK = 157, /* AFS Extend a file lock */
FSRELEASELOCK = 158, /* AFS Release a file lock */
FSLOOKUP = 161, /* AFS lookup file in directory */
FSINLINEBULKSTATUS = 65536, /* AFS Fetch multiple file statuses with inline errors */
FSFETCHDATA64 = 65537, /* AFS Fetch file data */
FSSTOREDATA64 = 65538, /* AFS Store file data */
FSGIVEUPALLCALLBACKS = 65539, /* AFS Give up all outstanding callbacks on a server */
......
......@@ -96,26 +96,6 @@ int afs_register_server_cb_interest(struct afs_vnode *vnode,
return 0;
}
/*
* Set a vnode's interest on a server.
*/
void afs_set_cb_interest(struct afs_vnode *vnode, struct afs_cb_interest *cbi)
{
struct afs_cb_interest *old_cbi = NULL;
if (vnode->cb_interest == cbi)
return;
write_seqlock(&vnode->cb_lock);
if (vnode->cb_interest != cbi) {
afs_get_cb_interest(cbi);
old_cbi = vnode->cb_interest;
vnode->cb_interest = cbi;
}
write_sequnlock(&vnode->cb_lock);
afs_put_cb_interest(afs_v2net(vnode), cbi);
}
/*
* Remove an interest on a server.
*/
......@@ -150,6 +130,7 @@ void afs_break_callback(struct afs_vnode *vnode)
write_seqlock(&vnode->cb_lock);
clear_bit(AFS_VNODE_NEW_CONTENT, &vnode->flags);
if (test_and_clear_bit(AFS_VNODE_CB_PROMISED, &vnode->flags)) {
vnode->cb_break++;
afs_clear_permits(vnode);
......@@ -207,7 +188,7 @@ static void afs_break_one_callback(struct afs_server *server,
* allow the fileserver to break callback promises
*/
void afs_break_callbacks(struct afs_server *server, size_t count,
struct afs_callback callbacks[])
struct afs_callback_break *callbacks)
{
_enter("%p,%zu,", server, count);
......@@ -219,9 +200,9 @@ void afs_break_callbacks(struct afs_server *server, size_t count,
callbacks->fid.vid,
callbacks->fid.vnode,
callbacks->fid.unique,
callbacks->version,
callbacks->expiry,
callbacks->type
callbacks->cb.version,
callbacks->cb.expiry,
callbacks->cb.type
);
afs_break_one_callback(server, &callbacks->fid);
}
......
......@@ -18,7 +18,7 @@
#include <keys/rxrpc-type.h>
#include "internal.h"
unsigned __read_mostly afs_cell_gc_delay = 10;
static unsigned __read_mostly afs_cell_gc_delay = 10;
static void afs_manage_cell(struct work_struct *);
......@@ -75,7 +75,7 @@ struct afs_cell *afs_lookup_cell_rcu(struct afs_net *net,
cell = rcu_dereference_raw(net->ws_cell);
if (cell) {
afs_get_cell(cell);
continue;
break;
}
ret = -EDESTADDRREQ;
continue;
......@@ -130,6 +130,8 @@ static struct afs_cell *afs_alloc_cell(struct afs_net *net,
_leave(" = -ENAMETOOLONG");
return ERR_PTR(-ENAMETOOLONG);
}
if (namelen == 5 && memcmp(name, "@cell", 5) == 0)
return ERR_PTR(-EINVAL);
_enter("%*.*s,%s", namelen, namelen, name, vllist);
......@@ -334,7 +336,7 @@ int afs_cell_init(struct afs_net *net, const char *rootcell)
return PTR_ERR(new_root);
}
set_bit(AFS_CELL_FL_NO_GC, &new_root->flags);
if (!test_and_set_bit(AFS_CELL_FL_NO_GC, &new_root->flags))
afs_get_cell(new_root);
/* install the new cell */
......@@ -411,7 +413,7 @@ static void afs_cell_destroy(struct rcu_head *rcu)
ASSERTCMP(atomic_read(&cell->usage), ==, 0);
afs_put_addrlist(cell->vl_addrs);
afs_put_addrlist(rcu_access_pointer(cell->vl_addrs));
key_put(cell->anonymous_key);
kfree(cell);
......
......@@ -178,8 +178,8 @@ static void SRXAFSCB_CallBack(struct work_struct *work)
*/
static int afs_deliver_cb_callback(struct afs_call *call)
{
struct afs_callback_break *cb;
struct sockaddr_rxrpc srx;
struct afs_callback *cb;
struct afs_server *server;
__be32 *bp;
int ret, loop;
......@@ -201,7 +201,7 @@ static int afs_deliver_cb_callback(struct afs_call *call)
call->count = ntohl(call->tmp);
_debug("FID count: %u", call->count);
if (call->count > AFSCBMAX)
return -EBADMSG;
return afs_protocol_error(call, -EBADMSG);
call->buffer = kmalloc(call->count * 3 * 4, GFP_KERNEL);
if (!call->buffer)
......@@ -218,7 +218,7 @@ static int afs_deliver_cb_callback(struct afs_call *call)
_debug("unmarshall FID array");
call->request = kcalloc(call->count,
sizeof(struct afs_callback),
sizeof(struct afs_callback_break),
GFP_KERNEL);
if (!call->request)
return -ENOMEM;
......@@ -229,7 +229,7 @@ static int afs_deliver_cb_callback(struct afs_call *call)
cb->fid.vid = ntohl(*bp++);
cb->fid.vnode = ntohl(*bp++);
cb->fid.unique = ntohl(*bp++);
cb->type = AFSCM_CB_UNTYPED;
cb->cb.type = AFSCM_CB_UNTYPED;
}
call->offset = 0;
......@@ -245,7 +245,7 @@ static int afs_deliver_cb_callback(struct afs_call *call)
call->count2 = ntohl(call->tmp);
_debug("CB count: %u", call->count2);
if (call->count2 != call->count && call->count2 != 0)
return -EBADMSG;
return afs_protocol_error(call, -EBADMSG);
call->offset = 0;
call->unmarshall++;
......@@ -260,9 +260,9 @@ static int afs_deliver_cb_callback(struct afs_call *call)
cb = call->request;
bp = call->buffer;
for (loop = call->count2; loop > 0; loop--, cb++) {
cb->version = ntohl(*bp++);
cb->expiry = ntohl(*bp++);
cb->type = ntohl(*bp++);
cb->cb.version = ntohl(*bp++);
cb->cb.expiry = ntohl(*bp++);
cb->cb.type = ntohl(*bp++);
}
call->offset = 0;
......@@ -500,9 +500,9 @@ static int afs_deliver_cb_probe_uuid(struct afs_call *call)
b = call->buffer;
r = call->request;
r->time_low = ntohl(b[0]);
r->time_mid = ntohl(b[1]);
r->time_hi_and_version = ntohl(b[2]);
r->time_low = b[0];
r->time_mid = htons(ntohl(b[1]));
r->time_hi_and_version = htons(ntohl(b[2]));
r->clock_seq_hi_and_reserved = ntohl(b[3]);
r->clock_seq_low = ntohl(b[4]);
......
This diff is collapsed.
This diff is collapsed.
/* dir.c: AFS dynamic root handling
*
* Copyright (C) 2018 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 Licence
* as published by the Free Software Foundation; either version
* 2 of the Licence, or (at your option) any later version.
*/
#include <linux/fs.h>
#include <linux/namei.h>
#include <linux/dns_resolver.h>
#include "internal.h"
const struct file_operations afs_dynroot_file_operations = {
.open = dcache_dir_open,
.release = dcache_dir_close,
.iterate_shared = dcache_readdir,
.llseek = dcache_dir_lseek,
};
/*
* Probe to see if a cell may exist. This prevents positive dentries from
* being created unnecessarily.
*/
static int afs_probe_cell_name(struct dentry *dentry)
{
struct afs_cell *cell;
const char *name = dentry->d_name.name;
size_t len = dentry->d_name.len;
int ret;
/* Names prefixed with a dot are R/W mounts. */
if (name[0] == '.') {
if (len == 1)
return -EINVAL;
name++;
len--;
}
cell = afs_lookup_cell_rcu(afs_d2net(dentry), name, len);
if (!IS_ERR(cell)) {
afs_put_cell(afs_d2net(dentry), cell);
return 0;
}
ret = dns_query("afsdb", name, len, "ipv4", NULL, NULL);
if (ret == -ENODATA)
ret = -EDESTADDRREQ;
return ret;
}
/*
* Try to auto mount the mountpoint with pseudo directory, if the autocell
* operation is setted.
*/
struct inode *afs_try_auto_mntpt(struct dentry *dentry, struct inode *dir)
{
struct afs_vnode *vnode = AFS_FS_I(dir);
struct inode *inode;
int ret = -ENOENT;
_enter("%p{%pd}, {%x:%u}",
dentry, dentry, vnode->fid.vid, vnode->fid.vnode);
if (!test_bit(AFS_VNODE_AUTOCELL, &vnode->flags))
goto out;
ret = afs_probe_cell_name(dentry);
if (ret < 0)
goto out;
inode = afs_iget_pseudo_dir(dir->i_sb, false);
if (IS_ERR(inode)) {
ret = PTR_ERR(inode);
goto out;
}
_leave("= %p", inode);
return inode;
out:
_leave("= %d", ret);
return ERR_PTR(ret);
}
/*
* Look up @cell in a dynroot directory. This is a substitution for the
* local cell name for the net namespace.
*/
static struct dentry *afs_lookup_atcell(struct dentry *dentry)
{
struct afs_cell *cell;
struct afs_net *net = afs_d2net(dentry);
struct dentry *ret;
unsigned int seq = 0;
char *name;
int len;
if (!net->ws_cell)
return ERR_PTR(-ENOENT);
ret = ERR_PTR(-ENOMEM);
name = kmalloc(AFS_MAXCELLNAME + 1, GFP_KERNEL);
if (!name)
goto out_p;
rcu_read_lock();
do {
read_seqbegin_or_lock(&net->cells_lock, &seq);
cell = rcu_dereference_raw(net->ws_cell);
if (cell) {
len = cell->name_len;
memcpy(name, cell->name, len + 1);
}
} while (need_seqretry(&net->cells_lock, seq));
done_seqretry(&net->cells_lock, seq);
rcu_read_unlock();
ret = ERR_PTR(-ENOENT);
if (!cell)
goto out_n;
ret = lookup_one_len(name, dentry->d_parent, len);
/* We don't want to d_add() the @cell dentry here as we don't want to
* the cached dentry to hide changes to the local cell name.
*/
out_n:
kfree(name);
out_p:
return ret;
}
/*
* Look up an entry in a dynroot directory.
*/
static struct dentry *afs_dynroot_lookup(struct inode *dir, struct dentry *dentry,
unsigned int flags)
{
struct afs_vnode *vnode;
struct inode *inode;
int ret;
vnode = AFS_FS_I(dir);
_enter("%pd", dentry);
ASSERTCMP(d_inode(dentry), ==, NULL);
if (dentry->d_name.len >= AFSNAMEMAX) {
_leave(" = -ENAMETOOLONG");
return ERR_PTR(-ENAMETOOLONG);
}
if (dentry->d_name.len == 5 &&
memcmp(dentry->d_name.name, "@cell", 5) == 0)
return afs_lookup_atcell(dentry);
inode = afs_try_auto_mntpt(dentry, dir);
if (IS_ERR(inode)) {
ret = PTR_ERR(inode);
if (ret == -ENOENT) {
d_add(dentry, NULL);
_leave(" = NULL [negative]");
return NULL;
}
_leave(" = %d [do]", ret);
return ERR_PTR(ret);
}
d_add(dentry, inode);
_leave(" = 0 { ino=%lu v=%u }",
d_inode(dentry)->i_ino, d_inode(dentry)->i_generation);
return NULL;
}
const struct inode_operations afs_dynroot_inode_operations = {
.lookup = afs_dynroot_lookup,
};
/*
* Dirs in the dynamic root don't need revalidation.
*/
static int afs_dynroot_d_revalidate(struct dentry *dentry, unsigned int flags)
{
return 1;
}
/*
* Allow the VFS to enquire as to whether a dentry should be unhashed (mustn't
* sleep)
* - called from dput() when d_count is going to 0.
* - return 1 to request dentry be unhashed, 0 otherwise
*/
static int afs_dynroot_d_delete(const struct dentry *dentry)
{
return d_really_is_positive(dentry);
}
const struct dentry_operations afs_dynroot_dentry_operations = {
.d_revalidate = afs_dynroot_d_revalidate,
.d_delete = afs_dynroot_d_delete,
.d_release = afs_d_release,
.d_automount = afs_d_automount,
};
......@@ -30,7 +30,6 @@ static int afs_readpages(struct file *filp, struct address_space *mapping,
const struct file_operations afs_file_operations = {
.open = afs_open,
.flush = afs_flush,
.release = afs_release,
.llseek = generic_file_llseek,
.read_iter = generic_file_read_iter,
......@@ -147,6 +146,9 @@ int afs_open(struct inode *inode, struct file *file)
goto error_af;
}
if (file->f_flags & O_TRUNC)
set_bit(AFS_VNODE_NEW_CONTENT, &vnode->flags);
file->private_data = af;
_leave(" = 0");
return 0;
......@@ -170,6 +172,9 @@ int afs_release(struct inode *inode, struct file *file)
_enter("{%x:%u},", vnode->fid.vid, vnode->fid.vnode);
if ((file->f_mode & FMODE_WRITE))
return vfs_fsync(file, 0);
file->private_data = NULL;
if (af->wb)
afs_put_wb_key(af->wb);
......@@ -187,10 +192,12 @@ void afs_put_read(struct afs_read *req)
{
int i;
if (atomic_dec_and_test(&req->usage)) {
if (refcount_dec_and_test(&req->usage)) {
for (i = 0; i < req->nr_pages; i++)
if (req->pages[i])
put_page(req->pages[i]);
if (req->pages != req->array)
kfree(req->pages);
kfree(req);
}
}
......@@ -240,6 +247,12 @@ int afs_fetch_data(struct afs_vnode *vnode, struct key *key, struct afs_read *de
ret = afs_end_vnode_operation(&fc);
}
if (ret == 0) {
afs_stat_v(vnode, n_fetches);
atomic_long_add(desc->actual_len,
&afs_v2net(vnode)->n_fetch_bytes);
}
_leave(" = %d", ret);
return ret;
}
......@@ -297,10 +310,11 @@ int afs_page_filler(void *data, struct page *page)
* end of the file, the server will return a short read and the
* unmarshalling code will clear the unfilled space.
*/
atomic_set(&req->usage, 1);
refcount_set(&req->usage, 1);
req->pos = (loff_t)page->index << PAGE_SHIFT;
req->len = PAGE_SIZE;
req->nr_pages = 1;
req->pages = req->array;
req->pages[0] = page;
get_page(page);
......@@ -309,10 +323,6 @@ int afs_page_filler(void *data, struct page *page)
ret = afs_fetch_data(vnode, key, req);
afs_put_read(req);
if (ret >= 0 && S_ISDIR(inode->i_mode) &&
!afs_dir_check_page(inode, page))
ret = -EIO;
if (ret < 0) {
if (ret == -ENOENT) {
_debug("got NOENT from server"
......@@ -447,10 +457,11 @@ static int afs_readpages_one(struct file *file, struct address_space *mapping,
if (!req)
return -ENOMEM;
atomic_set(&req->usage, 1);
refcount_set(&req->usage, 1);
req->page_done = afs_readpages_page_done;
req->pos = first->index;
req->pos <<= PAGE_SHIFT;
req->pages = req->array;
/* Transfer the pages to the request. We add them in until one fails
* to add to the LRU and then we stop (as that'll make a hole in the
......
......@@ -613,7 +613,7 @@ static int afs_do_getlk(struct file *file, struct file_lock *fl)
posix_test_lock(file, fl);
if (fl->fl_type == F_UNLCK) {
/* no local locks; consult the server */
ret = afs_fetch_status(vnode, key);
ret = afs_fetch_status(vnode, key, false);
if (ret < 0)
goto error;
......
This diff is collapsed.
......@@ -30,12 +30,11 @@ static const struct inode_operations afs_symlink_inode_operations = {
};
/*
* map the AFS file status to the inode member variables
* Initialise an inode from the vnode status.
*/
static int afs_inode_map_status(struct afs_vnode *vnode, struct key *key)
static int afs_inode_init_from_status(struct afs_vnode *vnode, struct key *key)
{
struct inode *inode = AFS_VNODE_TO_I(vnode);
bool changed;
_debug("FS: ft=%d lk=%d sz=%llu ver=%Lu mod=%hu",
vnode->status.type,
......@@ -46,16 +45,21 @@ static int afs_inode_map_status(struct afs_vnode *vnode, struct key *key)
read_seqlock_excl(&vnode->cb_lock);
afs_update_inode_from_status(vnode, &vnode->status, NULL,
AFS_VNODE_NOT_YET_SET);
switch (vnode->status.type) {
case AFS_FTYPE_FILE:
inode->i_mode = S_IFREG | vnode->status.mode;
inode->i_op = &afs_file_inode_operations;
inode->i_fop = &afs_file_operations;
inode->i_mapping->a_ops = &afs_fs_aops;
break;
case AFS_FTYPE_DIR:
inode->i_mode = S_IFDIR | vnode->status.mode;
inode->i_op = &afs_dir_inode_operations;
inode->i_fop = &afs_dir_file_operations;
inode->i_mapping->a_ops = &afs_dir_aops;
break;
case AFS_FTYPE_SYMLINK:
/* Symlinks with a mode of 0644 are actually mountpoints. */
......@@ -67,45 +71,31 @@ static int afs_inode_map_status(struct afs_vnode *vnode, struct key *key)
inode->i_mode = S_IFDIR | 0555;
inode->i_op = &afs_mntpt_inode_operations;
inode->i_fop = &afs_mntpt_file_operations;
inode->i_mapping->a_ops = &afs_fs_aops;
} else {
inode->i_mode = S_IFLNK | vnode->status.mode;
inode->i_op = &afs_symlink_inode_operations;
inode->i_mapping->a_ops = &afs_fs_aops;
}
inode_nohighmem(inode);
break;
default:
printk("kAFS: AFS vnode with undefined type\n");
read_sequnlock_excl(&vnode->cb_lock);
return -EBADMSG;
return afs_protocol_error(NULL, -EBADMSG);
}
changed = (vnode->status.size != inode->i_size);
set_nlink(inode, vnode->status.nlink);
inode->i_uid = vnode->status.owner;
inode->i_gid = vnode->status.group;
inode->i_size = vnode->status.size;
inode->i_ctime.tv_sec = vnode->status.mtime_client;
inode->i_ctime.tv_nsec = 0;
inode->i_atime = inode->i_mtime = inode->i_ctime;
inode->i_blocks = 0;
inode->i_generation = vnode->fid.unique;
inode_set_iversion_raw(inode, vnode->status.data_version);
inode->i_mapping->a_ops = &afs_fs_aops;
vnode->invalid_before = vnode->status.data_version;
read_sequnlock_excl(&vnode->cb_lock);
#ifdef CONFIG_AFS_FSCACHE
if (changed)
fscache_attr_changed(vnode->cache);
#endif
return 0;
}
/*
* Fetch file status from the volume.
*/
int afs_fetch_status(struct afs_vnode *vnode, struct key *key)
int afs_fetch_status(struct afs_vnode *vnode, struct key *key, bool new_inode)
{
struct afs_fs_cursor fc;
int ret;
......@@ -119,7 +109,7 @@ int afs_fetch_status(struct afs_vnode *vnode, struct key *key)
if (afs_begin_vnode_operation(&fc, vnode, key)) {
while (afs_select_fileserver(&fc)) {
fc.cb_break = vnode->cb_break + vnode->cb_s_break;
afs_fs_fetch_file_status(&fc, NULL);
afs_fs_fetch_file_status(&fc, NULL, new_inode);
}
afs_check_for_remote_deletion(&fc, fc.vnode);
......@@ -255,6 +245,11 @@ static void afs_get_inode_cache(struct afs_vnode *vnode)
} __packed key;
struct afs_vnode_cache_aux aux;
if (vnode->status.type == AFS_FTYPE_DIR) {
vnode->cache = NULL;
return;
}
key.vnode_id = vnode->fid.vnode;
key.unique = vnode->fid.unique;
key.vnode_id_ext[0] = 0;
......@@ -307,7 +302,7 @@ struct inode *afs_iget(struct super_block *sb, struct key *key,
if (!status) {
/* it's a remotely extant inode */
ret = afs_fetch_status(vnode, key);
ret = afs_fetch_status(vnode, key, true);
if (ret < 0)
goto bad_inode;
} else {
......@@ -331,15 +326,12 @@ struct inode *afs_iget(struct super_block *sb, struct key *key,
vnode->cb_expires_at += ktime_get_real_seconds();
}
/* set up caching before mapping the status, as map-status reads the
* first page of symlinks to see if they're really mountpoints */
inode->i_size = vnode->status.size;
afs_get_inode_cache(vnode);
ret = afs_inode_map_status(vnode, key);
ret = afs_inode_init_from_status(vnode, key);
if (ret < 0)
goto bad_inode;
afs_get_inode_cache(vnode);
/* success */
clear_bit(AFS_VNODE_UNSET, &vnode->flags);
inode->i_flags |= S_NOATIME;
......@@ -349,10 +341,6 @@ struct inode *afs_iget(struct super_block *sb, struct key *key,
/* failure */
bad_inode:
#ifdef CONFIG_AFS_FSCACHE
fscache_relinquish_cookie(vnode->cache, NULL, ret == -ENOENT);
vnode->cache = NULL;
#endif
iget_failed(inode);
_leave(" = %d [bad]", ret);
return ERR_PTR(ret);
......@@ -407,8 +395,11 @@ int afs_validate(struct afs_vnode *vnode, struct key *key)
if (test_bit(AFS_VNODE_CB_PROMISED, &vnode->flags)) {
if (vnode->cb_s_break != vnode->cb_interest->server->cb_s_break) {
vnode->cb_s_break = vnode->cb_interest->server->cb_s_break;
} else if (!test_bit(AFS_VNODE_DIR_MODIFIED, &vnode->flags) &&
!test_bit(AFS_VNODE_ZAP_DATA, &vnode->flags) &&
} else if (vnode->status.type == AFS_FTYPE_DIR &&
test_bit(AFS_VNODE_DIR_VALID, &vnode->flags) &&
vnode->cb_expires_at - 10 > now) {
valid = true;
} else if (!test_bit(AFS_VNODE_ZAP_DATA, &vnode->flags) &&
vnode->cb_expires_at - 10 > now) {
valid = true;
}
......@@ -432,7 +423,7 @@ int afs_validate(struct afs_vnode *vnode, struct key *key)
* access */
if (!test_bit(AFS_VNODE_CB_PROMISED, &vnode->flags)) {
_debug("not promised");
ret = afs_fetch_status(vnode, key);
ret = afs_fetch_status(vnode, key, false);
if (ret < 0) {
if (ret == -ENOENT) {
set_bit(AFS_VNODE_DELETED, &vnode->flags);
......@@ -453,8 +444,6 @@ int afs_validate(struct afs_vnode *vnode, struct key *key)
* different */
if (test_and_clear_bit(AFS_VNODE_ZAP_DATA, &vnode->flags))
afs_zap_data(vnode);
clear_bit(AFS_VNODE_DIR_MODIFIED, &vnode->flags);
mutex_unlock(&vnode->validate_lock);
valid:
_leave(" = 0");
......@@ -544,7 +533,7 @@ void afs_evict_inode(struct inode *inode)
}
#endif
afs_put_permits(vnode->permit_cache);
afs_put_permits(rcu_access_pointer(vnode->permit_cache));
_leave("");
}
......
This diff is collapsed.
......@@ -34,11 +34,42 @@ MODULE_PARM_DESC(rootcell, "root AFS cell name and VL server IP addr list");
struct workqueue_struct *afs_wq;
struct afs_net __afs_net;
#if defined(CONFIG_ALPHA)
const char afs_init_sysname[] = "alpha_linux26";
#elif defined(CONFIG_X86_64)
const char afs_init_sysname[] = "amd64_linux26";
#elif defined(CONFIG_ARM)
const char afs_init_sysname[] = "arm_linux26";
#elif defined(CONFIG_ARM64)
const char afs_init_sysname[] = "aarch64_linux26";
#elif defined(CONFIG_X86_32)
const char afs_init_sysname[] = "i386_linux26";
#elif defined(CONFIG_IA64)
const char afs_init_sysname[] = "ia64_linux26";
#elif defined(CONFIG_PPC64)
const char afs_init_sysname[] = "ppc64_linux26";
#elif defined(CONFIG_PPC32)
const char afs_init_sysname[] = "ppc_linux26";
#elif defined(CONFIG_S390)
#ifdef CONFIG_64BIT
const char afs_init_sysname[] = "s390x_linux26";
#else
const char afs_init_sysname[] = "s390_linux26";
#endif
#elif defined(CONFIG_SPARC64)
const char afs_init_sysname[] = "sparc64_linux26";
#elif defined(CONFIG_SPARC32)
const char afs_init_sysname[] = "sparc_linux26";
#else
const char afs_init_sysname[] = "unknown_linux26";
#endif
/*
* Initialise an AFS network namespace record.
*/
static int __net_init afs_net_init(struct afs_net *net)
{
struct afs_sysnames *sysnames;
int ret;
net->live = true;
......@@ -67,6 +98,16 @@ static int __net_init afs_net_init(struct afs_net *net)
INIT_WORK(&net->fs_manager, afs_manage_servers);
timer_setup(&net->fs_timer, afs_servers_timer, 0);
ret = -ENOMEM;
sysnames = kzalloc(sizeof(*sysnames), GFP_KERNEL);
if (!sysnames)
goto error_sysnames;
sysnames->subs[0] = (char *)&afs_init_sysname;
sysnames->nr = 1;
refcount_set(&sysnames->usage, 1);
net->sysnames = sysnames;
rwlock_init(&net->sysnames_lock);
/* Register the /proc stuff */
ret = afs_proc_init(net);
if (ret < 0)
......@@ -92,6 +133,8 @@ static int __net_init afs_net_init(struct afs_net *net)
net->live = false;
afs_proc_cleanup(net);
error_proc:
afs_put_sysnames(net->sysnames);
error_sysnames:
net->live = false;
return ret;
}
......@@ -106,6 +149,7 @@ static void __net_exit afs_net_exit(struct afs_net *net)
afs_purge_servers(net);
afs_close_socket(net);
afs_proc_cleanup(net);
afs_put_sysnames(net->sysnames);
}
/*
......
This diff is collapsed.
......@@ -21,7 +21,7 @@
/*
* Initialise a filesystem server cursor for iterating over FS servers.
*/
void afs_init_fs_cursor(struct afs_fs_cursor *fc, struct afs_vnode *vnode)
static void afs_init_fs_cursor(struct afs_fs_cursor *fc, struct afs_vnode *vnode)
{
memset(fc, 0, sizeof(*fc));
}
......
......@@ -926,3 +926,12 @@ int afs_extract_data(struct afs_call *call, void *buf, size_t count,
afs_set_call_complete(call, ret, remote_abort);
return ret;
}
/*
* Log protocol error production.
*/
noinline int afs_protocol_error(struct afs_call *call, int error)
{
trace_afs_protocol_error(call, error, __builtin_return_address(0));
return error;
}
......@@ -178,18 +178,14 @@ void afs_cache_permit(struct afs_vnode *vnode, struct key *key,
}
}
if (cb_break != (vnode->cb_break + vnode->cb_interest->server->cb_s_break)) {
rcu_read_unlock();
if (cb_break != (vnode->cb_break + vnode->cb_interest->server->cb_s_break))
goto someone_else_changed_it;
}
/* We need a ref on any permits list we want to copy as we'll have to
* drop the lock to do memory allocation.
*/
if (permits && !refcount_inc_not_zero(&permits->usage)) {
rcu_read_unlock();
if (permits && !refcount_inc_not_zero(&permits->usage))
goto someone_else_changed_it;
}
rcu_read_unlock();
......@@ -278,6 +274,7 @@ void afs_cache_permit(struct afs_vnode *vnode, struct key *key,
/* Someone else changed the cache under us - don't recheck at this
* time.
*/
rcu_read_unlock();
return;
}
......@@ -296,8 +293,6 @@ int afs_check_permit(struct afs_vnode *vnode, struct key *key,
_enter("{%x:%u},%x",
vnode->fid.vid, vnode->fid.vnode, key_serial(key));
permits = vnode->permit_cache;
/* check the permits to see if we've got one yet */
if (key == vnode->volume->cell->anonymous_key) {
_debug("anon");
......@@ -327,7 +322,7 @@ int afs_check_permit(struct afs_vnode *vnode, struct key *key,
*/
_debug("no valid permit");
ret = afs_fetch_status(vnode, key);
ret = afs_fetch_status(vnode, key, false);
if (ret < 0) {
*_access = 0;
_leave(" = %d", ret);
......
......@@ -59,7 +59,8 @@ struct afs_server *afs_find_server(struct afs_net *net,
alist = rcu_dereference(server->addresses);
for (i = alist->nr_ipv4; i < alist->nr_addrs; i++) {
b = &alist->addrs[i].transport.sin6;
diff = (u16)a->sin6_port - (u16)b->sin6_port;
diff = ((u16 __force)a->sin6_port -
(u16 __force)b->sin6_port);
if (diff == 0)
diff = memcmp(&a->sin6_addr,
&b->sin6_addr,
......@@ -79,10 +80,11 @@ struct afs_server *afs_find_server(struct afs_net *net,
alist = rcu_dereference(server->addresses);
for (i = 0; i < alist->nr_ipv4; i++) {
b = &alist->addrs[i].transport.sin6;
diff = (u16)a->sin6_port - (u16)b->sin6_port;
diff = ((u16 __force)a->sin6_port -
(u16 __force)b->sin6_port);
if (diff == 0)
diff = ((u32)a->sin6_addr.s6_addr32[3] -
(u32)b->sin6_addr.s6_addr32[3]);
diff = ((u32 __force)a->sin6_addr.s6_addr32[3] -
(u32 __force)b->sin6_addr.s6_addr32[3]);
if (diff == 0)
goto found;
if (diff < 0) {
......@@ -381,7 +383,7 @@ static void afs_server_rcu(struct rcu_head *rcu)
{
struct afs_server *server = container_of(rcu, struct afs_server, rcu);
afs_put_addrlist(server->addresses);
afs_put_addrlist(rcu_access_pointer(server->addresses));
kfree(server);
}
......@@ -390,7 +392,7 @@ static void afs_server_rcu(struct rcu_head *rcu)
*/
static void afs_destroy_server(struct afs_net *net, struct afs_server *server)
{
struct afs_addr_list *alist = server->addresses;
struct afs_addr_list *alist = rcu_access_pointer(server->addresses);
struct afs_addr_cursor ac = {
.alist = alist,
.addr = &alist->addrs[0],
......
......@@ -418,6 +418,9 @@ static int afs_fill_super(struct super_block *sb,
if (!sb->s_root)
goto error;
if (params->dyn_root)
sb->s_d_op = &afs_dynroot_dentry_operations;
else
sb->s_d_op = &afs_fs_dentry_operations;
_leave(" = 0");
......
......@@ -303,7 +303,7 @@ struct afs_addr_list *afs_vl_get_addrs_u(struct afs_net *net,
r->uuid.clock_seq_hi_and_reserved = htonl(u->clock_seq_hi_and_reserved);
r->uuid.clock_seq_low = htonl(u->clock_seq_low);
for (i = 0; i < 6; i++)
r->uuid.node[i] = ntohl(u->node[i]);
r->uuid.node[i] = htonl(u->node[i]);
trace_afs_make_vl_call(call);
return (struct afs_addr_list *)afs_make_call(ac, call, GFP_KERNEL, false);
......@@ -450,7 +450,7 @@ static int afs_deliver_yfsvl_get_endpoints(struct afs_call *call)
call->count2 = ntohl(*bp); /* Type or next count */
if (call->count > YFS_MAXENDPOINTS)
return -EBADMSG;
return afs_protocol_error(call, -EBADMSG);
alist = afs_alloc_addrlist(call->count, FS_SERVICE, AFS_FS_PORT);
if (!alist)
......@@ -474,7 +474,7 @@ static int afs_deliver_yfsvl_get_endpoints(struct afs_call *call)
size = sizeof(__be32) * (1 + 4 + 1);
break;
default:
return -EBADMSG;
return afs_protocol_error(call, -EBADMSG);
}
size += sizeof(__be32);
......@@ -487,24 +487,24 @@ static int afs_deliver_yfsvl_get_endpoints(struct afs_call *call)
switch (call->count2) {
case YFS_ENDPOINT_IPV4:
if (ntohl(bp[0]) != sizeof(__be32) * 2)
return -EBADMSG;
return afs_protocol_error(call, -EBADMSG);
afs_merge_fs_addr4(alist, bp[1], ntohl(bp[2]));
bp += 3;
break;
case YFS_ENDPOINT_IPV6:
if (ntohl(bp[0]) != sizeof(__be32) * 5)
return -EBADMSG;
return afs_protocol_error(call, -EBADMSG);
afs_merge_fs_addr6(alist, bp + 1, ntohl(bp[5]));
bp += 6;
break;
default:
return -EBADMSG;
return afs_protocol_error(call, -EBADMSG);
}
/* Got either the type of the next entry or the count of
* volEndpoints if no more fsEndpoints.
*/
call->count2 = htonl(*bp++);
call->count2 = ntohl(*bp++);
call->offset = 0;
call->count--;
......@@ -517,7 +517,7 @@ static int afs_deliver_yfsvl_get_endpoints(struct afs_call *call)
if (!call->count)
goto end;
if (call->count > YFS_MAXENDPOINTS)
return -EBADMSG;
return afs_protocol_error(call, -EBADMSG);
call->unmarshall = 3;
......@@ -531,7 +531,7 @@ static int afs_deliver_yfsvl_get_endpoints(struct afs_call *call)
return ret;
bp = call->buffer;
call->count2 = htonl(*bp++);
call->count2 = ntohl(*bp++);
call->offset = 0;
call->unmarshall = 4;
......@@ -545,7 +545,7 @@ static int afs_deliver_yfsvl_get_endpoints(struct afs_call *call)
size = sizeof(__be32) * (1 + 4 + 1);
break;
default:
return -EBADMSG;
return afs_protocol_error(call, -EBADMSG);
}
if (call->count > 1)
......@@ -558,16 +558,16 @@ static int afs_deliver_yfsvl_get_endpoints(struct afs_call *call)
switch (call->count2) {
case YFS_ENDPOINT_IPV4:
if (ntohl(bp[0]) != sizeof(__be32) * 2)
return -EBADMSG;
return afs_protocol_error(call, -EBADMSG);
bp += 3;
break;
case YFS_ENDPOINT_IPV6:
if (ntohl(bp[0]) != sizeof(__be32) * 5)
return -EBADMSG;
return afs_protocol_error(call, -EBADMSG);
bp += 6;
break;
default:
return -EBADMSG;
return afs_protocol_error(call, -EBADMSG);
}
/* Got either the type of the next entry or the count of
......@@ -576,7 +576,7 @@ static int afs_deliver_yfsvl_get_endpoints(struct afs_call *call)
call->offset = 0;
call->count--;
if (call->count > 0) {
call->count2 = htonl(*bp++);
call->count2 = ntohl(*bp++);
goto again;
}
......
......@@ -42,10 +42,11 @@ static int afs_fill_page(struct afs_vnode *vnode, struct key *key,
if (!req)
return -ENOMEM;
atomic_set(&req->usage, 1);
refcount_set(&req->usage, 1);
req->pos = pos;
req->len = len;
req->nr_pages = 1;
req->pages = req->array;
req->pages[0] = page;
get_page(page);
......@@ -124,7 +125,12 @@ int afs_write_begin(struct file *file, struct address_space *mapping,
page->index, priv);
goto flush_conflicting_write;
}
if (to < f || from > t)
/* If the file is being filled locally, allow inter-write
* spaces to be merged into writes. If it's not, only write
* back what the user gives us.
*/
if (!test_bit(AFS_VNODE_NEW_CONTENT, &vnode->flags) &&
(to < f || from > t))
goto flush_conflicting_write;
if (from < f)
f = from;
......@@ -355,6 +361,12 @@ static int afs_store_data(struct address_space *mapping,
}
switch (ret) {
case 0:
afs_stat_v(vnode, n_stores);
atomic_long_add((last * PAGE_SIZE + to) -
(first * PAGE_SIZE + offset),
&afs_v2net(vnode)->n_store_bytes);
break;
case -EACCES:
case -EPERM:
case -ENOKEY:
......@@ -412,7 +424,8 @@ static int afs_write_back_from_locked_page(struct address_space *mapping,
trace_afs_page_dirty(vnode, tracepoint_string("WARN"),
primary_page->index, priv);
if (start >= final_page || to < PAGE_SIZE)
if (start >= final_page ||
(to < PAGE_SIZE && !test_bit(AFS_VNODE_NEW_CONTENT, &vnode->flags)))
goto no_more;
start++;
......@@ -433,9 +446,10 @@ static int afs_write_back_from_locked_page(struct address_space *mapping,
}
for (loop = 0; loop < n; loop++) {
if (to != PAGE_SIZE)
break;
page = pages[loop];
if (to != PAGE_SIZE &&
!test_bit(AFS_VNODE_NEW_CONTENT, &vnode->flags))
break;
if (page->index > final_page)
break;
if (!trylock_page(page))
......@@ -448,7 +462,8 @@ static int afs_write_back_from_locked_page(struct address_space *mapping,
priv = page_private(page);
f = priv & AFS_PRIV_MAX;
t = priv >> AFS_PRIV_SHIFT;
if (f != 0) {
if (f != 0 &&
!test_bit(AFS_VNODE_NEW_CONTENT, &vnode->flags)) {
unlock_page(page);
break;
}
......@@ -734,20 +749,6 @@ int afs_fsync(struct file *file, loff_t start, loff_t end, int datasync)
return file_write_and_wait_range(file, start, end);
}
/*
* Flush out all outstanding writes on a file opened for writing when it is
* closed.
*/
int afs_flush(struct file *file, fl_owner_t id)
{
_enter("");
if ((file->f_mode & FMODE_WRITE) == 0)
return 0;
return vfs_fsync(file, 0);
}
/*
* notification that a previously read-only page is about to become writable
* - if it returns an error, the caller will deliver a bus error signal
......
/* AFS fileserver XDR types
*
* Copyright (C) 2018 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 Licence
* as published by the Free Software Foundation; either version
* 2 of the Licence, or (at your option) any later version.
*/
#ifndef XDR_FS_H
#define XDR_FS_H
struct afs_xdr_AFSFetchStatus {
__be32 if_version;
#define AFS_FSTATUS_VERSION 1
__be32 type;
__be32 nlink;
__be32 size_lo;
__be32 data_version_lo;
__be32 author;
__be32 owner;
__be32 caller_access;
__be32 anon_access;
__be32 mode;
__be32 parent_vnode;
__be32 parent_unique;
__be32 seg_size;
__be32 mtime_client;
__be32 mtime_server;
__be32 group;
__be32 sync_counter;
__be32 data_version_hi;
__be32 lock_count;
__be32 size_hi;
__be32 abort_code;
} __packed;
#define AFS_DIR_HASHTBL_SIZE 128
#define AFS_DIR_DIRENT_SIZE 32
#define AFS_DIR_SLOTS_PER_BLOCK 64
#define AFS_DIR_BLOCK_SIZE 2048
#define AFS_DIR_BLOCKS_PER_PAGE (PAGE_SIZE / AFS_DIR_BLOCK_SIZE)
#define AFS_DIR_MAX_SLOTS 65536
#define AFS_DIR_BLOCKS_WITH_CTR 128
#define AFS_DIR_MAX_BLOCKS 1023
#define AFS_DIR_RESV_BLOCKS 1
#define AFS_DIR_RESV_BLOCKS0 13
/*
* Directory entry structure.
*/
union afs_xdr_dirent {
struct {
u8 valid;
u8 unused[1];
__be16 hash_next;
__be32 vnode;
__be32 unique;
u8 name[16];
u8 overflow[4]; /* if any char of the name (inc
* NUL) reaches here, consume
* the next dirent too */
} u;
u8 extended_name[32];
} __packed;
/*
* Directory block header (one at the beginning of every 2048-byte block).
*/
struct afs_xdr_dir_hdr {
__be16 npages;
__be16 magic;
#define AFS_DIR_MAGIC htons(1234)
u8 reserved;
u8 bitmap[8];
u8 pad[19];
} __packed;
/*
* Directory block layout
*/
union afs_xdr_dir_block {
struct afs_xdr_dir_hdr hdr;
struct {
struct afs_xdr_dir_hdr hdr;
u8 alloc_ctrs[AFS_DIR_MAX_BLOCKS];
__be16 hashtable[AFS_DIR_HASHTBL_SIZE];
} meta;
union afs_xdr_dirent dirents[AFS_DIR_SLOTS_PER_BLOCK];
} __packed;
/*
* Directory layout on a linux VM page.
*/
struct afs_xdr_dir_page {
union afs_xdr_dir_block blocks[AFS_DIR_BLOCKS_PER_PAGE];
};
#endif /* XDR_FS_H */
......@@ -1667,7 +1667,7 @@ typedef int (*filldir_t)(struct dir_context *, const char *, int, loff_t, u64,
unsigned);
struct dir_context {
const filldir_t actor;
filldir_t actor;
loff_t pos;
};
......
......@@ -49,6 +49,7 @@ enum afs_fs_operation {
afs_FS_ExtendLock = 157, /* AFS Extend a file lock */
afs_FS_ReleaseLock = 158, /* AFS Release a file lock */
afs_FS_Lookup = 161, /* AFS lookup file in directory */
afs_FS_InlineBulkStatus = 65536, /* AFS Fetch multiple file statuses with errors */
afs_FS_FetchData64 = 65537, /* AFS Fetch file data */
afs_FS_StoreData64 = 65538, /* AFS Store file data */
afs_FS_GiveUpAllCallBacks = 65539, /* AFS Give up all our callbacks on a server */
......@@ -62,6 +63,27 @@ enum afs_vl_operation {
afs_VL_GetCapabilities = 65537, /* AFS Get VL server capabilities */
};
enum afs_edit_dir_op {
afs_edit_dir_create,
afs_edit_dir_create_error,
afs_edit_dir_create_inval,
afs_edit_dir_create_nospc,
afs_edit_dir_delete,
afs_edit_dir_delete_error,
afs_edit_dir_delete_inval,
afs_edit_dir_delete_noent,
};
enum afs_edit_dir_reason {
afs_edit_dir_for_create,
afs_edit_dir_for_link,
afs_edit_dir_for_mkdir,
afs_edit_dir_for_rename,
afs_edit_dir_for_rmdir,
afs_edit_dir_for_symlink,
afs_edit_dir_for_unlink,
};
#endif /* end __AFS_DECLARE_TRACE_ENUMS_ONCE_ONLY */
/*
......@@ -93,6 +115,7 @@ enum afs_vl_operation {
EM(afs_FS_ExtendLock, "FS.ExtendLock") \
EM(afs_FS_ReleaseLock, "FS.ReleaseLock") \
EM(afs_FS_Lookup, "FS.Lookup") \
EM(afs_FS_InlineBulkStatus, "FS.InlineBulkStatus") \
EM(afs_FS_FetchData64, "FS.FetchData64") \
EM(afs_FS_StoreData64, "FS.StoreData64") \
EM(afs_FS_GiveUpAllCallBacks, "FS.GiveUpAllCallBacks") \
......@@ -104,6 +127,25 @@ enum afs_vl_operation {
EM(afs_YFSVL_GetEndpoints, "YFSVL.GetEndpoints") \
E_(afs_VL_GetCapabilities, "VL.GetCapabilities")
#define afs_edit_dir_ops \
EM(afs_edit_dir_create, "create") \
EM(afs_edit_dir_create_error, "c_fail") \
EM(afs_edit_dir_create_inval, "c_invl") \
EM(afs_edit_dir_create_nospc, "c_nspc") \
EM(afs_edit_dir_delete, "delete") \
EM(afs_edit_dir_delete_error, "d_err ") \
EM(afs_edit_dir_delete_inval, "d_invl") \
E_(afs_edit_dir_delete_noent, "d_nent")
#define afs_edit_dir_reasons \
EM(afs_edit_dir_for_create, "Create") \
EM(afs_edit_dir_for_link, "Link ") \
EM(afs_edit_dir_for_mkdir, "MkDir ") \
EM(afs_edit_dir_for_rename, "Rename") \
EM(afs_edit_dir_for_rmdir, "RmDir ") \
EM(afs_edit_dir_for_symlink, "Symlnk") \
E_(afs_edit_dir_for_unlink, "Unlink")
/*
* Export enum symbols via userspace.
......@@ -116,6 +158,8 @@ enum afs_vl_operation {
afs_call_traces;
afs_fs_operations;
afs_vl_operations;
afs_edit_dir_ops;
afs_edit_dir_reasons;
/*
* Now redefine the EM() and E_() macros to map the enums to the strings that
......@@ -462,6 +506,75 @@ TRACE_EVENT(afs_call_state,
__entry->ret, __entry->abort)
);
TRACE_EVENT(afs_edit_dir,
TP_PROTO(struct afs_vnode *dvnode,
enum afs_edit_dir_reason why,
enum afs_edit_dir_op op,
unsigned int block,
unsigned int slot,
unsigned int f_vnode,
unsigned int f_unique,
const char *name),
TP_ARGS(dvnode, why, op, block, slot, f_vnode, f_unique, name),
TP_STRUCT__entry(
__field(unsigned int, vnode )
__field(unsigned int, unique )
__field(enum afs_edit_dir_reason, why )
__field(enum afs_edit_dir_op, op )
__field(unsigned int, block )
__field(unsigned short, slot )
__field(unsigned int, f_vnode )
__field(unsigned int, f_unique )
__array(char, name, 18 )
),
TP_fast_assign(
int __len = strlen(name);
__len = min(__len, 17);
__entry->vnode = dvnode->fid.vnode;
__entry->unique = dvnode->fid.unique;
__entry->why = why;
__entry->op = op;
__entry->block = block;
__entry->slot = slot;
__entry->f_vnode = f_vnode;
__entry->f_unique = f_unique;
memcpy(__entry->name, name, __len);
__entry->name[__len] = 0;
),
TP_printk("d=%x:%x %s %s %u[%u] f=%x:%x %s",
__entry->vnode, __entry->unique,
__print_symbolic(__entry->why, afs_edit_dir_reasons),
__print_symbolic(__entry->op, afs_edit_dir_ops),
__entry->block, __entry->slot,
__entry->f_vnode, __entry->f_unique,
__entry->name)
);
TRACE_EVENT(afs_protocol_error,
TP_PROTO(struct afs_call *call, int error, const void *where),
TP_ARGS(call, error, where),
TP_STRUCT__entry(
__field(unsigned int, call )
__field(int, error )
__field(const void *, where )
),
TP_fast_assign(
__entry->call = call ? call->debug_id : 0;
__entry->error = error;
__entry->where = where;
),
TP_printk("c=%08x r=%d sp=%pSR",
__entry->call, __entry->error, __entry->where)
);
#endif /* _TRACE_AFS_H */
/* This part must be outside protection */
......
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