Merge tag 'afs-next-20190507' of git://git.kernel.org/pub/scm/linux/kernel/git/dhowel...
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 8 May 2019 03:51:58 +0000 (20:51 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 8 May 2019 03:51:58 +0000 (20:51 -0700)
Pull AFS updates from David Howells:
 "A set of fix and development patches for AFS for 5.2.

  Summary:

   - Fix the AFS file locking so that sqlite can run on an AFS mount and
     also so that firefox and gnome can use a homedir that's mounted
     through AFS.

     This required emulation of fine-grained locking when the server
     will only support whole-file locks and no upgrade/downgrade. Four
     modes are provided, settable by mount parameter:

       "flock=local"   - No reference to the server

       "flock=openafs" - Fine-grained locks are local-only, whole-file
                         locks require sufficient server locks

       "flock=strict"  - All locks require sufficient server locks

       "flock=write"   - Always get an exclusive server lock

     If the volume is a read-only or backup volume, then flock=local for
     that volume.

   - Log extra information for a couple of cases where the client mucks
     up somehow: AFS vnode with undefined type and dir check failure -
     in both cases we seem to end up with unfilled data, but the issues
     happen infrequently and are difficult to reproduce at will.

   - Implement silly rename for unlink() and rename().

   - Set i_blocks so that du can get some information about usage.

   - Fix xattr handlers to return the right amount of data and to not
     overflow buffers.

   - Implement getting/setting raw AFS and YFS ACLs as xattrs"

* tag 'afs-next-20190507' of git://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-fs:
  afs: Implement YFS ACL setting
  afs: Get YFS ACLs and information through xattrs
  afs: implement acl setting
  afs: Get an AFS3 ACL as an xattr
  afs: Fix getting the afs.fid xattr
  afs: Fix the afs.cell and afs.volume xattr handlers
  afs: Calculate i_blocks based on file size
  afs: Log more information for "kAFS: AFS vnode with undefined type\n"
  afs: Provide mount-time configurable byte-range file locking emulation
  afs: Add more tracepoints
  afs: Implement sillyrename for unlink and rename
  afs: Add directory reload tracepoint
  afs: Handle lock rpc ops failing on a file that got deleted
  afs: Improve dir check failure reports
  afs: Add file locking tracepoints
  afs: Further fix file locking
  afs: Fix AFS file locking to allow fine grained locks
  afs: Calculate lock extend timer from set/extend reply reception
  afs: Split wait from afs_make_call()

1  2 
fs/afs/flock.c
fs/afs/fsclient.c
fs/afs/rxrpc.c
fs/afs/super.c
fs/afs/vlclient.c
fs/afs/yfsclient.c
include/linux/fs.h

diff --combined fs/afs/flock.c
index 6a0174258382a696e02bc716a9e8784d584a9f6b,ef313f4c1d114ff0ebc7cbb7408f3637473bf4be..adc88eff7849e2f6ba2b0542fb27935be8eec799
  
  #define AFS_LOCK_GRANTED      0
  #define AFS_LOCK_PENDING      1
+ #define AFS_LOCK_YOUR_TRY     2
  
  struct workqueue_struct *afs_lock_manager;
  
+ static void afs_next_locker(struct afs_vnode *vnode, int error);
  static void afs_fl_copy_lock(struct file_lock *new, struct file_lock *fl);
  static void afs_fl_release_private(struct file_lock *fl);
  
@@@ -24,6 -26,14 +26,14 @@@ static const struct file_lock_operation
        .fl_release_private     = afs_fl_release_private,
  };
  
+ static inline void afs_set_lock_state(struct afs_vnode *vnode, enum afs_lock_state state)
+ {
+       _debug("STATE %u -> %u", vnode->lock_state, state);
+       vnode->lock_state = state;
+ }
+ static atomic_t afs_file_lock_debug_id;
  /*
   * if the callback is broken on this vnode, then the lock may now be available
   */
