From 9dc6f8983207edad1ec8d47fa59249f3ce34c0a5 Mon Sep 17 00:00:00 2001
From: "Yan, Zheng" <zheng.z.yan@intel.com>
Date: Thu, 20 Jun 2013 10:32:46 +0800
Subject: [PATCH] osdc: re-calculate truncate_size for strip objects

Fixes #5380
Signed-off-by: Yan, Zheng <zheng.z.yan@intel.com>
---
 src/client/Client.cc     |  9 +++++----
 src/librbd/ImageCtx.cc   |  4 ++--
 src/librbd/internal.cc   | 10 +++++-----
 src/osd/osd_types.h      |  6 ++++--
 src/osdc/Filer.cc        |  2 +-
 src/osdc/Filer.h         | 12 ++++++------
 src/osdc/ObjectCacher.cc | 28 ++++++++++++++++++++++------
 src/osdc/ObjectCacher.h  | 16 +++++++++-------
 src/osdc/Objecter.h      |  8 ++++----
 src/osdc/Striper.cc      | 45 ++++++++++++++++++++++++++++++++++++++++++---
 src/osdc/Striper.h       | 19 +++++++++++++++----
 src/test/test_striper.cc |  5 ++++-
 12 files changed, 119 insertions(+), 45 deletions(-)

diff --git a/src/client/Client.cc b/src/client/Client.cc
index 204dc98..3b36ef0 100644
--- a/src/client/Client.cc
+++ b/src/client/Client.cc
@@ -512,6 +512,7 @@ void Client::update_inode_file_bits(Inode *in,
 	       << truncate_size << dendl;
       in->truncate_size = truncate_size;
       in->oset.truncate_size = truncate_size;
+      objectcacher->recalc_truncate_size(&in->oset, &in->layout);
     } else {
       ldout(cct, 0) << "Hmmm, truncate_seq && truncate_size changed on non-file inode!" << dendl;
     }
