diff options
Diffstat (limited to 'fs/ceph/file.c')
| -rw-r--r-- | fs/ceph/file.c | 123 | 
1 files changed, 48 insertions, 75 deletions
| diff --git a/fs/ceph/file.c b/fs/ceph/file.c index 284d2fda663d..04fd34557de8 100644 --- a/fs/ceph/file.c +++ b/fs/ceph/file.c @@ -240,8 +240,7 @@ static int ceph_init_file_info(struct inode *inode, struct file *file,  	INIT_LIST_HEAD(&fi->rw_contexts);  	fi->filp_gen = READ_ONCE(ceph_inode_to_client(inode)->filp_gen); -	if ((file->f_mode & FMODE_WRITE) && -	    ci->i_inline_version != CEPH_INLINE_NONE) { +	if ((file->f_mode & FMODE_WRITE) && ceph_has_inline_data(ci)) {  		ret = ceph_uninline_data(file);  		if (ret < 0)  			goto error; @@ -568,7 +567,7 @@ static void ceph_async_create_cb(struct ceph_mds_client *mdsc,  		char *path = ceph_mdsc_build_path(req->r_dentry, &pathlen,  						  &base, 0); -		pr_warn("ceph: async create failure path=(%llx)%s result=%d!\n", +		pr_warn("async create failure path=(%llx)%s result=%d!\n",  			base, IS_ERR(path) ? "<<bad>>" : path, result);  		ceph_mdsc_free_path(path, pathlen); @@ -611,6 +610,7 @@ static int ceph_finish_async_create(struct inode *dir, struct dentry *dentry,  	struct ceph_mds_reply_inode in = { };  	struct ceph_mds_reply_info_in iinfo = { .in = &in };  	struct ceph_inode_info *ci = ceph_inode(dir); +	struct ceph_dentry_info *di = ceph_dentry(dentry);  	struct inode *inode;  	struct timespec64 now;  	struct ceph_string *pool_ns; @@ -709,6 +709,12 @@ static int ceph_finish_async_create(struct inode *dir, struct dentry *dentry,  		file->f_mode |= FMODE_CREATED;  		ret = finish_open(file, dentry, ceph_open);  	} + +	spin_lock(&dentry->d_lock); +	di->flags &= ~CEPH_DENTRY_ASYNC_CREATE; +	wake_up_bit(&di->flags, CEPH_DENTRY_ASYNC_CREATE_BIT); +	spin_unlock(&dentry->d_lock); +  	return ret;  } @@ -735,6 +741,15 @@ int ceph_atomic_open(struct inode *dir, struct dentry *dentry,  	if (dentry->d_name.len > NAME_MAX)  		return -ENAMETOOLONG; +	err = ceph_wait_on_conflict_unlink(dentry); +	if (err) +		return err; +	/* +	 * Do not truncate the file, since atomic_open is called before the +	 * permission check. The caller will do the truncation afterward. +	 */ +	flags &= ~O_TRUNC; +  	if (flags & O_CREAT) {  		if (ceph_quota_is_max_files_exceeded(dir))  			return -EDQUOT; @@ -781,9 +796,16 @@ retry:  		    (req->r_dir_caps =  		      try_prep_async_create(dir, dentry, &lo,  					    &req->r_deleg_ino))) { +			struct ceph_dentry_info *di = ceph_dentry(dentry); +  			set_bit(CEPH_MDS_R_ASYNC, &req->r_req_flags);  			req->r_args.open.flags |= cpu_to_le32(CEPH_O_EXCL);  			req->r_callback = ceph_async_create_cb; + +			spin_lock(&dentry->d_lock); +			di->flags |= CEPH_DENTRY_ASYNC_CREATE; +			spin_unlock(&dentry->d_lock); +  			err = ceph_mdsc_submit_request(mdsc, dir, req);  			if (!err) {  				err = ceph_finish_async_create(dir, dentry, @@ -802,9 +824,7 @@ retry:  	}  	set_bit(CEPH_MDS_R_PARENT_LOCKED, &req->r_req_flags); -	err = ceph_mdsc_do_request(mdsc, -				   (flags & (O_CREAT|O_TRUNC)) ? dir : NULL, -				   req); +	err = ceph_mdsc_do_request(mdsc, (flags & O_CREAT) ? dir : NULL, req);  	if (err == -ENOENT) {  		dentry = ceph_handle_snapdir(req, dentry);  		if (IS_ERR(dentry)) { @@ -960,9 +980,8 @@ static ssize_t ceph_sync_read(struct kiocb *iocb, struct iov_iter *to,  		osd_req_op_extent_osd_data_pages(req, 0, pages, len, page_off,  						 false, false); -		ret = ceph_osdc_start_request(osdc, req, false); -		if (!ret) -			ret = ceph_osdc_wait_request(osdc, req); +		ceph_osdc_start_request(osdc, req); +		ret = ceph_osdc_wait_request(osdc, req);  		ceph_update_read_metrics(&fsc->mdsc->metric,  					 req->r_start_latency, @@ -1225,7 +1244,7 @@ static void ceph_aio_retry_work(struct work_struct *work)  	req->r_inode = inode;  	req->r_priv = aio_req; -	ret = ceph_osdc_start_request(req->r_osdc, req, false); +	ceph_osdc_start_request(req->r_osdc, req);  out:  	if (ret < 0) {  		req->r_result = ret; @@ -1362,9 +1381,8 @@ ceph_direct_read_write(struct kiocb *iocb, struct iov_iter *iter,  			continue;  		} -		ret = ceph_osdc_start_request(req->r_osdc, req, false); -		if (!ret) -			ret = ceph_osdc_wait_request(&fsc->client->osdc, req); +		ceph_osdc_start_request(req->r_osdc, req); +		ret = ceph_osdc_wait_request(&fsc->client->osdc, req);  		if (write)  			ceph_update_write_metrics(metric, req->r_start_latency, @@ -1427,8 +1445,7 @@ ceph_direct_read_write(struct kiocb *iocb, struct iov_iter *iter,  					       r_private_item);  			list_del_init(&req->r_private_item);  			if (ret >= 0) -				ret = ceph_osdc_start_request(req->r_osdc, -							      req, false); +				ceph_osdc_start_request(req->r_osdc, req);  			if (ret < 0) {  				req->r_result = ret;  				ceph_aio_complete_req(req); @@ -1541,9 +1558,8 @@ ceph_sync_write(struct kiocb *iocb, struct iov_iter *from, loff_t pos,  						false, true);  		req->r_mtime = mtime; -		ret = ceph_osdc_start_request(&fsc->client->osdc, req, false); -		if (!ret) -			ret = ceph_osdc_wait_request(&fsc->client->osdc, req); +		ceph_osdc_start_request(&fsc->client->osdc, req); +		ret = ceph_osdc_wait_request(&fsc->client->osdc, req);  		ceph_update_write_metrics(&fsc->mdsc->metric, req->r_start_latency,  					  req->r_end_latency, len, ret); @@ -1627,7 +1643,7 @@ again:  		     inode, ceph_vinop(inode), iocb->ki_pos, (unsigned)len,  		     ceph_cap_string(got)); -		if (ci->i_inline_version == CEPH_INLINE_NONE) { +		if (!ceph_has_inline_data(ci)) {  			if (!retry_op && (iocb->ki_flags & IOCB_DIRECT)) {  				ret = ceph_direct_read_write(iocb, to,  							     NULL, NULL); @@ -1890,7 +1906,7 @@ retry_snap:  		if (dirty)  			__mark_inode_dirty(inode, dirty);  		if (ceph_quota_is_max_bytes_approaching(inode, iocb->ki_pos)) -			ceph_check_caps(ci, 0, NULL); +			ceph_check_caps(ci, CHECK_CAPS_FLUSH, NULL);  	}  	dout("aio_write %p %llx.%llx %llu~%u  dropping cap refs on %s\n", @@ -1930,57 +1946,15 @@ out_unlocked:   */  static loff_t ceph_llseek(struct file *file, loff_t offset, int whence)  { -	struct inode *inode = file->f_mapping->host; -	struct ceph_fs_client *fsc = ceph_inode_to_client(inode); -	loff_t i_size; -	loff_t ret; - -	inode_lock(inode); -  	if (whence == SEEK_END || whence == SEEK_DATA || whence == SEEK_HOLE) { +		struct inode *inode = file_inode(file); +		int ret; +  		ret = ceph_do_getattr(inode, CEPH_STAT_CAP_SIZE, false);  		if (ret < 0) -			goto out; -	} - -	i_size = i_size_read(inode); -	switch (whence) { -	case SEEK_END: -		offset += i_size; -		break; -	case SEEK_CUR: -		/* -		 * Here we special-case the lseek(fd, 0, SEEK_CUR) -		 * position-querying operation.  Avoid rewriting the "same" -		 * f_pos value back to the file because a concurrent read(), -		 * write() or lseek() might have altered it -		 */ -		if (offset == 0) { -			ret = file->f_pos; -			goto out; -		} -		offset += file->f_pos; -		break; -	case SEEK_DATA: -		if (offset < 0 || offset >= i_size) { -			ret = -ENXIO; -			goto out; -		} -		break; -	case SEEK_HOLE: -		if (offset < 0 || offset >= i_size) { -			ret = -ENXIO; -			goto out; -		} -		offset = i_size; -		break; +			return ret;  	} - -	ret = vfs_setpos(file, offset, max(i_size, fsc->max_file_size)); - -out: -	inode_unlock(inode); -	return ret; +	return generic_file_llseek(file, offset, whence);  }  static inline void ceph_zero_partial_page( @@ -2049,12 +2023,10 @@ static int ceph_zero_partial_object(struct inode *inode,  	}  	req->r_mtime = inode->i_mtime; -	ret = ceph_osdc_start_request(&fsc->client->osdc, req, false); -	if (!ret) { -		ret = ceph_osdc_wait_request(&fsc->client->osdc, req); -		if (ret == -ENOENT) -			ret = 0; -	} +	ceph_osdc_start_request(&fsc->client->osdc, req); +	ret = ceph_osdc_wait_request(&fsc->client->osdc, req); +	if (ret == -ENOENT) +		ret = 0;  	ceph_osdc_put_request(req);  out: @@ -2356,7 +2328,7 @@ static ssize_t ceph_do_objects_copy(struct ceph_inode_info *src_ci, u64 *src_off  		if (IS_ERR(req))  			ret = PTR_ERR(req);  		else { -			ceph_osdc_start_request(osdc, req, false); +			ceph_osdc_start_request(osdc, req);  			ret = ceph_osdc_wait_request(osdc, req);  			ceph_update_copyfrom_metrics(&fsc->mdsc->metric,  						     req->r_start_latency, @@ -2549,7 +2521,8 @@ static ssize_t __ceph_copy_file_range(struct file *src_file, loff_t src_off,  		/* Let the MDS know about dst file size change */  		if (ceph_inode_set_size(dst_inode, dst_off) ||  		    ceph_quota_is_max_bytes_approaching(dst_inode, dst_off)) -			ceph_check_caps(dst_ci, CHECK_CAPS_AUTHONLY, NULL); +			ceph_check_caps(dst_ci, CHECK_CAPS_AUTHONLY | CHECK_CAPS_FLUSH, +					NULL);  	}  	/* Mark Fw dirty */  	spin_lock(&dst_ci->i_ceph_lock); |