@@@ -31,7 -41,14 +41,14 @@@ void afs_lock_may_be_available(struct a
  {
        _enter("{%llx:%llu}", vnode->fid.vid, vnode->fid.vnode);
  
-       queue_delayed_work(afs_lock_manager, &vnode->lock_work, 0);
+       if (vnode->lock_state != AFS_VNODE_LOCK_WAITING_FOR_CB)
+               return;
+       spin_lock(&vnode->lock);
+       if (vnode->lock_state == AFS_VNODE_LOCK_WAITING_FOR_CB)
+               afs_next_locker(vnode, 0);
+       trace_afs_flock_ev(vnode, NULL, afs_flock_callback_break, 0);
+       spin_unlock(&vnode->lock);
  }
  
  /*
   */
  static void afs_schedule_lock_extension(struct afs_vnode *vnode)
  {
-       queue_delayed_work(afs_lock_manager, &vnode->lock_work,
-                          AFS_LOCKWAIT * HZ / 2);
+       ktime_t expires_at, now, duration;
+       u64 duration_j;
+       expires_at = ktime_add_ms(vnode->locked_at, AFS_LOCKWAIT * 1000 / 2);
+       now = ktime_get_real();
+       duration = ktime_sub(expires_at, now);
+       if (duration <= 0)
+               duration_j = 0;
+       else
+               duration_j = nsecs_to_jiffies(ktime_to_ns(duration));
+       queue_delayed_work(afs_lock_manager, &vnode->lock_work, duration_j);
+ }
+ /*
+  * In the case of successful completion of a lock operation, record the time
+  * the reply appeared and start the lock extension timer.
+  */
+ void afs_lock_op_done(struct afs_call *call)
+ {
+       struct afs_vnode *vnode = call->reply[0];
+       if (call->error == 0) {
+               spin_lock(&vnode->lock);
+               trace_afs_flock_ev(vnode, NULL, afs_flock_timestamp, 0);
+               vnode->locked_at = call->reply_time;
+               afs_schedule_lock_extension(vnode);
+               spin_unlock(&vnode->lock);
+       }
  }
  
  /*
   * first lock in the queue is itself a readlock)
   * - the caller must hold the vnode lock
   */
- static void afs_grant_locks(struct afs_vnode *vnode, struct file_lock *fl)
+ static void afs_grant_locks(struct afs_vnode *vnode)
  {
        struct file_lock *p, *_p;
+       bool exclusive = (vnode->lock_type == AFS_LOCK_WRITE);
  
-       list_move_tail(&fl->fl_u.afs.link, &vnode->granted_locks);
-       if (fl->fl_type == F_RDLCK) {
-               list_for_each_entry_safe(p, _p, &vnode->pending_locks,
-                                        fl_u.afs.link) {
-                       if (p->fl_type == F_RDLCK) {
-                               p->fl_u.afs.state = AFS_LOCK_GRANTED;
-                               list_move_tail(&p->fl_u.afs.link,
-                                              &vnode->granted_locks);
-                               wake_up(&p->fl_wait);
-                       }
+       list_for_each_entry_safe(p, _p, &vnode->pending_locks, fl_u.afs.link) {
+               if (!exclusive && p->fl_type == F_WRLCK)
+                       continue;
+               list_move_tail(&p->fl_u.afs.link, &vnode->granted_locks);
+               p->fl_u.afs.state = AFS_LOCK_GRANTED;
+               trace_afs_flock_op(vnode, p, afs_flock_op_grant);
+               wake_up(&p->fl_wait);
+       }
+ }
+ /*
+  * If an error is specified, reject every pending lock that matches the
+  * authentication and type of the lock we failed to get.  If there are any
+  * remaining lockers, try to wake up one of them to have a go.
+  */
+ static void afs_next_locker(struct afs_vnode *vnode, int error)
+ {
+       struct file_lock *p, *_p, *next = NULL;
+       struct key *key = vnode->lock_key;
+       unsigned int fl_type = F_RDLCK;
+       _enter("");
+       if (vnode->lock_type == AFS_LOCK_WRITE)
+               fl_type = F_WRLCK;
+       list_for_each_entry_safe(p, _p, &vnode->pending_locks, fl_u.afs.link) {
+               if (error &&
+                   p->fl_type == fl_type &&
+                   afs_file_key(p->fl_file) == key) {
+                       list_del_init(&p->fl_u.afs.link);
+                       p->fl_u.afs.state = error;
+                       wake_up(&p->fl_wait);
                }
+               /* Select the next locker to hand off to. */
+               if (next &&
+                   (next->fl_type == F_WRLCK || p->fl_type == F_RDLCK))
+                       continue;
+               next = p;
        }
+       vnode->lock_key = NULL;
+       key_put(key);
+       if (next) {
+               afs_set_lock_state(vnode, AFS_VNODE_LOCK_SETTING);
+               next->fl_u.afs.state = AFS_LOCK_YOUR_TRY;
+               trace_afs_flock_op(vnode, next, afs_flock_op_wake);
+               wake_up(&next->fl_wait);
+       } else {
+               afs_set_lock_state(vnode, AFS_VNODE_LOCK_NONE);
+               trace_afs_flock_ev(vnode, NULL, afs_flock_no_lockers, 0);
+       }
+       _leave("");
+ }
+ /*
+  * Kill off all waiters in the the pending lock queue due to the vnode being
+  * deleted.
+  */
+ static void afs_kill_lockers_enoent(struct afs_vnode *vnode)
+ {
+       struct file_lock *p;
+       afs_set_lock_state(vnode, AFS_VNODE_LOCK_DELETED);
+       while (!list_empty(&vnode->pending_locks)) {
+               p = list_entry(vnode->pending_locks.next,
+                              struct file_lock, fl_u.afs.link);
+               list_del_init(&p->fl_u.afs.link);
+               p->fl_u.afs.state = -ENOENT;
+               wake_up(&p->fl_wait);
+       }
+       key_put(vnode->lock_key);
+       vnode->lock_key = NULL;
  }
  
  /*
@@@ -170,8 -282,6 +282,6 @@@ void afs_lock_work(struct work_struct *
  {
        struct afs_vnode *vnode =
                container_of(work, struct afs_vnode, lock_work.work);
-       struct file_lock *fl, *next;
-       afs_lock_type_t type;
        struct key *key;
        int ret;
  
@@@ -183,35 -293,28 +293,28 @@@ again
        _debug("wstate %u for %p", vnode->lock_state, vnode);
        switch (vnode->lock_state) {
        case AFS_VNODE_LOCK_NEED_UNLOCK:
-               _debug("unlock");
-               vnode->lock_state = AFS_VNODE_LOCK_UNLOCKING;
+               afs_set_lock_state(vnode, AFS_VNODE_LOCK_UNLOCKING);
+               trace_afs_flock_ev(vnode, NULL, afs_flock_work_unlocking, 0);
                spin_unlock(&vnode->lock);
  
                /* attempt to release the server lock; if it fails, we just
                 * wait 5 minutes and it'll expire anyway */
                ret = afs_release_lock(vnode, vnode->lock_key);
-               if (ret < 0)
+               if (ret < 0 && vnode->lock_state != AFS_VNODE_LOCK_DELETED) {
+                       trace_afs_flock_ev(vnode, NULL, afs_flock_release_fail,
+                                          ret);
                        printk(KERN_WARNING "AFS:"
                               " Failed to release lock on {%llx:%llx} error %d\n",
                               vnode->fid.vid, vnode->fid.vnode, ret);
-               spin_lock(&vnode->lock);
-               key_put(vnode->lock_key);
-               vnode->lock_key = NULL;
-               vnode->lock_state = AFS_VNODE_LOCK_NONE;
-               if (list_empty(&vnode->pending_locks)) {
-                       spin_unlock(&vnode->lock);
-                       return;
                }
  
-               /* The new front of the queue now owns the state variables. */
-               next = list_entry(vnode->pending_locks.next,
-                                 struct file_lock, fl_u.afs.link);
-               vnode->lock_key = key_get(afs_file_key(next->fl_file));
-               vnode->lock_type = (next->fl_type == F_RDLCK) ? AFS_LOCK_READ : AFS_LOCK_WRITE;
-               vnode->lock_state = AFS_VNODE_LOCK_WAITING_FOR_CB;
-               goto again;
+               spin_lock(&vnode->lock);
+               if (ret == -ENOENT)
+                       afs_kill_lockers_enoent(vnode);
+               else
+                       afs_next_locker(vnode, 0);
+               spin_unlock(&vnode->lock);
+               return;
  
        /* If we've already got a lock, then it must be time to extend that
         * lock as AFS locks time out after 5 minutes.
                ASSERT(!list_empty(&vnode->granted_locks));
  
                key = key_get(vnode->lock_key);
-               vnode->lock_state = AFS_VNODE_LOCK_EXTENDING;
+               afs_set_lock_state(vnode, AFS_VNODE_LOCK_EXTENDING);
+               trace_afs_flock_ev(vnode, NULL, afs_flock_work_extending, 0);
                spin_unlock(&vnode->lock);
  
                ret = afs_extend_lock(vnode, key); /* RPC */
                key_put(key);
  
-               if (ret < 0)
+               if (ret < 0) {
+                       trace_afs_flock_ev(vnode, NULL, afs_flock_extend_fail,
+                                          ret);
                        pr_warning("AFS: Failed to extend lock on {%llx:%llx} error %d\n",
                                   vnode->fid.vid, vnode->fid.vnode, ret);
+               }
  
                spin_lock(&vnode->lock);
  
+               if (ret == -ENOENT) {
+                       afs_kill_lockers_enoent(vnode);
+                       spin_unlock(&vnode->lock);
+                       return;
+               }
                if (vnode->lock_state != AFS_VNODE_LOCK_EXTENDING)
                        goto again;
-               vnode->lock_state = AFS_VNODE_LOCK_GRANTED;
+               afs_set_lock_state(vnode, AFS_VNODE_LOCK_GRANTED);
  
-               if (ret == 0)
-                       afs_schedule_lock_extension(vnode);
-               else
+               if (ret != 0)
                        queue_delayed_work(afs_lock_manager, &vnode->lock_work,
                                           HZ * 10);
                spin_unlock(&vnode->lock);
                _leave(" [ext]");
                return;
  
-               /* If we don't have a granted lock, then we must've been called
-                * back by the server, and so if might be possible to get a
-                * lock we're currently waiting for.
-                */
+       /* If we're waiting for a callback to indicate lock release, we can't
+        * actually rely on this, so need to recheck at regular intervals.  The
+        * problem is that the server might not notify us if the lock just
+        * expires (say because a client died) rather than being explicitly
+        * released.
+        */
        case AFS_VNODE_LOCK_WAITING_FOR_CB:
-               _debug("get");
-               key = key_get(vnode->lock_key);
-               type = vnode->lock_type;
-               vnode->lock_state = AFS_VNODE_LOCK_SETTING;
+               _debug("retry");
+               afs_next_locker(vnode, 0);
                spin_unlock(&vnode->lock);
+               return;
  
-               ret = afs_set_lock(vnode, key, type); /* RPC */
-               key_put(key);
-               spin_lock(&vnode->lock);
-               switch (ret) {
-               case -EWOULDBLOCK:
-                       _debug("blocked");
-                       break;
-               case 0:
-                       _debug("acquired");
-                       vnode->lock_state = AFS_VNODE_LOCK_GRANTED;
-                       /* Fall through */
-               default:
-                       /* Pass the lock or the error onto the first locker in
-                        * the list - if they're looking for this type of lock.
-                        * If they're not, we assume that whoever asked for it
-                        * took a signal.
-                        */
-                       if (list_empty(&vnode->pending_locks)) {
-                               _debug("withdrawn");
-                               vnode->lock_state = AFS_VNODE_LOCK_NEED_UNLOCK;
-                               goto again;
-                       }
-                       fl = list_entry(vnode->pending_locks.next,
-                                       struct file_lock, fl_u.afs.link);
-                       type = (fl->fl_type == F_RDLCK) ? AFS_LOCK_READ : AFS_LOCK_WRITE;
-                       if (vnode->lock_type != type) {
-                               _debug("changed");
-                               vnode->lock_state = AFS_VNODE_LOCK_NEED_UNLOCK;
-                               goto again;
-                       }
-                       fl->fl_u.afs.state = ret;
-                       if (ret == 0)
-                               afs_grant_locks(vnode, fl);
-                       else
-                               list_del_init(&fl->fl_u.afs.link);
-                       wake_up(&fl->fl_wait);
-                       spin_unlock(&vnode->lock);
-                       _leave(" [granted]");
-                       return;
-               }
+       case AFS_VNODE_LOCK_DELETED:
+               afs_kill_lockers_enoent(vnode);
+               spin_unlock(&vnode->lock);
+               return;
  
 +              /* Fall through */
        default:
                /* Looks like a lock request was withdrawn. */
                spin_unlock(&vnode->lock);
   */
  static void afs_defer_unlock(struct afs_vnode *vnode)
  {
-       _enter("");
+       _enter("%u", vnode->lock_state);
  
-       if (vnode->lock_state == AFS_VNODE_LOCK_GRANTED ||
-           vnode->lock_state == AFS_VNODE_LOCK_EXTENDING) {
+       if (list_empty(&vnode->granted_locks) &&
+           (vnode->lock_state == AFS_VNODE_LOCK_GRANTED ||
+            vnode->lock_state == AFS_VNODE_LOCK_EXTENDING)) {
                cancel_delayed_work(&vnode->lock_work);
  
-               vnode->lock_state = AFS_VNODE_LOCK_NEED_UNLOCK;
-               afs_lock_may_be_available(vnode);
+               afs_set_lock_state(vnode, AFS_VNODE_LOCK_NEED_UNLOCK);
+               trace_afs_flock_ev(vnode, NULL, afs_flock_defer_unlock, 0);
+               queue_delayed_work(afs_lock_manager, &vnode->lock_work, 0);
        }
  }
  
   * whether we think that we have a locking permit.
   */
  static int afs_do_setlk_check(struct afs_vnode *vnode, struct key *key,
-                             afs_lock_type_t type, bool can_sleep)
+                             enum afs_flock_mode mode, afs_lock_type_t type)
  {
        afs_access_t access;
        int ret;
        if (type == AFS_LOCK_READ) {
                if (!(access & (AFS_ACE_INSERT | AFS_ACE_WRITE | AFS_ACE_LOCK)))
                        return -EACCES;
-               if (vnode->status.lock_count == -1 && !can_sleep)
-                       return -EAGAIN; /* Write locked */
        } else {
                if (!(access & (AFS_ACE_INSERT | AFS_ACE_WRITE)))
                        return -EACCES;
-               if (vnode->status.lock_count != 0 && !can_sleep)
-                       return -EAGAIN; /* Locked */
        }
  
        return 0;
  }
  
- /*
-  * Remove the front runner from the pending queue.
-  * - The caller must hold vnode->lock.
-  */
- static void afs_dequeue_lock(struct afs_vnode *vnode, struct file_lock *fl)
- {
-       struct file_lock *next;
-       _enter("");
-       /* ->lock_type, ->lock_key and ->lock_state only belong to this
-        * file_lock if we're at the front of the pending queue or if we have
-        * the lock granted or if the lock_state is NEED_UNLOCK or UNLOCKING.
-        */
-       if (vnode->granted_locks.next == &fl->fl_u.afs.link &&
-           vnode->granted_locks.prev == &fl->fl_u.afs.link) {
-               list_del_init(&fl->fl_u.afs.link);
-               afs_defer_unlock(vnode);
-               return;
-       }
-       if (!list_empty(&vnode->granted_locks) ||
-           vnode->pending_locks.next != &fl->fl_u.afs.link) {
-               list_del_init(&fl->fl_u.afs.link);
-               return;
-       }
-       list_del_init(&fl->fl_u.afs.link);
-       key_put(vnode->lock_key);
-       vnode->lock_key = NULL;
-       vnode->lock_state = AFS_VNODE_LOCK_NONE;
-       if (list_empty(&vnode->pending_locks))
-               return;
-       /* The new front of the queue now owns the state variables. */
-       next = list_entry(vnode->pending_locks.next,
-                         struct file_lock, fl_u.afs.link);
-       vnode->lock_key = key_get(afs_file_key(next->fl_file));
-       vnode->lock_type = (next->fl_type == F_RDLCK) ? AFS_LOCK_READ : AFS_LOCK_WRITE;
-       vnode->lock_state = AFS_VNODE_LOCK_WAITING_FOR_CB;
-       afs_lock_may_be_available(vnode);
- }
  /*
   * request a lock on a file on the server
   */
@@@ -427,97 -452,162 +453,162 @@@ static int afs_do_setlk(struct file *fi
  {
        struct inode *inode = locks_inode(file);
        struct afs_vnode *vnode = AFS_FS_I(inode);
+       enum afs_flock_mode mode = AFS_FS_S(inode->i_sb)->flock_mode;
        afs_lock_type_t type;
        struct key *key = afs_file_key(file);
+       bool partial, no_server_lock = false;
        int ret;
  
-       _enter("{%llx:%llu},%u", vnode->fid.vid, vnode->fid.vnode, fl->fl_type);
+       if (mode == afs_flock_mode_unset)
+               mode = afs_flock_mode_openafs;
  
-       /* only whole-file locks are supported */
-       if (fl->fl_start != 0 || fl->fl_end != OFFSET_MAX)
-               return -EINVAL;
+       _enter("{%llx:%llu},%llu-%llu,%u,%u",
+              vnode->fid.vid, vnode->fid.vnode,
+              fl->fl_start, fl->fl_end, fl->fl_type, mode);
  
        fl->fl_ops = &afs_lock_ops;
        INIT_LIST_HEAD(&fl->fl_u.afs.link);
        fl->fl_u.afs.state = AFS_LOCK_PENDING;
  
+       partial = (fl->fl_start != 0 || fl->fl_end != OFFSET_MAX);
        type = (fl->fl_type == F_RDLCK) ? AFS_LOCK_READ : AFS_LOCK_WRITE;
+       if (mode == afs_flock_mode_write && partial)
+               type = AFS_LOCK_WRITE;
  
-       ret = afs_do_setlk_check(vnode, key, type, fl->fl_flags & FL_SLEEP);
+       ret = afs_do_setlk_check(vnode, key, mode, type);
        if (ret < 0)
                return ret;
  
-       spin_lock(&vnode->lock);
+       trace_afs_flock_op(vnode, fl, afs_flock_op_set_lock);
  
-       /* If we've already got a readlock on the server then we instantly
-        * grant another readlock, irrespective of whether there are any
-        * pending writelocks.
+       /* AFS3 protocol only supports full-file locks and doesn't provide any
+        * method of upgrade/downgrade, so we need to emulate for partial-file
+        * locks.
+        *
+        * The OpenAFS client only gets a server lock for a full-file lock and
+        * keeps partial-file locks local.  Allow this behaviour to be emulated
+        * (as the default).
         */
-       if (type == AFS_LOCK_READ &&
-           vnode->lock_state == AFS_VNODE_LOCK_GRANTED &&
-           vnode->lock_type == AFS_LOCK_READ) {
-               _debug("instant readlock");
-               ASSERT(!list_empty(&vnode->granted_locks));
-               goto share_existing_lock;
+       if (mode == afs_flock_mode_local ||
+           (partial && mode == afs_flock_mode_openafs)) {
+               no_server_lock = true;
+               goto skip_server_lock;
        }
  
+       spin_lock(&vnode->lock);
        list_add_tail(&fl->fl_u.afs.link, &vnode->pending_locks);
  
+       ret = -ENOENT;
+       if (vnode->lock_state == AFS_VNODE_LOCK_DELETED)
+               goto error_unlock;
+       /* If we've already got a lock on the server then try to move to having
+        * the VFS grant the requested lock.  Note that this means that other
+        * clients may get starved out.
+        */
+       _debug("try %u", vnode->lock_state);
+       if (vnode->lock_state == AFS_VNODE_LOCK_GRANTED) {
+               if (type == AFS_LOCK_READ) {
+                       _debug("instant readlock");
+                       list_move_tail(&fl->fl_u.afs.link, &vnode->granted_locks);
+                       fl->fl_u.afs.state = AFS_LOCK_GRANTED;
+                       goto vnode_is_locked_u;
+               }
+               if (vnode->lock_type == AFS_LOCK_WRITE) {
+                       _debug("instant writelock");
+                       list_move_tail(&fl->fl_u.afs.link, &vnode->granted_locks);
+                       fl->fl_u.afs.state = AFS_LOCK_GRANTED;
+                       goto vnode_is_locked_u;
+               }
+       }
+       if (vnode->lock_state == AFS_VNODE_LOCK_NONE &&
+           !(fl->fl_flags & FL_SLEEP)) {
+               ret = -EAGAIN;
+               if (type == AFS_LOCK_READ) {
+                       if (vnode->status.lock_count == -1)
+                               goto lock_is_contended; /* Write locked */
+               } else {
+                       if (vnode->status.lock_count != 0)
+                               goto lock_is_contended; /* Locked */
+               }
+       }
        if (vnode->lock_state != AFS_VNODE_LOCK_NONE)
                goto need_to_wait;
  
+ try_to_lock:
        /* We don't have a lock on this vnode and we aren't currently waiting
         * for one either, so ask the server for a lock.
         *
         * Note that we need to be careful if we get interrupted by a signal
         * after dispatching the request as we may still get the lock, even
         * though we don't wait for the reply (it's not too bad a problem - the
-        * lock will expire in 10 mins anyway).
+        * lock will expire in 5 mins anyway).
         */
-       _debug("not locked");
+       trace_afs_flock_ev(vnode, fl, afs_flock_try_to_lock, 0);
        vnode->lock_key = key_get(key);
        vnode->lock_type = type;
-       vnode->lock_state = AFS_VNODE_LOCK_SETTING;
+       afs_set_lock_state(vnode, AFS_VNODE_LOCK_SETTING);
        spin_unlock(&vnode->lock);
  
        ret = afs_set_lock(vnode, key, type); /* RPC */
  
        spin_lock(&vnode->lock);
        switch (ret) {
+       case -EKEYREJECTED:
+       case -EKEYEXPIRED:
+       case -EKEYREVOKED:
+       case -EPERM:
+       case -EACCES:
+               fl->fl_u.afs.state = ret;
+               trace_afs_flock_ev(vnode, fl, afs_flock_fail_perm, ret);
+               list_del_init(&fl->fl_u.afs.link);
+               afs_next_locker(vnode, ret);
+               goto error_unlock;
+       case -ENOENT:
+               fl->fl_u.afs.state = ret;
+               trace_afs_flock_ev(vnode, fl, afs_flock_fail_other, ret);
+               list_del_init(&fl->fl_u.afs.link);
+               afs_kill_lockers_enoent(vnode);
+               goto error_unlock;
        default:
-               goto abort_attempt;
+               fl->fl_u.afs.state = ret;
+               trace_afs_flock_ev(vnode, fl, afs_flock_fail_other, ret);
+               list_del_init(&fl->fl_u.afs.link);
+               afs_next_locker(vnode, 0);
+               goto error_unlock;
  
        case -EWOULDBLOCK:
                /* The server doesn't have a lock-waiting queue, so the client
                 * will have to retry.  The server will break the outstanding
                 * callbacks on a file when a lock is released.
                 */
-               _debug("would block");
                ASSERT(list_empty(&vnode->granted_locks));
                ASSERTCMP(vnode->pending_locks.next, ==, &fl->fl_u.afs.link);
-               vnode->lock_state = AFS_VNODE_LOCK_WAITING_FOR_CB;
-               goto need_to_wait;
+               goto lock_is_contended;
  
        case 0:
-               _debug("acquired");
-               break;
+               afs_set_lock_state(vnode, AFS_VNODE_LOCK_GRANTED);
+               trace_afs_flock_ev(vnode, fl, afs_flock_acquired, type);
+               afs_grant_locks(vnode);
+               goto vnode_is_locked_u;
        }
  
-       /* we've acquired a server lock, but it needs to be renewed after 5
-        * mins */
-       vnode->lock_state = AFS_VNODE_LOCK_GRANTED;
-       afs_schedule_lock_extension(vnode);
- share_existing_lock:
-       /* the lock has been granted as far as we're concerned... */
-       fl->fl_u.afs.state = AFS_LOCK_GRANTED;
-       list_move_tail(&fl->fl_u.afs.link, &vnode->granted_locks);
- given_lock:
-       /* ... but we do still need to get the VFS's blessing */
+ vnode_is_locked_u:
        spin_unlock(&vnode->lock);
-       ret = posix_lock_file(file, fl, NULL);
+ vnode_is_locked:
+       /* the lock has been granted by the server... */
+       ASSERTCMP(fl->fl_u.afs.state, ==, AFS_LOCK_GRANTED);
+ skip_server_lock:
+       /* ... but the VFS still needs to distribute access on this client. */
+       trace_afs_flock_ev(vnode, fl, afs_flock_vfs_locking, 0);
+       ret = locks_lock_file_wait(file, fl);
+       trace_afs_flock_ev(vnode, fl, afs_flock_vfs_lock, ret);
        if (ret < 0)
                goto vfs_rejected_lock;
  
        _leave(" = 0");
        return 0;
  
+ lock_is_contended:
+       if (!(fl->fl_flags & FL_SLEEP)) {
+               list_del_init(&fl->fl_u.afs.link);
+               afs_next_locker(vnode, 0);
+               ret = -EAGAIN;
+               goto error_unlock;
+       }
+       afs_set_lock_state(vnode, AFS_VNODE_LOCK_WAITING_FOR_CB);
+       trace_afs_flock_ev(vnode, fl, afs_flock_would_block, ret);
+       queue_delayed_work(afs_lock_manager, &vnode->lock_work, HZ * 5);
  need_to_wait:
        /* We're going to have to wait.  Either this client doesn't have a lock
         * on the server yet and we need to wait for a callback to occur, or
-        * the client does have a lock on the server, but it belongs to some
-        * other process(es) and is incompatible with the lock we want.
+        * the client does have a lock on the server, but it's shared and we
+        * need an exclusive lock.
         */
-       ret = -EAGAIN;
-       if (fl->fl_flags & FL_SLEEP) {
-               spin_unlock(&vnode->lock);
+       spin_unlock(&vnode->lock);
  
-               _debug("sleep");
-               ret = wait_event_interruptible(fl->fl_wait,
-                                              fl->fl_u.afs.state != AFS_LOCK_PENDING);
+       trace_afs_flock_ev(vnode, fl, afs_flock_waiting, 0);
+       ret = wait_event_interruptible(fl->fl_wait,
+                                      fl->fl_u.afs.state != AFS_LOCK_PENDING);
+       trace_afs_flock_ev(vnode, fl, afs_flock_waited, ret);
  
+       if (fl->fl_u.afs.state >= 0 && fl->fl_u.afs.state != AFS_LOCK_GRANTED) {
                spin_lock(&vnode->lock);
-       }
  
-       if (fl->fl_u.afs.state == AFS_LOCK_GRANTED)
-               goto given_lock;
-       if (fl->fl_u.afs.state < 0)
-               ret = fl->fl_u.afs.state;
+               switch (fl->fl_u.afs.state) {
+               case AFS_LOCK_YOUR_TRY:
+                       fl->fl_u.afs.state = AFS_LOCK_PENDING;
+                       goto try_to_lock;
+               case AFS_LOCK_PENDING:
+                       if (ret > 0) {
+                               /* We need to retry the lock.  We may not be
+                                * notified by the server if it just expired
+                                * rather than being released.
+                                */
+                               ASSERTCMP(vnode->lock_state, ==, AFS_VNODE_LOCK_WAITING_FOR_CB);
+                               afs_set_lock_state(vnode, AFS_VNODE_LOCK_SETTING);
+                               fl->fl_u.afs.state = AFS_LOCK_PENDING;
+                               goto try_to_lock;
+                       }
+                       goto error_unlock;
+               case AFS_LOCK_GRANTED:
+               default:
+                       break;
+               }
  
- abort_attempt:
-       /* we aren't going to get the lock, either because we're unwilling to
-        * wait, or because some signal happened */
-       _debug("abort");
-       afs_dequeue_lock(vnode, fl);
+               spin_unlock(&vnode->lock);
+       }
  
- error_unlock:
-       spin_unlock(&vnode->lock);
-       _leave(" = %d", ret);
-       return ret;
+       if (fl->fl_u.afs.state == AFS_LOCK_GRANTED)
+               goto vnode_is_locked;
+       ret = fl->fl_u.afs.state;
+       goto error;
  
  vfs_rejected_lock:
        /* The VFS rejected the lock we just obtained, so we have to discard
         * deal with.
         */
        _debug("vfs refused %d", ret);
+       if (no_server_lock)
+               goto error;
        spin_lock(&vnode->lock);
        list_del_init(&fl->fl_u.afs.link);
-       if (list_empty(&vnode->granted_locks))
-               afs_defer_unlock(vnode);
-       goto error_unlock;
+       afs_defer_unlock(vnode);
+ error_unlock:
+       spin_unlock(&vnode->lock);
+ error:
+       _leave(" = %d", ret);
+       return ret;
  }
  
  /*
@@@ -585,14 -705,12 +706,12 @@@ static int afs_do_unlk(struct file *fil
  
        _enter("{%llx:%llu},%u", vnode->fid.vid, vnode->fid.vnode, fl->fl_type);
  
+       trace_afs_flock_op(vnode, fl, afs_flock_op_unlock);
        /* Flush all pending writes before doing anything with locks. */
        vfs_fsync(file, 0);
  
-       /* only whole-file unlocks are supported */
-       if (fl->fl_start != 0 || fl->fl_end != OFFSET_MAX)
-               return -EINVAL;
-       ret = posix_lock_file(file, fl, NULL);
+       ret = locks_lock_file_wait(file, fl);
        _leave(" = %d [%u]", ret, vnode->lock_state);
        return ret;
  }
@@@ -608,6 -726,9 +727,9 @@@ static int afs_do_getlk(struct file *fi
  
        _enter("");
  
+       if (vnode->lock_state == AFS_VNODE_LOCK_DELETED)
+               return -ENOENT;
        fl->fl_type = F_UNLCK;
  
        /* check local lock records first */
                        goto error;
  
                lock_count = READ_ONCE(vnode->status.lock_count);
-               if (lock_count > 0)
-                       fl->fl_type = F_RDLCK;
-               else
-                       fl->fl_type = F_WRLCK;
-               fl->fl_start = 0;
-               fl->fl_end = OFFSET_MAX;
+               if (lock_count != 0) {
+                       if (lock_count > 0)
+                               fl->fl_type = F_RDLCK;
+                       else
+                               fl->fl_type = F_WRLCK;
+                       fl->fl_start = 0;
+                       fl->fl_end = OFFSET_MAX;
+                       fl->fl_pid = 0;
+               }
        }
  
        ret = 0;
@@@ -639,6 -763,8 +764,8 @@@ error
  int afs_lock(struct file *file, int cmd, struct file_lock *fl)
  {
        struct afs_vnode *vnode = AFS_FS_I(locks_inode(file));
+       enum afs_flock_operation op;
+       int ret;
  
        _enter("{%llx:%llu},%d,{t=%x,fl=%x,r=%Ld:%Ld}",
               vnode->fid.vid, vnode->fid.vnode, cmd,
  
        if (IS_GETLK(cmd))
                return afs_do_getlk(file, fl);
+       fl->fl_u.afs.debug_id = atomic_inc_return(&afs_file_lock_debug_id);
+       trace_afs_flock_op(vnode, fl, afs_flock_op_lock);
        if (fl->fl_type == F_UNLCK)
-               return afs_do_unlk(file, fl);
-       return afs_do_setlk(file, fl);
+               ret = afs_do_unlk(file, fl);
+       else
+               ret = afs_do_setlk(file, fl);
+       switch (ret) {
+       case 0:         op = afs_flock_op_return_ok; break;
+       case -EAGAIN:   op = afs_flock_op_return_eagain; break;
+       case -EDEADLK:  op = afs_flock_op_return_edeadlk; break;
+       default:        op = afs_flock_op_return_error; break;
+       }
+       trace_afs_flock_op(vnode, fl, op);
+       return ret;
  }
  
  /*
  int afs_flock(struct file *file, int cmd, struct file_lock *fl)
  {
        struct afs_vnode *vnode = AFS_FS_I(locks_inode(file));
+       enum afs_flock_operation op;
+       int ret;
  
        _enter("{%llx:%llu},%d,{t=%x,fl=%x}",
               vnode->fid.vid, vnode->fid.vnode, cmd,
        if (!(fl->fl_flags & FL_FLOCK))
                return -ENOLCK;
  
+       fl->fl_u.afs.debug_id = atomic_inc_return(&afs_file_lock_debug_id);
+       trace_afs_flock_op(vnode, fl, afs_flock_op_flock);
        /* we're simulating flock() locks using posix locks on the server */
        if (fl->fl_type == F_UNLCK)
-               return afs_do_unlk(file, fl);
-       return afs_do_setlk(file, fl);
+               ret = afs_do_unlk(file, fl);
+       else
+               ret = afs_do_setlk(file, fl);
+       switch (ret) {
+       case 0:         op = afs_flock_op_return_ok; break;
+       case -EAGAIN:   op = afs_flock_op_return_eagain; break;
+       case -EDEADLK:  op = afs_flock_op_return_edeadlk; break;
+       default:        op = afs_flock_op_return_error; break;
+       }
+       trace_afs_flock_op(vnode, fl, op);
+       return ret;
  }
  
  /*
@@@ -695,7 -850,10 +851,10 @@@ static void afs_fl_copy_lock(struct fil
  
        _enter("");
  
+       new->fl_u.afs.debug_id = atomic_inc_return(&afs_file_lock_debug_id);
        spin_lock(&vnode->lock);
+       trace_afs_flock_op(vnode, new, afs_flock_op_copy_lock);
        list_add(&new->fl_u.afs.link, &fl->fl_u.afs.link);
        spin_unlock(&vnode->lock);
  }
@@@ -711,7 -869,12 +870,12 @@@ static void afs_fl_release_private(stru
        _enter("");
  
        spin_lock(&vnode->lock);
-       afs_dequeue_lock(vnode, fl);
+       trace_afs_flock_op(vnode, fl, afs_flock_op_release_lock);
+       list_del_init(&fl->fl_u.afs.link);
+       if (list_empty(&vnode->granted_locks))
+               afs_defer_unlock(vnode);
        _debug("state %u for %p", vnode->lock_state, vnode);
        spin_unlock(&vnode->lock);
  }
diff --combined fs/afs/fsclient.c
index b68471ce5c35e5a7f18c64da5fdc4304d1b487e1,7f1722b9e432b94ae8495b31e6cda2267bdcbe68..1296f5dc4c1e5f23e0019701646d35080dbbdf26
@@@ -468,7 -468,9 +468,9 @@@ int afs_fs_fetch_file_status(struct afs
        call->cb_break = fc->cb_break;
        afs_use_fs_server(call, fc->cbi);
        trace_afs_make_fs_call(call, &vnode->fid);
-       return afs_make_call(&fc->ac, call, GFP_NOFS, false);
+       afs_make_call(&fc->ac, call, GFP_NOFS);
+       return afs_wait_for_call_to_complete(call, &fc->ac);
  }
  
  /*
@@@ -498,7 -500,7 +500,7 @@@ static int afs_deliver_fs_fetch_data(st
                        afs_extract_to_tmp(call);
                }
  
 -              /* extract the returned data length */
 +              /* Fall through - and extract the returned data length */
        case 1:
                _debug("extract data length");
                ret = afs_extract_data(call, true);
                iov_iter_bvec(&call->iter, READ, call->bvec, 1, size);
                ASSERTCMP(size, <=, PAGE_SIZE);
  
 -              /* extract the returned data */
 +              /* Fall through - and extract the returned data */
        case 2:
                _debug("extract data %zu/%llu",
                       iov_iter_count(&call->iter), req->remain);
                /* Discard any excess data the server gave us */
                iov_iter_discard(&call->iter, READ, req->actual_len - req->len);
                call->unmarshall = 3;
 +
 +              /* Fall through */
        case 3:
                _debug("extract discard %zu/%llu",
                       iov_iter_count(&call->iter), req->actual_len - req->len);
                call->unmarshall = 4;
                afs_extract_to_buf(call, (21 + 3 + 6) * 4);
  
 -              /* extract the metadata */
 +              /* Fall through - and extract the metadata */
        case 4:
                ret = afs_extract_data(call, false);
                if (ret < 0)
@@@ -662,7 -662,8 +664,8 @@@ static int afs_fs_fetch_data64(struct a
        call->cb_break = fc->cb_break;
        afs_use_fs_server(call, fc->cbi);
        trace_afs_make_fs_call(call, &vnode->fid);
-       return afs_make_call(&fc->ac, call, GFP_NOFS, false);
+       afs_make_call(&fc->ac, call, GFP_NOFS);
+       return afs_wait_for_call_to_complete(call, &fc->ac);
  }
  
  /*
@@@ -709,7 -710,8 +712,8 @@@ int afs_fs_fetch_data(struct afs_fs_cur
        call->cb_break = fc->cb_break;
        afs_use_fs_server(call, fc->cbi);
        trace_afs_make_fs_call(call, &vnode->fid);
-       return afs_make_call(&fc->ac, call, GFP_NOFS, false);
+       afs_make_call(&fc->ac, call, GFP_NOFS);
+       return afs_wait_for_call_to_complete(call, &fc->ac);
  }
  
  /*
@@@ -828,14 -830,16 +832,16 @@@ int afs_fs_create(struct afs_fs_cursor 
        *bp++ = 0; /* segment size */
  
        afs_use_fs_server(call, fc->cbi);
-       trace_afs_make_fs_call(call, &vnode->fid);
-       return afs_make_call(&fc->ac, call, GFP_NOFS, false);
+       trace_afs_make_fs_call1(call, &vnode->fid, name);
+       afs_make_call(&fc->ac, call, GFP_NOFS);
+       return afs_wait_for_call_to_complete(call, &fc->ac);
  }
  
  /*
-  * deliver reply data to an FS.RemoveFile or FS.RemoveDir
+  * Deliver reply data to any operation that returns file status and volume
+  * sync.
   */
- static int afs_deliver_fs_remove(struct afs_call *call)
+ static int afs_deliver_fs_status_and_vol(struct afs_call *call)
  {
        struct afs_vnode *vnode = call->reply[0];
        const __be32 *bp;
  static const struct afs_call_type afs_RXFSRemoveFile = {
        .name           = "FS.RemoveFile",
        .op             = afs_FS_RemoveFile,
-       .deliver        = afs_deliver_fs_remove,
+       .deliver        = afs_deliver_fs_status_and_vol,
        .destructor     = afs_flat_call_destructor,
  };
  
  static const struct afs_call_type afs_RXFSRemoveDir = {
        .name           = "FS.RemoveDir",
        .op             = afs_FS_RemoveDir,
-       .deliver        = afs_deliver_fs_remove,
+       .deliver        = afs_deliver_fs_status_and_vol,
        .destructor     = afs_flat_call_destructor,
  };
  
@@@ -923,8 -927,9 +929,9 @@@ int afs_fs_remove(struct afs_fs_cursor 
        }
  
        afs_use_fs_server(call, fc->cbi);
-       trace_afs_make_fs_call(call, &dvnode->fid);
-       return afs_make_call(&fc->ac, call, GFP_NOFS, false);
+       trace_afs_make_fs_call1(call, &dvnode->fid, name);
+       afs_make_call(&fc->ac, call, GFP_NOFS);
+       return afs_wait_for_call_to_complete(call, &fc->ac);
  }
  
  /*
@@@ -1015,8 -1020,9 +1022,9 @@@ int afs_fs_link(struct afs_fs_cursor *f
        *bp++ = htonl(vnode->fid.unique);
  
        afs_use_fs_server(call, fc->cbi);
-       trace_afs_make_fs_call(call, &vnode->fid);
-       return afs_make_call(&fc->ac, call, GFP_NOFS, false);
+       trace_afs_make_fs_call1(call, &vnode->fid, name);
+       afs_make_call(&fc->ac, call, GFP_NOFS);
+       return afs_wait_for_call_to_complete(call, &fc->ac);
  }
  
  /*
@@@ -1129,8 -1135,9 +1137,9 @@@ int afs_fs_symlink(struct afs_fs_curso
        *bp++ = 0; /* segment size */
  
        afs_use_fs_server(call, fc->cbi);
-       trace_afs_make_fs_call(call, &vnode->fid);
-       return afs_make_call(&fc->ac, call, GFP_NOFS, false);
+       trace_afs_make_fs_call1(call, &vnode->fid, name);
+       afs_make_call(&fc->ac, call, GFP_NOFS);
+       return afs_wait_for_call_to_complete(call, &fc->ac);
  }
  
  /*
@@@ -1247,8 -1254,9 +1256,9 @@@ int afs_fs_rename(struct afs_fs_cursor 
        }
  
        afs_use_fs_server(call, fc->cbi);
-       trace_afs_make_fs_call(call, &orig_dvnode->fid);
-       return afs_make_call(&fc->ac, call, GFP_NOFS, false);
+       trace_afs_make_fs_call2(call, &orig_dvnode->fid, orig_name, new_name);
+       afs_make_call(&fc->ac, call, GFP_NOFS);
+       return afs_wait_for_call_to_complete(call, &fc->ac);
  }
  
  /*
@@@ -1352,7 -1360,8 +1362,8 @@@ static int afs_fs_store_data64(struct a
        *bp++ = htonl((u32) i_size);
  
        trace_afs_make_fs_call(call, &vnode->fid);
-       return afs_make_call(&fc->ac, call, GFP_NOFS, false);
+       afs_make_call(&fc->ac, call, GFP_NOFS);
+       return afs_wait_for_call_to_complete(call, &fc->ac);
  }
  
  /*
@@@ -1428,7 -1437,8 +1439,8 @@@ int afs_fs_store_data(struct afs_fs_cur
  
        afs_use_fs_server(call, fc->cbi);
        trace_afs_make_fs_call(call, &vnode->fid);
-       return afs_make_call(&fc->ac, call, GFP_NOFS, false);
+       afs_make_call(&fc->ac, call, GFP_NOFS);
+       return afs_wait_for_call_to_complete(call, &fc->ac);
  }
  
  /*
@@@ -1526,7 -1536,8 +1538,8 @@@ static int afs_fs_setattr_size64(struc
  
        afs_use_fs_server(call, fc->cbi);
        trace_afs_make_fs_call(call, &vnode->fid);
-       return afs_make_call(&fc->ac, call, GFP_NOFS, false);
+       afs_make_call(&fc->ac, call, GFP_NOFS);
+       return afs_wait_for_call_to_complete(call, &fc->ac);
  }
  
  /*
@@@ -1572,7 -1583,8 +1585,8 @@@ static int afs_fs_setattr_size(struct a
  
        afs_use_fs_server(call, fc->cbi);
        trace_afs_make_fs_call(call, &vnode->fid);
-       return afs_make_call(&fc->ac, call, GFP_NOFS, false);
+       afs_make_call(&fc->ac, call, GFP_NOFS);
+       return afs_wait_for_call_to_complete(call, &fc->ac);
  }
  
  /*
@@@ -1616,7 -1628,8 +1630,8 @@@ int afs_fs_setattr(struct afs_fs_curso
  
        afs_use_fs_server(call, fc->cbi);
        trace_afs_make_fs_call(call, &vnode->fid);
-       return afs_make_call(&fc->ac, call, GFP_NOFS, false);
+       afs_make_call(&fc->ac, call, GFP_NOFS);
+       return afs_wait_for_call_to_complete(call, &fc->ac);
  }
  
  /*
@@@ -1636,7 -1649,7 +1651,7 @@@ static int afs_deliver_fs_get_volume_st
                call->unmarshall++;
                afs_extract_to_buf(call, 12 * 4);
  
 -              /* extract the returned status record */
 +              /* Fall through - and extract the returned status record */
        case 1:
                _debug("extract status");
                ret = afs_extract_data(call, true);
                call->unmarshall++;
                afs_extract_to_tmp(call);
  
 -              /* extract the volume name length */
 +              /* Fall through - and extract the volume name length */
        case 2:
                ret = afs_extract_data(call, true);
                if (ret < 0)
                afs_extract_begin(call, call->reply[2], size);
                call->unmarshall++;
  
 -              /* extract the volume name */
 +              /* Fall through - and extract the volume name */
        case 3:
                _debug("extract volname");
                ret = afs_extract_data(call, true);
                afs_extract_to_tmp(call);
                call->unmarshall++;
  
 -              /* extract the offline message length */
 +              /* Fall through - and extract the offline message length */
        case 4:
                ret = afs_extract_data(call, true);
                if (ret < 0)
                afs_extract_begin(call, call->reply[2], size);
                call->unmarshall++;
  
 -              /* extract the offline message */
 +              /* Fall through - and extract the offline message */
        case 5:
                _debug("extract offline");
                ret = afs_extract_data(call, true);
                afs_extract_to_tmp(call);
                call->unmarshall++;
  
 -              /* extract the message of the day length */
 +              /* Fall through - and extract the message of the day length */
        case 6:
                ret = afs_extract_data(call, true);
                if (ret < 0)
                afs_extract_begin(call, call->reply[2], size);
                call->unmarshall++;
  
 -              /* extract the message of the day */
 +              /* Fall through - and extract the message of the day */
        case 7:
                _debug("extract motd");
                ret = afs_extract_data(call, false);
@@@ -1800,7 -1813,8 +1815,8 @@@ int afs_fs_get_volume_status(struct afs
  
        afs_use_fs_server(call, fc->cbi);
        trace_afs_make_fs_call(call, &vnode->fid);
-       return afs_make_call(&fc->ac, call, GFP_NOFS, false);
+       afs_make_call(&fc->ac, call, GFP_NOFS);
+       return afs_wait_for_call_to_complete(call, &fc->ac);
  }
  
  /*
@@@ -1832,6 -1846,7 +1848,7 @@@ static const struct afs_call_type afs_R
        .name           = "FS.SetLock",
        .op             = afs_FS_SetLock,
        .deliver        = afs_deliver_fs_xxxx_lock,
+       .done           = afs_lock_op_done,
        .destructor     = afs_flat_call_destructor,
  };
  
@@@ -1842,6 -1857,7 +1859,7 @@@ static const struct afs_call_type afs_R
        .name           = "FS.ExtendLock",
        .op             = afs_FS_ExtendLock,
        .deliver        = afs_deliver_fs_xxxx_lock,
+       .done           = afs_lock_op_done,
        .destructor     = afs_flat_call_destructor,
  };
  
@@@ -1876,6 -1892,7 +1894,7 @@@ int afs_fs_set_lock(struct afs_fs_curso
  
        call->key = fc->key;
        call->reply[0] = vnode;
+       call->want_reply_time = true;
  
        /* marshall the parameters */
        bp = call->request;
        *bp++ = htonl(type);
  
        afs_use_fs_server(call, fc->cbi);
-       trace_afs_make_fs_call(call, &vnode->fid);
-       return afs_make_call(&fc->ac, call, GFP_NOFS, false);
+       trace_afs_make_fs_calli(call, &vnode->fid, type);
+       afs_make_call(&fc->ac, call, GFP_NOFS);
+       return afs_wait_for_call_to_complete(call, &fc->ac);
  }
  
  /*
@@@ -1911,6 -1929,7 +1931,7 @@@ int afs_fs_extend_lock(struct afs_fs_cu
  
        call->key = fc->key;
        call->reply[0] = vnode;
+       call->want_reply_time = true;
  
        /* marshall the parameters */
        bp = call->request;
  
        afs_use_fs_server(call, fc->cbi);
        trace_afs_make_fs_call(call, &vnode->fid);
-       return afs_make_call(&fc->ac, call, GFP_NOFS, false);
+       afs_make_call(&fc->ac, call, GFP_NOFS);
+       return afs_wait_for_call_to_complete(call, &fc->ac);
  }
  
  /*
@@@ -1955,7 -1975,8 +1977,8 @@@ int afs_fs_release_lock(struct afs_fs_c
  
        afs_use_fs_server(call, fc->cbi);
        trace_afs_make_fs_call(call, &vnode->fid);
-       return afs_make_call(&fc->ac, call, GFP_NOFS, false);
+       afs_make_call(&fc->ac, call, GFP_NOFS);
+       return afs_wait_for_call_to_complete(call, &fc->ac);
  }
  
  /*
@@@ -2000,7 -2021,8 +2023,8 @@@ int afs_fs_give_up_all_callbacks(struc
        *bp++ = htonl(FSGIVEUPALLCALLBACKS);
  
        /* Can't take a ref on server */
-       return afs_make_call(ac, call, GFP_NOFS, false);
+       afs_make_call(ac, call, GFP_NOFS);
+       return afs_wait_for_call_to_complete(call, ac);
  }
  
  /*
@@@ -2018,7 -2040,7 +2042,7 @@@ static int afs_deliver_fs_get_capabilit
                afs_extract_to_tmp(call);
                call->unmarshall++;
  
 -              /* Extract the capabilities word count */
 +              /* Fall through - and extract the capabilities word count */
        case 1:
                ret = afs_extract_data(call, true);
                if (ret < 0)
                iov_iter_discard(&call->iter, READ, count * sizeof(__be32));
                call->unmarshall++;
  
 -              /* Extract capabilities words */
 +              /* Fall through - and extract capabilities words */
        case 2:
                ret = afs_extract_data(call, false);
                if (ret < 0)
