]> Git Repo - linux.git/commitdiff
Merge tag 'hardening-v6.8-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/kees...
authorLinus Torvalds <[email protected]>
Wed, 10 Jan 2024 19:03:52 +0000 (11:03 -0800)
committerLinus Torvalds <[email protected]>
Wed, 10 Jan 2024 19:03:52 +0000 (11:03 -0800)
Pull hardening updates from Kees Cook:

 - Introduce the param_unknown_fn type and other clean ups (Andy
   Shevchenko)

 - Various __counted_by annotations (Christophe JAILLET, Gustavo A. R.
   Silva, Kees Cook)

 - Add KFENCE test to LKDTM (Stephen Boyd)

 - Various strncpy() refactorings (Justin Stitt)

 - Fix qnx4 to avoid writing into the smaller of two overlapping buffers

 - Various strlcpy() refactorings

* tag 'hardening-v6.8-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux:
  qnx4: Use get_directory_fname() in qnx4_match()
  qnx4: Extract dir entry filename processing into helper
  atags_proc: Add __counted_by for struct buffer and use struct_size()
  tracing/uprobe: Replace strlcpy() with strscpy()
  params: Fix multi-line comment style
  params: Sort headers
  params: Use size_add() for kmalloc()
  params: Do not go over the limit when getting the string length
  params: Introduce the param_unknown_fn type
  lkdtm: Add kfence read after free crash type
  nvme-fc: replace deprecated strncpy with strscpy
  nvdimm/btt: replace deprecated strncpy with strscpy
  nvme-fabrics: replace deprecated strncpy with strscpy
  drm/modes: replace deprecated strncpy with strscpy_pad
  afs: Add __counted_by for struct afs_acl and use struct_size()
  VMCI: Annotate struct vmci_handle_arr with __counted_by
  i40e: Annotate struct i40e_qvlist_info with __counted_by
  HID: uhid: replace deprecated strncpy with strscpy
  samples: Replace strlcpy() with strscpy()
  SUNRPC: Replace strlcpy() with strscpy()

1  2 
drivers/nvme/host/fabrics.c
drivers/nvme/host/fc.c
fs/afs/internal.h

index aa88606a44c40f2b88c1cb8c0286d57632960755,830bf01df4b81a4e03591b00954a8f17c214925a..b5752a77ad989f04a14ef9416f6244cf5255441d
@@@ -387,8 -387,8 +387,8 @@@ static struct nvmf_connect_data *nvmf_c
  
        uuid_copy(&data->hostid, &ctrl->opts->host->id);
        data->cntlid = cpu_to_le16(cntlid);
-       strncpy(data->subsysnqn, ctrl->opts->subsysnqn, NVMF_NQN_SIZE);
-       strncpy(data->hostnqn, ctrl->opts->host->nqn, NVMF_NQN_SIZE);
+       strscpy(data->subsysnqn, ctrl->opts->subsysnqn, NVMF_NQN_SIZE);
+       strscpy(data->hostnqn, ctrl->opts->host->nqn, NVMF_NQN_SIZE);
  
        return data;
  }
@@@ -667,10 -667,8 +667,10 @@@ static const match_table_t opt_tokens 
  #endif
        { NVMF_OPT_FAIL_FAST_TMO,       "fast_io_fail_tmo=%d"   },
        { NVMF_OPT_DISCOVERY,           "discovery"             },
 +#ifdef CONFIG_NVME_HOST_AUTH
        { NVMF_OPT_DHCHAP_SECRET,       "dhchap_secret=%s"      },
        { NVMF_OPT_DHCHAP_CTRL_SECRET,  "dhchap_ctrl_secret=%s" },
 +#endif
  #ifdef CONFIG_NVME_TCP_TLS
        { NVMF_OPT_TLS,                 "tls"                   },
  #endif
