Commit 260a9803 authored by David Howells's avatar David Howells Committed by David S. Miller

[AFS]: Add "directory write" support.

Add support for the create, link, symlink, unlink, mkdir, rmdir and
rename VFS operations to the in-kernel AFS filesystem.

Also:

 (1) Fix dentry and inode revalidation.  d_revalidate should only look at
     state of the dentry.  Revalidation of the contents of an inode pointed to
     by a dentry is now separate.

 (2) Fix afs_lookup() to hash negative dentries as well as positive ones.
Signed-off-by: default avatarDavid Howells <dhowells@redhat.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent c35eccb1
...@@ -106,18 +106,36 @@ struct afs_file_status { ...@@ -106,18 +106,36 @@ struct afs_file_status {
afs_file_type_t type; /* file type */ afs_file_type_t type; /* file type */
unsigned nlink; /* link count */ unsigned nlink; /* link count */
size_t size; /* file size */ u64 size; /* file size */
afs_dataversion_t data_version; /* current data version */ afs_dataversion_t data_version; /* current data version */
unsigned author; /* author ID */ u32 author; /* author ID */
unsigned owner; /* owner ID */ u32 owner; /* owner 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 */
struct afs_fid parent; /* parent file ID */ struct afs_fid parent; /* parent dir ID for non-dirs only */
time_t mtime_client; /* last time client changed data */ time_t mtime_client; /* last time client changed data */
time_t mtime_server; /* last time server changed data */ time_t mtime_server; /* last time server changed data */
}; };
/*
* AFS file status change request
*/
struct afs_store_status {
u32 mask; /* which bits of the struct are set */
u32 mtime_client; /* last time client changed data */
u32 owner; /* owner ID */
u32 group; /* group ID */
umode_t mode; /* UNIX mode */
};
#define AFS_SET_MTIME 0x01 /* set the mtime */
#define AFS_SET_OWNER 0x02 /* set the owner ID */
#define AFS_SET_GROUP 0x04 /* set the group ID (unsupported?) */
#define AFS_SET_MODE 0x08 /* set the UNIX mode */
#define AFS_SET_SEG_SIZE 0x10 /* set the segment size (unsupported) */
/* /*
* AFS volume synchronisation information * AFS volume synchronisation information
*/ */
......
...@@ -16,12 +16,19 @@ ...@@ -16,12 +16,19 @@
#define FS_SERVICE 1 /* AFS File Service ID */ #define FS_SERVICE 1 /* AFS File Service ID */
enum AFS_FS_Operations { enum AFS_FS_Operations {
FSFETCHSTATUS = 132, /* AFS Fetch file status */
FSFETCHDATA = 130, /* AFS Fetch file data */ FSFETCHDATA = 130, /* AFS Fetch file data */
FSFETCHSTATUS = 132, /* AFS Fetch file status */
FSREMOVEFILE = 136, /* AFS Remove a file */
FSCREATEFILE = 137, /* AFS Create a file */
FSRENAME = 138, /* AFS Rename or move a file or directory */
FSSYMLINK = 139, /* AFS Create a symbolic link */
FSLINK = 140, /* AFS Create a hard link */
FSMAKEDIR = 141, /* AFS Create a directory */
FSREMOVEDIR = 142, /* AFS Remove a directory */
FSGIVEUPCALLBACKS = 147, /* AFS Discard callback promises */ FSGIVEUPCALLBACKS = 147, /* AFS Discard callback promises */
FSGETVOLUMEINFO = 148, /* AFS Get root volume information */ FSGETVOLUMEINFO = 148, /* AFS Get root volume information */
FSGETROOTVOLUME = 151, /* AFS Get root volume name */ FSGETROOTVOLUME = 151, /* AFS Get root volume name */
FSLOOKUP = 161 /* AFS lookup file in directory */ FSLOOKUP = 161, /* AFS lookup file in directory */
}; };
enum AFS_FS_Errors { enum AFS_FS_Errors {
......
...@@ -44,7 +44,8 @@ void afs_init_callback_state(struct afs_server *server) ...@@ -44,7 +44,8 @@ void afs_init_callback_state(struct afs_server *server)
while (!RB_EMPTY_ROOT(&server->cb_promises)) { while (!RB_EMPTY_ROOT(&server->cb_promises)) {
vnode = rb_entry(server->cb_promises.rb_node, vnode = rb_entry(server->cb_promises.rb_node,
struct afs_vnode, cb_promise); struct afs_vnode, cb_promise);
printk("\nUNPROMISE on %p\n", vnode); _debug("UNPROMISE { vid=%x vn=%u uq=%u}",
vnode->fid.vid, vnode->fid.vnode, vnode->fid.unique);
rb_erase(&vnode->cb_promise, &server->cb_promises); rb_erase(&vnode->cb_promise, &server->cb_promises);
vnode->cb_promised = false; vnode->cb_promised = false;
} }
...@@ -68,7 +69,7 @@ void afs_broken_callback_work(struct work_struct *work) ...@@ -68,7 +69,7 @@ void afs_broken_callback_work(struct work_struct *work)
/* we're only interested in dealing with a broken callback on *this* /* we're only interested in dealing with a broken callback on *this*
* vnode and only if no-one else has dealt with it yet */ * vnode and only if no-one else has dealt with it yet */
if (!mutex_trylock(&vnode->cb_broken_lock)) if (!mutex_trylock(&vnode->validate_lock))
return; /* someone else is dealing with it */ return; /* someone else is dealing with it */
if (test_bit(AFS_VNODE_CB_BROKEN, &vnode->flags)) { if (test_bit(AFS_VNODE_CB_BROKEN, &vnode->flags)) {
...@@ -84,13 +85,14 @@ void afs_broken_callback_work(struct work_struct *work) ...@@ -84,13 +85,14 @@ void afs_broken_callback_work(struct work_struct *work)
/* if the vnode's data version number changed then its contents /* if the vnode's data version number changed then its contents
* are different */ * are different */
if (test_and_clear_bit(AFS_VNODE_ZAP_DATA, &vnode->flags)) { if (test_and_clear_bit(AFS_VNODE_ZAP_DATA, &vnode->flags)) {
_debug("zap data"); _debug("zap data {%x:%u}",
vnode->fid.vid, vnode->fid.vnode);
invalidate_remote_inode(&vnode->vfs_inode); invalidate_remote_inode(&vnode->vfs_inode);
} }
} }
out: out:
mutex_unlock(&vnode->cb_broken_lock); mutex_unlock(&vnode->validate_lock);
/* avoid the potential race whereby the mutex_trylock() in this /* avoid the potential race whereby the mutex_trylock() in this
* function happens again between the clear_bit() and the * function happens again between the clear_bit() and the
...@@ -251,6 +253,32 @@ static void afs_do_give_up_callback(struct afs_server *server, ...@@ -251,6 +253,32 @@ static void afs_do_give_up_callback(struct afs_server *server,
_leave(""); _leave("");
} }
/*
* discard the callback on a deleted item
*/
void afs_discard_callback_on_delete(struct afs_vnode *vnode)
{
struct afs_server *server = vnode->server;
_enter("%d", vnode->cb_promised);
if (!vnode->cb_promised) {
_leave(" [not promised]");
return;
}
ASSERT(server != NULL);
spin_lock(&server->cb_lock);
if (vnode->cb_promised) {
ASSERT(server->cb_promises.rb_node != NULL);
rb_erase(&vnode->cb_promise, &server->cb_promises);
vnode->cb_promised = false;
}
spin_unlock(&server->cb_lock);
_leave("");
}
/* /*
* give up the callback registered for a vnode on the file server when the * give up the callback registered for a vnode on the file server when the
* inode is being cleared * inode is being cleared
......
This diff is collapsed.
...@@ -50,6 +50,7 @@ int afs_open(struct inode *inode, struct file *file) ...@@ -50,6 +50,7 @@ int afs_open(struct inode *inode, struct file *file)
{ {
struct afs_vnode *vnode = AFS_FS_I(inode); struct afs_vnode *vnode = AFS_FS_I(inode);
struct key *key; struct key *key;
int ret;
_enter("{%x:%x},", vnode->fid.vid, vnode->fid.vnode); _enter("{%x:%x},", vnode->fid.vid, vnode->fid.vnode);
...@@ -59,6 +60,12 @@ int afs_open(struct inode *inode, struct file *file) ...@@ -59,6 +60,12 @@ int afs_open(struct inode *inode, struct file *file)
return PTR_ERR(key); return PTR_ERR(key);
} }
ret = afs_validate(vnode, key);
if (ret < 0) {
_leave(" = %d [val]", ret);
return ret;
}
file->private_data = key; file->private_data = key;
_leave(" = 0"); _leave(" = 0");
return 0; return 0;
......
This diff is collapsed.
...@@ -33,7 +33,7 @@ static int afs_inode_map_status(struct afs_vnode *vnode, struct key *key) ...@@ -33,7 +33,7 @@ static int afs_inode_map_status(struct afs_vnode *vnode, struct key *key)
{ {
struct inode *inode = AFS_VNODE_TO_I(vnode); struct inode *inode = AFS_VNODE_TO_I(vnode);
_debug("FS: ft=%d lk=%d sz=%Zu ver=%Lu mod=%hu", _debug("FS: ft=%d lk=%d sz=%llu ver=%Lu mod=%hu",
vnode->status.type, vnode->status.type,
vnode->status.nlink, vnode->status.nlink,
vnode->status.size, vnode->status.size,
...@@ -115,8 +115,9 @@ static int afs_iget5_set(struct inode *inode, void *opaque) ...@@ -115,8 +115,9 @@ static int afs_iget5_set(struct inode *inode, void *opaque)
/* /*
* inode retrieval * inode retrieval
*/ */
inline struct inode *afs_iget(struct super_block *sb, struct key *key, struct inode *afs_iget(struct super_block *sb, struct key *key,
struct afs_fid *fid) struct afs_fid *fid, struct afs_file_status *status,
struct afs_callback *cb)
{ {
struct afs_iget_data data = { .fid = *fid }; struct afs_iget_data data = { .fid = *fid };
struct afs_super_info *as; struct afs_super_info *as;
...@@ -156,16 +157,37 @@ inline struct inode *afs_iget(struct super_block *sb, struct key *key, ...@@ -156,16 +157,37 @@ inline struct inode *afs_iget(struct super_block *sb, struct key *key,
&vnode->cache); &vnode->cache);
#endif #endif
/* okay... it's a new inode */ if (!status) {
set_bit(AFS_VNODE_CB_BROKEN, &vnode->flags); /* it's a remotely extant inode */
ret = afs_vnode_fetch_status(vnode, NULL, key); set_bit(AFS_VNODE_CB_BROKEN, &vnode->flags);
if (ret < 0) ret = afs_vnode_fetch_status(vnode, NULL, key);
goto bad_inode; if (ret < 0)
goto bad_inode;
} else {
/* it's an inode we just created */
memcpy(&vnode->status, status, sizeof(vnode->status));
if (!cb) {
/* it's a symlink we just created (the fileserver
* didn't give us a callback) */
vnode->cb_version = 0;
vnode->cb_expiry = 0;
vnode->cb_type = 0;
vnode->cb_expires = get_seconds();
} else {
vnode->cb_version = cb->version;
vnode->cb_expiry = cb->expiry;
vnode->cb_type = cb->type;
vnode->cb_expires = vnode->cb_expiry + get_seconds();
}
}
ret = afs_inode_map_status(vnode, key); ret = afs_inode_map_status(vnode, key);
if (ret < 0) if (ret < 0)
goto bad_inode; goto bad_inode;
/* success */ /* success */
clear_bit(AFS_VNODE_UNSET, &vnode->flags);
inode->i_flags |= S_NOATIME; inode->i_flags |= S_NOATIME;
unlock_new_inode(inode); unlock_new_inode(inode);
_leave(" = %p [CB { v=%u t=%u }]", inode, vnode->cb_version, vnode->cb_type); _leave(" = %p [CB { v=%u t=%u }]", inode, vnode->cb_version, vnode->cb_type);
...@@ -181,6 +203,78 @@ inline struct inode *afs_iget(struct super_block *sb, struct key *key, ...@@ -181,6 +203,78 @@ inline struct inode *afs_iget(struct super_block *sb, struct key *key,
return ERR_PTR(ret); return ERR_PTR(ret);
} }
/*
* validate a vnode/inode
* - there are several things we need to check
* - parent dir data changes (rm, rmdir, rename, mkdir, create, link,
* symlink)
* - parent dir metadata changed (security changes)
* - dentry data changed (write, truncate)
* - dentry metadata changed (security changes)
*/
int afs_validate(struct afs_vnode *vnode, struct key *key)
{
int ret;
_enter("{v={%x:%u} fl=%lx},%x",
vnode->fid.vid, vnode->fid.vnode, vnode->flags,
key_serial(key));
if (vnode->cb_promised &&
!test_bit(AFS_VNODE_CB_BROKEN, &vnode->flags) &&
!test_bit(AFS_VNODE_MODIFIED, &vnode->flags) &&
!test_bit(AFS_VNODE_ZAP_DATA, &vnode->flags)) {
if (vnode->cb_expires < get_seconds() + 10) {
_debug("callback expired");
set_bit(AFS_VNODE_CB_BROKEN, &vnode->flags);
} else {
goto valid;
}
}
if (test_bit(AFS_VNODE_DELETED, &vnode->flags))
goto valid;
mutex_lock(&vnode->validate_lock);
/* if the promise has expired, we need to check the server again to get
* a new promise - note that if the (parent) directory's metadata was
* changed then the security may be different and we may no longer have
* access */
if (!vnode->cb_promised ||
test_bit(AFS_VNODE_CB_BROKEN, &vnode->flags)) {
_debug("not promised");
ret = afs_vnode_fetch_status(vnode, NULL, key);
if (ret < 0)
goto error_unlock;
_debug("new promise [fl=%lx]", vnode->flags);
}
if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) {
_debug("file already deleted");
ret = -ESTALE;
goto error_unlock;
}
/* if the vnode's data version number changed then its contents are
* different */
if (test_and_clear_bit(AFS_VNODE_ZAP_DATA, &vnode->flags)) {
_debug("zap data {%x:%d}", vnode->fid.vid, vnode->fid.vnode);
invalidate_remote_inode(&vnode->vfs_inode);
}
clear_bit(AFS_VNODE_MODIFIED, &vnode->flags);
mutex_unlock(&vnode->validate_lock);
valid:
_leave(" = 0");
return 0;
error_unlock:
mutex_unlock(&vnode->validate_lock);
_leave(" = %d", ret);
return ret;
}
/* /*
* read the attributes of an inode * read the attributes of an inode
*/ */
...@@ -207,9 +301,10 @@ void afs_clear_inode(struct inode *inode) ...@@ -207,9 +301,10 @@ void afs_clear_inode(struct inode *inode)
vnode = AFS_FS_I(inode); vnode = AFS_FS_I(inode);
_enter("ino=%lu { vn=%08x v=%u x=%u t=%u }", _enter("{%x:%d.%d} v=%u x=%u t=%u }",
inode->i_ino, vnode->fid.vid,
vnode->fid.vnode, vnode->fid.vnode,
vnode->fid.unique,
vnode->cb_version, vnode->cb_version,
vnode->cb_expiry, vnode->cb_expiry,
vnode->cb_type); vnode->cb_type);
......
...@@ -80,6 +80,7 @@ struct afs_call { ...@@ -80,6 +80,7 @@ struct afs_call {
void *reply; /* reply buffer (first part) */ void *reply; /* reply buffer (first part) */
void *reply2; /* reply buffer (second part) */ void *reply2; /* reply buffer (second part) */
void *reply3; /* reply buffer (third part) */ void *reply3; /* reply buffer (third part) */
void *reply4; /* reply buffer (fourth part) */
enum { /* call state */ enum { /* call state */
AFS_CALL_REQUESTING, /* request is being sent for outgoing call */ AFS_CALL_REQUESTING, /* request is being sent for outgoing call */
AFS_CALL_AWAIT_REPLY, /* awaiting reply to outgoing call */ AFS_CALL_AWAIT_REPLY, /* awaiting reply to outgoing call */
...@@ -300,19 +301,18 @@ struct afs_vnode { ...@@ -300,19 +301,18 @@ struct afs_vnode {
#endif #endif
struct afs_permits *permits; /* cache of permits so far obtained */ struct afs_permits *permits; /* cache of permits so far obtained */
struct mutex permits_lock; /* lock for altering permits list */ struct mutex permits_lock; /* lock for altering permits list */
struct mutex validate_lock; /* lock for validating this vnode */
wait_queue_head_t update_waitq; /* status fetch waitqueue */ wait_queue_head_t update_waitq; /* status fetch waitqueue */
unsigned update_cnt; /* number of outstanding ops that will update the int update_cnt; /* number of outstanding ops that will update the
* status */ * status */
spinlock_t lock; /* waitqueue/flags lock */ spinlock_t lock; /* waitqueue/flags lock */
unsigned long flags; unsigned long flags;
#define AFS_VNODE_CB_BROKEN 0 /* set if vnode's callback was broken */ #define AFS_VNODE_CB_BROKEN 0 /* set if vnode's callback was broken */
#define AFS_VNODE_CHANGED 1 /* set if vnode's metadata changed */ #define AFS_VNODE_UNSET 1 /* set if vnode attributes not yet set */
#define AFS_VNODE_MODIFIED 2 /* set if vnode's data modified */ #define AFS_VNODE_MODIFIED 2 /* set if vnode's data modified */
#define AFS_VNODE_ZAP_DATA 3 /* set if vnode's data should be invalidated */ #define AFS_VNODE_ZAP_DATA 3 /* set if vnode's data should be invalidated */
#define AFS_VNODE_DELETED 4 /* set if vnode deleted on server */ #define AFS_VNODE_DELETED 4 /* set if vnode deleted on server */
#define AFS_VNODE_MOUNTPOINT 5 /* set if vnode is a mountpoint symlink */ #define AFS_VNODE_MOUNTPOINT 5 /* set if vnode is a mountpoint symlink */
#define AFS_VNODE_DIR_CHANGED 6 /* set if vnode's parent dir metadata changed */
#define AFS_VNODE_DIR_MODIFIED 7 /* set if vnode's parent dir data modified */
long acl_order; /* ACL check count (callback break count) */ long acl_order; /* ACL check count (callback break count) */
...@@ -320,7 +320,6 @@ struct afs_vnode { ...@@ -320,7 +320,6 @@ struct afs_vnode {
struct rb_node server_rb; /* link in server->fs_vnodes */ struct rb_node server_rb; /* link in server->fs_vnodes */
struct rb_node cb_promise; /* link in server->cb_promises */ struct rb_node cb_promise; /* link in server->cb_promises */
struct work_struct cb_broken_work; /* work to be done on callback break */ struct work_struct cb_broken_work; /* work to be done on callback break */
struct mutex cb_broken_lock; /* lock against multiple attempts to fix break */
time_t cb_expires; /* time at which callback expires */ time_t cb_expires; /* time at which callback expires */
time_t cb_expires_at; /* time used to order cb_promise */ time_t cb_expires_at; /* time used to order cb_promise */
unsigned cb_version; /* callback version */ unsigned cb_version; /* callback version */
...@@ -388,6 +387,7 @@ extern void afs_init_callback_state(struct afs_server *); ...@@ -388,6 +387,7 @@ extern void afs_init_callback_state(struct afs_server *);
extern void afs_broken_callback_work(struct work_struct *); extern void afs_broken_callback_work(struct work_struct *);
extern void afs_break_callbacks(struct afs_server *, size_t, extern void afs_break_callbacks(struct afs_server *, size_t,
struct afs_callback[]); struct afs_callback[]);
extern void afs_discard_callback_on_delete(struct afs_vnode *);
extern void afs_give_up_callback(struct afs_vnode *); extern void afs_give_up_callback(struct afs_vnode *);
extern void afs_dispatch_give_up_callbacks(struct work_struct *); extern void afs_dispatch_give_up_callbacks(struct work_struct *);
extern void afs_flush_callback_breaks(struct afs_server *); extern void afs_flush_callback_breaks(struct afs_server *);
...@@ -448,14 +448,34 @@ extern int afs_fs_give_up_callbacks(struct afs_server *, ...@@ -448,14 +448,34 @@ extern int afs_fs_give_up_callbacks(struct afs_server *,
const struct afs_wait_mode *); const struct afs_wait_mode *);
extern int afs_fs_fetch_data(struct afs_server *, struct key *, extern int afs_fs_fetch_data(struct afs_server *, struct key *,
struct afs_vnode *, off_t, size_t, struct page *, struct afs_vnode *, off_t, size_t, struct page *,
struct afs_volsync *,
const struct afs_wait_mode *); const struct afs_wait_mode *);
extern int afs_fs_create(struct afs_server *, struct key *,
struct afs_vnode *, const char *, umode_t,
struct afs_fid *, struct afs_file_status *,
struct afs_callback *,
const struct afs_wait_mode *);
extern int afs_fs_remove(struct afs_server *, struct key *,
struct afs_vnode *, const char *, bool,
const struct afs_wait_mode *);
extern int afs_fs_link(struct afs_server *, struct key *, struct afs_vnode *,
struct afs_vnode *, const char *,
const struct afs_wait_mode *);
extern int afs_fs_symlink(struct afs_server *, struct key *,
struct afs_vnode *, const char *, const char *,
struct afs_fid *, struct afs_file_status *,
const struct afs_wait_mode *);
extern int afs_fs_rename(struct afs_server *, struct key *,
struct afs_vnode *, const char *,
struct afs_vnode *, const char *,
const struct afs_wait_mode *);
/* /*
* inode.c * inode.c
*/ */
extern struct inode *afs_iget(struct super_block *, struct key *, extern struct inode *afs_iget(struct super_block *, struct key *,
struct afs_fid *); struct afs_fid *, struct afs_file_status *,
struct afs_callback *);
extern int afs_validate(struct afs_vnode *, struct key *);
extern int afs_inode_getattr(struct vfsmount *, struct dentry *, extern int afs_inode_getattr(struct vfsmount *, struct dentry *,
struct kstat *); struct kstat *);
extern void afs_zap_permits(struct rcu_head *); extern void afs_zap_permits(struct rcu_head *);
...@@ -522,7 +542,11 @@ extern int afs_permission(struct inode *, int, struct nameidata *); ...@@ -522,7 +542,11 @@ extern int afs_permission(struct inode *, int, struct nameidata *);
*/ */
extern spinlock_t afs_server_peer_lock; extern spinlock_t afs_server_peer_lock;
#define afs_get_server(S) do { atomic_inc(&(S)->usage); } while(0) #define afs_get_server(S) \
do { \
_debug("GET SERVER %d", atomic_read(&(S)->usage)); \
atomic_inc(&(S)->usage); \
} while(0)
extern struct afs_server *afs_lookup_server(struct afs_cell *, extern struct afs_server *afs_lookup_server(struct afs_cell *,
const struct in_addr *); const struct in_addr *);
...@@ -588,10 +612,24 @@ static inline struct inode *AFS_VNODE_TO_I(struct afs_vnode *vnode) ...@@ -588,10 +612,24 @@ static inline struct inode *AFS_VNODE_TO_I(struct afs_vnode *vnode)
return &vnode->vfs_inode; return &vnode->vfs_inode;
} }
extern void afs_vnode_finalise_status_update(struct afs_vnode *,
struct afs_server *);
extern int afs_vnode_fetch_status(struct afs_vnode *, struct afs_vnode *, extern int afs_vnode_fetch_status(struct afs_vnode *, struct afs_vnode *,
struct key *); struct key *);
extern int afs_vnode_fetch_data(struct afs_vnode *, struct key *, extern int afs_vnode_fetch_data(struct afs_vnode *, struct key *,
off_t, size_t, struct page *); off_t, size_t, struct page *);
extern int afs_vnode_create(struct afs_vnode *, struct key *, const char *,
umode_t, struct afs_fid *, struct afs_file_status *,
struct afs_callback *, struct afs_server **);
extern int afs_vnode_remove(struct afs_vnode *, struct key *, const char *,
bool);
extern int afs_vnode_link(struct afs_vnode *, struct afs_vnode *, struct key *,
const char *);
extern int afs_vnode_symlink(struct afs_vnode *, struct key *, const char *,
const char *, struct afs_fid *,
struct afs_file_status *, struct afs_server **);
extern int afs_vnode_rename(struct afs_vnode *, struct afs_vnode *,
struct key *, const char *, const char *);
/* /*
* volume.c * volume.c
......
...@@ -22,6 +22,7 @@ int afs_abort_to_error(u32 abort_code) ...@@ -22,6 +22,7 @@ int afs_abort_to_error(u32 abort_code)
{ {
switch (abort_code) { switch (abort_code) {
case 13: return -EACCES; case 13: return -EACCES;
case 30: return -EROFS;
case VSALVAGE: return -EIO; case VSALVAGE: return -EIO;
case VNOVNODE: return -ENOENT; case VNOVNODE: return -ENOENT;
case VNOVOL: return -ENOMEDIUM; case VNOVOL: return -ENOMEDIUM;
...@@ -33,6 +34,24 @@ int afs_abort_to_error(u32 abort_code) ...@@ -33,6 +34,24 @@ int afs_abort_to_error(u32 abort_code)
case VOVERQUOTA: return -EDQUOT; case VOVERQUOTA: return -EDQUOT;
case VBUSY: return -EBUSY; case VBUSY: return -EBUSY;
case VMOVED: return -ENXIO; case VMOVED: return -ENXIO;
default: return -EIO; case 0x2f6df0c: return -EACCES;
case 0x2f6df0f: return -EBUSY;
case 0x2f6df10: return -EEXIST;
case 0x2f6df11: return -EXDEV;
case 0x2f6df13: return -ENOTDIR;
case 0x2f6df14: return -EISDIR;
case 0x2f6df15: return -EINVAL;
case 0x2f6df1a: return -EFBIG;
case 0x2f6df1b: return -ENOSPC;
case 0x2f6df1d: return -EROFS;
case 0x2f6df1e: return -EMLINK;
case 0x2f6df20: return -EDOM;
case 0x2f6df21: return -ERANGE;
case 0x2f6df22: return -EDEADLK;
case 0x2f6df23: return -ENAMETOOLONG;
case 0x2f6df24: return -ENOLCK;
case 0x2f6df26: return -ENOTEMPTY;
case 0x2f6df78: return -EDQUOT;
default: return -EREMOTEIO;
} }
} }
...@@ -92,7 +92,7 @@ static struct afs_vnode *afs_get_auth_inode(struct afs_vnode *vnode, ...@@ -92,7 +92,7 @@ static struct afs_vnode *afs_get_auth_inode(struct afs_vnode *vnode,
ASSERT(auth_inode != NULL); ASSERT(auth_inode != NULL);
} else { } else {
auth_inode = afs_iget(vnode->vfs_inode.i_sb, key, auth_inode = afs_iget(vnode->vfs_inode.i_sb, key,
&vnode->status.parent); &vnode->status.parent, NULL, NULL);
if (IS_ERR(auth_inode)) if (IS_ERR(auth_inode))
return ERR_PTR(PTR_ERR(auth_inode)); return ERR_PTR(PTR_ERR(auth_inode));
} }
...@@ -288,7 +288,8 @@ int afs_permission(struct inode *inode, int mask, struct nameidata *nd) ...@@ -288,7 +288,8 @@ int afs_permission(struct inode *inode, int mask, struct nameidata *nd)
struct key *key; struct key *key;
int ret; int ret;
_enter("{%x:%x},%x,", vnode->fid.vid, vnode->fid.vnode, mask); _enter("{{%x:%x},%lx},%x,",
vnode->fid.vid, vnode->fid.vnode, vnode->flags, mask);
key = afs_request_key(vnode->volume->cell); key = afs_request_key(vnode->volume->cell);
if (IS_ERR(key)) { if (IS_ERR(key)) {
...@@ -296,13 +297,19 @@ int afs_permission(struct inode *inode, int mask, struct nameidata *nd) ...@@ -296,13 +297,19 @@ int afs_permission(struct inode *inode, int mask, struct nameidata *nd)
return PTR_ERR(key); return PTR_ERR(key);
} }
/* if the promise has expired, we need to check the server again */
if (!vnode->cb_promised) {
_debug("not promised");
ret = afs_vnode_fetch_status(vnode, NULL, key);
if (ret < 0)
goto error;
_debug("new promise [fl=%lx]", vnode->flags);
}
/* check the permits to see if we've got one yet */ /* check the permits to see if we've got one yet */
ret = afs_check_permit(vnode, key, &access); ret = afs_check_permit(vnode, key, &access);
if (ret < 0) { if (ret < 0)
key_put(key); goto error;
_leave(" = %d [check]", ret);
return ret;
}
/* interpret the access mask */ /* interpret the access mask */
_debug("REQ %x ACC %x on %s", _debug("REQ %x ACC %x on %s",
...@@ -336,10 +343,14 @@ int afs_permission(struct inode *inode, int mask, struct nameidata *nd) ...@@ -336,10 +343,14 @@ int afs_permission(struct inode *inode, int mask, struct nameidata *nd)
} }
key_put(key); key_put(key);
return generic_permission(inode, mask, NULL); ret = generic_permission(inode, mask, NULL);
_leave(" = %d", ret);
return ret;
permission_denied: permission_denied:
ret = -EACCES;
error:
key_put(key); key_put(key);
_leave(" = -EACCES"); _leave(" = %d", ret);
return -EACCES; return ret;
} }
...@@ -223,6 +223,8 @@ void afs_put_server(struct afs_server *server) ...@@ -223,6 +223,8 @@ void afs_put_server(struct afs_server *server)
_enter("%p{%d}", server, atomic_read(&server->usage)); _enter("%p{%d}", server, atomic_read(&server->usage));
_debug("PUT SERVER %d", atomic_read(&server->usage));
ASSERTCMP(atomic_read(&server->usage), >, 0); ASSERTCMP(atomic_read(&server->usage), >, 0);
if (likely(!atomic_dec_and_test(&server->usage))) { if (likely(!atomic_dec_and_test(&server->usage))) {
......
...@@ -331,7 +331,7 @@ static int afs_fill_super(struct super_block *sb, void *data) ...@@ -331,7 +331,7 @@ static int afs_fill_super(struct super_block *sb, void *data)
fid.vid = as->volume->vid; fid.vid = as->volume->vid;
fid.vnode = 1; fid.vnode = 1;
fid.unique = 1; fid.unique = 1;
inode = afs_iget(sb, params->key, &fid); inode = afs_iget(sb, params->key, &fid, NULL, NULL);
if (IS_ERR(inode)) if (IS_ERR(inode))
goto error_inode; goto error_inode;
...@@ -473,9 +473,9 @@ static void afs_i_init_once(void *_vnode, struct kmem_cache *cachep, ...@@ -473,9 +473,9 @@ static void afs_i_init_once(void *_vnode, struct kmem_cache *cachep,
inode_init_once(&vnode->vfs_inode); inode_init_once(&vnode->vfs_inode);
init_waitqueue_head(&vnode->update_waitq); init_waitqueue_head(&vnode->update_waitq);
mutex_init(&vnode->permits_lock); mutex_init(&vnode->permits_lock);
mutex_init(&vnode->validate_lock);
spin_lock_init(&vnode->lock); spin_lock_init(&vnode->lock);
INIT_WORK(&vnode->cb_broken_work, afs_broken_callback_work); INIT_WORK(&vnode->cb_broken_work, afs_broken_callback_work);
mutex_init(&vnode->cb_broken_lock);
} }
} }
...@@ -497,7 +497,7 @@ static struct inode *afs_alloc_inode(struct super_block *sb) ...@@ -497,7 +497,7 @@ static struct inode *afs_alloc_inode(struct super_block *sb)
vnode->volume = NULL; vnode->volume = NULL;
vnode->update_cnt = 0; vnode->update_cnt = 0;
vnode->flags = 0; vnode->flags = 1 << AFS_VNODE_UNSET;
vnode->cb_promised = false; vnode->cb_promised = false;
return &vnode->vfs_inode; return &vnode->vfs_inode;
......
This diff is collapsed.
...@@ -295,6 +295,7 @@ struct afs_server *afs_volume_pick_fileserver(struct afs_vnode *vnode) ...@@ -295,6 +295,7 @@ struct afs_server *afs_volume_pick_fileserver(struct afs_vnode *vnode)
* - releases the ref on the server struct that was acquired by picking * - releases the ref on the server struct that was acquired by picking
* - records result of using a particular server to access a volume * - records result of using a particular server to access a volume
* - return 0 to try again, 1 if okay or to issue error * - return 0 to try again, 1 if okay or to issue error
* - the caller must release the server struct if result was 0
*/ */
int afs_volume_release_fileserver(struct afs_vnode *vnode, int afs_volume_release_fileserver(struct afs_vnode *vnode,
struct afs_server *server, struct afs_server *server,
...@@ -312,7 +313,8 @@ int afs_volume_release_fileserver(struct afs_vnode *vnode, ...@@ -312,7 +313,8 @@ int afs_volume_release_fileserver(struct afs_vnode *vnode,
case 0: case 0:
server->fs_act_jif = jiffies; server->fs_act_jif = jiffies;
server->fs_state = 0; server->fs_state = 0;
break; _leave("");
return 1;
/* the fileserver denied all knowledge of the volume */ /* the fileserver denied all knowledge of the volume */
case -ENOMEDIUM: case -ENOMEDIUM:
...@@ -377,14 +379,12 @@ int afs_volume_release_fileserver(struct afs_vnode *vnode, ...@@ -377,14 +379,12 @@ int afs_volume_release_fileserver(struct afs_vnode *vnode,
server->fs_act_jif = jiffies; server->fs_act_jif = jiffies;
case -ENOMEM: case -ENOMEM:
case -ENONET: case -ENONET:
break; /* tell the caller to accept the result */
afs_put_server(server);
_leave(" [local failure]");
return 1;
} }
/* tell the caller to accept the result */
afs_put_server(server);
_leave("");
return 1;
/* tell the caller to loop around and try the next server */ /* tell the caller to loop around and try the next server */
try_next_server_upw: try_next_server_upw:
up_write(&volume->server_sem); up_write(&volume->server_sem);
......
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