@@@ -2070,12 -2092,11 +2094,11 @@@ static const struct afs_call_type afs_R
   * Probe a fileserver for the capabilities that it supports.  This can
   * return up to 196 words.
   */
- int afs_fs_get_capabilities(struct afs_net *net,
-                           struct afs_server *server,
-                           struct afs_addr_cursor *ac,
-                           struct key *key,
-                           unsigned int server_index,
-                           bool async)
+ struct afs_call *afs_fs_get_capabilities(struct afs_net *net,
+                                        struct afs_server *server,
+                                        struct afs_addr_cursor *ac,
+                                        struct key *key,
+                                        unsigned int server_index)
  {
        struct afs_call *call;
        __be32 *bp;
  
        call = afs_alloc_flat_call(net, &afs_RXFSGetCapabilities, 1 * 4, 16 * 4);
        if (!call)
-               return -ENOMEM;
+               return ERR_PTR(-ENOMEM);
  
        call->key = key;
        call->reply[0] = afs_get_server(server);
        call->reply[1] = (void *)(long)server_index;
        call->upgrade = true;
        call->want_reply_time = true;
+       call->async = true;
  
        /* marshall the parameters */
        bp = call->request;
  
        /* Can't take a ref on server */
        trace_afs_make_fs_call(call, NULL);
-       return afs_make_call(ac, call, GFP_NOFS, async);
+       afs_make_call(ac, call, GFP_NOFS);
+       return call;
  }
  
  /*
@@@ -2185,7 -2208,8 +2210,8 @@@ int afs_fs_fetch_status(struct afs_fs_c
        call->cb_break = fc->cb_break;
        afs_use_fs_server(call, fc->cbi);
        trace_afs_make_fs_call(call, fid);
-       return afs_make_call(&fc->ac, call, GFP_NOFS, false);
+       afs_make_call(&fc->ac, call, GFP_NOFS);
+       return afs_wait_for_call_to_complete(call, &fc->ac);
  }
  
  /*
@@@ -2208,7 -2232,6 +2234,7 @@@ static int afs_deliver_fs_inline_bulk_s
                call->unmarshall++;
  
                /* Extract the file status count and array in two steps */
 +              /* Fall through */
        case 1:
                _debug("extract status count");
                ret = afs_extract_data(call, true);
        more_counts:
                afs_extract_to_buf(call, 21 * sizeof(__be32));
  
 +              /* Fall through */
        case 2:
                _debug("extract status array %u", call->count);
                ret = afs_extract_data(call, true);
                afs_extract_to_tmp(call);
  
                /* Extract the callback count and array in two steps */
 +              /* Fall through */
        case 3:
                _debug("extract CB count");
                ret = afs_extract_data(call, true);
        more_cbs:
                afs_extract_to_buf(call, 3 * sizeof(__be32));
  
 +              /* Fall through */
        case 4:
                _debug("extract CB array");
                ret = afs_extract_data(call, true);
                afs_extract_to_buf(call, 6 * sizeof(__be32));
                call->unmarshall++;
  
 +              /* Fall through */
        case 5:
                ret = afs_extract_data(call, false);
                if (ret < 0)
