]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
mds: avoid check session connection's features when issuing caps
authorYan, Zheng <zyan@redhat.com>
Mon, 11 Mar 2019 12:05:25 +0000 (20:05 +0800)
committerNathan Cutler <ncutler@suse.com>
Wed, 10 Apr 2019 21:54:44 +0000 (23:54 +0200)
Session connection can be null for imported session. The fix is
recording which features client does not support in cap when cap
is newly added.

Fixes: https://tracker.ceph.com/issues/38652
Signed-off-by: "Yan, Zheng" <zyan@redhat.com>
(cherry picked from commit 63410d858a5b52f485a270dbc4b58e45abf1e923)

src/mds/CInode.cc
src/mds/CInode.h
src/mds/Capability.cc
src/mds/Capability.h
src/mds/Locker.cc
src/mds/MDCache.cc

index 178533abf939cefc8edad1778c7400dbf361f1af..4f86399e6b7579944e80ebb289c1e583f3eb12e1 100644 (file)
@@ -3160,7 +3160,8 @@ int CInode::get_xlocker_mask(client_t client) const
     (linklock.gcaps_xlocker_mask(client) << linklock.get_cap_shift());
 }
 
-int CInode::get_caps_allowed_for_client(Session *session, mempool_inode *file_i) const
+int CInode::get_caps_allowed_for_client(Session *session, Capability *cap,
+                                       mempool_inode *file_i) const
 {
   client_t client = session->get_client();
   int allowed;
@@ -3174,13 +3175,23 @@ int CInode::get_caps_allowed_for_client(Session *session, mempool_inode *file_i)
   }
 
   if (!is_dir()) {
-    if ((file_i->inline_data.version != CEPH_INLINE_NONE &&
-        !session->get_connection()->has_feature(
-          CEPH_FEATURE_MDS_INLINE_DATA)) ||
-       (!file_i->layout.pool_ns.empty() &&
-        !session->get_connection()->has_feature(
-          CEPH_FEATURE_FS_FILE_LAYOUT_V2)))
-      allowed &= ~(CEPH_CAP_FILE_RD | CEPH_CAP_FILE_WR);
+    if (file_i->inline_data.version == CEPH_INLINE_NONE &&
+       file_i->layout.pool_ns.empty()) {
+      // noop
+    } else if (cap) {
+      if ((file_i->inline_data.version != CEPH_INLINE_NONE &&
+          cap->is_noinline()) ||
+         (!file_i->layout.pool_ns.empty() &&
+          cap->is_nopoolns()))
+       allowed &= ~(CEPH_CAP_FILE_RD | CEPH_CAP_FILE_WR);
+    } else {
+      auto& conn = session->get_connection();
+      if ((file_i->inline_data.version != CEPH_INLINE_NONE &&
+          !conn->has_feature(CEPH_FEATURE_MDS_INLINE_DATA)) ||
+         (!file_i->layout.pool_ns.empty() &&
+          !conn->has_feature(CEPH_FEATURE_FS_FILE_LAYOUT_V2)))
+       allowed &= ~(CEPH_CAP_FILE_RD | CEPH_CAP_FILE_WR);
+    }
   }
   return allowed;
 }