diff --combined drivers/nvme/host/fc.c
index 1d51925ea67fd166413cd38a8ce2ffd9ce060175,a719ca2cd406b13207ec584672b6afd92fbbbc7f..043f2d7798c1150f255c975524338dceea1cb7d1
@@@ -557,7 -557,7 +557,7 @@@ nvme_fc_rport_get(struct nvme_fc_rport 
  static void
  nvme_fc_resume_controller(struct nvme_fc_ctrl *ctrl)
  {
 -      switch (ctrl->ctrl.state) {
 +      switch (nvme_ctrl_state(&ctrl->ctrl)) {
        case NVME_CTRL_NEW:
        case NVME_CTRL_CONNECTING:
                /*
@@@ -793,7 -793,7 +793,7 @@@ nvme_fc_ctrl_connectivity_loss(struct n
                "NVME-FC{%d}: controller connectivity lost. Awaiting "
                "Reconnect", ctrl->cnum);
  
 -      switch (ctrl->ctrl.state) {
 +      switch (nvme_ctrl_state(&ctrl->ctrl)) {
        case NVME_CTRL_NEW:
        case NVME_CTRL_LIVE:
                /*
@@@ -1218,10 -1218,10 +1218,10 @@@ nvme_fc_connect_admin_queue(struct nvme
        /* Linux supports only Dynamic controllers */
        assoc_rqst->assoc_cmd.cntlid = cpu_to_be16(0xffff);
        uuid_copy(&assoc_rqst->assoc_cmd.hostid, &ctrl->ctrl.opts->host->id);
-       strncpy(assoc_rqst->assoc_cmd.hostnqn, ctrl->ctrl.opts->host->nqn,
-               min(FCNVME_ASSOC_HOSTNQN_LEN, NVMF_NQN_SIZE));
-       strncpy(assoc_rqst->assoc_cmd.subnqn, ctrl->ctrl.opts->subsysnqn,
-               min(FCNVME_ASSOC_SUBNQN_LEN, NVMF_NQN_SIZE));
+       strscpy(assoc_rqst->assoc_cmd.hostnqn, ctrl->ctrl.opts->host->nqn,
+               sizeof(assoc_rqst->assoc_cmd.hostnqn));
+       strscpy(assoc_rqst->assoc_cmd.subnqn, ctrl->ctrl.opts->subsysnqn,
+               sizeof(assoc_rqst->assoc_cmd.subnqn));
  
        lsop->queue = queue;
        lsreq->rqstaddr = assoc_rqst;
@@@ -2530,6 -2530,12 +2530,6 @@@ __nvme_fc_abort_outstanding_ios(struct 
         * clean up the admin queue. Same thing as above.
         */
        nvme_quiesce_admin_queue(&ctrl->ctrl);
 -
 -      /*
 -       * Open-coding nvme_cancel_admin_tagset() as fc
 -       * is not using nvme_cancel_request().
 -       */
 -      nvme_stop_keep_alive(&ctrl->ctrl);
        blk_sync_queue(ctrl->ctrl.admin_q);
        blk_mq_tagset_busy_iter(&ctrl->admin_tag_set,
                                nvme_fc_terminate_exchange, &ctrl->ctrl);
@@@ -2548,17 -2554,24 +2548,17 @@@ nvme_fc_error_recovery(struct nvme_fc_c
         * the controller.  Abort any ios on the association and let the
         * create_association error path resolve things.
         */
 -      enum nvme_ctrl_state state;
 -      unsigned long flags;
 -
 -      spin_lock_irqsave(&ctrl->lock, flags);
 -      state = ctrl->ctrl.state;
 -      if (state == NVME_CTRL_CONNECTING) {
 -              set_bit(ASSOC_FAILED, &ctrl->flags);
 -              spin_unlock_irqrestore(&ctrl->lock, flags);
 +      if (ctrl->ctrl.state == NVME_CTRL_CONNECTING) {
                __nvme_fc_abort_outstanding_ios(ctrl, true);
 +              set_bit(ASSOC_FAILED, &ctrl->flags);
                dev_warn(ctrl->ctrl.device,
                        "NVME-FC{%d}: transport error during (re)connect\n",
                        ctrl->cnum);
                return;
        }
 -      spin_unlock_irqrestore(&ctrl->lock, flags);
  
        /* Otherwise, only proceed if in LIVE state - e.g. on first error */
 -      if (state != NVME_CTRL_LIVE)
 +      if (ctrl->ctrl.state != NVME_CTRL_LIVE)
                return;
  
        dev_warn(ctrl->ctrl.device,
@@@ -3125,12 -3138,11 +3125,12 @@@ nvme_fc_create_association(struct nvme_
        nvme_unquiesce_admin_queue(&ctrl->ctrl);
  
        ret = nvme_init_ctrl_finish(&ctrl->ctrl, false);
 -      if (!ret && test_bit(ASSOC_FAILED, &ctrl->flags))
 -              ret = -EIO;
        if (ret)
                goto out_disconnect_admin_queue;
 -
 +      if (test_bit(ASSOC_FAILED, &ctrl->flags)) {
 +              ret = -EIO;
 +              goto out_stop_keep_alive;
 +      }
        /* sanity checks */
  
        /* FC-NVME does not have other data in the capsule */
                dev_err(ctrl->ctrl.device, "icdoff %d is not supported!\n",
                                ctrl->ctrl.icdoff);
                ret = NVME_SC_INVALID_FIELD | NVME_SC_DNR;
 -              goto out_disconnect_admin_queue;
 +              goto out_stop_keep_alive;
        }
  
        /* FC-NVME supports normal SGL Data Block Descriptors */
                dev_err(ctrl->ctrl.device,
                        "Mandatory sgls are not supported!\n");
                ret = NVME_SC_INVALID_FIELD | NVME_SC_DNR;
 -              goto out_disconnect_admin_queue;
 +              goto out_stop_keep_alive;
        }
  
        if (opts->queue_size > ctrl->ctrl.maxcmd) {
                else
                        ret = nvme_fc_recreate_io_queues(ctrl);
        }
 -
 -      spin_lock_irqsave(&ctrl->lock, flags);
        if (!ret && test_bit(ASSOC_FAILED, &ctrl->flags))
                ret = -EIO;
 -      if (ret) {
 -              spin_unlock_irqrestore(&ctrl->lock, flags);
 +      if (ret)
                goto out_term_aen_ops;
 -      }
 +
        changed = nvme_change_ctrl_state(&ctrl->ctrl, NVME_CTRL_LIVE);
 -      spin_unlock_irqrestore(&ctrl->lock, flags);
  
        ctrl->ctrl.nr_reconnects = 0;
  
  
  out_term_aen_ops:
        nvme_fc_term_aen_ops(ctrl);
 +out_stop_keep_alive:
 +      nvme_stop_keep_alive(&ctrl->ctrl);
  out_disconnect_admin_queue:
        dev_warn(ctrl->ctrl.device,
                "NVME-FC{%d}: create_assoc failed, assoc_id %llx ret %d\n",
@@@ -3308,7 -3322,7 +3308,7 @@@ nvme_fc_reconnect_or_delete(struct nvme
        unsigned long recon_delay = ctrl->ctrl.opts->reconnect_delay * HZ;
        bool recon = true;
  
 -      if (ctrl->ctrl.state != NVME_CTRL_CONNECTING)
 +      if (nvme_ctrl_state(&ctrl->ctrl) != NVME_CTRL_CONNECTING)
                return;
  
        if (portptr->port_state == FC_OBJSTATE_ONLINE) {
diff --combined fs/afs/internal.h
index e33ace259cc618439d1a3cfc6f0e0098910412dd,9d6f1aa65776a4b976ef696e9bbf1b0861f8c605..55aa0679d8cec4b349424239852372e39b656395
@@@ -33,7 -33,6 +33,7 @@@
  struct pagevec;
  struct afs_call;
  struct afs_vnode;
 +struct afs_server_probe;
  
  /*
   * Partial file-locking emulation mode.  (The problem being that AFS3 only
@@@ -73,34 -72,6 +73,34 @@@ enum afs_call_state 
        AFS_CALL_COMPLETE,              /* Completed or failed */
  };
  
 +/*
 + * Address preferences.
 + */
 +struct afs_addr_preference {
 +      union {
 +              struct in_addr  ipv4_addr;      /* AF_INET address to compare against */
 +              struct in6_addr ipv6_addr;      /* AF_INET6 address to compare against */
 +      };
 +      sa_family_t             family;         /* Which address to use */
 +      u16                     prio;           /* Priority */
 +      u8                      subnet_mask;    /* How many bits to compare */
 +};
 +
 +struct afs_addr_preference_list {
 +      struct rcu_head         rcu;
 +      u16                     version;        /* Incremented when prefs list changes */
 +      u8                      ipv6_off;       /* Offset of IPv6 addresses */
 +      u8                      nr;             /* Number of addresses in total */
 +      u8                      max_prefs;      /* Number of prefs allocated */
 +      struct afs_addr_preference prefs[] __counted_by(max_prefs);
 +};
 +
 +struct afs_address {
 +      struct rxrpc_peer       *peer;
 +      short                   last_error;     /* Last error from this address */
 +      u16                     prio;           /* Address priority */
 +};
 +
  /*
   * List of server addresses.
   */
@@@ -108,17 -79,15 +108,17 @@@ struct afs_addr_list 
        struct rcu_head         rcu;
        refcount_t              usage;
        u32                     version;        /* Version */
 +      unsigned int            debug_id;
 +      unsigned int            addr_pref_version; /* Version of address preference list */
        unsigned char           max_addrs;
        unsigned char           nr_addrs;
        unsigned char           preferred;      /* Preferred address */
        unsigned char           nr_ipv4;        /* Number of IPv4 addresses */
        enum dns_record_source  source:8;
        enum dns_lookup_status  status:8;
 -      unsigned long           failed;         /* Mask of addrs that failed locally/ICMP */
 +      unsigned long           probe_failed;   /* Mask of addrs that failed locally/ICMP */
        unsigned long           responded;      /* Mask of addrs that responded */
 -      struct sockaddr_rxrpc   addrs[] __counted_by(max_addrs);
 +      struct afs_address      addrs[] __counted_by(max_addrs);
  #define AFS_MAX_ADDRESSES ((unsigned int)(sizeof(unsigned long) * 8))
  };
  
   */
  struct afs_call {
        const struct afs_call_type *type;       /* type of call */
 -      struct afs_addr_list    *alist;         /* Address is alist[addr_ix] */
        wait_queue_head_t       waitq;          /* processes awaiting completion */
        struct work_struct      async_work;     /* async I/O processor */
        struct work_struct      work;           /* actual work processor */
        struct rxrpc_call       *rxcall;        /* RxRPC call handle */
 +      struct rxrpc_peer       *peer;          /* Remote endpoint */
        struct key              *key;           /* security for this call */
        struct afs_net          *net;           /* The network namespace */
        struct afs_server       *server;        /* The fileserver record if fs op (pins ref) */
        };
        void                    *buffer;        /* reply receive buffer */
        union {
 -              long                    ret0;   /* Value to reply with instead of 0 */
 +              struct afs_endpoint_state *probe;
 +              struct afs_addr_list    *vl_probe;
                struct afs_addr_list    *ret_alist;
                struct afs_vldb_entry   *ret_vldb;
                char                    *ret_str;
        };
 +      struct afs_fid          fid;            /* Primary vnode ID (or all zeroes) */
 +      unsigned char           probe_index;    /* Address in ->probe_alist */
        struct afs_operation    *op;
        unsigned int            server_index;
        refcount_t              ref;
        unsigned                reply_max;      /* maximum size of reply */
        unsigned                count2;         /* count used in unmarshalling */
        unsigned char           unmarshall;     /* unmarshalling phase */
 -      unsigned char           addr_ix;        /* Address in ->alist */
        bool                    drop_ref;       /* T if need to drop ref for incoming call */
        bool                    need_attention; /* T if RxRPC poked us */
        bool                    async;          /* T if asynchronous */
        bool                    upgrade;        /* T to request service upgrade */
        bool                    intr;           /* T if interruptible */
        bool                    unmarshalling_error; /* T if an unmarshalling error occurred */
 +      bool                    responded;      /* Got a response from the call (may be abort) */
        u16                     service_id;     /* Actual service ID (after upgrade) */
        unsigned int            debug_id;       /* Trace ID */
        u32                     operation_ID;   /* operation ID for an incoming call */
@@@ -340,8 -306,6 +340,8 @@@ struct afs_net 
        struct proc_dir_entry   *proc_afs;      /* /proc/net/afs directory */
        struct afs_sysnames     *sysnames;
        rwlock_t                sysnames_lock;
 +      struct afs_addr_preference_list __rcu *address_prefs;
 +      u16                     address_pref_version;
  
        /* Statistics counters */
        atomic_t                n_lookup;       /* Number of lookups done */
@@@ -415,7 -379,6 +415,7 @@@ struct afs_cell 
        unsigned int            debug_id;
  
        /* The volumes belonging to this cell */
 +      struct rw_semaphore     vs_lock;        /* Lock for server->volumes */
        struct rb_root          volumes;        /* Tree of volumes on this server */
        struct hlist_head       proc_volumes;   /* procfs volume list */
        seqlock_t               volume_lock;    /* For volumes */
        /* Active fileserver interaction state. */
        struct rb_root          fs_servers;     /* afs_server (by server UUID) */
        seqlock_t               fs_lock;        /* For fs_servers  */
 -      struct rw_semaphore     fs_open_mmaps_lock;
 -      struct list_head        fs_open_mmaps;  /* List of vnodes that are mmapped */
 -      atomic_t                fs_s_break;     /* Counter of CB.InitCallBackState messages */
  
        /* VL server list. */
        rwlock_t                vl_servers_lock; /* Lock on vl_servers */
@@@ -446,14 -412,13 +446,14 @@@ struct afs_vlserver 
        rwlock_t                lock;           /* Lock on addresses */
        refcount_t              ref;
        unsigned int            rtt;            /* Server's current RTT in uS */
 +      unsigned int            debug_id;
  
        /* Probe state */
        wait_queue_head_t       probe_wq;
        atomic_t                probe_outstanding;
        spinlock_t              probe_lock;
        struct {
 -              unsigned int    rtt;            /* RTT in uS */
 +              unsigned int    rtt;            /* Best RTT in uS (or UINT_MAX) */
                u32             abort_code;
                short           error;
                unsigned short  flags;
  #define AFS_VLSERVER_PROBE_LOCAL_FAILURE      0x08 /* A local failure prevented a probe */
        } probe;
  
 +      u16                     service_id;     /* Service ID we're using */
        u16                     port;
        u16                     name_len;       /* Length of name */
        char                    name[];         /* Server name, case-flattened */
@@@ -513,39 -477,12 +513,39 @@@ struct afs_vldb_entry 
  #define AFS_VOL_VTM_RW        0x01 /* R/W version of the volume is available (on this server) */
  #define AFS_VOL_VTM_RO        0x02 /* R/O version of the volume is available (on this server) */
  #define AFS_VOL_VTM_BAK       0x04 /* backup version of the volume is available (on this server) */
 +      u8                      vlsf_flags[AFS_NMAXNSERVERS];
        short                   error;
        u8                      nr_servers;     /* Number of server records */
        u8                      name_len;
        u8                      name[AFS_MAXVOLNAME + 1]; /* NUL-padded volume name */
  };
  
 +/*
 + * Fileserver endpoint state.  The records the addresses of a fileserver's
 + * endpoints and the state and result of a round of probing on them.  This
 + * allows the rotation algorithm to access those results without them being
 + * erased by a subsequent round of probing.
 + */
 +struct afs_endpoint_state {
 +      struct rcu_head         rcu;
 +      struct afs_addr_list    *addresses;     /* The addresses being probed */
 +      unsigned long           responsive_set; /* Bitset of responsive endpoints */
 +      unsigned long           failed_set;     /* Bitset of endpoints we failed to probe */
 +      refcount_t              ref;
 +      unsigned int            server_id;      /* Debug ID of server */
 +      unsigned int            probe_seq;      /* Probe sequence (from server::probe_counter) */
 +      atomic_t                nr_probing;     /* Number of outstanding probes */
 +      unsigned int            rtt;            /* Best RTT in uS (or UINT_MAX) */
 +      s32                     abort_code;
 +      short                   error;
 +      unsigned long           flags;
 +#define AFS_ESTATE_RESPONDED  0               /* Set if the server responded */
 +#define AFS_ESTATE_SUPERSEDED 1               /* Set if this record has been superseded */
 +#define AFS_ESTATE_IS_YFS     2               /* Set if probe upgraded to YFS */
 +#define AFS_ESTATE_NOT_YFS    3               /* Set if probe didn't upgrade to YFS */
 +#define AFS_ESTATE_LOCAL_FAILURE 4            /* Set if there was a local failure (eg. ENOMEM) */
 +};
 +
  /*
   * Record of fileserver with which we're actively communicating.
   */
@@@ -556,6 -493,7 +556,6 @@@ struct afs_server 
                struct afs_uuid _uuid;
        };
  
 -      struct afs_addr_list    __rcu *addresses;
        struct afs_cell         *cell;          /* Cell to which belongs (pins ref) */
        struct rb_node          uuid_rb;        /* Link in net->fs_servers */
        struct afs_server __rcu *uuid_next;     /* Next server with same UUID */
        struct hlist_node       addr4_link;     /* Link in net->fs_addresses4 */
        struct hlist_node       addr6_link;     /* Link in net->fs_addresses6 */
        struct hlist_node       proc_link;      /* Link in net->fs_proc */
 -      struct work_struct      initcb_work;    /* Work for CB.InitCallBackState* */
 +      struct list_head        volumes;        /* RCU list of afs_server_entry objects */
        struct afs_server       *gc_next;       /* Next server in manager's list */
        time64_t                unuse_time;     /* Time at which last unused */
        unsigned long           flags;
        refcount_t              ref;            /* Object refcount */
        atomic_t                active;         /* Active user count */
        u32                     addr_version;   /* Address list version */
 +      u16                     service_id;     /* Service ID we're using. */
        unsigned int            rtt;            /* Server's current RTT in uS */
        unsigned int            debug_id;       /* Debugging ID for traces */
  
        /* file service access */
        rwlock_t                fs_lock;        /* access lock */
  
 -      /* callback promise management */
 -      unsigned                cb_s_break;     /* Break-everything counter. */
 -
        /* Probe state */
 +      struct afs_endpoint_state __rcu *endpoint_state; /* Latest endpoint/probe state */
        unsigned long           probed_at;      /* Time last probe was dispatched (jiffies) */
        wait_queue_head_t       probe_wq;
 -      atomic_t                probe_outstanding;
 +      unsigned int            probe_counter;  /* Number of probes issued */
        spinlock_t              probe_lock;
 -      struct {
 -              unsigned int    rtt;            /* RTT in uS */
 -              u32             abort_code;
 -              short           error;
 -              bool            responded:1;
 -              bool            is_yfs:1;
 -              bool            not_yfs:1;
 -              bool            local_failure:1;
 -      } probe;
  };
  
 +enum afs_ro_replicating {
 +      AFS_RO_NOT_REPLICATING,                 /* Not doing replication */
 +      AFS_RO_REPLICATING_USE_OLD,             /* Replicating; use old version */
 +      AFS_RO_REPLICATING_USE_NEW,             /* Replicating; switch to new version */
 +} __mode(byte);
 +
  /*
   * Replaceable volume server list.
   */
  struct afs_server_entry {
        struct afs_server       *server;
 +      struct afs_volume       *volume;
 +      struct list_head        slink;          /* Link in server->volumes */
 +      time64_t                cb_expires_at;  /* Time at which volume-level callback expires */
 +      unsigned long           flags;
 +#define AFS_SE_EXCLUDED               0               /* Set if server is to be excluded in rotation */
 +#define AFS_SE_VOLUME_OFFLINE 1               /* Set if volume offline notice given */
 +#define AFS_SE_VOLUME_BUSY    2               /* Set if volume busy notice given */
  };
  
  struct afs_server_list {
 -      afs_volid_t             vids[AFS_MAXTYPES]; /* Volume IDs */
 +      struct rcu_head         rcu;
        refcount_t              usage;
 +      bool                    attached;       /* T if attached to servers */
 +      enum afs_ro_replicating ro_replicating; /* RW->RO update (probably) in progress */
        unsigned char           nr_servers;
 -      unsigned char           preferred;      /* Preferred server */
        unsigned short          vnovol_mask;    /* Servers to be skipped due to VNOVOL */
        unsigned int            seq;            /* Set to ->servers_seq when installed */
        rwlock_t                lock;
   * Live AFS volume management.
   */
  struct afs_volume {
 -      union {
 -              struct rcu_head rcu;
 -              afs_volid_t     vid;            /* volume ID */
 -      };
 +      struct rcu_head rcu;
 +      afs_volid_t             vid;            /* The volume ID of this volume */
 +      afs_volid_t             vids[AFS_MAXTYPES]; /* All associated volume IDs */
        refcount_t              ref;
        time64_t                update_at;      /* Time at which to next update */
        struct afs_cell         *cell;          /* Cell to which belongs (pins ref) */
        struct rb_node          cell_node;      /* Link in cell->volumes */
        struct hlist_node       proc_link;      /* Link in cell->proc_volumes */
        struct super_block __rcu *sb;           /* Superblock on which inodes reside */
 +      struct work_struct      destructor;     /* Deferred destructor */
        unsigned long           flags;
  #define AFS_VOLUME_NEEDS_UPDATE       0       /* - T if an update needs performing */
  #define AFS_VOLUME_UPDATING   1       /* - T if an update is in progress */
  #define AFS_VOLUME_WAIT               2       /* - T if users must wait for update */
  #define AFS_VOLUME_DELETED    3       /* - T if volume appears deleted */
 -#define AFS_VOLUME_OFFLINE    4       /* - T if volume offline notice given */
 -#define AFS_VOLUME_BUSY               5       /* - T if volume busy notice given */
 -#define AFS_VOLUME_MAYBE_NO_IBULK 6   /* - T if some servers don't have InlineBulkStatus */
 +#define AFS_VOLUME_MAYBE_NO_IBULK 4   /* - T if some servers don't have InlineBulkStatus */
 +#define AFS_VOLUME_RM_TREE    5       /* - Set if volume removed from cell->volumes */
  #ifdef CONFIG_AFS_FSCACHE
        struct fscache_volume   *cache;         /* Caching cookie */
  #endif
        rwlock_t                servers_lock;   /* Lock for ->servers */
        unsigned int            servers_seq;    /* Incremented each time ->servers changes */
  
 -      unsigned                cb_v_break;     /* Break-everything counter. */
 +      /* RO release tracking */
 +      struct mutex            volsync_lock;   /* Time/state evaluation lock */
 +      time64_t                creation_time;  /* Volume creation time (or TIME64_MIN) */
 +      time64_t                update_time;    /* Volume update time (or TIME64_MIN) */
 +
 +      /* Callback management */
 +      struct mutex            cb_check_lock;  /* Lock to control race to check after v_break */
 +      time64_t                cb_expires_at;  /* Earliest volume callback expiry time */
 +      atomic_t                cb_ro_snapshot; /* RO volume update-from-snapshot counter */
 +      atomic_t                cb_v_break;     /* Volume-break event counter. */
 +      atomic_t                cb_v_check;     /* Volume-break has-been-checked counter. */
 +      atomic_t                cb_scrub;       /* Scrub-all-data event counter. */
        rwlock_t                cb_v_break_lock;
 +      struct rw_semaphore     open_mmaps_lock;
 +      struct list_head        open_mmaps;     /* List of vnodes that are mmapped */
  
        afs_voltype_t           type;           /* type of volume */
        char                    type_force;     /* force volume type (suppress R/O -> R/W) */
@@@ -710,6 -632,7 +710,6 @@@ struct afs_vnode 
        spinlock_t              wb_lock;        /* lock for wb_keys */
        spinlock_t              lock;           /* waitqueue/flags lock */
        unsigned long           flags;
 -#define AFS_VNODE_CB_PROMISED 0               /* Set if vnode has a callback promise */
  #define AFS_VNODE_UNSET               1               /* set if vnode attributes not yet set */
  #define AFS_VNODE_DIR_VALID   2               /* Set if dir contents are valid */
  #define AFS_VNODE_ZAP_DATA    3               /* set if vnode's data should be invalidated */
        struct list_head        cb_mmap_link;   /* Link in cell->fs_open_mmaps */
        void                    *cb_server;     /* Server with callback/filelock */
        atomic_t                cb_nr_mmap;     /* Number of mmaps */
 -      unsigned int            cb_fs_s_break;  /* Mass server break counter (cell->fs_s_break) */
 -      unsigned int            cb_s_break;     /* Mass break counter on ->server */
 -      unsigned int            cb_v_break;     /* Mass break counter on ->volume */
 +      unsigned int            cb_ro_snapshot; /* RO volume release counter on ->volume */
 +      unsigned int            cb_scrub;       /* Scrub counter on ->volume */
        unsigned int            cb_break;       /* Break counter on vnode */
 +      unsigned int            cb_v_check;     /* Break check counter on ->volume */
        seqlock_t               cb_lock;        /* Lock for ->cb_server, ->status, ->cb_*break */
  
 -      time64_t                cb_expires_at;  /* time at which callback expires */
 +      atomic64_t              cb_expires_at;  /* time at which callback expires */
 +#define AFS_NO_CB_PROMISE TIME64_MIN
  };
  
  static inline struct fscache_cookie *afs_vnode_cache(struct afs_vnode *vnode)
@@@ -790,49 -712,40 +790,49 @@@ struct afs_permits 
   * Error prioritisation and accumulation.
   */
  struct afs_error {
 -      short   error;                  /* Accumulated error */
 +      s32     abort_code;             /* Cumulative abort code */
 +      short   error;                  /* Cumulative error */
        bool    responded;              /* T if server responded */
 -};
 -
 -/*
 - * Cursor for iterating over a server's address list.
 - */
 -struct afs_addr_cursor {
 -      struct afs_addr_list    *alist;         /* Current address list (pins ref) */
 -      unsigned long           tried;          /* Tried addresses */
 -      signed char             index;          /* Current address */
 -      bool                    responded;      /* T if the current address responded */
 -      unsigned short          nr_iterations;  /* Number of address iterations */
 -      short                   error;
 -      u32                     abort_code;
 +      bool    aborted;                /* T if ->error is from an abort */
  };
  
  /*
   * Cursor for iterating over a set of volume location servers.
   */
  struct afs_vl_cursor {
 -      struct afs_addr_cursor  ac;
        struct afs_cell         *cell;          /* The cell we're querying */
        struct afs_vlserver_list *server_list;  /* Current server list (pins ref) */
        struct afs_vlserver     *server;        /* Server on which this resides */
 +      struct afs_addr_list    *alist;         /* Current address list (pins ref) */
        struct key              *key;           /* Key for the server */
 -      unsigned long           untried;        /* Bitmask of untried servers */
 -      short                   index;          /* Current server */
 -      short                   error;
 +      unsigned long           untried_servers; /* Bitmask of untried servers */
 +      unsigned long           addr_tried;     /* Tried addresses */
 +      struct afs_error        cumul_error;    /* Cumulative error */
 +      unsigned int            debug_id;
 +      s32                     call_abort_code;
 +      short                   call_error;     /* Error from single call */
 +      short                   server_index;   /* Current server */
 +      signed char             addr_index;     /* Current address */
        unsigned short          flags;
  #define AFS_VL_CURSOR_STOP    0x0001          /* Set to cease iteration */
  #define AFS_VL_CURSOR_RETRY   0x0002          /* Set to do a retry */
  #define AFS_VL_CURSOR_RETRIED 0x0004          /* Set if started a retry */
 -      unsigned short          nr_iterations;  /* Number of server iterations */
 +      short                   nr_iterations;  /* Number of server iterations */
 +      bool                    call_responded; /* T if the current address responded */
 +};
 +
 +/*
 + * Fileserver state tracking for an operation.  An array of these is kept,
 + * indexed by server index.
 + */
 +struct afs_server_state {
 +      /* Tracking of fileserver probe state.  Other operations may interfere
 +       * by probing a fileserver when accessing other volumes.
 +       */
 +      unsigned int            probe_seq;
 +      unsigned long           untried_addrs;  /* Addresses we haven't tried yet */
 +      struct wait_queue_entry probe_waiter;
 +      struct afs_endpoint_state *endpoint_state; /* Endpoint state being monitored */
  };
  
  /*
@@@ -853,7 -766,7 +853,7 @@@ struct afs_vnode_param 
        struct afs_fid          fid;            /* Fid to access */
        struct afs_status_cb    scb;            /* Returned status and callback promise */
        afs_dataversion_t       dv_before;      /* Data version before the call */
 -      unsigned int            cb_break_before; /* cb_break + cb_s_break before the call */
 +      unsigned int            cb_break_before; /* cb_break before the call */
        u8                      dv_delta;       /* Expected change in data version */
        bool                    put_vnode:1;    /* T if we have a ref on the vnode */
        bool                    need_io_lock:1; /* T if we need the I/O lock on this */
@@@ -878,17 -791,17 +878,17 @@@ struct afs_operation 
        struct afs_volume       *volume;        /* Volume being accessed */
        struct afs_vnode_param  file[2];
        struct afs_vnode_param  *more_files;
 -      struct afs_volsync      volsync;
 +      struct afs_volsync      pre_volsync;    /* Volsync before op */
 +      struct afs_volsync      volsync;        /* Volsync returned by op */
        struct dentry           *dentry;        /* Dentry to be altered */
        struct dentry           *dentry_2;      /* Second dentry to be altered */
        struct timespec64       mtime;          /* Modification time to record */
        struct timespec64       ctime;          /* Change time to set */
 +      struct afs_error        cumul_error;    /* Cumulative error */
        short                   nr_files;       /* Number of entries in file[], more_files */
 -      short                   error;
        unsigned int            debug_id;
  
        unsigned int            cb_v_break;     /* Volume break counter before op */
 -      unsigned int            cb_s_break;     /* Server break counter before op */
  
        union {
                struct {
        };
  
        /* Fileserver iteration state */
 -      struct afs_addr_cursor  ac;
        struct afs_server_list  *server_list;   /* Current server list (pins ref) */
        struct afs_server       *server;        /* Server we're using (ref pinned by server_list) */
 +      struct afs_endpoint_state *estate;      /* Current endpoint state (doesn't pin ref) */
 +      struct afs_server_state *server_states; /* States of the servers involved */
        struct afs_call         *call;
 -      unsigned long           untried;        /* Bitmask of untried servers */
 -      short                   index;          /* Current server */
 -      unsigned short          nr_iterations;  /* Number of server iterations */
 +      unsigned long           untried_servers; /* Bitmask of untried servers */
 +      unsigned long           addr_tried;     /* Tried addresses */
 +      s32                     call_abort_code; /* Abort code from single call */
 +      short                   call_error;     /* Error from single call */
 +      short                   server_index;   /* Current server */
 +      short                   nr_iterations;  /* Number of server iterations */
 +      signed char             addr_index;     /* Current address */
 +      bool                    call_responded; /* T if the current address responded */
  
        unsigned int            flags;
  #define AFS_OPERATION_STOP            0x0001  /* Set to cease iteration */
@@@ -1047,32 -954,31 +1047,32 @@@ static inline bool afs_is_folio_dirty_m
  /*
   * addr_list.c
   */
 -static inline struct afs_addr_list *afs_get_addrlist(struct afs_addr_list *alist)
 -{
 -      if (alist)
 -              refcount_inc(&alist->usage);
 -      return alist;
 -}
 -extern struct afs_addr_list *afs_alloc_addrlist(unsigned int,
 -                                              unsigned short,
 -                                              unsigned short);
 -extern void afs_put_addrlist(struct afs_addr_list *);
 +struct afs_addr_list *afs_get_addrlist(struct afs_addr_list *alist, enum afs_alist_trace reason);
 +extern struct afs_addr_list *afs_alloc_addrlist(unsigned int nr);
 +extern void afs_put_addrlist(struct afs_addr_list *alist, enum afs_alist_trace reason);
  extern struct afs_vlserver_list *afs_parse_text_addrs(struct afs_net *,
                                                      const char *, size_t, char,
                                                      unsigned short, unsigned short);
 +bool afs_addr_list_same(const struct afs_addr_list *a,
 +                      const struct afs_addr_list *b);
  extern struct afs_vlserver_list *afs_dns_query(struct afs_cell *, time64_t *);
 -extern bool afs_iterate_addresses(struct afs_addr_cursor *);
 -extern int afs_end_cursor(struct afs_addr_cursor *);
  
 -extern void afs_merge_fs_addr4(struct afs_addr_list *, __be32, u16);
 -extern void afs_merge_fs_addr6(struct afs_addr_list *, __be32 *, u16);
 +extern int afs_merge_fs_addr4(struct afs_net *net, struct afs_addr_list *addr,
 +                            __be32 xdr, u16 port);
 +extern int afs_merge_fs_addr6(struct afs_net *net, struct afs_addr_list *addr,
 +                            __be32 *xdr, u16 port);
 +
 +/*
 + * addr_prefs.c
 + */
 +int afs_proc_addr_prefs_write(struct file *file, char *buf, size_t size);
 +void afs_get_address_preferences_rcu(struct afs_net *net, struct afs_addr_list *alist);
 +void afs_get_address_preferences(struct afs_net *net, struct afs_addr_list *alist);
  
  /*
   * callback.c
   */
  extern void afs_invalidate_mmap_work(struct work_struct *);
 -extern void afs_server_init_callback_work(struct work_struct *work);
  extern void afs_init_callback_state(struct afs_server *);
  extern void __afs_break_callback(struct afs_vnode *, enum afs_cb_break_reason);
  extern void afs_break_callback(struct afs_vnode *, enum afs_cb_break_reason);
@@@ -1080,15 -986,13 +1080,15 @@@ extern void afs_break_callbacks(struct 
  
  static inline unsigned int afs_calc_vnode_cb_break(struct afs_vnode *vnode)
  {
 -      return vnode->cb_break + vnode->cb_v_break;
 +      return vnode->cb_break + vnode->cb_ro_snapshot + vnode->cb_scrub;
  }
  
  static inline bool afs_cb_is_broken(unsigned int cb_break,
                                    const struct afs_vnode *vnode)
  {
 -      return cb_break != (vnode->cb_break + vnode->volume->cb_v_break);
 +      return cb_break != (vnode->cb_break +
 +                          atomic_read(&vnode->volume->cb_ro_snapshot) +
 +                          atomic_read(&vnode->volume->cb_scrub));
  }
  
  /*
@@@ -1204,16 -1108,15 +1204,16 @@@ extern void afs_fs_get_volume_status(st
  extern void afs_fs_set_lock(struct afs_operation *);
  extern void afs_fs_extend_lock(struct afs_operation *);
  extern void afs_fs_release_lock(struct afs_operation *);
 -extern int afs_fs_give_up_all_callbacks(struct afs_net *, struct afs_server *,
 -                                      struct afs_addr_cursor *, struct key *);
 -extern bool afs_fs_get_capabilities(struct afs_net *, struct afs_server *,
 -                                  struct afs_addr_cursor *, struct key *);
 +int afs_fs_give_up_all_callbacks(struct afs_net *net, struct afs_server *server,
 +                               struct afs_address *addr, struct key *key);
 +bool afs_fs_get_capabilities(struct afs_net *net, struct afs_server *server,
 +                           struct afs_endpoint_state *estate, unsigned int addr_index,
 +                           struct key *key);
  extern void afs_fs_inline_bulk_status(struct afs_operation *);
  
  struct afs_acl {
        u32     size;
-       u8      data[];
+       u8      data[] __counted_by(size);
  };
  
  extern void afs_fs_fetch_acl(struct afs_operation *);
@@@ -1228,6 -1131,11 +1228,6 @@@ extern bool afs_begin_vnode_operation(s
  extern void afs_wait_for_operation(struct afs_operation *);
  extern int afs_do_sync_operation(struct afs_operation *);
  
 -static inline void afs_op_nomem(struct afs_operation *op)
 -{
 -      op->error = -ENOMEM;
 -}
 -
  static inline void afs_op_set_vnode(struct afs_operation *op, unsigned int n,
                                    struct afs_vnode *vnode)
  {
@@@ -1244,17 -1152,12 +1244,17 @@@ static inline void afs_op_set_fid(struc
  /*
   * fs_probe.c
   */
 +struct afs_endpoint_state *afs_get_endpoint_state(struct afs_endpoint_state *estate,
 +                                                enum afs_estate_trace where);
 +void afs_put_endpoint_state(struct afs_endpoint_state *estate, enum afs_estate_trace where);
  extern void afs_fileserver_probe_result(struct afs_call *);
 -extern void afs_fs_probe_fileserver(struct afs_net *, struct afs_server *, struct key *, bool);
 -extern int afs_wait_for_fs_probes(struct afs_server_list *, unsigned long);
 +void afs_fs_probe_fileserver(struct afs_net *net, struct afs_server *server,
 +                           struct afs_addr_list *new_addrs, struct key *key);
 +int afs_wait_for_fs_probes(struct afs_operation *op, struct afs_server_state *states, bool intr);
  extern void afs_probe_fileserver(struct afs_net *, struct afs_server *);
  extern void afs_fs_probe_dispatcher(struct work_struct *);
 -extern int afs_wait_for_one_fs_probe(struct afs_server *, bool);
 +int afs_wait_for_one_fs_probe(struct afs_server *server, struct afs_endpoint_state *estate,
 +                            unsigned long exclude, bool is_intr);
  extern void afs_fs_probe_cleanup(struct afs_net *);
  
  /*
@@@ -1268,6 -1171,9 +1268,6 @@@ extern int afs_ilookup5_test_by_fid(str
  extern struct inode *afs_iget_pseudo_dir(struct super_block *, bool);
  extern struct inode *afs_iget(struct afs_operation *, struct afs_vnode_param *);
  extern struct inode *afs_root_iget(struct super_block *, struct key *);
 -extern bool afs_check_validity(struct afs_vnode *);
 -extern int afs_validate(struct afs_vnode *, struct key *);
 -bool afs_pagecache_valid(struct afs_vnode *);
  extern int afs_getattr(struct mnt_idmap *idmap, const struct path *,
                       struct kstat *, u32, unsigned int);
  extern int afs_setattr(struct mnt_idmap *idmap, struct dentry *, struct iattr *);
@@@ -1323,31 -1229,6 +1323,31 @@@ static inline void __afs_stat(atomic_t 
  extern int afs_abort_to_error(u32);
  extern void afs_prioritise_error(struct afs_error *, int, u32);
  
 +static inline void afs_op_nomem(struct afs_operation *op)
 +{
 +      op->cumul_error.error = -ENOMEM;
 +}
 +
 +static inline int afs_op_error(const struct afs_operation *op)
 +{
 +      return op->cumul_error.error;
 +}
 +
 +static inline s32 afs_op_abort_code(const struct afs_operation *op)
 +{
 +      return op->cumul_error.abort_code;
 +}
 +
 +static inline int afs_op_set_error(struct afs_operation *op, int error)
 +{
 +      return op->cumul_error.error = error;
 +}
 +
 +static inline void afs_op_accumulate_error(struct afs_operation *op, int error, s32 abort_code)
 +{
 +      afs_prioritise_error(&op->cumul_error, error, abort_code);
 +}
 +
  /*
   * mntpt.c
   */
@@@ -1378,7 -1259,6 +1378,7 @@@ static inline void afs_put_sysnames(str
  /*
   * rotate.c
   */
 +void afs_clear_server_states(struct afs_operation *op);
  extern bool afs_select_fileserver(struct afs_operation *);
  extern void afs_dump_edestaddrreq(const struct afs_operation *);
  
@@@ -1391,8 -1271,8 +1391,8 @@@ extern int __net_init afs_open_socket(s
  extern void __net_exit afs_close_socket(struct afs_net *);
  extern void afs_charge_preallocation(struct work_struct *);
  extern void afs_put_call(struct afs_call *);
 -extern void afs_make_call(struct afs_addr_cursor *, struct afs_call *, gfp_t);
 -extern long afs_wait_for_call_to_complete(struct afs_call *, struct afs_addr_cursor *);
 +void afs_make_call(struct afs_call *call, gfp_t gfp);
 +void afs_wait_for_call_to_complete(struct afs_call *call);
  extern struct afs_call *afs_alloc_flat_call(struct afs_net *,
                                            const struct afs_call_type *,
                                            size_t, size_t);
@@@ -1405,16 -1285,12 +1405,16 @@@ extern int afs_protocol_error(struct af
  static inline void afs_make_op_call(struct afs_operation *op, struct afs_call *call,
                                    gfp_t gfp)
  {
 -      op->call = call;
 -      op->type = call->type;
 -      call->op = op;
 -      call->key = op->key;
 -      call->intr = !(op->flags & AFS_OPERATION_UNINTR);
 -      afs_make_call(&op->ac, call, gfp);
 +      struct afs_addr_list *alist = op->estate->addresses;
 +
 +      op->call        = call;
 +      op->type        = call->type;
 +      call->op        = op;
 +      call->key       = op->key;
 +      call->intr      = !(op->flags & AFS_OPERATION_UNINTR);
 +      call->peer      = rxrpc_kernel_get_peer(alist->addrs[op->addr_index].peer);
 +      call->service_id = op->server->service_id;
 +      afs_make_call(call, gfp);
  }
  
  static inline void afs_extract_begin(struct afs_call *call, void *buf, size_t size)
@@@ -1523,7 -1399,8 +1523,7 @@@ extern void __exit afs_clean_up_permit_
   */
  extern spinlock_t afs_server_peer_lock;
  
 -extern struct afs_server *afs_find_server(struct afs_net *,
 -                                        const struct sockaddr_rxrpc *);
 +extern struct afs_server *afs_find_server(struct afs_net *, const struct rxrpc_peer *);
  extern struct afs_server *afs_find_server_by_uuid(struct afs_net *, const uuid_t *);
  extern struct afs_server *afs_lookup_server(struct afs_cell *, struct key *, const uuid_t *, u32);
  extern struct afs_server *afs_get_server(struct afs_server *, enum afs_server_trace);
@@@ -1535,7 -1412,7 +1535,7 @@@ extern void afs_manage_servers(struct w
  extern void afs_servers_timer(struct timer_list *);
  extern void afs_fs_probe_timer(struct timer_list *);
  extern void __net_exit afs_purge_servers(struct afs_net *);
 -extern bool afs_check_server_record(struct afs_operation *, struct afs_server *);
 +bool afs_check_server_record(struct afs_operation *op, struct afs_server *server, struct key *key);
  
  static inline void afs_inc_servers_outstanding(struct afs_net *net)
  {
@@@ -1563,14 -1440,10 +1563,14 @@@ static inline struct afs_server_list *a
  }
  
  extern void afs_put_serverlist(struct afs_net *, struct afs_server_list *);
 -extern struct afs_server_list *afs_alloc_server_list(struct afs_cell *, struct key *,
 -                                                   struct afs_vldb_entry *,
 -                                                   u8);
 +struct afs_server_list *afs_alloc_server_list(struct afs_volume *volume,
 +                                            struct key *key,
 +                                            struct afs_vldb_entry *vldb);
  extern bool afs_annotate_server_list(struct afs_server_list *, struct afs_server_list *);
 +void afs_attach_volume_to_servers(struct afs_volume *volume, struct afs_server_list *slist);
 +void afs_reattach_volume_to_servers(struct afs_volume *volume, struct afs_server_list *slist,
 +                                  struct afs_server_list *old);
 +void afs_detach_volume_from_servers(struct afs_volume *volume, struct afs_server_list *slist);
  
  /*
   * super.c
  extern int __init afs_fs_init(void);
  extern void afs_fs_exit(void);
  
 +/*
 + * validation.c
 + */
 +bool afs_check_validity(const struct afs_vnode *vnode);
 +int afs_update_volume_state(struct afs_operation *op);
 +int afs_validate(struct afs_vnode *vnode, struct key *key);
 +
  /*
   * vlclient.c
   */
  extern struct afs_vldb_entry *afs_vl_get_entry_by_name_u(struct afs_vl_cursor *,
                                                         const char *, int);
  extern struct afs_addr_list *afs_vl_get_addrs_u(struct afs_vl_cursor *, const uuid_t *);
 -extern struct afs_call *afs_vl_get_capabilities(struct afs_net *, struct afs_addr_cursor *,
 -                                              struct key *, struct afs_vlserver *, unsigned int);
 +struct afs_call *afs_vl_get_capabilities(struct afs_net *net,
 +                                       struct afs_addr_list *alist,
 +                                       unsigned int addr_index,
 +                                       struct key *key,
 +                                       struct afs_vlserver *server,
 +                                       unsigned int server_index);
  extern struct afs_addr_list *afs_yfsvl_get_endpoints(struct afs_vl_cursor *, const uuid_t *);
  extern char *afs_yfsvl_get_cell_name(struct afs_vl_cursor *);
  
@@@ -1650,9 -1512,8 +1650,9 @@@ extern struct afs_vlserver_list *afs_ex
  extern struct afs_volume *afs_create_volume(struct afs_fs_context *);
  extern int afs_activate_volume(struct afs_volume *);
  extern void afs_deactivate_volume(struct afs_volume *);
 +bool afs_try_get_volume(struct afs_volume *volume, enum afs_volume_trace reason);
  extern struct afs_volume *afs_get_volume(struct afs_volume *, enum afs_volume_trace);
 -extern void afs_put_volume(struct afs_net *, struct afs_volume *, enum afs_volume_trace);
 +void afs_put_volume(struct afs_volume *volume, enum afs_volume_trace reason);
  extern int afs_check_volume_status(struct afs_volume *, struct afs_operation *);
  
  /*
@@@ -1739,7 -1600,7 +1739,7 @@@ static inline void afs_update_dentry_ve
                                             struct afs_vnode_param *dir_vp,
                                             struct dentry *dentry)
  {
 -      if (!op->error)
 +      if (!op->cumul_error.error)
                dentry->d_fsdata =
                        (void *)(unsigned long)dir_vp->scb.status.data_version;
  }
This page took 0.163142 seconds and 4 git commands to generate.