@@@ -2370,5 -2389,180 +2396,180 @@@ int afs_fs_inline_bulk_status(struct af
        call->cb_break = fc->cb_break;
        afs_use_fs_server(call, fc->cbi);
        trace_afs_make_fs_call(call, &fids[0]);
-       return afs_make_call(&fc->ac, call, GFP_NOFS, false);
+       afs_make_call(&fc->ac, call, GFP_NOFS);
+       return afs_wait_for_call_to_complete(call, &fc->ac);
+ }
+ /*
+  * deliver reply data to an FS.FetchACL
+  */
+ static int afs_deliver_fs_fetch_acl(struct afs_call *call)
+ {
+       struct afs_vnode *vnode = call->reply[1];
+       struct afs_acl *acl;
+       const __be32 *bp;
+       unsigned int size;
+       int ret;
+       _enter("{%u}", call->unmarshall);
+       switch (call->unmarshall) {
+       case 0:
+               afs_extract_to_tmp(call);
+               call->unmarshall++;
+               /* extract the returned data length */
+       case 1:
+               ret = afs_extract_data(call, true);
+               if (ret < 0)
+                       return ret;
+               size = call->count2 = ntohl(call->tmp);
+               size = round_up(size, 4);
+               acl = kmalloc(struct_size(acl, data, size), GFP_KERNEL);
+               if (!acl)
+                       return -ENOMEM;
+               call->reply[0] = acl;
+               acl->size = call->count2;
+               afs_extract_begin(call, acl->data, size);
+               call->unmarshall++;
+               /* extract the returned data */
+       case 2:
+               ret = afs_extract_data(call, true);
+               if (ret < 0)
+                       return ret;
+               afs_extract_to_buf(call, (21 + 6) * 4);
+               call->unmarshall++;
+               /* extract the metadata */
+       case 3:
+               ret = afs_extract_data(call, false);
+               if (ret < 0)
+                       return ret;
+               bp = call->buffer;
+               ret = afs_decode_status(call, &bp, &vnode->status, vnode,
+                                       &vnode->status.data_version, NULL);
+               if (ret < 0)
+                       return ret;
+               xdr_decode_AFSVolSync(&bp, call->reply[2]);
+               call->unmarshall++;
+       case 4:
+               break;
+       }
+       _leave(" = 0 [done]");
+       return 0;
+ }
+ static void afs_destroy_fs_fetch_acl(struct afs_call *call)
+ {
+       kfree(call->reply[0]);
+       afs_flat_call_destructor(call);
+ }
+ /*
+  * FS.FetchACL operation type
+  */
+ static const struct afs_call_type afs_RXFSFetchACL = {
+       .name           = "FS.FetchACL",
+       .op             = afs_FS_FetchACL,
+       .deliver        = afs_deliver_fs_fetch_acl,
+       .destructor     = afs_destroy_fs_fetch_acl,
+ };
+ /*
+  * Fetch the ACL for a file.
+  */
+ struct afs_acl *afs_fs_fetch_acl(struct afs_fs_cursor *fc)
+ {
+       struct afs_vnode *vnode = fc->vnode;
+       struct afs_call *call;
+       struct afs_net *net = afs_v2net(vnode);
+       __be32 *bp;
+       _enter(",%x,{%llx:%llu},,",
+              key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode);
+       call = afs_alloc_flat_call(net, &afs_RXFSFetchACL, 16, (21 + 6) * 4);
+       if (!call) {
+               fc->ac.error = -ENOMEM;
+               return ERR_PTR(-ENOMEM);
+       }
+       call->key = fc->key;
+       call->reply[0] = NULL;
+       call->reply[1] = vnode;
+       call->reply[2] = NULL; /* volsync */
+       call->ret_reply0 = true;
+       /* marshall the parameters */
+       bp = call->request;
+       bp[0] = htonl(FSFETCHACL);
+       bp[1] = htonl(vnode->fid.vid);
+       bp[2] = htonl(vnode->fid.vnode);
+       bp[3] = htonl(vnode->fid.unique);
+       call->cb_break = fc->cb_break;
+       afs_use_fs_server(call, fc->cbi);
+       trace_afs_make_fs_call(call, &vnode->fid);
+       afs_make_call(&fc->ac, call, GFP_KERNEL);
+       return (struct afs_acl *)afs_wait_for_call_to_complete(call, &fc->ac);
+ }
+ /*
+  * FS.StoreACL operation type
+  */
+ static const struct afs_call_type afs_RXFSStoreACL = {
+       .name           = "FS.StoreACL",
+       .op             = afs_FS_StoreACL,
+       .deliver        = afs_deliver_fs_status_and_vol,
+       .destructor     = afs_flat_call_destructor,
+ };
+ /*
+  * Fetch the ACL for a file.
+  */
+ int afs_fs_store_acl(struct afs_fs_cursor *fc, const struct afs_acl *acl)
+ {
+       struct afs_vnode *vnode = fc->vnode;
+       struct afs_call *call;
+       struct afs_net *net = afs_v2net(vnode);
+       size_t size;
+       __be32 *bp;
+       _enter(",%x,{%llx:%llu},,",
+              key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode);
+       size = round_up(acl->size, 4);
+       call = afs_alloc_flat_call(net, &afs_RXFSStoreACL,
+                                  5 * 4 + size, (21 + 6) * 4);
+       if (!call) {
+               fc->ac.error = -ENOMEM;
+               return -ENOMEM;
+       }
+       call->key = fc->key;
+       call->reply[0] = vnode;
+       call->reply[2] = NULL; /* volsync */
+       /* marshall the parameters */
+       bp = call->request;
+       bp[0] = htonl(FSSTOREACL);
+       bp[1] = htonl(vnode->fid.vid);
+       bp[2] = htonl(vnode->fid.vnode);
+       bp[3] = htonl(vnode->fid.unique);
+       bp[4] = htonl(acl->size);
+       memcpy(&bp[5], acl->data, acl->size);
+       if (acl->size != size)
+               memset((void *)&bp[5] + acl->size, 0, size - acl->size);
+       trace_afs_make_fs_call(call, &vnode->fid);
+       afs_make_call(&fc->ac, call, GFP_KERNEL);
+       return afs_wait_for_call_to_complete(call, &fc->ac);
  }
