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: ...@@ -11,7 +11,7 @@ Contents:
- Proc filesystem. - Proc filesystem.
- The cell database. - The cell database.
- Security. - Security.
- Examples. - The @sys substitution.
======== ========
...@@ -230,3 +230,29 @@ If a file is opened with a particular key and then the file descriptor is ...@@ -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 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 socket), then the operations on the file will be made with key that was used to
open the file. 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 := \ ...@@ -12,6 +12,8 @@ kafs-objs := \
cell.o \ cell.o \
cmservice.o \ cmservice.o \
dir.o \ dir.o \
dir_edit.o \
dynroot.o \
file.o \ file.o \
flock.o \ flock.o \
fsclient.o \ fsclient.o \
......
...@@ -243,9 +243,9 @@ void afs_merge_fs_addr4(struct afs_addr_list *alist, __be32 xdr, u16 port) ...@@ -243,9 +243,9 @@ void afs_merge_fs_addr4(struct afs_addr_list *alist, __be32 xdr, u16 port)
xport == a->sin6_port) xport == a->sin6_port)
return; return;
if (xdr == a->sin6_addr.s6_addr32[3] && if (xdr == a->sin6_addr.s6_addr32[3] &&
xport < a->sin6_port) (u16 __force)xport < (u16 __force)a->sin6_port)
break; break;
if (xdr < a->sin6_addr.s6_addr32[3]) if ((u32 __force)xdr < (u32 __force)a->sin6_addr.s6_addr32[3])
break; break;
} }
...@@ -280,7 +280,7 @@ void afs_merge_fs_addr6(struct afs_addr_list *alist, __be32 *xdr, u16 port) ...@@ -280,7 +280,7 @@ void afs_merge_fs_addr6(struct afs_addr_list *alist, __be32 *xdr, u16 port)
xport == a->sin6_port) xport == a->sin6_port)
return; return;
if (diff == 0 && if (diff == 0 &&
xport < a->sin6_port) (u16 __force)xport < (u16 __force)a->sin6_port)
break; break;
if (diff < 0) if (diff < 0)
break; break;
......
...@@ -67,10 +67,14 @@ typedef enum { ...@@ -67,10 +67,14 @@ typedef enum {
} afs_callback_type_t; } afs_callback_type_t;
struct afs_callback { struct afs_callback {
struct afs_fid fid; /* file identifier */ unsigned version; /* Callback version */
unsigned version; /* callback version */ unsigned expiry; /* Time at which expires */
unsigned expiry; /* time at which expires */ afs_callback_type_t type; /* Type of callback */
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 */ #define AFSCBMAX 50 /* maximum callbacks transferred per bulk op */
...@@ -123,21 +127,20 @@ typedef u32 afs_access_t; ...@@ -123,21 +127,20 @@ typedef u32 afs_access_t;
* AFS file status information * AFS file status information
*/ */
struct afs_file_status { struct afs_file_status {
unsigned if_version; /* interface version */ u64 size; /* file size */
#define AFS_FSTATUS_VERSION 1 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 */ afs_file_type_t type; /* file type */
unsigned nlink; /* link count */ unsigned nlink; /* link count */
u64 size; /* file size */
afs_dataversion_t data_version; /* current data version */
u32 author; /* author ID */ u32 author; /* author ID */
kuid_t owner; /* owner ID */ u32 owner; /* owner ID */
kgid_t group; /* group ID */ u32 group; /* group ID */
afs_access_t caller_access; /* access rights for authenticated caller */ afs_access_t caller_access; /* access rights for authenticated caller */
afs_access_t anon_access; /* access rights for unauthenticated caller */ afs_access_t anon_access; /* access rights for unauthenticated caller */
umode_t mode; /* UNIX mode */ 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 */ s32 lock_count; /* file lock count (0=UNLK -1=WRLCK +ve=#RDLCK */
}; };
......
...@@ -31,10 +31,12 @@ enum AFS_FS_Operations { ...@@ -31,10 +31,12 @@ enum AFS_FS_Operations {
FSGETVOLUMEINFO = 148, /* AFS Get information about a volume */ FSGETVOLUMEINFO = 148, /* AFS Get information about a volume */
FSGETVOLUMESTATUS = 149, /* AFS Get volume status information */ FSGETVOLUMESTATUS = 149, /* AFS Get volume status information */
FSGETROOTVOLUME = 151, /* AFS Get root volume name */ FSGETROOTVOLUME = 151, /* AFS Get root volume name */
FSBULKSTATUS = 155, /* AFS Fetch multiple file statuses */
FSSETLOCK = 156, /* AFS Request a file lock */ FSSETLOCK = 156, /* AFS Request a file lock */
FSEXTENDLOCK = 157, /* AFS Extend a file lock */ FSEXTENDLOCK = 157, /* AFS Extend a file lock */
FSRELEASELOCK = 158, /* AFS Release a file lock */ FSRELEASELOCK = 158, /* AFS Release a file lock */
FSLOOKUP = 161, /* AFS lookup file in directory */ FSLOOKUP = 161, /* AFS lookup file in directory */
FSINLINEBULKSTATUS = 65536, /* AFS Fetch multiple file statuses with inline errors */
FSFETCHDATA64 = 65537, /* AFS Fetch file data */ FSFETCHDATA64 = 65537, /* AFS Fetch file data */
FSSTOREDATA64 = 65538, /* AFS Store file data */ FSSTOREDATA64 = 65538, /* AFS Store file data */
FSGIVEUPALLCALLBACKS = 65539, /* AFS Give up all outstanding callbacks on a server */ 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, ...@@ -96,26 +96,6 @@ int afs_register_server_cb_interest(struct afs_vnode *vnode,
return 0; 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. * Remove an interest on a server.
*/ */
...@@ -150,6 +130,7 @@ void afs_break_callback(struct afs_vnode *vnode) ...@@ -150,6 +130,7 @@ void afs_break_callback(struct afs_vnode *vnode)
write_seqlock(&vnode->cb_lock); write_seqlock(&vnode->cb_lock);
clear_bit(AFS_VNODE_NEW_CONTENT, &vnode->flags);
if (test_and_clear_bit(AFS_VNODE_CB_PROMISED, &vnode->flags)) { if (test_and_clear_bit(AFS_VNODE_CB_PROMISED, &vnode->flags)) {
vnode->cb_break++; vnode->cb_break++;
afs_clear_permits(vnode); afs_clear_permits(vnode);
...@@ -207,7 +188,7 @@ static void afs_break_one_callback(struct afs_server *server, ...@@ -207,7 +188,7 @@ static void afs_break_one_callback(struct afs_server *server,
* allow the fileserver to break callback promises * allow the fileserver to break callback promises
*/ */
void afs_break_callbacks(struct afs_server *server, size_t count, 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); _enter("%p,%zu,", server, count);
...@@ -219,9 +200,9 @@ void afs_break_callbacks(struct afs_server *server, size_t count, ...@@ -219,9 +200,9 @@ void afs_break_callbacks(struct afs_server *server, size_t count,
callbacks->fid.vid, callbacks->fid.vid,
callbacks->fid.vnode, callbacks->fid.vnode,
callbacks->fid.unique, callbacks->fid.unique,
callbacks->version, callbacks->cb.version,
callbacks->expiry, callbacks->cb.expiry,
callbacks->type callbacks->cb.type
); );
afs_break_one_callback(server, &callbacks->fid); afs_break_one_callback(server, &callbacks->fid);
} }
......
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
#include <keys/rxrpc-type.h> #include <keys/rxrpc-type.h>
#include "internal.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 *); static void afs_manage_cell(struct work_struct *);
...@@ -75,7 +75,7 @@ struct afs_cell *afs_lookup_cell_rcu(struct afs_net *net, ...@@ -75,7 +75,7 @@ struct afs_cell *afs_lookup_cell_rcu(struct afs_net *net,
cell = rcu_dereference_raw(net->ws_cell); cell = rcu_dereference_raw(net->ws_cell);
if (cell) { if (cell) {
afs_get_cell(cell); afs_get_cell(cell);
continue; break;
} }
ret = -EDESTADDRREQ; ret = -EDESTADDRREQ;
continue; continue;
...@@ -130,6 +130,8 @@ static struct afs_cell *afs_alloc_cell(struct afs_net *net, ...@@ -130,6 +130,8 @@ static struct afs_cell *afs_alloc_cell(struct afs_net *net,
_leave(" = -ENAMETOOLONG"); _leave(" = -ENAMETOOLONG");
return ERR_PTR(-ENAMETOOLONG); return ERR_PTR(-ENAMETOOLONG);
} }
if (namelen == 5 && memcmp(name, "@cell", 5) == 0)
return ERR_PTR(-EINVAL);
_enter("%*.*s,%s", namelen, namelen, name, vllist); _enter("%*.*s,%s", namelen, namelen, name, vllist);
...@@ -334,8 +336,8 @@ int afs_cell_init(struct afs_net *net, const char *rootcell) ...@@ -334,8 +336,8 @@ int afs_cell_init(struct afs_net *net, const char *rootcell)
return PTR_ERR(new_root); 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); afs_get_cell(new_root);
/* install the new cell */ /* install the new cell */
write_seqlock(&net->cells_lock); write_seqlock(&net->cells_lock);
...@@ -411,7 +413,7 @@ static void afs_cell_destroy(struct rcu_head *rcu) ...@@ -411,7 +413,7 @@ static void afs_cell_destroy(struct rcu_head *rcu)
ASSERTCMP(atomic_read(&cell->usage), ==, 0); 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); key_put(cell->anonymous_key);
kfree(cell); kfree(cell);
......
...@@ -178,8 +178,8 @@ static void SRXAFSCB_CallBack(struct work_struct *work) ...@@ -178,8 +178,8 @@ static void SRXAFSCB_CallBack(struct work_struct *work)
*/ */
static int afs_deliver_cb_callback(struct afs_call *call) static int afs_deliver_cb_callback(struct afs_call *call)
{ {
struct afs_callback_break *cb;
struct sockaddr_rxrpc srx; struct sockaddr_rxrpc srx;
struct afs_callback *cb;
struct afs_server *server; struct afs_server *server;
__be32 *bp; __be32 *bp;
int ret, loop; int ret, loop;
...@@ -201,7 +201,7 @@ static int afs_deliver_cb_callback(struct afs_call *call) ...@@ -201,7 +201,7 @@ static int afs_deliver_cb_callback(struct afs_call *call)
call->count = ntohl(call->tmp); call->count = ntohl(call->tmp);
_debug("FID count: %u", call->count); _debug("FID count: %u", call->count);
if (call->count > AFSCBMAX) if (call->count > AFSCBMAX)
return -EBADMSG; return afs_protocol_error(call, -EBADMSG);
call->buffer = kmalloc(call->count * 3 * 4, GFP_KERNEL); call->buffer = kmalloc(call->count * 3 * 4, GFP_KERNEL);
if (!call->buffer) if (!call->buffer)
...@@ -218,7 +218,7 @@ static int afs_deliver_cb_callback(struct afs_call *call) ...@@ -218,7 +218,7 @@ static int afs_deliver_cb_callback(struct afs_call *call)
_debug("unmarshall FID array"); _debug("unmarshall FID array");
call->request = kcalloc(call->count, call->request = kcalloc(call->count,
sizeof(struct afs_callback), sizeof(struct afs_callback_break),
GFP_KERNEL); GFP_KERNEL);
if (!call->request) if (!call->request)
return -ENOMEM; return -ENOMEM;
...@@ -229,7 +229,7 @@ static int afs_deliver_cb_callback(struct afs_call *call) ...@@ -229,7 +229,7 @@ static int afs_deliver_cb_callback(struct afs_call *call)
cb->fid.vid = ntohl(*bp++); cb->fid.vid = ntohl(*bp++);
cb->fid.vnode = ntohl(*bp++); cb->fid.vnode = ntohl(*bp++);
cb->fid.unique = ntohl(*bp++); cb->fid.unique = ntohl(*bp++);
cb->type = AFSCM_CB_UNTYPED; cb->cb.type = AFSCM_CB_UNTYPED;
} }
call->offset = 0; call->offset = 0;
...@@ -245,7 +245,7 @@ static int afs_deliver_cb_callback(struct afs_call *call) ...@@ -245,7 +245,7 @@ static int afs_deliver_cb_callback(struct afs_call *call)
call->count2 = ntohl(call->tmp); call->count2 = ntohl(call->tmp);
_debug("CB count: %u", call->count2); _debug("CB count: %u", call->count2);
if (call->count2 != call->count && call->count2 != 0) if (call->count2 != call->count && call->count2 != 0)
return -EBADMSG; return afs_protocol_error(call, -EBADMSG);
call->offset = 0; call->offset = 0;
call->unmarshall++; call->unmarshall++;
...@@ -260,9 +260,9 @@ static int afs_deliver_cb_callback(struct afs_call *call) ...@@ -260,9 +260,9 @@ static int afs_deliver_cb_callback(struct afs_call *call)
cb = call->request; cb = call->request;
bp = call->buffer; bp = call->buffer;
for (loop = call->count2; loop > 0; loop--, cb++) { for (loop = call->count2; loop > 0; loop--, cb++) {
cb->version = ntohl(*bp++); cb->cb.version = ntohl(*bp++);
cb->expiry = ntohl(*bp++); cb->cb.expiry = ntohl(*bp++);
cb->type = ntohl(*bp++); cb->cb.type = ntohl(*bp++);
} }
call->offset = 0; call->offset = 0;
...@@ -500,9 +500,9 @@ static int afs_deliver_cb_probe_uuid(struct afs_call *call) ...@@ -500,9 +500,9 @@ static int afs_deliver_cb_probe_uuid(struct afs_call *call)
b = call->buffer; b = call->buffer;
r = call->request; r = call->request;
r->time_low = ntohl(b[0]); r->time_low = b[0];
r->time_mid = ntohl(b[1]); r->time_mid = htons(ntohl(b[1]));
r->time_hi_and_version = ntohl(b[2]); r->time_hi_and_version = htons(ntohl(b[2]));
r->clock_seq_hi_and_reserved = ntohl(b[3]); r->clock_seq_hi_and_reserved = ntohl(b[3]);
r->clock_seq_low = ntohl(b[4]); 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, ...@@ -30,7 +30,6 @@ static int afs_readpages(struct file *filp, struct address_space *mapping,
const struct file_operations afs_file_operations = { const struct file_operations afs_file_operations = {
.open = afs_open, .open = afs_open,
.flush = afs_flush,
.release = afs_release, .release = afs_release,
.llseek = generic_file_llseek, .llseek = generic_file_llseek,
.read_iter = generic_file_read_iter, .read_iter = generic_file_read_iter,
...@@ -146,6 +145,9 @@ int afs_open(struct inode *inode, struct file *file) ...@@ -146,6 +145,9 @@ int afs_open(struct inode *inode, struct file *file)
if (ret < 0) if (ret < 0)
goto error_af; goto error_af;
} }
if (file->f_flags & O_TRUNC)
set_bit(AFS_VNODE_NEW_CONTENT, &vnode->flags);
file->private_data = af; file->private_data = af;
_leave(" = 0"); _leave(" = 0");
...@@ -170,6 +172,9 @@ int afs_release(struct inode *inode, struct file *file) ...@@ -170,6 +172,9 @@ int afs_release(struct inode *inode, struct file *file)
_enter("{%x:%u},", vnode->fid.vid, vnode->fid.vnode); _enter("{%x:%u},", vnode->fid.vid, vnode->fid.vnode);
if ((file->f_mode & FMODE_WRITE))
return vfs_fsync(file, 0);
file->private_data = NULL; file->private_data = NULL;
if (af->wb) if (af->wb)
afs_put_wb_key(af->wb); afs_put_wb_key(af->wb);
...@@ -187,10 +192,12 @@ void afs_put_read(struct afs_read *req) ...@@ -187,10 +192,12 @@ void afs_put_read(struct afs_read *req)
{ {
int i; int i;
if (atomic_dec_and_test(&req->usage)) { if (refcount_dec_and_test(&req->usage)) {
for (i = 0; i < req->nr_pages; i++) for (i = 0; i < req->nr_pages; i++)
if (req->pages[i]) if (req->pages[i])
put_page(req->pages[i]); put_page(req->pages[i]);
if (req->pages != req->array)
kfree(req->pages);
kfree(req); kfree(req);
} }
} }
...@@ -240,6 +247,12 @@ int afs_fetch_data(struct afs_vnode *vnode, struct key *key, struct afs_read *de ...@@ -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); 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); _leave(" = %d", ret);
return ret; return ret;
} }
...@@ -297,10 +310,11 @@ int afs_page_filler(void *data, struct page *page) ...@@ -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 * end of the file, the server will return a short read and the
* unmarshalling code will clear the unfilled space. * 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->pos = (loff_t)page->index << PAGE_SHIFT;
req->len = PAGE_SIZE; req->len = PAGE_SIZE;
req->nr_pages = 1; req->nr_pages = 1;
req->pages = req->array;
req->pages[0] = page; req->pages[0] = page;
get_page(page); get_page(page);
...@@ -309,10 +323,6 @@ int afs_page_filler(void *data, struct page *page) ...@@ -309,10 +323,6 @@ int afs_page_filler(void *data, struct page *page)
ret = afs_fetch_data(vnode, key, req); ret = afs_fetch_data(vnode, key, req);
afs_put_read(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 < 0) {
if (ret == -ENOENT) { if (ret == -ENOENT) {
_debug("got NOENT from server" _debug("got NOENT from server"
...@@ -447,10 +457,11 @@ static int afs_readpages_one(struct file *file, struct address_space *mapping, ...@@ -447,10 +457,11 @@ static int afs_readpages_one(struct file *file, struct address_space *mapping,
if (!req) if (!req)
return -ENOMEM; return -ENOMEM;
atomic_set(&req->usage, 1); refcount_set(&req->usage, 1);
req->page_done = afs_readpages_page_done; req->page_done = afs_readpages_page_done;
req->pos = first->index; req->pos = first->index;
req->pos <<= PAGE_SHIFT; req->pos <<= PAGE_SHIFT;
req->pages = req->array;
/* Transfer the pages to the request. We add them in until one fails /* 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 * 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) ...@@ -613,7 +613,7 @@ static int afs_do_getlk(struct file *file, struct file_lock *fl)
posix_test_lock(file, fl); posix_test_lock(file, fl);
if (fl->fl_type == F_UNLCK) { if (fl->fl_type == F_UNLCK) {
/* no local locks; consult the server */ /* no local locks; consult the server */
ret = afs_fetch_status(vnode, key); ret = afs_fetch_status(vnode, key, false);
if (ret < 0) if (ret < 0)
goto error; goto error;
......
This diff is collapsed.
...@@ -30,12 +30,11 @@ static const struct inode_operations afs_symlink_inode_operations = { ...@@ -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); struct inode *inode = AFS_VNODE_TO_I(vnode);
bool changed;
_debug("FS: ft=%d lk=%d sz=%llu ver=%Lu mod=%hu", _debug("FS: ft=%d lk=%d sz=%llu ver=%Lu mod=%hu",
vnode->status.type, vnode->status.type,
...@@ -46,16 +45,21 @@ static int afs_inode_map_status(struct afs_vnode *vnode, struct key *key) ...@@ -46,16 +45,21 @@ static int afs_inode_map_status(struct afs_vnode *vnode, struct key *key)
read_seqlock_excl(&vnode->cb_lock); read_seqlock_excl(&vnode->cb_lock);
afs_update_inode_from_status(vnode, &vnode->status, NULL,
AFS_VNODE_NOT_YET_SET);
switch (vnode->status.type) { switch (vnode->status.type) {
case AFS_FTYPE_FILE: case AFS_FTYPE_FILE:
inode->i_mode = S_IFREG | vnode->status.mode; inode->i_mode = S_IFREG | vnode->status.mode;
inode->i_op = &afs_file_inode_operations; inode->i_op = &afs_file_inode_operations;
inode->i_fop = &afs_file_operations; inode->i_fop = &afs_file_operations;
inode->i_mapping->a_ops = &afs_fs_aops;
break; break;
case AFS_FTYPE_DIR: case AFS_FTYPE_DIR:
inode->i_mode = S_IFDIR | vnode->status.mode; inode->i_mode = S_IFDIR | vnode->status.mode;
inode->i_op = &afs_dir_inode_operations; inode->i_op = &afs_dir_inode_operations;
inode->i_fop = &afs_dir_file_operations; inode->i_fop = &afs_dir_file_operations;
inode->i_mapping->a_ops = &afs_dir_aops;
break; break;
case AFS_FTYPE_SYMLINK: case AFS_FTYPE_SYMLINK:
/* Symlinks with a mode of 0644 are actually mountpoints. */ /* 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) ...@@ -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_mode = S_IFDIR | 0555;
inode->i_op = &afs_mntpt_inode_operations; inode->i_op = &afs_mntpt_inode_operations;
inode->i_fop = &afs_mntpt_file_operations; inode->i_fop = &afs_mntpt_file_operations;
inode->i_mapping->a_ops = &afs_fs_aops;
} else { } else {
inode->i_mode = S_IFLNK | vnode->status.mode; inode->i_mode = S_IFLNK | vnode->status.mode;
inode->i_op = &afs_symlink_inode_operations; inode->i_op = &afs_symlink_inode_operations;
inode->i_mapping->a_ops = &afs_fs_aops;
} }
inode_nohighmem(inode); inode_nohighmem(inode);
break; break;
default: default:
printk("kAFS: AFS vnode with undefined type\n"); printk("kAFS: AFS vnode with undefined type\n");
read_sequnlock_excl(&vnode->cb_lock); 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_blocks = 0;
inode->i_generation = vnode->fid.unique; vnode->invalid_before = vnode->status.data_version;
inode_set_iversion_raw(inode, vnode->status.data_version);
inode->i_mapping->a_ops = &afs_fs_aops;
read_sequnlock_excl(&vnode->cb_lock); read_sequnlock_excl(&vnode->cb_lock);
#ifdef CONFIG_AFS_FSCACHE
if (changed)
fscache_attr_changed(vnode->cache);
#endif
return 0; return 0;
} }
/* /*
* Fetch file status from the volume. * 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; struct afs_fs_cursor fc;
int ret; int ret;
...@@ -119,7 +109,7 @@ int afs_fetch_status(struct afs_vnode *vnode, struct key *key) ...@@ -119,7 +109,7 @@ int afs_fetch_status(struct afs_vnode *vnode, struct key *key)
if (afs_begin_vnode_operation(&fc, vnode, key)) { if (afs_begin_vnode_operation(&fc, vnode, key)) {
while (afs_select_fileserver(&fc)) { while (afs_select_fileserver(&fc)) {
fc.cb_break = vnode->cb_break + vnode->cb_s_break; 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); afs_check_for_remote_deletion(&fc, fc.vnode);
...@@ -255,6 +245,11 @@ static void afs_get_inode_cache(struct afs_vnode *vnode) ...@@ -255,6 +245,11 @@ static void afs_get_inode_cache(struct afs_vnode *vnode)
} __packed key; } __packed key;
struct afs_vnode_cache_aux aux; struct afs_vnode_cache_aux aux;
if (vnode->status.type == AFS_FTYPE_DIR) {
vnode->cache = NULL;
return;
}
key.vnode_id = vnode->fid.vnode; key.vnode_id = vnode->fid.vnode;
key.unique = vnode->fid.unique; key.unique = vnode->fid.unique;
key.vnode_id_ext[0] = 0; key.vnode_id_ext[0] = 0;
...@@ -307,7 +302,7 @@ struct inode *afs_iget(struct super_block *sb, struct key *key, ...@@ -307,7 +302,7 @@ struct inode *afs_iget(struct super_block *sb, struct key *key,
if (!status) { if (!status) {
/* it's a remotely extant inode */ /* it's a remotely extant inode */
ret = afs_fetch_status(vnode, key); ret = afs_fetch_status(vnode, key, true);
if (ret < 0) if (ret < 0)
goto bad_inode; goto bad_inode;
} else { } else {
...@@ -331,15 +326,12 @@ struct inode *afs_iget(struct super_block *sb, struct key *key, ...@@ -331,15 +326,12 @@ struct inode *afs_iget(struct super_block *sb, struct key *key,
vnode->cb_expires_at += ktime_get_real_seconds(); vnode->cb_expires_at += ktime_get_real_seconds();
} }
/* set up caching before mapping the status, as map-status reads the ret = afs_inode_init_from_status(vnode, key);
* 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);
if (ret < 0) if (ret < 0)
goto bad_inode; goto bad_inode;
afs_get_inode_cache(vnode);
/* success */ /* success */
clear_bit(AFS_VNODE_UNSET, &vnode->flags); clear_bit(AFS_VNODE_UNSET, &vnode->flags);
inode->i_flags |= S_NOATIME; inode->i_flags |= S_NOATIME;
...@@ -349,10 +341,6 @@ struct inode *afs_iget(struct super_block *sb, struct key *key, ...@@ -349,10 +341,6 @@ struct inode *afs_iget(struct super_block *sb, struct key *key,
/* failure */ /* failure */
bad_inode: bad_inode:
#ifdef CONFIG_AFS_FSCACHE
fscache_relinquish_cookie(vnode->cache, NULL, ret == -ENOENT);
vnode->cache = NULL;
#endif
iget_failed(inode); iget_failed(inode);
_leave(" = %d [bad]", ret); _leave(" = %d [bad]", ret);
return ERR_PTR(ret); return ERR_PTR(ret);
...@@ -407,8 +395,11 @@ int afs_validate(struct afs_vnode *vnode, struct key *key) ...@@ -407,8 +395,11 @@ int afs_validate(struct afs_vnode *vnode, struct key *key)
if (test_bit(AFS_VNODE_CB_PROMISED, &vnode->flags)) { if (test_bit(AFS_VNODE_CB_PROMISED, &vnode->flags)) {
if (vnode->cb_s_break != vnode->cb_interest->server->cb_s_break) { if (vnode->cb_s_break != vnode->cb_interest->server->cb_s_break) {
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) && } else if (vnode->status.type == AFS_FTYPE_DIR &&
!test_bit(AFS_VNODE_ZAP_DATA, &vnode->flags) && 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) { vnode->cb_expires_at - 10 > now) {
valid = true; valid = true;
} }
...@@ -432,7 +423,7 @@ int afs_validate(struct afs_vnode *vnode, struct key *key) ...@@ -432,7 +423,7 @@ int afs_validate(struct afs_vnode *vnode, struct key *key)
* access */ * access */
if (!test_bit(AFS_VNODE_CB_PROMISED, &vnode->flags)) { if (!test_bit(AFS_VNODE_CB_PROMISED, &vnode->flags)) {
_debug("not promised"); _debug("not promised");
ret = afs_fetch_status(vnode, key); ret = afs_fetch_status(vnode, key, false);
if (ret < 0) { if (ret < 0) {
if (ret == -ENOENT) { if (ret == -ENOENT) {
set_bit(AFS_VNODE_DELETED, &vnode->flags); set_bit(AFS_VNODE_DELETED, &vnode->flags);
...@@ -453,8 +444,6 @@ int afs_validate(struct afs_vnode *vnode, struct key *key) ...@@ -453,8 +444,6 @@ int afs_validate(struct afs_vnode *vnode, struct key *key)
* different */ * different */
if (test_and_clear_bit(AFS_VNODE_ZAP_DATA, &vnode->flags)) if (test_and_clear_bit(AFS_VNODE_ZAP_DATA, &vnode->flags))
afs_zap_data(vnode); afs_zap_data(vnode);
clear_bit(AFS_VNODE_DIR_MODIFIED, &vnode->flags);
mutex_unlock(&vnode->validate_lock); mutex_unlock(&vnode->validate_lock);
valid: valid:
_leave(" = 0"); _leave(" = 0");
...@@ -544,7 +533,7 @@ void afs_evict_inode(struct inode *inode) ...@@ -544,7 +533,7 @@ void afs_evict_inode(struct inode *inode)
} }
#endif #endif
afs_put_permits(vnode->permit_cache); afs_put_permits(rcu_access_pointer(vnode->permit_cache));
_leave(""); _leave("");
} }
......
This diff is collapsed.
...@@ -34,11 +34,42 @@ MODULE_PARM_DESC(rootcell, "root AFS cell name and VL server IP addr list"); ...@@ -34,11 +34,42 @@ MODULE_PARM_DESC(rootcell, "root AFS cell name and VL server IP addr list");
struct workqueue_struct *afs_wq; struct workqueue_struct *afs_wq;
struct afs_net __afs_net; 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. * Initialise an AFS network namespace record.
*/ */
static int __net_init afs_net_init(struct afs_net *net) static int __net_init afs_net_init(struct afs_net *net)
{ {
struct afs_sysnames *sysnames;
int ret; int ret;
net->live = true; net->live = true;
...@@ -67,6 +98,16 @@ static int __net_init afs_net_init(struct afs_net *net) ...@@ -67,6 +98,16 @@ static int __net_init afs_net_init(struct afs_net *net)
INIT_WORK(&net->fs_manager, afs_manage_servers); INIT_WORK(&net->fs_manager, afs_manage_servers);
timer_setup(&net->fs_timer, afs_servers_timer, 0); 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 */ /* Register the /proc stuff */
ret = afs_proc_init(net); ret = afs_proc_init(net);
if (ret < 0) if (ret < 0)
...@@ -92,6 +133,8 @@ static int __net_init afs_net_init(struct afs_net *net) ...@@ -92,6 +133,8 @@ static int __net_init afs_net_init(struct afs_net *net)
net->live = false; net->live = false;
afs_proc_cleanup(net); afs_proc_cleanup(net);
error_proc: error_proc:
afs_put_sysnames(net->sysnames);
error_sysnames:
net->live = false; net->live = false;
return ret; return ret;
} }
...@@ -106,6 +149,7 @@ static void __net_exit afs_net_exit(struct afs_net *net) ...@@ -106,6 +149,7 @@ static void __net_exit afs_net_exit(struct afs_net *net)
afs_purge_servers(net); afs_purge_servers(net);
afs_close_socket(net); afs_close_socket(net);
afs_proc_cleanup(net); afs_proc_cleanup(net);
afs_put_sysnames(net->sysnames);
} }
/* /*
......
This diff is collapsed.
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
/* /*
* Initialise a filesystem server cursor for iterating over FS servers. * 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)); memset(fc, 0, sizeof(*fc));
} }
......
...@@ -926,3 +926,12 @@ int afs_extract_data(struct afs_call *call, void *buf, size_t count, ...@@ -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); afs_set_call_complete(call, ret, remote_abort);
return ret; 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, ...@@ -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)) { if (cb_break != (vnode->cb_break + vnode->cb_interest->server->cb_s_break))
rcu_read_unlock();
goto someone_else_changed_it; goto someone_else_changed_it;
}
/* We need a ref on any permits list we want to copy as we'll have to /* We need a ref on any permits list we want to copy as we'll have to
* drop the lock to do memory allocation. * drop the lock to do memory allocation.
*/ */
if (permits && !refcount_inc_not_zero(&permits->usage)) { if (permits && !refcount_inc_not_zero(&permits->usage))
rcu_read_unlock();
goto someone_else_changed_it; goto someone_else_changed_it;
}
rcu_read_unlock(); rcu_read_unlock();
...@@ -278,6 +274,7 @@ void afs_cache_permit(struct afs_vnode *vnode, struct key *key, ...@@ -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 /* Someone else changed the cache under us - don't recheck at this
* time. * time.
*/ */
rcu_read_unlock();
return; return;
} }
...@@ -296,8 +293,6 @@ int afs_check_permit(struct afs_vnode *vnode, struct key *key, ...@@ -296,8 +293,6 @@ int afs_check_permit(struct afs_vnode *vnode, struct key *key,
_enter("{%x:%u},%x", _enter("{%x:%u},%x",
vnode->fid.vid, vnode->fid.vnode, key_serial(key)); vnode->fid.vid, vnode->fid.vnode, key_serial(key));
permits = vnode->permit_cache;
/* check the permits to see if we've got one yet */ /* check the permits to see if we've got one yet */
if (key == vnode->volume->cell->anonymous_key) { if (key == vnode->volume->cell->anonymous_key) {
_debug("anon"); _debug("anon");
...@@ -327,7 +322,7 @@ int afs_check_permit(struct afs_vnode *vnode, struct key *key, ...@@ -327,7 +322,7 @@ int afs_check_permit(struct afs_vnode *vnode, struct key *key,
*/ */
_debug("no valid permit"); _debug("no valid permit");
ret = afs_fetch_status(vnode, key); ret = afs_fetch_status(vnode, key, false);
if (ret < 0) { if (ret < 0) {
*_access = 0; *_access = 0;
_leave(" = %d", ret); _leave(" = %d", ret);
......
...@@ -59,7 +59,8 @@ struct afs_server *afs_find_server(struct afs_net *net, ...@@ -59,7 +59,8 @@ struct afs_server *afs_find_server(struct afs_net *net,
alist = rcu_dereference(server->addresses); alist = rcu_dereference(server->addresses);
for (i = alist->nr_ipv4; i < alist->nr_addrs; i++) { for (i = alist->nr_ipv4; i < alist->nr_addrs; i++) {
b = &alist->addrs[i].transport.sin6; 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) if (diff == 0)
diff = memcmp(&a->sin6_addr, diff = memcmp(&a->sin6_addr,
&b->sin6_addr, &b->sin6_addr,
...@@ -79,10 +80,11 @@ struct afs_server *afs_find_server(struct afs_net *net, ...@@ -79,10 +80,11 @@ struct afs_server *afs_find_server(struct afs_net *net,
alist = rcu_dereference(server->addresses); alist = rcu_dereference(server->addresses);
for (i = 0; i < alist->nr_ipv4; i++) { for (i = 0; i < alist->nr_ipv4; i++) {
b = &alist->addrs[i].transport.sin6; 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) if (diff == 0)
diff = ((u32)a->sin6_addr.s6_addr32[3] - diff = ((u32 __force)a->sin6_addr.s6_addr32[3] -
(u32)b->sin6_addr.s6_addr32[3]); (u32 __force)b->sin6_addr.s6_addr32[3]);
if (diff == 0) if (diff == 0)
goto found; goto found;
if (diff < 0) { if (diff < 0) {
...@@ -381,7 +383,7 @@ static void afs_server_rcu(struct rcu_head *rcu) ...@@ -381,7 +383,7 @@ static void afs_server_rcu(struct rcu_head *rcu)
{ {
struct afs_server *server = container_of(rcu, struct afs_server, 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); kfree(server);
} }
...@@ -390,7 +392,7 @@ static void afs_server_rcu(struct rcu_head *rcu) ...@@ -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) 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 = { struct afs_addr_cursor ac = {
.alist = alist, .alist = alist,
.addr = &alist->addrs[0], .addr = &alist->addrs[0],
......
...@@ -154,7 +154,7 @@ static int afs_show_devname(struct seq_file *m, struct dentry *root) ...@@ -154,7 +154,7 @@ static int afs_show_devname(struct seq_file *m, struct dentry *root)
seq_puts(m, "none"); seq_puts(m, "none");
return 0; return 0;
} }
switch (volume->type) { switch (volume->type) {
case AFSVL_RWVOL: case AFSVL_RWVOL:
break; break;
...@@ -269,7 +269,7 @@ static int afs_parse_device_name(struct afs_mount_params *params, ...@@ -269,7 +269,7 @@ static int afs_parse_device_name(struct afs_mount_params *params,
int cellnamesz; int cellnamesz;
_enter(",%s", name); _enter(",%s", name);
if (!name) { if (!name) {
printk(KERN_ERR "kAFS: no volume name specified\n"); printk(KERN_ERR "kAFS: no volume name specified\n");
return -EINVAL; return -EINVAL;
...@@ -418,7 +418,10 @@ static int afs_fill_super(struct super_block *sb, ...@@ -418,7 +418,10 @@ static int afs_fill_super(struct super_block *sb,
if (!sb->s_root) if (!sb->s_root)
goto error; goto error;
sb->s_d_op = &afs_fs_dentry_operations; if (params->dyn_root)
sb->s_d_op = &afs_dynroot_dentry_operations;
else
sb->s_d_op = &afs_fs_dentry_operations;
_leave(" = 0"); _leave(" = 0");
return 0; return 0;
...@@ -676,7 +679,7 @@ static int afs_statfs(struct dentry *dentry, struct kstatfs *buf) ...@@ -676,7 +679,7 @@ static int afs_statfs(struct dentry *dentry, struct kstatfs *buf)
buf->f_bfree = 0; buf->f_bfree = 0;
return 0; return 0;
} }
key = afs_request_key(vnode->volume->cell); key = afs_request_key(vnode->volume->cell);
if (IS_ERR(key)) if (IS_ERR(key))
return PTR_ERR(key); return PTR_ERR(key);
......
...@@ -303,7 +303,7 @@ struct afs_addr_list *afs_vl_get_addrs_u(struct afs_net *net, ...@@ -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_hi_and_reserved = htonl(u->clock_seq_hi_and_reserved);
r->uuid.clock_seq_low = htonl(u->clock_seq_low); r->uuid.clock_seq_low = htonl(u->clock_seq_low);
for (i = 0; i < 6; i++) 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); trace_afs_make_vl_call(call);
return (struct afs_addr_list *)afs_make_call(ac, call, GFP_KERNEL, false); 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) ...@@ -450,7 +450,7 @@ static int afs_deliver_yfsvl_get_endpoints(struct afs_call *call)
call->count2 = ntohl(*bp); /* Type or next count */ call->count2 = ntohl(*bp); /* Type or next count */
if (call->count > YFS_MAXENDPOINTS) if (call->count > YFS_MAXENDPOINTS)
return -EBADMSG; return afs_protocol_error(call, -EBADMSG);
alist = afs_alloc_addrlist(call->count, FS_SERVICE, AFS_FS_PORT); alist = afs_alloc_addrlist(call->count, FS_SERVICE, AFS_FS_PORT);
if (!alist) if (!alist)
...@@ -474,7 +474,7 @@ static int afs_deliver_yfsvl_get_endpoints(struct afs_call *call) ...@@ -474,7 +474,7 @@ static int afs_deliver_yfsvl_get_endpoints(struct afs_call *call)
size = sizeof(__be32) * (1 + 4 + 1); size = sizeof(__be32) * (1 + 4 + 1);
break; break;
default: default:
return -EBADMSG; return afs_protocol_error(call, -EBADMSG);
} }
size += sizeof(__be32); size += sizeof(__be32);
...@@ -487,24 +487,24 @@ static int afs_deliver_yfsvl_get_endpoints(struct afs_call *call) ...@@ -487,24 +487,24 @@ static int afs_deliver_yfsvl_get_endpoints(struct afs_call *call)
switch (call->count2) { switch (call->count2) {
case YFS_ENDPOINT_IPV4: case YFS_ENDPOINT_IPV4:
if (ntohl(bp[0]) != sizeof(__be32) * 2) 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])); afs_merge_fs_addr4(alist, bp[1], ntohl(bp[2]));
bp += 3; bp += 3;
break; break;
case YFS_ENDPOINT_IPV6: case YFS_ENDPOINT_IPV6:
if (ntohl(bp[0]) != sizeof(__be32) * 5) 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])); afs_merge_fs_addr6(alist, bp + 1, ntohl(bp[5]));
bp += 6; bp += 6;
break; break;
default: default:
return -EBADMSG; return afs_protocol_error(call, -EBADMSG);
} }
/* Got either the type of the next entry or the count of /* Got either the type of the next entry or the count of
* volEndpoints if no more fsEndpoints. * volEndpoints if no more fsEndpoints.
*/ */
call->count2 = htonl(*bp++); call->count2 = ntohl(*bp++);
call->offset = 0; call->offset = 0;
call->count--; call->count--;
...@@ -517,7 +517,7 @@ static int afs_deliver_yfsvl_get_endpoints(struct afs_call *call) ...@@ -517,7 +517,7 @@ static int afs_deliver_yfsvl_get_endpoints(struct afs_call *call)
if (!call->count) if (!call->count)
goto end; goto end;
if (call->count > YFS_MAXENDPOINTS) if (call->count > YFS_MAXENDPOINTS)
return -EBADMSG; return afs_protocol_error(call, -EBADMSG);
call->unmarshall = 3; call->unmarshall = 3;
...@@ -531,7 +531,7 @@ static int afs_deliver_yfsvl_get_endpoints(struct afs_call *call) ...@@ -531,7 +531,7 @@ static int afs_deliver_yfsvl_get_endpoints(struct afs_call *call)
return ret; return ret;
bp = call->buffer; bp = call->buffer;
call->count2 = htonl(*bp++); call->count2 = ntohl(*bp++);
call->offset = 0; call->offset = 0;
call->unmarshall = 4; call->unmarshall = 4;
...@@ -545,7 +545,7 @@ static int afs_deliver_yfsvl_get_endpoints(struct afs_call *call) ...@@ -545,7 +545,7 @@ static int afs_deliver_yfsvl_get_endpoints(struct afs_call *call)
size = sizeof(__be32) * (1 + 4 + 1); size = sizeof(__be32) * (1 + 4 + 1);
break; break;
default: default:
return -EBADMSG; return afs_protocol_error(call, -EBADMSG);
} }
if (call->count > 1) if (call->count > 1)
...@@ -558,16 +558,16 @@ static int afs_deliver_yfsvl_get_endpoints(struct afs_call *call) ...@@ -558,16 +558,16 @@ static int afs_deliver_yfsvl_get_endpoints(struct afs_call *call)
switch (call->count2) { switch (call->count2) {
case YFS_ENDPOINT_IPV4: case YFS_ENDPOINT_IPV4:
if (ntohl(bp[0]) != sizeof(__be32) * 2) if (ntohl(bp[0]) != sizeof(__be32) * 2)
return -EBADMSG; return afs_protocol_error(call, -EBADMSG);
bp += 3; bp += 3;
break; break;
case YFS_ENDPOINT_IPV6: case YFS_ENDPOINT_IPV6:
if (ntohl(bp[0]) != sizeof(__be32) * 5) if (ntohl(bp[0]) != sizeof(__be32) * 5)
return -EBADMSG; return afs_protocol_error(call, -EBADMSG);
bp += 6; bp += 6;
break; break;
default: default:
return -EBADMSG; return afs_protocol_error(call, -EBADMSG);
} }
/* Got either the type of the next entry or the count of /* 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) ...@@ -576,7 +576,7 @@ static int afs_deliver_yfsvl_get_endpoints(struct afs_call *call)
call->offset = 0; call->offset = 0;
call->count--; call->count--;
if (call->count > 0) { if (call->count > 0) {
call->count2 = htonl(*bp++); call->count2 = ntohl(*bp++);
goto again; goto again;
} }
......
...@@ -42,10 +42,11 @@ static int afs_fill_page(struct afs_vnode *vnode, struct key *key, ...@@ -42,10 +42,11 @@ static int afs_fill_page(struct afs_vnode *vnode, struct key *key,
if (!req) if (!req)
return -ENOMEM; return -ENOMEM;
atomic_set(&req->usage, 1); refcount_set(&req->usage, 1);
req->pos = pos; req->pos = pos;
req->len = len; req->len = len;
req->nr_pages = 1; req->nr_pages = 1;
req->pages = req->array;
req->pages[0] = page; req->pages[0] = page;
get_page(page); get_page(page);
...@@ -124,7 +125,12 @@ int afs_write_begin(struct file *file, struct address_space *mapping, ...@@ -124,7 +125,12 @@ int afs_write_begin(struct file *file, struct address_space *mapping,
page->index, priv); page->index, priv);
goto flush_conflicting_write; 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; goto flush_conflicting_write;
if (from < f) if (from < f)
f = from; f = from;
...@@ -355,6 +361,12 @@ static int afs_store_data(struct address_space *mapping, ...@@ -355,6 +361,12 @@ static int afs_store_data(struct address_space *mapping,
} }
switch (ret) { 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 -EACCES:
case -EPERM: case -EPERM:
case -ENOKEY: case -ENOKEY:
...@@ -412,7 +424,8 @@ static int afs_write_back_from_locked_page(struct address_space *mapping, ...@@ -412,7 +424,8 @@ static int afs_write_back_from_locked_page(struct address_space *mapping,
trace_afs_page_dirty(vnode, tracepoint_string("WARN"), trace_afs_page_dirty(vnode, tracepoint_string("WARN"),
primary_page->index, priv); 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; goto no_more;
start++; start++;
...@@ -433,9 +446,10 @@ static int afs_write_back_from_locked_page(struct address_space *mapping, ...@@ -433,9 +446,10 @@ static int afs_write_back_from_locked_page(struct address_space *mapping,
} }
for (loop = 0; loop < n; loop++) { for (loop = 0; loop < n; loop++) {
if (to != PAGE_SIZE)
break;
page = pages[loop]; page = pages[loop];
if (to != PAGE_SIZE &&
!test_bit(AFS_VNODE_NEW_CONTENT, &vnode->flags))
break;
if (page->index > final_page) if (page->index > final_page)
break; break;
if (!trylock_page(page)) if (!trylock_page(page))
...@@ -448,7 +462,8 @@ static int afs_write_back_from_locked_page(struct address_space *mapping, ...@@ -448,7 +462,8 @@ static int afs_write_back_from_locked_page(struct address_space *mapping,
priv = page_private(page); priv = page_private(page);
f = priv & AFS_PRIV_MAX; f = priv & AFS_PRIV_MAX;
t = priv >> AFS_PRIV_SHIFT; t = priv >> AFS_PRIV_SHIFT;
if (f != 0) { if (f != 0 &&
!test_bit(AFS_VNODE_NEW_CONTENT, &vnode->flags)) {
unlock_page(page); unlock_page(page);
break; break;
} }
...@@ -734,20 +749,6 @@ int afs_fsync(struct file *file, loff_t start, loff_t end, int datasync) ...@@ -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); 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 * 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 * - 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, ...@@ -1667,7 +1667,7 @@ typedef int (*filldir_t)(struct dir_context *, const char *, int, loff_t, u64,
unsigned); unsigned);
struct dir_context { struct dir_context {
const filldir_t actor; filldir_t actor;
loff_t pos; loff_t pos;
}; };
......
...@@ -49,6 +49,7 @@ enum afs_fs_operation { ...@@ -49,6 +49,7 @@ enum afs_fs_operation {
afs_FS_ExtendLock = 157, /* AFS Extend a file lock */ afs_FS_ExtendLock = 157, /* AFS Extend a file lock */
afs_FS_ReleaseLock = 158, /* AFS Release a file lock */ afs_FS_ReleaseLock = 158, /* AFS Release a file lock */
afs_FS_Lookup = 161, /* AFS lookup file in directory */ 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_FetchData64 = 65537, /* AFS Fetch file data */
afs_FS_StoreData64 = 65538, /* AFS Store file data */ afs_FS_StoreData64 = 65538, /* AFS Store file data */
afs_FS_GiveUpAllCallBacks = 65539, /* AFS Give up all our callbacks on a server */ afs_FS_GiveUpAllCallBacks = 65539, /* AFS Give up all our callbacks on a server */
...@@ -62,6 +63,27 @@ enum afs_vl_operation { ...@@ -62,6 +63,27 @@ enum afs_vl_operation {
afs_VL_GetCapabilities = 65537, /* AFS Get VL server capabilities */ 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 */ #endif /* end __AFS_DECLARE_TRACE_ENUMS_ONCE_ONLY */
/* /*
...@@ -93,6 +115,7 @@ enum afs_vl_operation { ...@@ -93,6 +115,7 @@ enum afs_vl_operation {
EM(afs_FS_ExtendLock, "FS.ExtendLock") \ EM(afs_FS_ExtendLock, "FS.ExtendLock") \
EM(afs_FS_ReleaseLock, "FS.ReleaseLock") \ EM(afs_FS_ReleaseLock, "FS.ReleaseLock") \
EM(afs_FS_Lookup, "FS.Lookup") \ EM(afs_FS_Lookup, "FS.Lookup") \
EM(afs_FS_InlineBulkStatus, "FS.InlineBulkStatus") \
EM(afs_FS_FetchData64, "FS.FetchData64") \ EM(afs_FS_FetchData64, "FS.FetchData64") \
EM(afs_FS_StoreData64, "FS.StoreData64") \ EM(afs_FS_StoreData64, "FS.StoreData64") \
EM(afs_FS_GiveUpAllCallBacks, "FS.GiveUpAllCallBacks") \ EM(afs_FS_GiveUpAllCallBacks, "FS.GiveUpAllCallBacks") \
...@@ -104,6 +127,25 @@ enum afs_vl_operation { ...@@ -104,6 +127,25 @@ enum afs_vl_operation {
EM(afs_YFSVL_GetEndpoints, "YFSVL.GetEndpoints") \ EM(afs_YFSVL_GetEndpoints, "YFSVL.GetEndpoints") \
E_(afs_VL_GetCapabilities, "VL.GetCapabilities") 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. * Export enum symbols via userspace.
...@@ -116,6 +158,8 @@ enum afs_vl_operation { ...@@ -116,6 +158,8 @@ enum afs_vl_operation {
afs_call_traces; afs_call_traces;
afs_fs_operations; afs_fs_operations;
afs_vl_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 * Now redefine the EM() and E_() macros to map the enums to the strings that
...@@ -462,6 +506,75 @@ TRACE_EVENT(afs_call_state, ...@@ -462,6 +506,75 @@ TRACE_EVENT(afs_call_state,
__entry->ret, __entry->abort) __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 */ #endif /* _TRACE_AFS_H */
/* This part must be outside protection */ /* 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