There was a possible scenario during NFS use where multiple NFS requests would
try to refresh a dentry and will call ll_prep_inode with different
requests. ll_update_inode's ll_smd updating code would then race
after a check for ll_smd being non-NULL and we endup with an lsm leak
and some processes possibly usign stale copy of lsm data.
i=adilger
i=rread
cfs_list_t lli_dead_list;
cfs_semaphore_t lli_och_sem; /* Protects access to och pointers
cfs_list_t lli_dead_list;
cfs_semaphore_t lli_och_sem; /* Protects access to och pointers
- and their usage counters */
+ and their usage counters, also
+ atomicity of check-update of
+ lli_smd */
/* We need all three because every inode may be opened in different
modes */
struct obd_client_handle *lli_mds_read_och;
/* We need all three because every inode may be opened in different
modes */
struct obd_client_handle *lli_mds_read_och;
LASSERT ((lsm != NULL) == ((body->valid & OBD_MD_FLEASIZE) != 0));
if (lsm != NULL) {
LASSERT ((lsm != NULL) == ((body->valid & OBD_MD_FLEASIZE) != 0));
if (lsm != NULL) {
+ cfs_down(&lli->lli_och_sem);
if (lli->lli_smd == NULL) {
if (lsm->lsm_magic != LOV_MAGIC_V1 &&
lsm->lsm_magic != LOV_MAGIC_V3) {
if (lli->lli_smd == NULL) {
if (lsm->lsm_magic != LOV_MAGIC_V1 &&
lsm->lsm_magic != LOV_MAGIC_V3) {
}
CDEBUG(D_INODE, "adding lsm %p to inode %lu/%u(%p)\n",
lsm, inode->i_ino, inode->i_generation, inode);
}
CDEBUG(D_INODE, "adding lsm %p to inode %lu/%u(%p)\n",
lsm, inode->i_ino, inode->i_generation, inode);
+ /* cl_inode_init must go before lli_smd or a race is
+ * possible where client thinks the file has stripes,
+ * but lov raid0 is not setup yet and parallel e.g.
+ * glimpse would try to use uninitialized lov */
cl_inode_init(inode, md);
cl_inode_init(inode, md);
- /* ll_inode_size_lock() requires it is only
- * called with lli_smd != NULL or lock_lsm == 0
- * or we can race between lock/unlock.
- * bug 9547 */
+ cfs_up(&lli->lli_och_sem);
lli->lli_maxbytes = lsm->lsm_maxbytes;
if (lli->lli_maxbytes > PAGE_CACHE_MAXBYTES)
lli->lli_maxbytes = PAGE_CACHE_MAXBYTES;
} else {
lli->lli_maxbytes = lsm->lsm_maxbytes;
if (lli->lli_maxbytes > PAGE_CACHE_MAXBYTES)
lli->lli_maxbytes = PAGE_CACHE_MAXBYTES;
} else {
+ cfs_up(&lli->lli_och_sem);
LASSERT(lli->lli_smd->lsm_magic == lsm->lsm_magic &&
lli->lli_smd->lsm_stripe_count ==
lsm->lsm_stripe_count);
LASSERT(lli->lli_smd->lsm_magic == lsm->lsm_magic &&
lli->lli_smd->lsm_stripe_count ==
lsm->lsm_stripe_count);