diff --combined fs/afs/rxrpc.c
index 3ed2c99c58abe4325661a6a3cbf12bbab2b2cdcf,bc5aa590f3483535ce37356594498c4fe50da18e..a34a89c75c6ac6e75195c0b9f5675aff10008bbf
@@@ -21,7 -21,6 +21,6 @@@
  struct workqueue_struct *afs_async_calls;
  
  static void afs_wake_up_call_waiter(struct sock *, struct rxrpc_call *, unsigned long);
- static long afs_wait_for_call_to_complete(struct afs_call *, struct afs_addr_cursor *);
  static void afs_wake_up_async_call(struct sock *, struct rxrpc_call *, unsigned long);
  static void afs_delete_async_call(struct work_struct *);
  static void afs_process_async_call(struct work_struct *);
@@@ -361,10 -360,10 +360,10 @@@ static int afs_send_pages(struct afs_ca
  }
  
  /*
-  * initiate a call
+  * Initiate a call and synchronously queue up the parameters for dispatch.  Any
+  * error is stored into the call struct, which the caller must check for.
   */
- long afs_make_call(struct afs_addr_cursor *ac, struct afs_call *call,
-                  gfp_t gfp, bool async)
+ void afs_make_call(struct afs_addr_cursor *ac, struct afs_call *call, gfp_t gfp)
  {
        struct sockaddr_rxrpc *srx = &ac->alist->addrs[ac->index];
        struct rxrpc_call *rxcall;
               call, call->type->name, key_serial(call->key),
               atomic_read(&call->net->nr_outstanding_calls));
  