@@ -3475,7 +3486,7 @@ int CInode::encode_inodestat(bufferlist& bl, Session *session,
      */
     ecap.caps = valid ? get_caps_allowed_by_type(CAP_ANY) : CEPH_STAT_CAP_INODE;
     if (last == CEPH_NOSNAP || is_any_caps())
-      ecap.caps = ecap.caps & get_caps_allowed_for_client(session, file_i);
+      ecap.caps = ecap.caps & get_caps_allowed_for_client(session, nullptr, file_i);
     ecap.seq = 0;
     ecap.mseq = 0;
     ecap.realm = 0;
@@ -3490,7 +3501,7 @@ int CInode::encode_inodestat(bufferlist& bl, Session *session,
     int issue = 0;
     if (!no_caps && cap) {
       int likes = get_caps_liked();
-      int allowed = get_caps_allowed_for_client(session, file_i);
+      int allowed = get_caps_allowed_for_client(session, cap, file_i);
       issue = (cap->wanted() | likes) & allowed;
       cap->issue_norevoke(issue);
       issue = cap->pending();
@@ -3666,22 +3677,23 @@ int CInode::encode_inodestat(bufferlist& bl, Session *session,
     encode(file_i->rstat.rctime, bl);
     dirfragtree.encode(bl);
     encode(symlink, bl);
-    if (session->get_connection()->has_feature(CEPH_FEATURE_DIRLAYOUTHASH)) {
+    auto& conn = session->get_connection();
+    if (conn->has_feature(CEPH_FEATURE_DIRLAYOUTHASH)) {
       encode(file_i->dir_layout, bl);
     }
     encode_xattrs();
-    if (session->get_connection()->has_feature(CEPH_FEATURE_MDS_INLINE_DATA)) {
+    if (conn->has_feature(CEPH_FEATURE_MDS_INLINE_DATA)) {
       encode(inline_version, bl);
       encode(inline_data, bl);
     }
-    if (session->get_connection()->has_feature(CEPH_FEATURE_MDS_QUOTA)) {
+    if (conn->has_feature(CEPH_FEATURE_MDS_QUOTA)) {
       mempool_inode *policy_i = ppolicy ? pi : oi;
       encode(policy_i->quota, bl);
     }
-    if (session->get_connection()->has_feature(CEPH_FEATURE_FS_FILE_LAYOUT_V2)) {
+    if (conn->has_feature(CEPH_FEATURE_FS_FILE_LAYOUT_V2)) {
       encode(layout.pool_ns, bl);
     }
-    if (session->get_connection()->has_feature(CEPH_FEATURE_FS_BTIME)) {
+    if (conn->has_feature(CEPH_FEATURE_FS_BTIME)) {
       encode(any_i->btime, bl);
       encode(any_i->change_attr, bl);
     }
index 54cbe46535fad221ef3685e14cdb80799f44553f..7db2c0e35428edd8ff01bc9903e266cf8b6af430 100644 (file)
@@ -1050,7 +1050,7 @@ public:
   int get_caps_allowed_by_type(int type) const;
   int get_caps_careful() const;
   int get_xlocker_mask(client_t client) const;
-  int get_caps_allowed_for_client(Session *s, mempool_inode *file_i) const;
+  int get_caps_allowed_for_client(Session *s, Capability *cap, mempool_inode *file_i) const;
 
   // caps issued, wanted
   int get_caps_issued(int *ploner = 0, int *pother = 0, int *pxlocker = 0,
index eadbd5cdff883544f77bd1960543b676064df988..8f852a9c327c370e619417d9b30878998974431a 100644 (file)
@@ -25,7 +25,7 @@
 
 void Capability::Export::encode(bufferlist &bl) const
 {
-  ENCODE_START(2, 2, bl);
+  ENCODE_START(3, 2, bl);
   encode(cap_id, bl);
   encode(wanted, bl);
   encode(issued, bl);
@@ -34,12 +34,13 @@ void Capability::Export::encode(bufferlist &bl) const
   encode(seq, bl);
   encode(mseq, bl);
   encode(last_issue_stamp, bl);
+  encode(state, bl);
   ENCODE_FINISH(bl);
 }
 
 void Capability::Export::decode(bufferlist::const_iterator &p)
 {
-  DECODE_START_LEGACY_COMPAT_LEN(2, 2, 2, p);
+  DECODE_START_LEGACY_COMPAT_LEN(3, 2, 2, p);
   decode(cap_id, p);
   decode(wanted, p);
   decode(issued, p);
@@ -48,6 +49,8 @@ void Capability::Export::decode(bufferlist::const_iterator &p)
   decode(seq, p);
   decode(mseq, p);
   decode(last_issue_stamp, p);
+  if (struct_v >= 3)
+    decode(state, p);
   DECODE_FINISH(p);
 }
 
@@ -156,6 +159,16 @@ Capability::Capability(CInode *i, Session *s, uint64_t id) :
   if (session) {
     session->touch_cap_bottom(this);
     cap_gen = session->get_cap_gen();
+
+    auto& conn = session->get_connection();
+    if (conn) {
+      if (!conn->has_feature(CEPH_FEATURE_MDS_INLINE_DATA))
+       state |= STATE_NOINLINE;
+      if (!conn->has_feature(CEPH_FEATURE_FS_FILE_LAYOUT_V2))
+       state |= STATE_NOPOOLNS;
+      if (!conn->has_feature(CEPH_FEATURE_MDS_QUOTA))
+       state |= STATE_NOQUOTA;
+    }
   }
 }
 
index 38681d95becc908ff16e2d03c9a6337a147088e6..7e16aa43038aa436a2d2397b613c350d0f7af2b0 100644 (file)
@@ -72,18 +72,20 @@ public:
   MEMPOOL_CLASS_HELPERS();
 
   struct Export {
-    int64_t cap_id;
-    int32_t wanted;
-    int32_t issued;
-    int32_t pending;
+    int64_t cap_id = 0;
+    int32_t wanted = 0;
+    int32_t issued = 0;
+    int32_t pending = 0;
     snapid_t client_follows;
-    ceph_seq_t seq;
-    ceph_seq_t mseq;
+    ceph_seq_t seq = 0;
+    ceph_seq_t mseq = 0;
     utime_t last_issue_stamp;
-    Export() : cap_id(0), wanted(0), issued(0), pending(0), seq(0), mseq(0) {}
-    Export(int64_t id, int w, int i, int p, snapid_t cf, ceph_seq_t s, ceph_seq_t m, utime_t lis) :
+    uint32_t state = 0;
+    Export() {}
+    Export(int64_t id, int w, int i, int p, snapid_t cf,
+          ceph_seq_t s, ceph_seq_t m, utime_t lis, unsigned st) :
       cap_id(id), wanted(w), issued(i), pending(p), client_follows(cf),
-      seq(s), mseq(m), last_issue_stamp(lis) {}
+      seq(s), mseq(m), last_issue_stamp(lis), state(st) {}
     void encode(bufferlist &bl) const;
     void decode(bufferlist::const_iterator &p);
     void dump(Formatter *f) const;
@@ -115,6 +117,12 @@ public:
   const static unsigned STATE_IMPORTING                = (1<<2);
   const static unsigned STATE_NEEDSNAPFLUSH    = (1<<3);
   const static unsigned STATE_CLIENTWRITEABLE  = (1<<4);
+  const static unsigned STATE_NOINLINE         = (1<<5);
+  const static unsigned STATE_NOPOOLNS         = (1<<6);
+  const static unsigned STATE_NOQUOTA          = (1<<7);
+
+  const static unsigned MASK_STATE_EXPORTED =
+    (STATE_CLIENTWRITEABLE | STATE_NOINLINE | STATE_NOPOOLNS | STATE_NOQUOTA);
 
   Capability(CInode *i=nullptr, Session *s=nullptr, uint64_t id=0);
   Capability(const Capability& other) = delete;
@@ -262,6 +270,10 @@ public:
     }
   }
 
+  bool is_noinline() const { return state & STATE_NOINLINE; }
+  bool is_nopoolns() const { return state & STATE_NOPOOLNS; }
+  bool is_noquota() const { return state & STATE_NOQUOTA; }
+
   CInode *get_inode() const { return inode; }
   Session *get_session() const { return session; }
   client_t get_client() const;
@@ -285,7 +297,7 @@ public:
   
   // -- exports --
   Export make_export() const {
-    return Export(cap_id, wanted(), issued(), pending(), client_follows, get_last_seq(), mseq+1, last_issue_stamp);
+    return Export(cap_id, wanted(), issued(), pending(), client_follows, get_last_seq(), mseq+1, last_issue_stamp, state);
   }
   void merge(const Export& other, bool auth_cap) {
     if (!is_stale()) {
@@ -302,6 +314,10 @@ public:
 
     client_follows = other.client_follows;
 
+    state |= other.state & MASK_STATE_EXPORTED;
+    if ((other.state & STATE_CLIENTWRITEABLE) && !is_notable())
+      mark_notable();
+
     // wanted
     set_wanted(wanted() | other.wanted);
     if (auth_cap)
index 584cf3b59fb030b02b002aad3ea70ed3ab16033b..9c439a2b65f9abd47ae1001c04ec328f4b948230 100644 (file)
@@ -2007,11 +2007,10 @@ bool Locker::issue_caps(CInode *in, Capability *only_cap)
     // add in any xlocker-only caps (for locks this client is the xlocker for)
     allowed |= xlocker_allowed & in->get_xlocker_mask(it->first);
 
-    Session *session = mds->get_session(it->first);
-    if (in->inode.inline_data.version != CEPH_INLINE_NONE &&
-       !(session &&
-         session->get_connection() &&
-         session->get_connection()->has_feature(CEPH_FEATURE_MDS_INLINE_DATA)))
+    if ((in->inode.inline_data.version != CEPH_INLINE_NONE &&
+        cap->is_noinline()) ||
+       (!in->inode.layout.pool_ns.empty() &&
+        cap->is_nopoolns()))
       allowed &= ~(CEPH_CAP_FILE_RD | CEPH_CAP_FILE_WR);
 
     int pending = cap->pending();
@@ -2079,7 +2078,7 @@ bool Locker::issue_caps(CInode *in, Capability *only_cap)
                                            mds->get_osd_epoch_barrier());
        in->encode_cap_message(m, cap);
 
-       mds->send_message_client_counted(m, it->first);
+       mds->send_message_client_counted(m, cap->get_session());
       }
     }
 
index b57fe15f899e5f4c235186d25c5870f57901ac2e..e51c52e55c53f84786a0d1b5a1444589e223a658 100644 (file)
@@ -1947,13 +1947,9 @@ void MDCache::broadcast_quota_to_client(CInode *in, client_t exclude_ct, bool qu
     mds->server->create_quota_realm(in);
 
   for (auto &p : in->client_caps) {
-    Session *session = mds->get_session(p.first);
-    if (!session ||
-       !session->get_connection() ||
-        !session->get_connection()->has_feature(CEPH_FEATURE_MDS_QUOTA))
-      continue;
-
     Capability *cap = &p.second;
+    if (cap->is_noquota())
+      continue;
 
     if (exclude_ct >= 0 && exclude_ct != p.first)
       goto update;
@@ -1990,7 +1986,7 @@ update:
     msg->ino = in->ino();
     msg->rstat = i->rstat;
     msg->quota = i->quota;
-    mds->send_message_client_counted(msg, session->get_connection());
+    mds->send_message_client_counted(msg, cap->get_session());
   }
   for (const auto &it : in->get_replicas()) {
     auto msg = MGatherCaps::create();