Implemented metadata write in pohmelfs_write()
[pohmelfs.git] / fs / pohmelfs / file.c
blob9d0c34ac6c3fa7fbe873d68391d292e6ccaabb62
1 /*
2 * Copyright (C) 2011+ Evgeniy Polyakov <zbr@ioremap.net>
3 */
5 #include <linux/fs.h>
7 #include "pohmelfs.h"
9 static int pohmelfs_setattr(struct dentry *dentry, struct iattr *iattr)
11 struct inode *inode = dentry->d_inode;
12 int err;
14 err = inode_change_ok(inode, iattr);
15 if (err)
16 return err;
18 if (iattr->ia_valid & ATTR_SIZE && iattr->ia_size != inode->i_size) {
19 truncate_setsize(inode, iattr->ia_size);
21 inode->i_mtime = inode->i_ctime = CURRENT_TIME;
22 if (inode_needs_sync(inode)) {
23 sync_inode_metadata(inode, 1);
26 setattr_copy(inode, iattr);
27 mark_inode_dirty(inode);
29 pr_info("pohmelfs_setattr: ino: %lu, size: %llu, mtime: %lu.%lu\n",
30 inode->i_ino, inode->i_size, inode->i_mtime.tv_sec, inode->i_mtime.tv_nsec);
32 return err;
35 static int pohmelfs_send_prepare_commit(struct pohmelfs_inode *pi, size_t len, loff_t pos, int prepare)
37 struct pohmelfs_io *io;
38 int err;
40 io = kmem_cache_zalloc(pohmelfs_io_cache, GFP_NOIO);
41 if (!io) {
42 err = -ENOMEM;
43 goto err_out_exit;
46 io->pi = pi;
47 io->id = &pi->id;
48 io->cmd = DNET_CMD_WRITE;
49 io->offset = pos;
50 io->num = len + pos;
51 io->cflags = DNET_FLAGS_NEED_ACK;
52 io->aflags = DNET_ATTR_NOCSUM;
53 if (prepare)
54 io->ioflags = DNET_IO_FLAGS_PREPARE;
55 else
56 io->ioflags = DNET_IO_FLAGS_COMMIT;
57 io->ioflags |= DNET_IO_FLAGS_PLAIN_WRITE;
59 err = pohmelfs_send_io(io);
61 kmem_cache_free(pohmelfs_io_cache, io);
62 err_out_exit:
63 return err;
66 static int pohmelfs_write_init(struct pohmelfs_trans *t)
68 struct pohmelfs_wait *wait = t->priv;
70 pohmelfs_wait_get(wait);
71 return 0;
74 static void pohmelfs_write_destroy(struct pohmelfs_trans *t)
76 struct pohmelfs_wait *wait = t->priv;
78 wake_up(&wait->wq);
79 pohmelfs_wait_put(wait);
82 static int pohmelfs_write_complete(struct pohmelfs_trans *t, struct pohmelfs_state *recv)
84 struct pohmelfs_wait *wait = t->priv;
85 struct pohmelfs_inode *pi = pohmelfs_inode(t->inode);
86 struct dnet_cmd *cmd = &recv->cmd;
87 unsigned long long trans = cmd->trans & ~DNET_TRANS_REPLY;
89 pr_info("pohmelfs: %s: write complete: %llu, flags: %x, status: %d\n",
90 pohmelfs_dump_id(pi->id.id), trans, cmd->flags, cmd->status);
92 if (cmd->flags & DNET_FLAGS_MORE)
93 return 0;
95 wait->condition = cmd->status;
96 if (!wait->condition)
97 wait->condition = 1;
99 return 0;
102 static int pohmelfs_send_write_metadata(struct pohmelfs_inode *pi, struct pohmelfs_io *pio, struct pohmelfs_wait *wait)
104 struct pohmelfs_sb *psb = pohmelfs_sb(pi->vfs_inode.i_sb);
105 struct timespec ts = CURRENT_TIME;
106 struct dnet_meta_update *mu;
107 struct dnet_meta *m;
108 int err, size;
109 void *data;
111 size = sizeof(struct dnet_meta) * 5 +
112 sizeof(struct dnet_meta_check_status) +
113 sizeof(struct dnet_meta_update) +
114 sizeof(struct dnet_meta_checksum) +
115 psb->fsid_len +
116 psb->group_num * sizeof(int);
118 data = kzalloc(size, GFP_NOIO);
119 if (!data) {
120 err = -ENOMEM;
121 goto err_out_exit;
124 m = data;
125 m->type = DNET_META_GROUPS;
126 m->size = psb->group_num * sizeof(int);
127 memcpy(m->data, psb->groups, m->size);
128 dnet_convert_meta(m);
130 m = (struct dnet_meta *)(m->data + le32_to_cpu(m->size));
131 m->type = DNET_META_NAMESPACE;
132 m->size = psb->fsid_len;
133 memcpy(m->data, psb->fsid, psb->fsid_len);
134 dnet_convert_meta(m);
136 m = (struct dnet_meta *)(m->data + le32_to_cpu(m->size));
137 m->type = DNET_META_CHECKSUM;
138 m->size = sizeof(struct dnet_meta_checksum);
139 /* do not fill, it will be updated on server */
140 dnet_convert_meta(m);
142 m = (struct dnet_meta *)(m->data + le32_to_cpu(m->size));
143 m->type = DNET_META_UPDATE;
144 m->size = sizeof(struct dnet_meta_update);
145 mu = (struct dnet_meta_update *)m->data;
146 mu->tm.tsec = ts.tv_sec;
147 mu->tm.tnsec = ts.tv_nsec;
148 dnet_convert_meta_update(mu);
149 dnet_convert_meta(m);
151 m = (struct dnet_meta *)(m->data + le32_to_cpu(m->size));
152 m->type = DNET_META_CHECK_STATUS;
153 m->size = sizeof(struct dnet_meta_check_status);
154 /* do not fill, it will be updated on server */
155 dnet_convert_meta(m);
157 memset(pio, 0, sizeof(struct pohmelfs_io));
159 pio->pi = pi;
160 pio->id = &pi->id;
161 pio->cmd = DNET_CMD_WRITE;
162 pio->ioflags = DNET_IO_FLAGS_OVERWRITE | DNET_IO_FLAGS_META;
163 pio->cflags = DNET_FLAGS_NEED_ACK;
164 pio->type = 1;
165 pio->cb.init = pohmelfs_write_init;
166 pio->cb.destroy = pohmelfs_write_destroy;
167 pio->cb.complete = pohmelfs_write_complete;
168 pio->priv = wait;
169 pio->data = data;
170 pio->size = size;
172 err = pohmelfs_send_io(pio);
173 if (err)
174 goto err_out_free;
176 err_out_free:
177 kfree(data);
178 err_out_exit:
179 return err;
182 static ssize_t pohmelfs_write(struct file *filp, const char __user *buf, size_t len, loff_t *ppos)
184 ssize_t err;
185 struct inode *inode = filp->f_mapping->host;
186 struct pohmelfs_sb *psb = pohmelfs_sb(inode->i_sb);
187 struct pohmelfs_inode *pi = pohmelfs_inode(inode);
188 struct pohmelfs_io *pio;
189 loff_t offset = *ppos;
190 struct pohmelfs_wait *wait;
191 long ret;
193 #if 0
194 err = pohmelfs_send_prepare_commit(pi, len, offset, 1);
195 if (err)
196 goto err_out_exit;
198 err = do_sync_write(filp, buf, len, ppos);
199 pohmelfs_send_prepare_commit(pi, 0, 0, 0);
200 #else
202 err = do_sync_write(filp, buf, len, ppos);
203 pr_info("pohmelfs_write: %s: ino: %lu size: %llu, notime: %d, mtime: %lu.%lu\n",
204 pohmelfs_dump_id(pi->id.id),
205 inode->i_ino, inode->i_size, IS_NOCMTIME(inode),
206 inode->i_mtime.tv_sec, inode->i_mtime.tv_nsec);
208 if (err < 0)
209 goto err_out_exit;
211 wait = pohmelfs_wait_alloc(pi);
212 if (!wait) {
213 err = -ENOMEM;
214 goto err_out_exit;
217 pio = kmem_cache_zalloc(pohmelfs_io_cache, GFP_NOIO);
218 if (!pio) {
219 err = -ENOMEM;
220 goto err_out_put;
223 pio->pi = pi;
224 pio->id = &pi->id;
225 pio->cmd = DNET_CMD_WRITE;
226 pio->offset = offset;
227 pio->size = err;
228 pio->cflags = DNET_FLAGS_NEED_ACK;
229 pio->aflags = DNET_ATTR_NOCSUM;
230 pio->ioflags = DNET_IO_FLAGS_OVERWRITE;
231 //pio->ioflags |= DNET_IO_FLAGS_PLAIN_WRITE;
232 pio->cb.init = pohmelfs_write_init;
233 pio->cb.destroy = pohmelfs_write_destroy;
234 pio->cb.complete = pohmelfs_write_complete;
235 pio->mapping = filp->f_mapping;
236 pio->priv = wait;
238 err = pohmelfs_send_io(pio);
239 if (err)
240 goto err_out_free;
242 err = pohmelfs_send_write_metadata(pi, pio, wait);
243 if (err)
244 goto err_out_free;
246 inode->i_sb->s_op->write_inode(inode, NULL);
248 ret = wait_event_interruptible_timeout(wait->wq,
249 wait->condition != 0 && atomic_read(&wait->refcnt.refcount) == 1,
250 msecs_to_jiffies(psb->write_wait_timeout));
251 if (ret <= 0) {
252 err = ret;
253 if (ret == 0)
254 err = -ETIMEDOUT;
255 goto err_out_free;
258 if (wait->condition < 0) {
259 err = wait->condition;
260 goto err_out_free;
263 err = len;
265 err_out_free:
266 kmem_cache_free(pohmelfs_io_cache, pio);
267 err_out_put:
268 pohmelfs_wait_put(wait);
269 #endif
270 err_out_exit:
271 return err;
274 const struct file_operations pohmelfs_file_ops = {
275 .open = generic_file_open,
277 .llseek = generic_file_llseek,
279 .read = do_sync_read,
280 .aio_read = generic_file_aio_read,
282 .mmap = generic_file_mmap,
284 .splice_read = generic_file_splice_read,
285 .splice_write = generic_file_splice_write,
287 .write = pohmelfs_write,
288 .aio_write = generic_file_aio_write,
291 const struct inode_operations pohmelfs_file_inode_operations = {
292 .setattr = pohmelfs_setattr,