-       call->async = async;
        call->addr_ix = ac->index;
        call->alist = afs_get_addrlist(ac->alist);
  
        rxcall = rxrpc_kernel_begin_call(call->net->socket, srx, call->key,
                                         (unsigned long)call,
                                         tx_total_len, gfp,
-                                        (async ?
+                                        (call->async ?
                                          afs_wake_up_async_call :
                                          afs_wake_up_call_waiter),
                                         call->upgrade,
  
        /* Note that at this point, we may have received the reply or an abort
         * - and an asynchronous call may already have completed.
+        *
+        * afs_wait_for_call_to_complete(call, ac)
+        * must be called to synchronously clean up.
         */
-       if (call->async) {
-               afs_put_call(call);
-               return -EINPROGRESS;
-       }
-       return afs_wait_for_call_to_complete(call, ac);
+       return;
  
  error_do_abort:
        if (ret != -ECONNABORTED) {
@@@ -495,9 -491,7 +491,7 @@@ error_kill_call
  
        ac->error = ret;
        call->state = AFS_CALL_COMPLETE;
-       afs_put_call(call);
        _leave(" = %d", ret);
-       return ret;
  }
  
  /*
@@@ -604,10 -598,10 +598,10 @@@ call_complete
  }
  
  /*
-  * wait synchronously for a call to complete
+  * Wait synchronously for a call to complete and clean up the call struct.
   */
static long afs_wait_for_call_to_complete(struct afs_call *call,
-                                         struct afs_addr_cursor *ac)
+ long afs_wait_for_call_to_complete(struct afs_call *call,
+                                  struct afs_addr_cursor *ac)
  {
        signed long rtt2, timeout;
        long ret;
  
        _enter("");
  
+       ret = call->error;
+       if (ret < 0)
+               goto out;
        rtt = rxrpc_kernel_get_rtt(call->net->socket, call->rxcall);
        rtt2 = nsecs_to_jiffies64(rtt) * 2;
        if (rtt2 < 2)
                break;
        }
  
+ out:
        _debug("call complete");
        afs_put_call(call);
        _leave(" = %p", (void *)ret);
@@@ -923,7 -922,6 +922,7 @@@ void afs_send_empty_reply(struct afs_ca
                _debug("oom");
                rxrpc_kernel_abort_call(net->socket, call->rxcall,
                                        RX_USER_ABORT, -ENOMEM, "KOO");
 +              /* Fall through */
        default:
                _leave(" [error]");
                return;
diff --combined fs/afs/super.c
index bab89763119b0cf27954ac007a15bbdd28002136,df5b0d8ef04988f396a4117fd3abab64f98fc642..783c68cd1a3587de5474ddaa67aff6a6d783e41c
@@@ -33,7 -33,6 +33,7 @@@ static void afs_i_init_once(void *foo)
  static void afs_kill_super(struct super_block *sb);
  static struct inode *afs_alloc_inode(struct super_block *sb);
  static void afs_destroy_inode(struct inode *inode);
 +static void afs_free_inode(struct inode *inode);
  static int afs_statfs(struct dentry *dentry, struct kstatfs *buf);
  static int afs_show_devname(struct seq_file *m, struct dentry *root);
  static int afs_show_options(struct seq_file *m, struct dentry *root);
@@@ -46,7 -45,7 +46,7 @@@ struct file_system_type afs_fs_type = 
        .init_fs_context        = afs_init_fs_context,
        .parameters             = &afs_fs_parameters,
        .kill_sb                = afs_kill_super,
-       .fs_flags               = 0,
+       .fs_flags               = FS_RENAME_DOES_D_MOVE,
  };
  MODULE_ALIAS_FS("afs");
  
@@@ -57,7 -56,6 +57,7 @@@ static const struct super_operations af
        .alloc_inode    = afs_alloc_inode,
        .drop_inode     = afs_drop_inode,
        .destroy_inode  = afs_destroy_inode,
 +      .free_inode     = afs_free_inode,
        .evict_inode    = afs_evict_inode,
        .show_devname   = afs_show_devname,
        .show_options   = afs_show_options,
@@@ -69,19 -67,30 +69,30 @@@ static atomic_t afs_count_active_inodes
  enum afs_param {
        Opt_autocell,
        Opt_dyn,
+       Opt_flock,
        Opt_source,
  };
  
  static const struct fs_parameter_spec afs_param_specs[] = {
        fsparam_flag  ("autocell",      Opt_autocell),
        fsparam_flag  ("dyn",           Opt_dyn),
+       fsparam_enum  ("flock",         Opt_flock),
        fsparam_string("source",        Opt_source),
        {}
  };
  
+ static const struct fs_parameter_enum afs_param_enums[] = {
+       { Opt_flock,    "local",        afs_flock_mode_local },
+       { Opt_flock,    "openafs",      afs_flock_mode_openafs },
+       { Opt_flock,    "strict",       afs_flock_mode_strict },
+       { Opt_flock,    "write",        afs_flock_mode_write },
+       {}
+ };
  static const struct fs_parameter_description afs_fs_parameters = {
        .name           = "kAFS",
        .specs          = afs_param_specs,
+       .enums          = afs_param_enums,
  };
  
  /*
@@@ -184,11 -193,22 +195,22 @@@ static int afs_show_devname(struct seq_
  static int afs_show_options(struct seq_file *m, struct dentry *root)
  {
        struct afs_super_info *as = AFS_FS_S(root->d_sb);
+       const char *p = NULL;
  
        if (as->dyn_root)
                seq_puts(m, ",dyn");
        if (test_bit(AFS_VNODE_AUTOCELL, &AFS_FS_I(d_inode(root))->flags))
                seq_puts(m, ",autocell");
+       switch (as->flock_mode) {
+       case afs_flock_mode_unset:      break;
+       case afs_flock_mode_local:      p = "local";    break;
+       case afs_flock_mode_openafs:    p = "openafs";  break;
+       case afs_flock_mode_strict:     p = "strict";   break;
+       case afs_flock_mode_write:      p = "write";    break;
+       }
+       if (p)
+               seq_printf(m, ",flock=%s", p);
        return 0;
  }
  
@@@ -317,6 -337,10 +339,10 @@@ static int afs_parse_param(struct fs_co
                ctx->dyn_root = true;
                break;
  
+       case Opt_flock:
+               ctx->flock_mode = result.uint_32;
+               break;
        default:
                return -EINVAL;
        }
@@@ -429,7 -453,7 +455,7 @@@ static int afs_fill_super(struct super_
                fid.vnode       = 1;
                fid.vnode_hi    = 0;
                fid.unique      = 1;
-               inode = afs_iget(sb, ctx->key, &fid, NULL, NULL, NULL);
+               inode = afs_iget(sb, ctx->key, &fid, NULL, NULL, NULL, NULL);
        }
  
        if (IS_ERR(inode))
@@@ -468,6 -492,7 +494,7 @@@ static struct afs_super_info *afs_alloc
        as = kzalloc(sizeof(struct afs_super_info), GFP_KERNEL);
        if (as) {
                as->net_ns = get_net(fc->net_ns);
+               as->flock_mode = ctx->flock_mode;
                if (ctx->dyn_root) {
                        as->dyn_root = true;
                } else {
@@@ -552,6 -577,7 +579,7 @@@ static int afs_get_tree(struct fs_conte
        }
  
        fc->root = dget(sb->s_root);
+       trace_afs_get_tree(as->cell, as->volume);
        _leave(" = 0 [%p]", sb);
        return 0;
  
@@@ -658,13 -684,17 +686,15 @@@ static struct inode *afs_alloc_inode(st
        vnode->cb_type          = 0;
        vnode->lock_state       = AFS_VNODE_LOCK_NONE;
  
+       init_rwsem(&vnode->rmdir_lock);
        _leave(" = %p", &vnode->vfs_inode);
        return &vnode->vfs_inode;
  }
  
 -static void afs_i_callback(struct rcu_head *head)
 +static void afs_free_inode(struct inode *inode)
  {
 -      struct inode *inode = container_of(head, struct inode, i_rcu);
 -      struct afs_vnode *vnode = AFS_FS_I(inode);
 -      kmem_cache_free(afs_inode_cachep, vnode);
 +      kmem_cache_free(afs_inode_cachep, AFS_FS_I(inode));
  }
  
  /*
@@@ -680,6 -710,7 +710,6 @@@ static void afs_destroy_inode(struct in
  
        ASSERTCMP(vnode->cb_interest, ==, NULL);
  
 -      call_rcu(&inode->i_rcu, afs_i_callback);
        atomic_dec(&afs_count_active_inodes);
  }
  
diff --combined fs/afs/vlclient.c
index b0175b3ef0e8b6bd647a59b033ca2889b3dd8f2f,e98ffe6df1c14af418065d4d7da39ef42c969d03..dd9ba4e96fb3ecc14d2fe4552fe209a09e6b2abc
@@@ -167,7 -167,8 +167,8 @@@ struct afs_vldb_entry *afs_vl_get_entry
                memset((void *)bp + volnamesz, 0, padsz);
  
        trace_afs_make_vl_call(call);
-       return (struct afs_vldb_entry *)afs_make_call(&vc->ac, call, GFP_KERNEL, false);
+       afs_make_call(&vc->ac, call, GFP_KERNEL);
+       return (struct afs_vldb_entry *)afs_wait_for_call_to_complete(call, &vc->ac);
  }
  
  /*
@@@ -195,9 -196,7 +196,9 @@@ static int afs_deliver_vl_get_addrs_u(s
                                   sizeof(struct afs_uuid__xdr) + 3 * sizeof(__be32));
                call->unmarshall++;
  
 -              /* Extract the returned uuid, uniquifier, nentries and blkaddrs size */
 +              /* Extract the returned uuid, uniquifier, nentries and
 +               * blkaddrs size */
 +              /* Fall through */
        case 1:
                ret = afs_extract_data(call, true);
                if (ret < 0)
                count = min(call->count, 4U);
                afs_extract_to_buf(call, count * sizeof(__be32));
  
 -              /* Extract entries */
 +              /* Fall through - and extract entries */
        case 2:
                ret = afs_extract_data(call, call->count > 4);
                if (ret < 0)
@@@ -306,7 -305,8 +307,8 @@@ struct afs_addr_list *afs_vl_get_addrs_
                r->uuid.node[i] = htonl(u->node[i]);
  
        trace_afs_make_vl_call(call);
-       return (struct afs_addr_list *)afs_make_call(&vc->ac, call, GFP_KERNEL, false);
+       afs_make_call(&vc->ac, call, GFP_KERNEL);
+       return (struct afs_addr_list *)afs_wait_for_call_to_complete(call, &vc->ac);
  }
  
  /*
@@@ -325,7 -325,7 +327,7 @@@ static int afs_deliver_vl_get_capabilit
                afs_extract_to_tmp(call);
                call->unmarshall++;
  
 -              /* Extract the capabilities word count */
 +              /* Fall through - and extract the capabilities word count */
        case 1:
                ret = afs_extract_data(call, true);
                if (ret < 0)
                call->unmarshall++;
                afs_extract_discard(call, count * sizeof(__be32));
  
 -              /* Extract capabilities words */
 +              /* Fall through - and extract capabilities words */
        case 2:
                ret = afs_extract_data(call, false);
                if (ret < 0)
@@@ -380,12 -380,11 +382,11 @@@ static const struct afs_call_type afs_R
   * We use this to probe for service upgrade to determine what the server at the
   * other end supports.
   */
- int afs_vl_get_capabilities(struct afs_net *net,
-                           struct afs_addr_cursor *ac,
-                           struct key *key,
-                           struct afs_vlserver *server,
-                           unsigned int server_index,
-                           bool async)
+ struct afs_call *afs_vl_get_capabilities(struct afs_net *net,
+                                        struct afs_addr_cursor *ac,
+                                        struct key *key,
+                                        struct afs_vlserver *server,
+                                        unsigned int server_index)
  {
        struct afs_call *call;
        __be32 *bp;
  
        call = afs_alloc_flat_call(net, &afs_RXVLGetCapabilities, 1 * 4, 16 * 4);
        if (!call)
-               return -ENOMEM;
+               return ERR_PTR(-ENOMEM);
  
        call->key = key;
        call->reply[0] = afs_get_vlserver(server);
        call->reply[1] = (void *)(long)server_index;
        call->upgrade = true;
        call->want_reply_time = true;
+       call->async = true;
  
        /* marshall the parameters */
        bp = call->request;
  
        /* Can't take a ref on server */
        trace_afs_make_vl_call(call);
-       return afs_make_call(ac, call, GFP_KERNEL, async);
+       afs_make_call(ac, call, GFP_KERNEL);
+       return call;
  }
  
  /*
@@@ -438,7 -439,6 +441,7 @@@ static int afs_deliver_yfsvl_get_endpoi
                /* Extract the returned uuid, uniquifier, fsEndpoints count and
                 * either the first fsEndpoint type or the volEndpoints
                 * count if there are no fsEndpoints. */
 +              /* Fall through */
        case 1:
                ret = afs_extract_data(call, true);
                if (ret < 0)
                afs_extract_to_buf(call, size);
                call->unmarshall = 2;
  
 -              /* Extract fsEndpoints[] entries */
 +              /* Fall through - and extract fsEndpoints[] entries */
        case 2:
                ret = afs_extract_data(call, true);
                if (ret < 0)
                 * extract the type of the next endpoint when we extract the
                 * data of the current one, but this is the first...
                 */
 +              /* Fall through */
        case 3:
                ret = afs_extract_data(call, true);
                if (ret < 0)
                afs_extract_to_buf(call, size);
                call->unmarshall = 4;
  
 -              /* Extract volEndpoints[] entries */
 +              /* Fall through - and extract volEndpoints[] entries */
        case 4:
                ret = afs_extract_data(call, true);
                if (ret < 0)
                afs_extract_discard(call, 0);
                call->unmarshall = 5;
  
 -              /* Done */
 +              /* Fall through - Done */
        case 5:
                ret = afs_extract_data(call, false);
                if (ret < 0)
@@@ -651,5 -650,6 +654,6 @@@ struct afs_addr_list *afs_yfsvl_get_end
        memcpy(bp, uuid, sizeof(*uuid)); /* Type opr_uuid */
  
        trace_afs_make_vl_call(call);
-       return (struct afs_addr_list *)afs_make_call(&vc->ac, call, GFP_KERNEL, false);
+       afs_make_call(&vc->ac, call, GFP_KERNEL);
+       return (struct afs_addr_list *)afs_wait_for_call_to_complete(call, &vc->ac);
  }
diff --combined fs/afs/yfsclient.c
index 871e29f06257be3abe7085d91c962eba0c7d7a0c,6d5af09e3f19dcdeeda144846197e2b791f6f003..6cf7d161baa1ecd3d069ecf1d30b214e8d6f8c37
@@@ -519,7 -519,8 +519,8 @@@ int yfs_fs_fetch_file_status(struct afs
        call->cb_break = fc->cb_break;
        afs_use_fs_server(call, fc->cbi);
        trace_afs_make_fs_call(call, &vnode->fid);
-       return afs_make_call(&fc->ac, call, GFP_NOFS, false);
+       afs_make_call(&fc->ac, call, GFP_NOFS);
+       return afs_wait_for_call_to_complete(call, &fc->ac);
  }
  
  /*
@@@ -544,7 -545,7 +545,7 @@@ static int yfs_deliver_fs_fetch_data64(
                afs_extract_to_tmp64(call);
                call->unmarshall++;
  
 -              /* extract the returned data length */
 +              /* Fall through - and extract the returned data length */
        case 1:
                _debug("extract data length");
                ret = afs_extract_data(call, true);
                iov_iter_bvec(&call->iter, READ, call->bvec, 1, size);
                ASSERTCMP(size, <=, PAGE_SIZE);
  
 -              /* extract the returned data */
 +              /* Fall through - and extract the returned data */
        case 2:
                _debug("extract data %zu/%llu",
                       iov_iter_count(&call->iter), req->remain);
                /* Discard any excess data the server gave us */
                iov_iter_discard(&call->iter, READ, req->actual_len - req->len);
                call->unmarshall = 3;
 +
 +              /* Fall through */
        case 3:
                _debug("extract discard %zu/%llu",
                       iov_iter_count(&call->iter), req->actual_len - req->len);
                                   sizeof(struct yfs_xdr_YFSCallBack) +
                                   sizeof(struct yfs_xdr_YFSVolSync));
  
 -              /* extract the metadata */
 +              /* Fall through - and extract the metadata */
        case 4:
                ret = afs_extract_data(call, false);
                if (ret < 0)
  
                call->unmarshall++;
  
 +              /* Fall through */
        case 5:
                break;
        }
