Whamcloud - gitweb
b=20989 Atomically check-update inode lli_smd to prevent updated race
authorOleg Drokin <green@linuxhacker.ru>
Fri, 19 Mar 2010 18:19:17 +0000 (11:19 -0700)
committerRobert Read <rread@sun.com>
Fri, 19 Mar 2010 18:19:17 +0000 (11:19 -0700)
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

lustre/llite/llite_internal.h
lustre/llite/llite_lib.c

index cff3891..9741c44 100644 (file)
@@ -149,7 +149,9 @@ struct ll_inode_info {
         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;
index 0a959a8..59a1ce5 100644 (file)
@@ -1539,6 +1539,7 @@ void ll_update_inode(struct inode *inode, struct lustre_md *md)
 
         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) {
@@ -1547,16 +1548,18 @@ void ll_update_inode(struct inode *inode, struct lustre_md *md)
                         }
                         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 */
                         lli->lli_smd = lsm;
                         lli->lli_smd = lsm;
+                        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);