/* ** reiserfs_unpack ** Function try to convert tail from direct item into indirect. ** It set up nopack attribute in the REISERFS_I(inode)->nopack */ int reiserfs_unpack(struct inode *inode, struct file *filp) { int retval = 0; int depth; int index; struct page *page; struct address_space *mapping; unsigned long write_from; unsigned long blocksize = inode->i_sb->s_blocksize; if (inode->i_size == 0) { REISERFS_I(inode)->i_flags |= i_nopack_mask; return 0; } /* ioctl already done */ if (REISERFS_I(inode)->i_flags & i_nopack_mask) { return 0; } depth = reiserfs_write_lock_once(inode->i_sb); /* we need to make sure nobody is changing the file size beneath us */ reiserfs_mutex_lock_safe(&inode->i_mutex, inode->i_sb); write_from = inode->i_size & (blocksize - 1); /* if we are on a block boundary, we are already unpacked. */ if (write_from == 0) { REISERFS_I(inode)->i_flags |= i_nopack_mask; goto out; } /* we unpack by finding the page with the tail, and calling ** __reiserfs_write_begin on that page. This will force a ** reiserfs_get_block to unpack the tail for us. */ index = inode->i_size >> PAGE_CACHE_SHIFT; mapping = inode->i_mapping; page = grab_cache_page(mapping, index); retval = -ENOMEM; if (!page) { goto out; } retval = __reiserfs_write_begin(page, write_from, 0); if (retval) goto out_unlock; /* conversion can change page contents, must flush */ flush_dcache_page(page); retval = reiserfs_commit_write(NULL, page, write_from, write_from); REISERFS_I(inode)->i_flags |= i_nopack_mask; out_unlock: unlock_page(page); page_cache_release(page); out: mutex_unlock(&inode->i_mutex); reiserfs_write_unlock_once(inode->i_sb, depth); return retval; }
/* * inode->i_mutex: down */ int reiserfs_xattr_set_handle(struct reiserfs_transaction_handle *th, struct inode *inode, const char *name, const void *buffer, size_t buffer_size, int flags) { int err = 0; struct dentry *dentry; struct page *page; char *data; size_t file_pos = 0; size_t buffer_pos = 0; size_t new_size; __u32 xahash = 0; if (get_inode_sd_version(inode) == STAT_DATA_V1) return -EOPNOTSUPP; reiserfs_write_unlock(inode->i_sb); if (!buffer) { err = lookup_and_delete_xattr(inode, name); reiserfs_write_lock(inode->i_sb); return err; } dentry = xattr_lookup(inode, name, flags); if (IS_ERR(dentry)) { reiserfs_write_lock(inode->i_sb); return PTR_ERR(dentry); } down_write(&REISERFS_I(inode)->i_xattr_sem); reiserfs_write_lock(inode->i_sb); xahash = xattr_hash(buffer, buffer_size); while (buffer_pos < buffer_size || buffer_pos == 0) { size_t chunk; size_t skip = 0; size_t page_offset = (file_pos & (PAGE_CACHE_SIZE - 1)); if (buffer_size - buffer_pos > PAGE_CACHE_SIZE) chunk = PAGE_CACHE_SIZE; else chunk = buffer_size - buffer_pos; page = reiserfs_get_page(dentry->d_inode, file_pos); if (IS_ERR(page)) { err = PTR_ERR(page); goto out_unlock; } lock_page(page); data = page_address(page); if (file_pos == 0) { struct reiserfs_xattr_header *rxh; skip = file_pos = sizeof(struct reiserfs_xattr_header); if (chunk + skip > PAGE_CACHE_SIZE) chunk = PAGE_CACHE_SIZE - skip; rxh = (struct reiserfs_xattr_header *)data; rxh->h_magic = cpu_to_le32(REISERFS_XATTR_MAGIC); rxh->h_hash = cpu_to_le32(xahash); } err = __reiserfs_write_begin(page, page_offset, chunk + skip); if (!err) { if (buffer) memcpy(data + skip, buffer + buffer_pos, chunk); err = reiserfs_commit_write(NULL, page, page_offset, page_offset + chunk + skip); } unlock_page(page); reiserfs_put_page(page); buffer_pos += chunk; file_pos += chunk; skip = 0; if (err || buffer_size == 0 || !buffer) break; } new_size = buffer_size + sizeof(struct reiserfs_xattr_header); if (!err && new_size < i_size_read(dentry->d_inode)) { struct iattr newattrs = { .ia_ctime = current_fs_time(inode->i_sb), .ia_size = new_size, .ia_valid = ATTR_SIZE | ATTR_CTIME, }; reiserfs_write_unlock(inode->i_sb); mutex_lock_nested(&dentry->d_inode->i_mutex, I_MUTEX_XATTR); down_write(&dentry->d_inode->i_alloc_sem); reiserfs_write_lock(inode->i_sb); err = reiserfs_setattr(dentry, &newattrs); up_write(&dentry->d_inode->i_alloc_sem); mutex_unlock(&dentry->d_inode->i_mutex); } else update_ctime(inode); out_unlock: up_write(&REISERFS_I(inode)->i_xattr_sem); dput(dentry); return err; }