@@@ -711,7 -709,8 +712,8 @@@ int yfs_fs_fetch_data(struct afs_fs_cur
        call->cb_break = fc->cb_break;
        afs_use_fs_server(call, fc->cbi);
        trace_afs_make_fs_call(call, &vnode->fid);
-       return afs_make_call(&fc->ac, call, GFP_NOFS, false);
+       afs_make_call(&fc->ac, call, GFP_NOFS);
+       return afs_wait_for_call_to_complete(call, &fc->ac);
  }
  
  /*
@@@ -810,8 -809,9 +812,9 @@@ int yfs_fs_create_file(struct afs_fs_cu
        yfs_check_req(call, bp);
  
        afs_use_fs_server(call, fc->cbi);
-       trace_afs_make_fs_call(call, &vnode->fid);
-       return afs_make_call(&fc->ac, call, GFP_NOFS, false);
+       trace_afs_make_fs_call1(call, &vnode->fid, name);
+       afs_make_call(&fc->ac, call, GFP_NOFS);
+       return afs_wait_for_call_to_complete(call, &fc->ac);
  }
  
  static const struct afs_call_type yfs_RXFSMakeDir = {
@@@ -873,8 -873,9 +876,9 @@@ int yfs_fs_make_dir(struct afs_fs_curso
        yfs_check_req(call, bp);
  
        afs_use_fs_server(call, fc->cbi);
-       trace_afs_make_fs_call(call, &vnode->fid);
-       return afs_make_call(&fc->ac, call, GFP_NOFS, false);
+       trace_afs_make_fs_call1(call, &vnode->fid, name);
+       afs_make_call(&fc->ac, call, GFP_NOFS);
+       return afs_wait_for_call_to_complete(call, &fc->ac);
  }
  
  /*
@@@ -963,8 -964,9 +967,9 @@@ int yfs_fs_remove_file2(struct afs_fs_c
        yfs_check_req(call, bp);
  
        afs_use_fs_server(call, fc->cbi);
-       trace_afs_make_fs_call(call, &dvnode->fid);
-       return afs_make_call(&fc->ac, call, GFP_NOFS, false);
+       trace_afs_make_fs_call1(call, &dvnode->fid, name);
+       afs_make_call(&fc->ac, call, GFP_NOFS);
+       return afs_wait_for_call_to_complete(call, &fc->ac);
  }
  
  /*
@@@ -1050,8 -1052,9 +1055,9 @@@ int yfs_fs_remove(struct afs_fs_cursor 
        yfs_check_req(call, bp);
  
        afs_use_fs_server(call, fc->cbi);
-       trace_afs_make_fs_call(call, &dvnode->fid);
-       return afs_make_call(&fc->ac, call, GFP_NOFS, false);
+       trace_afs_make_fs_call1(call, &dvnode->fid, name);
+       afs_make_call(&fc->ac, call, GFP_NOFS);
+       return afs_wait_for_call_to_complete(call, &fc->ac);
  }
  
  /*
@@@ -1135,8 -1138,9 +1141,9 @@@ int yfs_fs_link(struct afs_fs_cursor *f
        yfs_check_req(call, bp);
  
        afs_use_fs_server(call, fc->cbi);
-       trace_afs_make_fs_call(call, &vnode->fid);
-       return afs_make_call(&fc->ac, call, GFP_NOFS, false);
+       trace_afs_make_fs_call1(call, &vnode->fid, name);
+       afs_make_call(&fc->ac, call, GFP_NOFS);
+       return afs_wait_for_call_to_complete(call, &fc->ac);
  }
  
  /*
@@@ -1231,8 -1235,9 +1238,9 @@@ int yfs_fs_symlink(struct afs_fs_curso
        yfs_check_req(call, bp);
  
        afs_use_fs_server(call, fc->cbi);
-       trace_afs_make_fs_call(call, &dvnode->fid);
-       return afs_make_call(&fc->ac, call, GFP_NOFS, false);
+       trace_afs_make_fs_call1(call, &dvnode->fid, name);
+       afs_make_call(&fc->ac, call, GFP_NOFS);
+       return afs_wait_for_call_to_complete(call, &fc->ac);
  }
  
  /*
@@@ -1329,8 -1334,9 +1337,9 @@@ int yfs_fs_rename(struct afs_fs_cursor 
        yfs_check_req(call, bp);
  
        afs_use_fs_server(call, fc->cbi);
-       trace_afs_make_fs_call(call, &orig_dvnode->fid);
-       return afs_make_call(&fc->ac, call, GFP_NOFS, false);
+       trace_afs_make_fs_call2(call, &orig_dvnode->fid, orig_name, new_name);
+       afs_make_call(&fc->ac, call, GFP_NOFS);
+       return afs_wait_for_call_to_complete(call, &fc->ac);
  }
  
  /*
@@@ -1436,7 -1442,8 +1445,8 @@@ int yfs_fs_store_data(struct afs_fs_cur
  
        afs_use_fs_server(call, fc->cbi);
        trace_afs_make_fs_call(call, &vnode->fid);
-       return afs_make_call(&fc->ac, call, GFP_NOFS, false);
+       afs_make_call(&fc->ac, call, GFP_NOFS);
+       return afs_wait_for_call_to_complete(call, &fc->ac);
  }
  
  /*
@@@ -1524,7 -1531,8 +1534,8 @@@ static int yfs_fs_setattr_size(struct a
  
        afs_use_fs_server(call, fc->cbi);
        trace_afs_make_fs_call(call, &vnode->fid);
-       return afs_make_call(&fc->ac, call, GFP_NOFS, false);
+       afs_make_call(&fc->ac, call, GFP_NOFS);
+       return afs_wait_for_call_to_complete(call, &fc->ac);
  }
  
  /*
@@@ -1567,7 -1575,8 +1578,8 @@@ int yfs_fs_setattr(struct afs_fs_curso
  
        afs_use_fs_server(call, fc->cbi);
        trace_afs_make_fs_call(call, &vnode->fid);
-       return afs_make_call(&fc->ac, call, GFP_NOFS, false);
+       afs_make_call(&fc->ac, call, GFP_NOFS);
+       return afs_wait_for_call_to_complete(call, &fc->ac);
  }
  
  /*
@@@ -1587,7 -1596,7 +1599,7 @@@ static int yfs_deliver_fs_get_volume_st
                call->unmarshall++;
                afs_extract_to_buf(call, sizeof(struct yfs_xdr_YFSFetchVolumeStatus));
  
 -              /* extract the returned status record */
 +              /* Fall through - and extract the returned status record */
        case 1:
                _debug("extract status");
                ret = afs_extract_data(call, true);
                call->unmarshall++;
                afs_extract_to_tmp(call);
  
 -              /* extract the volume name length */
 +              /* Fall through - and extract the volume name length */
        case 2:
                ret = afs_extract_data(call, true);
                if (ret < 0)
                afs_extract_begin(call, call->reply[2], size);
                call->unmarshall++;
  
 -              /* extract the volume name */
 +              /* Fall through - and extract the volume name */
        case 3:
                _debug("extract volname");
                ret = afs_extract_data(call, true);
                afs_extract_to_tmp(call);
                call->unmarshall++;
  
 -              /* extract the offline message length */
 +              /* Fall through - and extract the offline message length */
        case 4:
                ret = afs_extract_data(call, true);
                if (ret < 0)
                afs_extract_begin(call, call->reply[2], size);
                call->unmarshall++;
  
 -              /* extract the offline message */
 +              /* Fall through - and extract the offline message */
        case 5:
                _debug("extract offline");
                ret = afs_extract_data(call, true);
                afs_extract_to_tmp(call);
                call->unmarshall++;
  
 -              /* extract the message of the day length */
 +              /* Fall through - and extract the message of the day length */
        case 6:
                ret = afs_extract_data(call, true);
                if (ret < 0)
                afs_extract_begin(call, call->reply[2], size);
                call->unmarshall++;
  
 -              /* extract the message of the day */
 +              /* Fall through - and extract the message of the day */
        case 7:
                _debug("extract motd");
                ret = afs_extract_data(call, false);
  
                call->unmarshall++;
  
 +              /* Fall through */
        case 8:
                break;
        }
@@@ -1755,13 -1763,15 +1767,15 @@@ int yfs_fs_get_volume_status(struct afs
  
        afs_use_fs_server(call, fc->cbi);
        trace_afs_make_fs_call(call, &vnode->fid);
-       return afs_make_call(&fc->ac, call, GFP_NOFS, false);
+       afs_make_call(&fc->ac, call, GFP_NOFS);
+       return afs_wait_for_call_to_complete(call, &fc->ac);
  }
  
  /*
-  * Deliver reply data to an YFS.SetLock, YFS.ExtendLock or YFS.ReleaseLock
+  * Deliver reply data to operations that just return a file status and a volume
+  * sync record.
   */
- static int yfs_deliver_fs_xxxx_lock(struct afs_call *call)
+ static int yfs_deliver_status_and_volsync(struct afs_call *call)
  {
        struct afs_vnode *vnode = call->reply[0];
        const __be32 *bp;
  static const struct afs_call_type yfs_RXYFSSetLock = {
        .name           = "YFS.SetLock",
        .op             = yfs_FS_SetLock,
-       .deliver        = yfs_deliver_fs_xxxx_lock,
+       .deliver        = yfs_deliver_status_and_volsync,
+       .done           = afs_lock_op_done,
        .destructor     = afs_flat_call_destructor,
  };
  
  static const struct afs_call_type yfs_RXYFSExtendLock = {
        .name           = "YFS.ExtendLock",
        .op             = yfs_FS_ExtendLock,
-       .deliver        = yfs_deliver_fs_xxxx_lock,
+       .deliver        = yfs_deliver_status_and_volsync,
+       .done           = afs_lock_op_done,
        .destructor     = afs_flat_call_destructor,
  };
  
  static const struct afs_call_type yfs_RXYFSReleaseLock = {
        .name           = "YFS.ReleaseLock",
        .op             = yfs_FS_ReleaseLock,
-       .deliver        = yfs_deliver_fs_xxxx_lock,
+       .deliver        = yfs_deliver_status_and_volsync,
        .destructor     = afs_flat_call_destructor,
  };
  
@@@ -1838,6 -1850,7 +1854,7 @@@ int yfs_fs_set_lock(struct afs_fs_curso
  
        call->key = fc->key;
        call->reply[0] = vnode;
+       call->want_reply_time = true;
  
        /* marshall the parameters */
        bp = call->request;
        yfs_check_req(call, bp);
  
        afs_use_fs_server(call, fc->cbi);
-       trace_afs_make_fs_call(call, &vnode->fid);
-       return afs_make_call(&fc->ac, call, GFP_NOFS, false);
+       trace_afs_make_fs_calli(call, &vnode->fid, type);
+       afs_make_call(&fc->ac, call, GFP_NOFS);
+       return afs_wait_for_call_to_complete(call, &fc->ac);
  }
  
  /*
@@@ -1874,6 -1888,7 +1892,7 @@@ int yfs_fs_extend_lock(struct afs_fs_cu
  
        call->key = fc->key;
        call->reply[0] = vnode;
+       call->want_reply_time = true;
  
        /* marshall the parameters */
        bp = call->request;
  
        afs_use_fs_server(call, fc->cbi);
        trace_afs_make_fs_call(call, &vnode->fid);
-       return afs_make_call(&fc->ac, call, GFP_NOFS, false);
+       afs_make_call(&fc->ac, call, GFP_NOFS);
+       return afs_wait_for_call_to_complete(call, &fc->ac);
  }
  
  /*
@@@ -1919,7 -1935,8 +1939,8 @@@ int yfs_fs_release_lock(struct afs_fs_c
  
        afs_use_fs_server(call, fc->cbi);
        trace_afs_make_fs_call(call, &vnode->fid);
-       return afs_make_call(&fc->ac, call, GFP_NOFS, false);
+       afs_make_call(&fc->ac, call, GFP_NOFS);
+       return afs_wait_for_call_to_complete(call, &fc->ac);
  }
  
  /*
@@@ -2007,7 -2024,8 +2028,8 @@@ int yfs_fs_fetch_status(struct afs_fs_c
        call->cb_break = fc->cb_break;
        afs_use_fs_server(call, fc->cbi);
        trace_afs_make_fs_call(call, fid);
-       return afs_make_call(&fc->ac, call, GFP_NOFS, false);
+       afs_make_call(&fc->ac, call, GFP_NOFS);
+       return afs_wait_for_call_to_complete(call, &fc->ac);
  }
  
  /*
@@@ -2030,7 -2048,6 +2052,7 @@@ static int yfs_deliver_fs_inline_bulk_s
                call->unmarshall++;
  
                /* Extract the file status count and array in two steps */
 +              /* Fall through */
        case 1:
                _debug("extract status count");
                ret = afs_extract_data(call, true);
        more_counts:
                afs_extract_to_buf(call, sizeof(struct yfs_xdr_YFSFetchStatus));
  
 +              /* Fall through */
        case 2:
                _debug("extract status array %u", call->count);
                ret = afs_extract_data(call, true);
                afs_extract_to_tmp(call);
  
                /* Extract the callback count and array in two steps */
 +              /* Fall through */
        case 3:
                _debug("extract CB count");
                ret = afs_extract_data(call, true);
        more_cbs:
                afs_extract_to_buf(call, sizeof(struct yfs_xdr_YFSCallBack));
  
 +              /* Fall through */
        case 4:
                _debug("extract CB array");
                ret = afs_extract_data(call, true);
                afs_extract_to_buf(call, sizeof(struct yfs_xdr_YFSVolSync));
                call->unmarshall++;
  
 +              /* Fall through */
        case 5:
                ret = afs_extract_data(call, false);
                if (ret < 0)
  
                call->unmarshall++;
  
 +              /* Fall through */
        case 6:
                break;
        }
