Whamcloud - gitweb
- fixed stupid bug with locking in MDS. It caused clients do not flush local
[fs/lustre-release.git] / lustre / snapfs / file.c
index 32b7041..a8a8860 100644 (file)
@@ -21,29 +21,38 @@ static int has_pages(struct inode *inode, int index)
 {
        unsigned long offset = index << PAGE_CACHE_SHIFT;
        unsigned long blk_start = offset >> inode->i_sb->s_blocksize_bits; 
-       unsigned long blk_end = (offset + PAGE_CACHE_SIZE) >> inode->i_sb->s_blocksize_bits; 
-       int inside = 0;
+       unsigned long blk_end = (offset + PAGE_CACHE_SIZE) >> 
+                               inode->i_sb->s_blocksize_bits; 
 
        while (blk_start <= blk_end) {
                if (inode->i_mapping && inode->i_mapping->a_ops) {
-                       inside = inode->i_mapping->a_ops->bmap(inode->i_mapping, blk_start);    
+                       if (inode->i_mapping->a_ops->bmap(inode->i_mapping, 
+                                                         blk_start))
+                               return 1;
                }
                blk_start++;
        }
-       return inside;
+       return 0;
 }
 
-static int copy_back_page(struct inode *dst, struct inode *src,
-                          int index)
+static int copy_back_page(struct inode *dst, 
+                         struct inode *src,
+                         unsigned long start,
+                         unsigned long end)
 {
        char *kaddr_src, *kaddr_dst;
         struct snap_cache *cache;
        struct address_space_operations *c_aops;
-       struct page *src_page, *dst_page;
+       struct page *src_page = NULL, *dst_page = NULL;
+       unsigned long index, offset, bytes;
        int    err = 0;
        ENTRY;
 
-       if (!has_pages(src, index)) 
+       offset = (start & (PAGE_CACHE_SIZE -1)); /* Within page */
+       bytes = end - start;
+        index = start >> PAGE_CACHE_SHIFT;
+
+       if (!has_pages(src, index) || bytes > 4096) 
                RETURN(0);
 
        cache = snap_find_cache(src->i_dev);
@@ -56,7 +65,7 @@ static int copy_back_page(struct inode *dst, struct inode *src,
 
        src_page = grab_cache_page(src->i_mapping, index);
        if (!src_page) {
-               CERROR("copy block %d from %lu to %lu ENOMEM \n",
+               CERROR("copy block %lu from %lu to %lu ENOMEM \n",
                          index, src->i_ino, dst->i_ino);
                RETURN(-ENOMEM);
        }
@@ -66,27 +75,29 @@ static int copy_back_page(struct inode *dst, struct inode *src,
        
        kaddr_src = kmap(src_page);
        if (!Page_Uptodate(src_page)) {
-               CERROR("Can not read page index %d of inode %lu\n",
+               CERROR("Can not read page index %lu of inode %lu\n",
                          index, src->i_ino);
                err = -EIO;
                goto unlock_src_page;
        }
        dst_page = grab_cache_page(dst->i_mapping, index);
        if (!dst_page) {
-               CERROR("copy block %d from %lu to %lu ENOMEM \n",
+               CERROR("copy block %lu from %lu to %lu ENOMEM \n",
                          index, src->i_ino, dst->i_ino);
                err = -ENOMEM;
                goto unlock_src_page;
        }       
        kaddr_dst = kmap(dst_page);
 
-       err = c_aops->prepare_write(NULL, dst_page, 0, PAGE_CACHE_SIZE);
+       err = c_aops->prepare_write(NULL, dst_page, offset, offset + bytes);
        if (err) 
                goto unlock_dst_page; 
        memcpy(kaddr_dst, kaddr_src, PAGE_CACHE_SIZE);
        flush_dcache_page(dst_page);
 
-       err = c_aops->commit_write(NULL, dst_page, 0, PAGE_CACHE_SIZE);
+       err = c_aops->commit_write(NULL, dst_page, offset, offset + bytes);
+       CDEBUG(D_SNAP, "copy back pages %p index %lu src %lu dst %lu \n",
+              dst_page, dst_page->index, src->i_ino, dst->i_ino); 
        if (err) 
                goto unlock_dst_page; 
        err = 1;
@@ -106,7 +117,7 @@ static ssize_t currentfs_write (struct file *filp, const char *buf,
         struct snap_cache *cache;
        struct inode *inode = filp->f_dentry->d_inode;
         struct file_operations *fops;
-       long   page[2]={-1,-1};
+       long   start[2]={-1,-1}, end[2]={-1,-1};
        struct snap_table *table;
        struct inode *cache_inode = NULL;
        int slot = 0, index = 0, result = 0;
@@ -123,81 +134,48 @@ static ssize_t currentfs_write (struct file *filp, const char *buf,
         if ( !cache ) 
                 RETURN(-EINVAL);
 
+       down(&inode->i_sem);
+
         if ( snap_needs_cow(inode) != -1 ) {
                 CDEBUG(D_SNAP, "snap_needs_cow for ino %lu \n",inode->i_ino);
                 snap_do_cow(inode, filp->f_dentry->d_parent->d_inode->i_ino, 0);
        }
 
         fops = filter_c2cffops(cache->cache_filter); 
-        if (!fops || !fops->write) 
-                RETURN(-EINVAL);
-
+        if (!fops || !fops->write) { 
+                up(&inode->i_sem); 
+               RETURN(-EINVAL);
+       }
         if (filp->f_flags & O_APPEND)
                 pos = inode->i_size;
         else {
                 pos = *ppos;
-                if (pos != *ppos)
+                if (pos != *ppos){
+                       up(&inode->i_sem); 
                         RETURN(-EINVAL);
+               }
         }
-
-       /*
-        * we only need to copy back the first and last blocks
-        */
-#if 0
-       mask = inode->i_sb->s_blocksize-1;
-       if( pos & mask )
-               block[0] = pos >> inode->i_sb->s_blocksize_bits;
-       pos += count - 1;
-       if( (pos+1) &  mask )
-               block[1] = pos >> inode->i_sb->s_blocksize_bits;
-       if( block[0] == block[1] )
-               block[1] = -1;
        
-       snapops = filter_c2csnapops(cache->cache_filter);
-
-       for (i = 0; i < 2; i++) {
-               if (block[i] == -1) 
-                       continue;
-               table = &snap_tables[cache->cache_snap_tableno];
-               /*Find the nearest block in snaptable and copy back it*/
-               for (slot = table->tbl_count - 1; slot >= 1; slot--) {
-                       cache_inode = NULL;
-                               index = table->snap_items[slot].index;
-                       cache_inode = snap_get_indirect(inode, NULL, index);
-
-                       if (!cache_inode)  continue;
-
-                       CDEBUG(D_SNAP, "find cache_ino %lu\n", cache_inode->i_ino);
-               
-                       if (snapops && snapops->copy_block) {
-                               result = snapops->copy_block(inode, cache_inode, block[i]);
-                               if (result == 1) {
-                                       CDEBUG(D_SNAP, "copy block %lu back from ind %lu to %lu\n", 
-                                              block[i], cache_inode->i_ino, inode->i_ino);
-                                               iput(cache_inode);
-                                       result = 0;
-                                       break;
-                               }
-                               if (result < 0) {
-                                       iput(cache_inode);
-                                       rc = result;
-                                       goto exit;
-                               }
-                       }
-                               iput(cache_inode);
-               }
+       CDEBUG(D_SNAP, "write offset %lld count %u \n", pos, count);
+       
+       if (pos & (PAGE_CACHE_SIZE - 1)) {
+               start[0] = pos & PAGE_CACHE_MASK;
+               end[0] = pos;
        }
-#else
-       if (pos & PAGE_CACHE_MASK)
-               page[0] = pos >> PAGE_CACHE_SHIFT;
        pos += count - 1;
-       if ((pos+1) & PAGE_CACHE_MASK)
-               page[1] = pos >> PAGE_CACHE_SHIFT;
-       if (page[0] == page[1])
-               page[1] = -1;
-       
+       if ((pos+1) & (PAGE_CACHE_SIZE - 1)) {
+               start[1] = pos;  
+               end[1] = PAGE_CACHE_ALIGN(pos);
+       }
+
+       if (((start[0] >> PAGE_CACHE_SHIFT) == (start[1] >> PAGE_CACHE_SHIFT)) ||
+           pos > inode->i_size) 
+               start[1] = -1;
+
+       CDEBUG(D_SNAP, "copy back start[0] %ld end[0] %ld start[1] %ld end[1] %ld \n",
+              start[0], end[0], start[1], end[1]);     
        for (i = 0; i < 2; i++) {
-               if (page[i] == -1) 
+               if (start[i] == -1) 
                        continue;
                table = &snap_tables[cache->cache_snap_tableno];
                /*Find the nearest page in snaptable and copy back it*/
@@ -210,10 +188,12 @@ static ssize_t currentfs_write (struct file *filp, const char *buf,
 
                        CDEBUG(D_SNAP, "find cache_ino %lu\n", cache_inode->i_ino);
                
-                       result = copy_back_page(inode, cache_inode, page[i]);
+                       result = copy_back_page(inode, cache_inode, start[i], end[i]);
                        if (result == 1) {
                                CDEBUG(D_SNAP, "copy page%lu back from ind %lu to %lu\n", 
-                                      page[i], cache_inode->i_ino, inode->i_ino);
+                                      (start[i] >> PAGE_CACHE_SHIFT), 
+                                      cache_inode->i_ino, 
+                                      inode->i_ino);
                                        iput(cache_inode);
                                result = 0;
                                break;
@@ -221,12 +201,14 @@ static ssize_t currentfs_write (struct file *filp, const char *buf,
                        if (result < 0) {
                                iput(cache_inode);
                                rc = result;
+                               up(&inode->i_sem);
                                goto exit;
                        }
                                iput(cache_inode);
                }
        }
-#endif
+       
+        up(&inode->i_sem); 
        rc = fops->write(filp, buf, count, ppos);
 exit:
         RETURN(rc);
@@ -254,7 +236,7 @@ static int currentfs_readpage(struct file *file, struct page *page)
        
        c_aops = filter_c2cfaops(cache->cache_filter);
 
-       block = page->index >> inode->i_sb->s_blocksize_bits;
+       block = (page->index << PAGE_CACHE_SHIFT) >> inode->i_sb->s_blocksize_bits;
 
        /* if there is a block in the cache, return the cache readpage */
        if(c_aops->bmap(inode->i_mapping, block) ) {
@@ -279,7 +261,6 @@ static int currentfs_readpage(struct file *file, struct page *page)
        table = &snap_tables[cache->cache_snap_tableno];
 
         for (slot = table->tbl_count - 1; slot >= 1; slot--) {
-               cache_inode = NULL;
                 index = table->snap_items[slot].index;
                cache_inode = snap_get_indirect(inode, NULL, index);
 
@@ -292,12 +273,19 @@ static int currentfs_readpage(struct file *file, struct page *page)
                 if (!search_older && c_aops->bmap(cache_inode->i_mapping, block)) 
                         break;
                 iput(cache_inode);
+               cache_inode = NULL;
         }
        if (pri_inode) iput(pri_inode);
 
-       if (!cache_inode )  
-               RETURN(-EINVAL);
-
+       if (!cache_inode) {
+               CDEBUG(D_SNAP, "block %lu is a hole of inode %lu \n", 
+                      block, inode->i_ino);
+               memset(kmap(page), 0, PAGE_CACHE_SIZE);
+               flush_dcache_page(page);
+               GOTO(exit, rc = 0);
+       }
+       CDEBUG(D_INODE, "readpage ino %lu icount %d \n", cache_inode->i_ino, 
+              atomic_read(&cache_inode->i_count));
        down(&cache_inode->i_sem);
 
        /*Here we have changed a file to read,
@@ -317,13 +305,14 @@ static int currentfs_readpage(struct file *file, struct page *page)
                GOTO(exit_release, rc = -EIO);
 
        memcpy(kmap(page), kmap(cache_page), PAGE_CACHE_SIZE);
+       flush_dcache_page(page);
 
        kunmap(cache_page);
        page_cache_release(cache_page);
 
        up(&cache_inode->i_sem);
        iput(cache_inode);
-       
+exit:  
        kunmap(page);
        SetPageUptodate(page);
        UnlockPage(page);
@@ -348,6 +337,8 @@ struct file_operations currentfs_file_fops = {
 };
                                                                                                                                                                                                      
 struct inode_operations currentfs_file_iops = {
-       revalidate:     NULL,
+       setattr:        currentfs_setattr,
+       setxattr:       currentfs_setxattr,
+       removexattr:    currentfs_removexattr,  
 };