@@ -2665,7 +2666,7 @@ void Client::_invalidate_inode_cache(Inode *in, int64_t off, int64_t len, bool k
   // invalidate our userspace inode cache
   if (cct->_conf->client_oc) {
     vector<ObjectExtent> ls;
-    Striper::file_to_extents(cct, in->ino, &in->layout, off, len, ls);
+    Striper::file_to_extents(cct, in->ino, &in->layout, off, len, in->truncate_size, ls);
     objectcacher->discard_set(&in->oset, ls);
   }
 
@@ -7734,7 +7735,7 @@ int Client::get_file_extent_osds(int fd, loff_t off, loff_t *len, vector<int>& o
   Inode *in = f->inode;
 
   vector<ObjectExtent> extents;
-  Striper::file_to_extents(cct, in->ino, &in->layout, off, 1, extents);
+  Striper::file_to_extents(cct, in->ino, &in->layout, off, 1, in->truncate_size, extents);
   assert(extents.size() == 1);
 
   pg_t pg = osdmap->object_locator_to_pg(extents[0].oid, extents[0].oloc);
@@ -7781,7 +7782,7 @@ int Client::get_file_stripe_address(int fd, loff_t offset, vector<entity_addr_t>
 
   // which object?
   vector<ObjectExtent> extents;
-  Striper::file_to_extents(cct, in->ino, &in->layout, offset, 1, extents);
+  Striper::file_to_extents(cct, in->ino, &in->layout, offset, 1, in->truncate_size, extents);
   assert(extents.size() == 1);
 
   // now we have the object and its 'layout'
@@ -7822,7 +7823,7 @@ int Client::enumerate_layout(int fd, vector<ObjectExtent>& result,
   Inode *in = f->inode;
 
   // map to a list of extents
-  Striper::file_to_extents(cct, in->ino, &in->layout, offset, length, result);
+  Striper::file_to_extents(cct, in->ino, &in->layout, offset, length, in->truncate_size, result);
 
   ldout(cct, 3) << "enumerate_layout(" << fd << ", " << length << ", " << offset << ") = 0" << dendl;
   return 0;
diff --git a/src/librbd/ImageCtx.cc b/src/librbd/ImageCtx.cc
index 6796bc8..2ab5fd9 100644
--- a/src/librbd/ImageCtx.cc
+++ b/src/librbd/ImageCtx.cc
@@ -475,7 +475,7 @@ namespace librbd {
     snap_lock.get_read();
     ObjectCacher::OSDRead *rd = object_cacher->prepare_read(snap_id, bl, 0);
     snap_lock.put_read();
-    ObjectExtent extent(o, 0 /* a lie */, off, len);
+    ObjectExtent extent(o, 0 /* a lie */, off, len, 0);
     extent.oloc.pool = data_ctx.get_id();
     extent.buffer_extents.push_back(make_pair(0, len));
     rd->extents.push_back(extent);
@@ -492,7 +492,7 @@ namespace librbd {
     ObjectCacher::OSDWrite *wr = object_cacher->prepare_write(snapc, bl,
 							      utime_t(), 0);
     snap_lock.put_read();
-    ObjectExtent extent(o, 0, off, len);
+    ObjectExtent extent(o, 0, off, len, 0);
     extent.oloc.pool = data_ctx.get_id();
     extent.buffer_extents.push_back(make_pair(0, len));
     wr->extents.push_back(extent);
diff --git a/src/librbd/internal.cc b/src/librbd/internal.cc
index 789ef86..1fd7942 100644
--- a/src/librbd/internal.cc
+++ b/src/librbd/internal.cc
@@ -184,7 +184,7 @@ namespace librbd {
     if (delete_off > newsize) {
       vector<ObjectExtent> extents;
       Striper::file_to_extents(ictx->cct, ictx->format_string, &ictx->layout,
-			       newsize, delete_off - newsize, extents);
+			       newsize, delete_off - newsize, 0, extents);
 
       for (vector<ObjectExtent>::iterator p = extents.begin();
 	   p != extents.end(); ++p) {
@@ -2482,7 +2482,7 @@ reprotect_and_return_err:
       // map to extents
       map<object_t,vector<ObjectExtent> > object_extents;
       Striper::file_to_extents(ictx->cct, ictx->format_string, &ictx->layout,
-			       off, read_len, object_extents, 0);
+			       off, read_len, 0, object_extents, 0);
 
       // get snap info for each object
       for (map<object_t,vector<ObjectExtent> >::iterator p = object_extents.begin();
@@ -2880,7 +2880,7 @@ reprotect_and_return_err:
 
     // map
     vector<ObjectExtent> extents;
-    Striper::file_to_extents(ictx->cct, ictx->format_string, &ictx->layout, off, mylen, extents);
+    Striper::file_to_extents(ictx->cct, ictx->format_string, &ictx->layout, off, mylen, 0, extents);
 
     c->get();
     c->init_time(ictx, AIO_TYPE_WRITE);
@@ -2960,7 +2960,7 @@ reprotect_and_return_err:
 
     // map
     vector<ObjectExtent> extents;
-    Striper::file_to_extents(ictx->cct, ictx->format_string, &ictx->layout, off, len, extents);
+    Striper::file_to_extents(ictx->cct, ictx->format_string, &ictx->layout, off, len, 0, extents);
 
     c->get();
     c->init_time(ictx, AIO_TYPE_DISCARD);
@@ -3056,7 +3056,7 @@ reprotect_and_return_err:
 	return r;
 
       Striper::file_to_extents(ictx->cct, ictx->format_string, &ictx->layout,
-			       p->first, len, object_extents, buffer_ofs);
+			       p->first, len, 0, object_extents, buffer_ofs);
       buffer_ofs += len;
     }
 
diff --git a/src/osd/osd_types.h b/src/osd/osd_types.h
index aafaa67..677efce 100644
--- a/src/osd/osd_types.h
+++ b/src/osd/osd_types.h
@@ -1635,13 +1635,15 @@ class ObjectExtent {
   uint64_t    objectno;
   uint64_t    offset;    // in object
   uint64_t    length;    // in object
+  uint64_t    truncate_size;	// in object
 
   object_locator_t oloc;   // object locator (pool etc)
 
   vector<pair<uint64_t,uint64_t> >  buffer_extents;  // off -> len.  extents in buffer being mapped (may be fragmented bc of striping!)
   
-  ObjectExtent() : objectno(0), offset(0), length(0) {}
-  ObjectExtent(object_t o, uint64_t ono, uint64_t off, uint64_t l) : oid(o), objectno(ono), offset(off), length(l) { }
+  ObjectExtent() : objectno(0), offset(0), length(0), truncate_size(0) {}
+  ObjectExtent(object_t o, uint64_t ono, uint64_t off, uint64_t l, uint64_t ts) :
+    oid(o), objectno(ono), offset(off), length(l), truncate_size(ts) { }
 };
 
 inline ostream& operator<<(ostream& out, const ObjectExtent &ex)
diff --git a/src/osdc/Filer.cc b/src/osdc/Filer.cc
index aec2910..7eb4ad6 100644
--- a/src/osdc/Filer.cc
+++ b/src/osdc/Filer.cc
@@ -102,7 +102,7 @@ void Filer::_probe(Probe *probe)
   probe->known_size.clear();
   probe->probing.clear();
   Striper::file_to_extents(cct, probe->ino, &probe->layout,
-			   probe->probing_off, probe->probing_len, probe->probing);
+			   probe->probing_off, probe->probing_len, 0, probe->probing);
   
   for (vector<ObjectExtent>::iterator p = probe->probing.begin();
        p != probe->probing.end();
diff --git a/src/osdc/Filer.h b/src/osdc/Filer.h
index cde4502..58414d3 100644
--- a/src/osdc/Filer.h
+++ b/src/osdc/Filer.h
@@ -107,7 +107,7 @@ class Filer {
            Context *onfinish) {
     assert(snap);  // (until there is a non-NOSNAP write)
     vector<ObjectExtent> extents;
-    Striper::file_to_extents(cct, ino, layout, offset, len, extents);
+    Striper::file_to_extents(cct, ino, layout, offset, len, 0, extents);
     objecter->sg_read(extents, snap, bl, flags, onfinish);
     return 0;
   }
@@ -124,7 +124,7 @@ class Filer {
            Context *onfinish) {
     assert(snap);  // (until there is a non-NOSNAP write)
     vector<ObjectExtent> extents;
-    Striper::file_to_extents(cct, ino, layout, offset, len, extents);
+    Striper::file_to_extents(cct, ino, layout, offset, len, truncate_size, extents);
     objecter->sg_read_trunc(extents, snap, bl, flags,
 			    truncate_size, truncate_seq, onfinish);
     return 0;
@@ -141,7 +141,7 @@ class Filer {
             Context *onack,
             Context *oncommit) {
     vector<ObjectExtent> extents;
-    Striper::file_to_extents(cct, ino, layout, offset, len, extents);
+    Striper::file_to_extents(cct, ino, layout, offset, len, 0, extents);
     objecter->sg_write(extents, snapc, bl, mtime, flags, onack, oncommit);
     return 0;
   }
@@ -159,7 +159,7 @@ class Filer {
             Context *onack,
             Context *oncommit) {
     vector<ObjectExtent> extents;
-    Striper::file_to_extents(cct, ino, layout, offset, len, extents);
+    Striper::file_to_extents(cct, ino, layout, offset, len, truncate_size, extents);
     objecter->sg_write_trunc(extents, snapc, bl, mtime, flags,
 		       truncate_size, truncate_seq, onack, oncommit);
     return 0;
@@ -176,7 +176,7 @@ class Filer {
 	       Context *onack,
 	       Context *oncommit) {
     vector<ObjectExtent> extents;
-    Striper::file_to_extents(cct, ino, layout, offset, len, extents);
+    Striper::file_to_extents(cct, ino, layout, offset, len, offset, extents);
     if (extents.size() == 1) {
       vector<OSDOp> ops(1);
       ops[0].op.op = CEPH_OSD_OP_TRIMTRUNC;
@@ -211,7 +211,7 @@ class Filer {
            Context *onack,
            Context *oncommit) {
     vector<ObjectExtent> extents;
-    Striper::file_to_extents(cct, ino, layout, offset, len, extents);
+    Striper::file_to_extents(cct, ino, layout, offset, len, offset, extents);
     if (extents.size() == 1) {
       if (extents[0].offset == 0 && extents[0].length == layout->fl_object_size)
 	objecter->remove(extents[0].oid, extents[0].oloc, 
diff --git a/src/osdc/ObjectCacher.cc b/src/osdc/ObjectCacher.cc
index 56c56d6..5188c75 100644
--- a/src/osdc/ObjectCacher.cc
+++ b/src/osdc/ObjectCacher.cc
@@ -555,7 +555,7 @@ void ObjectCacher::perf_stop()
 
 /* private */
 ObjectCacher::Object *ObjectCacher::get_object(sobject_t oid, ObjectSet *oset,
-                                 object_locator_t &l)
+					       object_locator_t &l, uint64_t ts)
 {
   assert(lock.is_locked());
   // have it?
@@ -567,7 +567,7 @@ ObjectCacher::Object *ObjectCacher::get_object(sobject_t oid, ObjectSet *oset,
   }
 
   // create it.
-  Object *o = new Object(this, oid, oset, l);
+  Object *o = new Object(this, oid, oset, l, ts);
   objects[l.pool][oid] = o;
   ob_lru.lru_insert_top(o);
   return o;
@@ -606,7 +606,7 @@ void ObjectCacher::bh_read(BufferHead *bh)
   // go
   writeback_handler.read(bh->ob->get_oid(), bh->ob->get_oloc(),
 			 bh->start(), bh->length(), bh->ob->get_snap(),
-			 &onfinish->bl, oset->truncate_size, oset->truncate_seq,
+			 &onfinish->bl, bh->ob->truncate_size, oset->truncate_seq,
 			 onfinish);
   ++reads_outstanding;
 }
@@ -793,7 +793,7 @@ void ObjectCacher::bh_write(BufferHead *bh)
   tid_t tid = writeback_handler.write(bh->ob->get_oid(), bh->ob->get_oloc(),
 				      bh->start(), bh->length(),
 				      bh->snapc, bh->bl, bh->last_write,
-				      oset->truncate_size, oset->truncate_seq,
+				      bh->ob->truncate_size, oset->truncate_seq,
 				      oncommit);
   ldout(cct, 20) << " tid " << tid << " on " << bh->ob->get_oid() << dendl;
 
@@ -1022,7 +1022,7 @@ int ObjectCacher::_readx(OSDRead *rd, ObjectSet *oset, Context *onfinish,
 
     // get Object cache
     sobject_t soid(ex_it->oid, rd->snap);
-    Object *o = get_object(soid, oset, ex_it->oloc);
+    Object *o = get_object(soid, oset, ex_it->oloc, ex_it->truncate_size);
     touch_ob(o);
 
     // does not exist and no hits?
@@ -1256,7 +1256,7 @@ int ObjectCacher::writex(OSDWrite *wr, ObjectSet *oset, Mutex& wait_on_lock,
        ++ex_it) {
     // get object cache
     sobject_t soid(ex_it->oid, CEPH_NOSNAP);
-    Object *o = get_object(soid, oset, ex_it->oloc);
+    Object *o = get_object(soid, oset, ex_it->oloc, ex_it->truncate_size);
 
     // map it all into a single bufferhead.
     BufferHead *bh = o->map_write(wr);
@@ -1817,6 +1817,22 @@ void ObjectCacher::discard_set(ObjectSet *oset, vector<ObjectExtent>& exls)
     flush_set_callback(flush_set_callback_arg, oset);
 }
 
+void ObjectCacher::recalc_truncate_size(ObjectSet *oset, ceph_file_layout *layout)
+{
+  assert(lock.is_locked());
+  ldout(cct, 10) << "recalc_truncate_size " << oset << dendl;
+  if (objects.size() <= (uint32_t)oset->poolid)
+    return;
+  for (hash_map<sobject_t, Object*>::iterator p = objects[oset->poolid].begin();
+       p != objects[oset->poolid].end();
+       ++p) {
+    if (p->first.snap != CEPH_NOSNAP)
+      continue;
+    p->second->truncate_size = Striper::object_truncate_size(cct, layout, p->first.oid,
+							     oset->truncate_size);
+  }
+}
+
 void ObjectCacher::verify_stats() const
 {
   assert(lock.is_locked());
diff --git a/src/osdc/ObjectCacher.h b/src/osdc/ObjectCacher.h
index 80a90bd..bc4654a 100644
--- a/src/osdc/ObjectCacher.h
+++ b/src/osdc/ObjectCacher.h
@@ -171,6 +171,7 @@ class ObjectCacher {
     ObjectSet *oset;
     xlist<Object*>::item set_item;
     object_locator_t oloc;
+    uint64_t truncate_size;
     
     bool complete;
     bool exists;
@@ -190,10 +191,10 @@ class ObjectCacher {
     Object(const Object& other);
     const Object& operator=(const Object& other);
 
-    Object(ObjectCacher *_oc, sobject_t o, ObjectSet *os, object_locator_t& l) : 
+    Object(ObjectCacher *_oc, sobject_t o, ObjectSet *os, object_locator_t& l, uint64_t ts) : 
       ref(0),
       oc(_oc),
-      oid(o), oset(os), set_item(this), oloc(l),
+      oid(o), oset(os), set_item(this), oloc(l), truncate_size(ts),
       complete(false), exists(true),
       last_write_tid(0), last_commit_tid(0),
       dirty_or_tx(0) {
@@ -364,7 +365,7 @@ class ObjectCacher {
   }
 
   Object *get_object(sobject_t oid, ObjectSet *oset,
-                     object_locator_t &l);
+                     object_locator_t &l, uint64_t ts);
   void close_object(Object *ob);
 
   // bh stats
@@ -621,12 +622,13 @@ public:
 
 
   // file functions
+  void recalc_truncate_size(ObjectSet *oset, ceph_file_layout *layout);
 
   /*** async+caching (non-blocking) file interface ***/
   int file_is_cached(ObjectSet *oset, ceph_file_layout *layout, snapid_t snapid,
 		     loff_t offset, uint64_t len) {
     vector<ObjectExtent> extents;
-    Striper::file_to_extents(cct, oset->ino, layout, offset, len, extents);
+    Striper::file_to_extents(cct, oset->ino, layout, offset, len, oset->truncate_size, extents);
     return is_cached(oset, extents, snapid);
   }
 
@@ -636,7 +638,7 @@ public:
 		int flags,
                 Context *onfinish) {
     OSDRead *rd = prepare_read(snapid, bl, flags);
-    Striper::file_to_extents(cct, oset->ino, layout, offset, len, rd->extents);
+    Striper::file_to_extents(cct, oset->ino, layout, offset, len, oset->truncate_size, rd->extents);
     return readx(rd, oset, onfinish);
   }
 
@@ -645,14 +647,14 @@ public:
                  bufferlist& bl, utime_t mtime, int flags,
 		 Mutex& wait_on_lock) {
     OSDWrite *wr = prepare_write(snapc, bl, mtime, flags);
-    Striper::file_to_extents(cct, oset->ino, layout, offset, len, wr->extents);
+    Striper::file_to_extents(cct, oset->ino, layout, offset, len, oset->truncate_size, wr->extents);
     return writex(wr, oset, wait_on_lock, NULL);
   }
 
   bool file_flush(ObjectSet *oset, ceph_file_layout *layout, const SnapContext& snapc,
                   loff_t offset, uint64_t len, Context *onfinish) {
     vector<ObjectExtent> extents;
-    Striper::file_to_extents(cct, oset->ino, layout, offset, len, extents);
+    Striper::file_to_extents(cct, oset->ino, layout, offset, len, oset->truncate_size, extents);
     return flush_set(oset, extents, onfinish);
   }
 };
diff --git a/src/osdc/Objecter.h b/src/osdc/Objecter.h
index bc4b0ae..b4086f6 100644
--- a/src/osdc/Objecter.h
+++ b/src/osdc/Objecter.h
@@ -1696,14 +1696,14 @@ public:
 		uint64_t trunc_size, __u32 trunc_seq, Context *onfinish) {
     if (extents.size() == 1) {
       read_trunc(extents[0].oid, extents[0].oloc, extents[0].offset, extents[0].length,
-	   snap, bl, flags, trunc_size, trunc_seq, onfinish);
+	   snap, bl, flags, extents[0].truncate_size, trunc_seq, onfinish);
     } else {
       C_GatherBuilder gather(cct);
       vector<bufferlist> resultbl(extents.size());
       int i=0;
       for (vector<ObjectExtent>::iterator p = extents.begin(); p != extents.end(); ++p) {
 	read_trunc(p->oid, p->oloc, p->offset, p->length,
-	     snap, &resultbl[i++], flags, trunc_size, trunc_seq, gather.new_sub());
+	     snap, &resultbl[i++], flags, p->truncate_size, trunc_seq, gather.new_sub());
       }
       gather.set_finisher(new C_SGRead(this, extents, resultbl, bl, onfinish));
       gather.activate();
@@ -1719,7 +1719,7 @@ public:
 		Context *onack, Context *oncommit) {
     if (extents.size() == 1) {
       write_trunc(extents[0].oid, extents[0].oloc, extents[0].offset, extents[0].length,
-	    snapc, bl, mtime, flags, trunc_size, trunc_seq, onack, oncommit);
+	    snapc, bl, mtime, flags, extents[0].truncate_size, trunc_seq, onack, oncommit);
     } else {
       C_GatherBuilder gack(cct, onack);
       C_GatherBuilder gcom(cct, oncommit);
@@ -1731,7 +1731,7 @@ public:
 	  bl.copy(bit->first, bit->second, cur);
 	assert(cur.length() == p->length);
 	write_trunc(p->oid, p->oloc, p->offset, p->length, 
-	      snapc, cur, mtime, flags, trunc_size, trunc_seq,
+	      snapc, cur, mtime, flags, p->truncate_size, trunc_seq,
 	      onack ? gack.new_sub():0,
 	      oncommit ? gcom.new_sub():0);
       }
diff --git a/src/osdc/Striper.cc b/src/osdc/Striper.cc
index b062845..bde3284 100644
--- a/src/osdc/Striper.cc
+++ b/src/osdc/Striper.cc
@@ -28,18 +28,19 @@
 
 void Striper::file_to_extents(CephContext *cct, const char *object_format,
 			    ceph_file_layout *layout,
-			    uint64_t offset, uint64_t len,
+			    uint64_t offset, uint64_t len, uint64_t trunc_size,
 			    vector<ObjectExtent>& extents,
 			    uint64_t buffer_offset)
 {
   map<object_t,vector<ObjectExtent> > object_extents;
-  file_to_extents(cct, object_format, layout, offset, len, object_extents, buffer_offset);
+  file_to_extents(cct, object_format, layout, offset, len, trunc_size,
+		  object_extents, buffer_offset);
   assimilate_extents(object_extents, extents);
 }
 
 void Striper::file_to_extents(CephContext *cct, const char *object_format,
 			      ceph_file_layout *layout,
-			      uint64_t offset, uint64_t len,
+			      uint64_t offset, uint64_t len, uint64_t trunc_size,
 			      map<object_t,vector<ObjectExtent> >& object_extents,
 			      uint64_t buffer_offset)
 {
@@ -108,6 +109,8 @@ void Striper::file_to_extents(CephContext *cct, const char *object_format,
 
       ex->offset = x_offset;
       ex->length = x_len;
+      ex->truncate_size = object_truncate_size(cct, layout, objectno, trunc_size);
+
       ldout(cct, 20) << " added new " << *ex << dendl;
     } else {
       // add to extent
@@ -174,6 +177,42 @@ void Striper::extent_to_file(CephContext *cct, ceph_file_layout *layout,
   }
 }
 
+uint64_t Striper::object_truncate_size(CephContext *cct, ceph_file_layout *layout,
+				       uint64_t objectno, uint64_t trunc_size)
+{
+  uint64_t obj_trunc_size;
+  if (trunc_size == 0 || trunc_size == (uint64_t)-1) {
+    obj_trunc_size = trunc_size;
+  } else {
+    __u32 object_size = layout->fl_object_size;
+    __u32 su = layout->fl_stripe_unit;
+    __u32 stripe_count = layout->fl_stripe_count;
+    assert(object_size >= su);
+    uint64_t stripes_per_object = object_size / su;
+
+    uint64_t objectsetno = objectno / stripe_count;
+    uint64_t trunc_objectsetno = trunc_size / object_size / stripe_count;
+    if (objectsetno > trunc_objectsetno)
+      obj_trunc_size = 0;
+    else if (objectsetno < trunc_objectsetno)
+      obj_trunc_size = object_size;
+    else {
+      uint64_t trunc_blockno = trunc_size / su;
+      uint64_t trunc_stripeno = trunc_blockno / stripe_count;
+      uint64_t trunc_stripepos = trunc_blockno % stripe_count;
+      uint64_t trunc_objectno = trunc_objectsetno * stripe_count + trunc_stripepos;
+      if (objectno < trunc_objectno)
+	obj_trunc_size = ((trunc_stripeno % stripes_per_object) + 1) * su;
+      else if (objectno > trunc_objectno)
+	obj_trunc_size = (trunc_stripeno % stripes_per_object) * su;
+      else
+	obj_trunc_size = (trunc_stripeno % stripes_per_object) * su + (trunc_size % su);
+    }
+  }
+  ldout(cct, 20) << "object_truncate_size " << objectno << " "
+		 << trunc_size << "->" << obj_trunc_size << dendl;
+  return obj_trunc_size;
+}
 
 // StripedReadResult
 
diff --git a/src/osdc/Striper.h b/src/osdc/Striper.h
index 9f05635..a767e3c 100644
--- a/src/osdc/Striper.h
+++ b/src/osdc/Striper.h
@@ -30,25 +30,25 @@ class CephContext;
      */
     static void file_to_extents(CephContext *cct, const char *object_format,
 				ceph_file_layout *layout,
-				uint64_t offset, uint64_t len,
+				uint64_t offset, uint64_t len, uint64_t trunc_size,
 				map<object_t, vector<ObjectExtent> >& extents,
 				uint64_t buffer_offset=0);
 
     static void file_to_extents(CephContext *cct, const char *object_format,
 				ceph_file_layout *layout,
-				uint64_t offset, uint64_t len,
+				uint64_t offset, uint64_t len, uint64_t trunc_size,
 				vector<ObjectExtent>& extents,
 				uint64_t buffer_offset=0);
 
     static void file_to_extents(CephContext *cct, inodeno_t ino,
 				ceph_file_layout *layout,
-				uint64_t offset, uint64_t len,
+				uint64_t offset, uint64_t len, uint64_t trunc_size,
 				vector<ObjectExtent>& extents) {
       // generate prefix/format
       char buf[32];
       snprintf(buf, sizeof(buf), "%llx.%%08llx", (long long unsigned)ino);
 
-      file_to_extents(cct, buf, layout, offset, len, extents);
+      file_to_extents(cct, buf, layout, offset, len, trunc_size, extents);
     }
 
     static void assimilate_extents(map<object_t,vector<ObjectExtent> >& object_extents,
@@ -61,6 +61,17 @@ class CephContext;
 			       uint64_t objectno, uint64_t off, uint64_t len,
 			       vector<pair<uint64_t, uint64_t> >& extents);
 
+    static uint64_t object_truncate_size(CephContext *cct, ceph_file_layout *layout, 
+					 uint64_t objectno, uint64_t trunc_size);
+
+    static uint64_t object_truncate_size(CephContext *cct, ceph_file_layout *layout,
+					 object_t oid, uint64_t trunc_size) {
+      uint64_t ino, objectno;
+      sscanf(oid.name.c_str(), "%llx.%08llx",
+	     (long long unsigned*)&ino, (long long unsigned*)&objectno);
+      return object_truncate_size(cct, layout, objectno, trunc_size);
+    }
+
     /*
      * helper to assemble a striped result
      */
diff --git a/src/test/test_striper.cc b/src/test/test_striper.cc
index d3e9285..262fba3 100644
--- a/src/test/test_striper.cc
+++ b/src/test/test_striper.cc
@@ -16,11 +16,14 @@ TEST(Striper, Stripe1)
   l.fl_stripe_count = 3;
 
   vector<ObjectExtent> ex;
-  Striper::file_to_extents(g_ceph_context, 1, &l, 5006035, 46419, ex);
+  Striper::file_to_extents(g_ceph_context, 1, &l, 5006035, 46419, 5006035, ex);
 
   cout << "result " << ex << std::endl;
 
   ASSERT_EQ(3u, ex.size());
+  ASSERT_EQ(98304u, ex[0].truncate_size);
+  ASSERT_EQ(ex[1].offset, ex[1].truncate_size);
+  ASSERT_EQ(94208u, ex[2].truncate_size);
 }
 
 
-- 
1.8.1.4