@@@ -2190,5 -2202,250 +2212,250 @@@ int yfs_fs_inline_bulk_status(struct af
        call->cb_break = fc->cb_break;
        afs_use_fs_server(call, fc->cbi);
        trace_afs_make_fs_call(call, &fids[0]);
-       return afs_make_call(&fc->ac, call, GFP_NOFS, false);
+       afs_make_call(&fc->ac, call, GFP_NOFS);
+       return afs_wait_for_call_to_complete(call, &fc->ac);
+ }
+ /*
+  * Deliver reply data to an YFS.FetchOpaqueACL.
+  */
+ static int yfs_deliver_fs_fetch_opaque_acl(struct afs_call *call)
+ {
+       struct afs_volsync *volsync = call->reply[2];
+       struct afs_vnode *vnode = call->reply[1];
+       struct yfs_acl *yacl =  call->reply[0];
+       struct afs_acl *acl;
+       const __be32 *bp;
+       unsigned int size;
+       int ret;
+       _enter("{%u}", call->unmarshall);
+       switch (call->unmarshall) {
+       case 0:
+               afs_extract_to_tmp(call);
+               call->unmarshall++;
+               /* Extract the file ACL length */
+       case 1:
+               ret = afs_extract_data(call, true);
+               if (ret < 0)
+                       return ret;
+               size = call->count2 = ntohl(call->tmp);
+               size = round_up(size, 4);
+               if (yacl->flags & YFS_ACL_WANT_ACL) {
+                       acl = kmalloc(struct_size(acl, data, size), GFP_KERNEL);
+                       if (!acl)
+                               return -ENOMEM;
+                       yacl->acl = acl;
+                       acl->size = call->count2;
+                       afs_extract_begin(call, acl->data, size);
+               } else {
+                       iov_iter_discard(&call->iter, READ, size);
+               }
+               call->unmarshall++;
+               /* Extract the file ACL */
+       case 2:
+               ret = afs_extract_data(call, true);
+               if (ret < 0)
+                       return ret;
+               afs_extract_to_tmp(call);
+               call->unmarshall++;
+               /* Extract the volume ACL length */
+       case 3:
+               ret = afs_extract_data(call, true);
+               if (ret < 0)
+                       return ret;
+               size = call->count2 = ntohl(call->tmp);
+               size = round_up(size, 4);
+               if (yacl->flags & YFS_ACL_WANT_VOL_ACL) {
+                       acl = kmalloc(struct_size(acl, data, size), GFP_KERNEL);
+                       if (!acl)
+                               return -ENOMEM;
+                       yacl->vol_acl = acl;
+                       acl->size = call->count2;
+                       afs_extract_begin(call, acl->data, size);
+               } else {
+                       iov_iter_discard(&call->iter, READ, size);
+               }
+               call->unmarshall++;
+               /* Extract the volume ACL */
+       case 4:
+               ret = afs_extract_data(call, true);
+               if (ret < 0)
+                       return ret;
+               afs_extract_to_buf(call,
+                                  sizeof(__be32) * 2 +
+                                  sizeof(struct yfs_xdr_YFSFetchStatus) +
+                                  sizeof(struct yfs_xdr_YFSVolSync));
+               call->unmarshall++;
+               /* extract the metadata */
+       case 5:
+               ret = afs_extract_data(call, false);
+               if (ret < 0)
+                       return ret;
+               bp = call->buffer;
+               yacl->inherit_flag = ntohl(*bp++);
+               yacl->num_cleaned = ntohl(*bp++);
+               ret = yfs_decode_status(call, &bp, &vnode->status, vnode,
+                                       &call->expected_version, NULL);
+               if (ret < 0)
+                       return ret;
+               xdr_decode_YFSVolSync(&bp, volsync);
+               call->unmarshall++;
+       case 6:
+               break;
+       }
+       _leave(" = 0 [done]");
+       return 0;
+ }
+ void yfs_free_opaque_acl(struct yfs_acl *yacl)
+ {
+       if (yacl) {
+               kfree(yacl->acl);
+               kfree(yacl->vol_acl);
+               kfree(yacl);
+       }
+ }
+ static void yfs_destroy_fs_fetch_opaque_acl(struct afs_call *call)
+ {
+       yfs_free_opaque_acl(call->reply[0]);
+       afs_flat_call_destructor(call);
+ }
+ /*
+  * YFS.FetchOpaqueACL operation type
+  */
+ static const struct afs_call_type yfs_RXYFSFetchOpaqueACL = {
+       .name           = "YFS.FetchOpaqueACL",
+       .op             = yfs_FS_FetchOpaqueACL,
+       .deliver        = yfs_deliver_fs_fetch_opaque_acl,
+       .destructor     = yfs_destroy_fs_fetch_opaque_acl,
+ };
+ /*
+  * Fetch the YFS advanced ACLs for a file.
+  */
+ struct yfs_acl *yfs_fs_fetch_opaque_acl(struct afs_fs_cursor *fc,
+                                       unsigned int flags)
+ {
+       struct afs_vnode *vnode = fc->vnode;
+       struct afs_call *call;
+       struct yfs_acl *yacl;
+       struct afs_net *net = afs_v2net(vnode);
+       __be32 *bp;
+       _enter(",%x,{%llx:%llu},,",
+              key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode);
+       call = afs_alloc_flat_call(net, &yfs_RXYFSFetchOpaqueACL,
+                                  sizeof(__be32) * 2 +
+                                  sizeof(struct yfs_xdr_YFSFid),
+                                  sizeof(__be32) * 2 +
+                                  sizeof(struct yfs_xdr_YFSFetchStatus) +
+                                  sizeof(struct yfs_xdr_YFSVolSync));
+       if (!call)
+               goto nomem;
+       yacl = kzalloc(sizeof(struct yfs_acl), GFP_KERNEL);
+       if (!yacl)
+               goto nomem_call;
+       yacl->flags = flags;
+       call->key = fc->key;
+       call->reply[0] = yacl;
+       call->reply[1] = vnode;
+       call->reply[2] = NULL; /* volsync */
+       call->ret_reply0 = true;
+       /* marshall the parameters */
+       bp = call->request;
+       bp = xdr_encode_u32(bp, YFSFETCHOPAQUEACL);
+       bp = xdr_encode_u32(bp, 0); /* RPC flags */
+       bp = xdr_encode_YFSFid(bp, &vnode->fid);
+       yfs_check_req(call, bp);
+       call->cb_break = fc->cb_break;
+       afs_use_fs_server(call, fc->cbi);
+       trace_afs_make_fs_call(call, &vnode->fid);
+       afs_make_call(&fc->ac, call, GFP_KERNEL);
+       return (struct yfs_acl *)afs_wait_for_call_to_complete(call, &fc->ac);
+ nomem_call:
+       afs_put_call(call);
+ nomem:
+       fc->ac.error = -ENOMEM;
+       return ERR_PTR(-ENOMEM);
+ }
+ /*
+  * YFS.StoreOpaqueACL2 operation type
+  */
+ static const struct afs_call_type yfs_RXYFSStoreOpaqueACL2 = {
+       .name           = "YFS.StoreOpaqueACL2",
+       .op             = yfs_FS_StoreOpaqueACL2,
+       .deliver        = yfs_deliver_status_and_volsync,
+       .destructor     = afs_flat_call_destructor,
+ };
+ /*
+  * Fetch the YFS ACL for a file.
+  */
+ int yfs_fs_store_opaque_acl2(struct afs_fs_cursor *fc, const struct afs_acl *acl)
+ {
+       struct afs_vnode *vnode = fc->vnode;
+       struct afs_call *call;
+       struct afs_net *net = afs_v2net(vnode);
+       size_t size;
+       __be32 *bp;
+       _enter(",%x,{%llx:%llu},,",
+              key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode);
+       size = round_up(acl->size, 4);
+       call = afs_alloc_flat_call(net, &yfs_RXYFSStoreStatus,
+                                  sizeof(__be32) * 2 +
+                                  sizeof(struct yfs_xdr_YFSFid) +
+                                  sizeof(__be32) + size,
+                                  sizeof(struct yfs_xdr_YFSFetchStatus) +
+                                  sizeof(struct yfs_xdr_YFSVolSync));
+       if (!call) {
+               fc->ac.error = -ENOMEM;
+               return -ENOMEM;
+       }
+       call->key = fc->key;
+       call->reply[0] = vnode;
+       call->reply[2] = NULL; /* volsync */
+       /* marshall the parameters */
+       bp = call->request;
+       bp = xdr_encode_u32(bp, YFSSTOREOPAQUEACL2);
+       bp = xdr_encode_u32(bp, 0); /* RPC flags */
+       bp = xdr_encode_YFSFid(bp, &vnode->fid);
+       bp = xdr_encode_u32(bp, acl->size);
+       memcpy(bp, acl->data, acl->size);
+       if (acl->size != size)
+               memset((void *)bp + acl->size, 0, size - acl->size);
+       yfs_check_req(call, bp);
+       trace_afs_make_fs_call(call, &vnode->fid);
+       afs_make_call(&fc->ac, call, GFP_KERNEL);
+       return afs_wait_for_call_to_complete(call, &fc->ac);
  }
diff --combined include/linux/fs.h
index 49d048ea0afbe5463cb612dd384bddea0bc3eb6b,744908e0bdecb0de03706d0a19300c080c65ae67..0fa5b47509d5a58b5d59b056c80f4eff4d2d07c4
@@@ -165,13 -165,10 +165,13 @@@ typedef int (dio_iodone_t)(struct kioc
  #define FMODE_NONOTIFY                ((__force fmode_t)0x4000000)
  
  /* File is capable of returning -EAGAIN if I/O will block */
 -#define FMODE_NOWAIT  ((__force fmode_t)0x8000000)
 +#define FMODE_NOWAIT          ((__force fmode_t)0x8000000)
 +
 +/* File represents mount that needs unmounting */
 +#define FMODE_NEED_UNMOUNT    ((__force fmode_t)0x10000000)
  
  /* File does not contribute to nr_files count */
 -#define FMODE_NOACCOUNT       ((__force fmode_t)0x20000000)
 +#define FMODE_NOACCOUNT               ((__force fmode_t)0x20000000)
  
  /*
   * Flag for rw_copy_check_uvector and compat_rw_copy_check_uvector
@@@ -697,10 -694,7 +697,10 @@@ struct inode 
  #ifdef CONFIG_IMA
        atomic_t                i_readcount; /* struct files open RO */
  #endif
 -      const struct file_operations    *i_fop; /* former ->i_op->default_file_ops */
 +      union {
 +              const struct file_operations    *i_fop; /* former ->i_op->default_file_ops */
 +              void (*free_inode)(struct inode *);
 +      };
        struct file_lock_context        *i_flctx;
        struct address_space    i_data;
        struct list_head        i_devices;
@@@ -975,6 -969,7 +975,6 @@@ static inline struct file *get_file(str
  #define get_file_rcu_many(x, cnt)     \
        atomic_long_add_unless(&(x)->f_count, (cnt), 0)
  #define get_file_rcu(x) get_file_rcu_many((x), 1)
 -#define fput_atomic(x)        atomic_long_add_unless(&(x)->f_count, -1, 1)
  #define file_count(x) atomic_long_read(&(x)->f_count)
  
  #define       MAX_NON_LFS     ((1UL<<31) - 1)
@@@ -1098,6 -1093,7 +1098,7 @@@ struct file_lock 
                struct {
                        struct list_head link;  /* link in AFS vnode's pending_locks list */
                        int state;              /* state of grant or error if -ve */
+                       unsigned int    debug_id;
                } afs;
        } fl_u;
  } __randomize_layout;
@@@ -1908,7 -1904,6 +1909,7 @@@ extern loff_t vfs_dedupe_file_range_one
  struct super_operations {
        struct inode *(*alloc_inode)(struct super_block *sb);
        void (*destroy_inode)(struct inode *);
 +      void (*free_inode)(struct inode *);
  
        void (*dirty_inode) (struct inode *, int flags);
        int (*write_inode) (struct inode *, struct writeback_control *wbc);
@@@ -2791,9 -2786,6 +2792,9 @@@ extern int vfs_fsync_range(struct file 
                           int datasync);
  extern int vfs_fsync(struct file *file, int datasync);
  
 +extern int sync_file_range(struct file *file, loff_t offset, loff_t nbytes,
 +                              unsigned int flags);
 +
  /*
   * Sync the bytes written if this was a synchronous write.  Expect ki_pos
   * to already be updated for the write, and will return either the amount