Commit f61ec2c9 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'afs-fixes-20171124' of git://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-fs

Pull AFS fixes from David Howells:

 - Make AFS file locking work again.

 - Don't write to a page that's being written out, but wait for it to
   complete.

 - Do d_drop() and d_add() in the right places.

 - Put keys on error paths.

 - Remove some redundant code.

* tag 'afs-fixes-20171124' of git://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-fs:
  afs: remove redundant assignment of dvnode to itself
  afs: cell: Remove unnecessary code in afs_lookup_cell
  afs: Fix signal handling in some file ops
  afs: Fix some dentry handling in dir ops and missing key_puts
  afs: Make afs_write_begin() avoid writing to a page that's being stored
  afs: Fix file locking
parents 7753ea09 43dd388b
...@@ -207,14 +207,9 @@ struct afs_cell *afs_lookup_cell(struct afs_net *net, ...@@ -207,14 +207,9 @@ struct afs_cell *afs_lookup_cell(struct afs_net *net,
rcu_read_lock(); rcu_read_lock();
cell = afs_lookup_cell_rcu(net, name, namesz); cell = afs_lookup_cell_rcu(net, name, namesz);
rcu_read_unlock(); rcu_read_unlock();
if (!IS_ERR(cell)) { if (!IS_ERR(cell))
if (excl) {
afs_put_cell(net, cell);
return ERR_PTR(-EEXIST);
}
goto wait_for_cell; goto wait_for_cell;
} }
}
/* Assume we're probably going to create a cell and preallocate and /* Assume we're probably going to create a cell and preallocate and
* mostly set up a candidate record. We can then use this to stash the * mostly set up a candidate record. We can then use this to stash the
......
...@@ -765,6 +765,8 @@ static void afs_vnode_new_inode(struct afs_fs_cursor *fc, ...@@ -765,6 +765,8 @@ static void afs_vnode_new_inode(struct afs_fs_cursor *fc,
if (fc->ac.error < 0) if (fc->ac.error < 0)
return; return;
d_drop(new_dentry);
inode = afs_iget(fc->vnode->vfs_inode.i_sb, fc->key, inode = afs_iget(fc->vnode->vfs_inode.i_sb, fc->key,
newfid, newstatus, newcb, fc->cbi); newfid, newstatus, newcb, fc->cbi);
if (IS_ERR(inode)) { if (IS_ERR(inode)) {
...@@ -775,9 +777,7 @@ static void afs_vnode_new_inode(struct afs_fs_cursor *fc, ...@@ -775,9 +777,7 @@ static void afs_vnode_new_inode(struct afs_fs_cursor *fc,
return; return;
} }
d_instantiate(new_dentry, inode); d_add(new_dentry, inode);
if (d_unhashed(new_dentry))
d_rehash(new_dentry);
} }
/* /*
...@@ -818,6 +818,8 @@ static int afs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) ...@@ -818,6 +818,8 @@ static int afs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
ret = afs_end_vnode_operation(&fc); ret = afs_end_vnode_operation(&fc);
if (ret < 0) if (ret < 0)
goto error_key; goto error_key;
} else {
goto error_key;
} }
key_put(key); key_put(key);
...@@ -972,7 +974,7 @@ static int afs_create(struct inode *dir, struct dentry *dentry, umode_t mode, ...@@ -972,7 +974,7 @@ static int afs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
struct afs_fs_cursor fc; struct afs_fs_cursor fc;
struct afs_file_status newstatus; struct afs_file_status newstatus;
struct afs_callback newcb; struct afs_callback newcb;
struct afs_vnode *dvnode = dvnode = AFS_FS_I(dir); struct afs_vnode *dvnode = AFS_FS_I(dir);
struct afs_fid newfid; struct afs_fid newfid;
struct key *key; struct key *key;
int ret; int ret;
...@@ -1006,6 +1008,8 @@ static int afs_create(struct inode *dir, struct dentry *dentry, umode_t mode, ...@@ -1006,6 +1008,8 @@ static int afs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
ret = afs_end_vnode_operation(&fc); ret = afs_end_vnode_operation(&fc);
if (ret < 0) if (ret < 0)
goto error_key; goto error_key;
} else {
goto error_key;
} }
key_put(key); key_put(key);
...@@ -1053,7 +1057,7 @@ static int afs_link(struct dentry *from, struct inode *dir, ...@@ -1053,7 +1057,7 @@ static int afs_link(struct dentry *from, struct inode *dir,
if (afs_begin_vnode_operation(&fc, dvnode, key)) { if (afs_begin_vnode_operation(&fc, dvnode, key)) {
if (mutex_lock_interruptible_nested(&vnode->io_lock, 1) < 0) { if (mutex_lock_interruptible_nested(&vnode->io_lock, 1) < 0) {
afs_end_vnode_operation(&fc); afs_end_vnode_operation(&fc);
return -ERESTARTSYS; goto error_key;
} }
while (afs_select_fileserver(&fc)) { while (afs_select_fileserver(&fc)) {
...@@ -1071,6 +1075,8 @@ static int afs_link(struct dentry *from, struct inode *dir, ...@@ -1071,6 +1075,8 @@ static int afs_link(struct dentry *from, struct inode *dir,
ret = afs_end_vnode_operation(&fc); ret = afs_end_vnode_operation(&fc);
if (ret < 0) if (ret < 0)
goto error_key; goto error_key;
} else {
goto error_key;
} }
key_put(key); key_put(key);
...@@ -1130,6 +1136,8 @@ static int afs_symlink(struct inode *dir, struct dentry *dentry, ...@@ -1130,6 +1136,8 @@ static int afs_symlink(struct inode *dir, struct dentry *dentry,
ret = afs_end_vnode_operation(&fc); ret = afs_end_vnode_operation(&fc);
if (ret < 0) if (ret < 0)
goto error_key; goto error_key;
} else {
goto error_key;
} }
key_put(key); key_put(key);
...@@ -1180,7 +1188,7 @@ static int afs_rename(struct inode *old_dir, struct dentry *old_dentry, ...@@ -1180,7 +1188,7 @@ static int afs_rename(struct inode *old_dir, struct dentry *old_dentry,
if (orig_dvnode != new_dvnode) { if (orig_dvnode != new_dvnode) {
if (mutex_lock_interruptible_nested(&new_dvnode->io_lock, 1) < 0) { if (mutex_lock_interruptible_nested(&new_dvnode->io_lock, 1) < 0) {
afs_end_vnode_operation(&fc); afs_end_vnode_operation(&fc);
return -ERESTARTSYS; goto error_key;
} }
} }
while (afs_select_fileserver(&fc)) { while (afs_select_fileserver(&fc)) {
...@@ -1199,14 +1207,9 @@ static int afs_rename(struct inode *old_dir, struct dentry *old_dentry, ...@@ -1199,14 +1207,9 @@ static int afs_rename(struct inode *old_dir, struct dentry *old_dentry,
goto error_key; goto error_key;
} }
key_put(key);
_leave(" = 0");
return 0;
error_key: error_key:
key_put(key); key_put(key);
error: error:
d_drop(new_dentry);
_leave(" = %d", ret); _leave(" = %d", ret);
return ret; return ret;
} }
This diff is collapsed.
...@@ -430,6 +430,16 @@ struct afs_volume { ...@@ -430,6 +430,16 @@ struct afs_volume {
u8 name[AFS_MAXVOLNAME + 1]; /* NUL-padded volume name */ u8 name[AFS_MAXVOLNAME + 1]; /* NUL-padded volume name */
}; };
enum afs_lock_state {
AFS_VNODE_LOCK_NONE, /* The vnode has no lock on the server */
AFS_VNODE_LOCK_WAITING_FOR_CB, /* We're waiting for the server to break the callback */
AFS_VNODE_LOCK_SETTING, /* We're asking the server for a lock */
AFS_VNODE_LOCK_GRANTED, /* We have a lock on the server */
AFS_VNODE_LOCK_EXTENDING, /* We're extending a lock on the server */
AFS_VNODE_LOCK_NEED_UNLOCK, /* We need to unlock on the server */
AFS_VNODE_LOCK_UNLOCKING, /* We're telling the server to unlock */
};
/* /*
* AFS inode private data * AFS inode private data
*/ */
...@@ -454,18 +464,16 @@ struct afs_vnode { ...@@ -454,18 +464,16 @@ struct afs_vnode {
#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_LOCKING 6 /* set if waiting for lock on vnode */ #define AFS_VNODE_AUTOCELL 6 /* set if Vnode is an auto mount point */
#define AFS_VNODE_READLOCKED 7 /* set if vnode is read-locked on the server */ #define AFS_VNODE_PSEUDODIR 7 /* set if Vnode is a pseudo directory */
#define AFS_VNODE_WRITELOCKED 8 /* set if vnode is write-locked on the server */
#define AFS_VNODE_UNLOCKING 9 /* set if vnode is being unlocked on the server */
#define AFS_VNODE_AUTOCELL 10 /* set if Vnode is an auto mount point */
#define AFS_VNODE_PSEUDODIR 11 /* set if Vnode is a pseudo directory */
struct list_head wb_keys; /* List of keys available for writeback */ struct list_head wb_keys; /* List of keys available for writeback */
struct list_head pending_locks; /* locks waiting to be granted */ struct list_head pending_locks; /* locks waiting to be granted */
struct list_head granted_locks; /* locks granted on this file */ struct list_head granted_locks; /* locks granted on this file */
struct delayed_work lock_work; /* work to be done in locking */ struct delayed_work lock_work; /* work to be done in locking */
struct key *unlock_key; /* key to be used in unlocking */ struct key *lock_key; /* Key to be used in lock ops */
enum afs_lock_state lock_state : 8;
afs_lock_type_t lock_type : 8;
/* outstanding callback notification on this file */ /* outstanding callback notification on this file */
struct afs_cb_interest *cb_interest; /* Server on which this resides */ struct afs_cb_interest *cb_interest; /* Server on which this resides */
...@@ -843,6 +851,7 @@ extern void afs_clear_permits(struct afs_vnode *); ...@@ -843,6 +851,7 @@ extern void afs_clear_permits(struct afs_vnode *);
extern void afs_cache_permit(struct afs_vnode *, struct key *, unsigned int); extern void afs_cache_permit(struct afs_vnode *, struct key *, unsigned int);
extern void afs_zap_permits(struct rcu_head *); extern void afs_zap_permits(struct rcu_head *);
extern struct key *afs_request_key(struct afs_cell *); extern struct key *afs_request_key(struct afs_cell *);
extern int afs_check_permit(struct afs_vnode *, struct key *, afs_access_t *);
extern int afs_permission(struct inode *, int); extern int afs_permission(struct inode *, int);
extern void __exit afs_clean_up_permit_cache(void); extern void __exit afs_clean_up_permit_cache(void);
......
...@@ -46,8 +46,7 @@ bool afs_begin_vnode_operation(struct afs_fs_cursor *fc, struct afs_vnode *vnode ...@@ -46,8 +46,7 @@ bool afs_begin_vnode_operation(struct afs_fs_cursor *fc, struct afs_vnode *vnode
return false; return false;
} }
if (test_bit(AFS_VNODE_READLOCKED, &vnode->flags) || if (vnode->lock_state != AFS_VNODE_LOCK_NONE)
test_bit(AFS_VNODE_WRITELOCKED, &vnode->flags))
fc->flags |= AFS_FS_CURSOR_CUR_ONLY; fc->flags |= AFS_FS_CURSOR_CUR_ONLY;
return true; return true;
} }
...@@ -438,14 +437,20 @@ bool afs_select_current_fileserver(struct afs_fs_cursor *fc) ...@@ -438,14 +437,20 @@ bool afs_select_current_fileserver(struct afs_fs_cursor *fc)
_enter(""); _enter("");
switch (fc->ac.error) {
case SHRT_MAX:
if (!cbi) { if (!cbi) {
fc->ac.error = -ESTALE; fc->ac.error = -ESTALE;
fc->flags |= AFS_FS_CURSOR_STOP; fc->flags |= AFS_FS_CURSOR_STOP;
return false; return false;
} }
fc->cbi = afs_get_cb_interest(vnode->cb_interest);
read_lock(&cbi->server->fs_lock); read_lock(&cbi->server->fs_lock);
alist = afs_get_addrlist(cbi->server->addresses); alist = rcu_dereference_protected(cbi->server->addresses,
lockdep_is_held(&cbi->server->fs_lock));
afs_get_addrlist(alist);
read_unlock(&cbi->server->fs_lock); read_unlock(&cbi->server->fs_lock);
if (!alist) { if (!alist) {
fc->ac.error = -ESTALE; fc->ac.error = -ESTALE;
...@@ -454,8 +459,45 @@ bool afs_select_current_fileserver(struct afs_fs_cursor *fc) ...@@ -454,8 +459,45 @@ bool afs_select_current_fileserver(struct afs_fs_cursor *fc)
} }
fc->ac.alist = alist; fc->ac.alist = alist;
fc->ac.addr = NULL;
fc->ac.start = READ_ONCE(alist->index);
fc->ac.index = fc->ac.start;
fc->ac.error = 0; fc->ac.error = 0;
fc->ac.begun = false;
goto iterate_address;
case 0:
default:
/* Success or local failure. Stop. */
fc->flags |= AFS_FS_CURSOR_STOP;
_leave(" = f [okay/local %d]", fc->ac.error);
return false;
case -ECONNABORTED:
fc->flags |= AFS_FS_CURSOR_STOP;
_leave(" = f [abort]");
return false;
case -ENETUNREACH:
case -EHOSTUNREACH:
case -ECONNREFUSED:
case -ETIMEDOUT:
case -ETIME:
_debug("no conn");
goto iterate_address;
}
iterate_address:
/* Iterate over the current server's address list to try and find an
* address on which it will respond to us.
*/
if (afs_iterate_addresses(&fc->ac)) {
_leave(" = t");
return true; return true;
}
afs_end_cursor(&fc->ac);
return false;
} }
/* /*
......
...@@ -284,7 +284,7 @@ void afs_cache_permit(struct afs_vnode *vnode, struct key *key, ...@@ -284,7 +284,7 @@ void afs_cache_permit(struct afs_vnode *vnode, struct key *key,
* permitted to be accessed with this authorisation, and if so, what access it * permitted to be accessed with this authorisation, and if so, what access it
* is granted * is granted
*/ */
static int afs_check_permit(struct afs_vnode *vnode, struct key *key, int afs_check_permit(struct afs_vnode *vnode, struct key *key,
afs_access_t *_access) afs_access_t *_access)
{ {
struct afs_permits *permits; struct afs_permits *permits;
......
...@@ -17,7 +17,7 @@ void afs_put_serverlist(struct afs_net *net, struct afs_server_list *slist) ...@@ -17,7 +17,7 @@ void afs_put_serverlist(struct afs_net *net, struct afs_server_list *slist)
{ {
int i; int i;
if (refcount_dec_and_test(&slist->usage)) { if (slist && refcount_dec_and_test(&slist->usage)) {
for (i = 0; i < slist->nr_servers; i++) { for (i = 0; i < slist->nr_servers; i++) {
afs_put_cb_interest(net, slist->servers[i].cb_interest); afs_put_cb_interest(net, slist->servers[i].cb_interest);
afs_put_server(net, slist->servers[i].server); afs_put_server(net, slist->servers[i].server);
......
...@@ -119,6 +119,11 @@ int afs_write_begin(struct file *file, struct address_space *mapping, ...@@ -119,6 +119,11 @@ int afs_write_begin(struct file *file, struct address_space *mapping,
} }
if (f != t) { if (f != t) {
if (PageWriteback(page)) {
trace_afs_page_dirty(vnode, tracepoint_string("alrdy"),
page->index, priv);
goto flush_conflicting_write;
}
if (to < f || from > t) if (to < f || from > t)
goto flush_conflicting_write; goto flush_conflicting_write;
if (from < f) if (from < f)
......
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