void v9fs_cache_session_get_cookie(struct v9fs_session_info *v9ses) { /* If no cache session tag was specified, we generate a random one. */ if (!v9ses->cachetag) v9fs_random_cachetag(v9ses); v9ses->fscache = fscache_acquire_cookie(v9fs_cache_netfs.primary_index, &v9fs_cache_session_index_def, v9ses); P9_DPRINTK(P9_DEBUG_FSC, "session %p get cookie %p", v9ses, v9ses->fscache); }
void v9fs_cache_inode_flush_cookie(struct inode *inode) { struct v9fs_inode *v9inode = V9FS_I(inode); if (!v9inode->fscache) return; P9_DPRINTK(P9_DEBUG_FSC, "inode %p flush cookie %p", inode, v9inode->fscache); fscache_relinquish_cookie(v9inode->fscache, 1); v9inode->fscache = NULL; }
int p9_client_uwrite(struct p9_fid *fid, const char __user *data, u64 offset, u32 count) { int err, n, rsize, total; struct p9_fcall *tc, *rc; struct p9_client *clnt; P9_DPRINTK(P9_DEBUG_9P, "fid %d offset %llu count %d\n", fid->fid, (long long unsigned) offset, count); err = 0; tc = NULL; rc = NULL; clnt = fid->clnt; total = 0; rsize = fid->iounit; if (!rsize || rsize > clnt->msize-P9_IOHDRSZ) rsize = clnt->msize - P9_IOHDRSZ; do { if (count < rsize) rsize = count; tc = p9_create_twrite_u(fid->fid, offset, rsize, data); if (IS_ERR(tc)) { err = PTR_ERR(tc); tc = NULL; goto error; } err = p9_conn_rpc(clnt->conn, tc, &rc); if (err) goto error; n = rc->params.rread.count; count -= n; data += n; offset += n; total += n; kfree(tc); tc = NULL; kfree(rc); rc = NULL; } while (count > 0); return total; error: kfree(tc); kfree(rc); return err; }
int p9_client_open(struct p9_fid *fid, int mode) { int err; struct p9_client *clnt; struct p9_req_t *req; struct p9_qid qid; int iounit; P9_DPRINTK(P9_DEBUG_9P, ">>> TOPEN fid %d mode %d\n", fid->fid, mode); err = 0; clnt = fid->clnt; if (fid->mode != -1) return -EINVAL; req = p9_client_rpc(clnt, P9_TOPEN, "db", fid->fid, mode); if (IS_ERR(req)) { err = PTR_ERR(req); goto error; } err = p9pdu_readf(req->rc, clnt->dotu, "Qd", &qid, &iounit); if (err) { p9pdu_dump(1, req->rc); goto free_and_error; } P9_DPRINTK(P9_DEBUG_9P, "<<< ROPEN qid %x.%llx.%x iounit %x\n", qid.type, (unsigned long long)qid.path, qid.version, iounit); fid->mode = mode; fid->iounit = iounit; free_and_error: p9_free_req(clnt, req); error: return err; }
int p9_client_version(struct p9_client *c) { int err = 0; struct p9_req_t *req; char *version; int msize; P9_DPRINTK(P9_DEBUG_9P, ">>> TVERSION msize %d extended %d\n", c->msize, c->dotu); req = p9_client_rpc(c, P9_TVERSION, "ds", c->msize, c->dotu ? "9P2000.u" : "9P2000"); if (IS_ERR(req)) return PTR_ERR(req); err = p9pdu_readf(req->rc, c->dotu, "ds", &msize, &version); if (err) { P9_DPRINTK(P9_DEBUG_9P, "version error %d\n", err); p9pdu_dump(1, req->rc); goto error; } P9_DPRINTK(P9_DEBUG_9P, "<<< RVERSION msize %d %s\n", msize, version); if (!memcmp(version, "9P2000.u", 8)) c->dotu = 1; else if (!memcmp(version, "9P2000", 6)) c->dotu = 0; else { err = -EREMOTEIO; goto error; } if (msize < c->msize) c->msize = msize; error: kfree(version); p9_free_req(c, req); return err; }
int v9fs_vfs_setattr_dotl(struct dentry *dentry, struct iattr *iattr) { int retval; struct v9fs_session_info *v9ses; struct p9_fid *fid; struct p9_iattr_dotl p9attr; P9_DPRINTK(P9_DEBUG_VFS, "\n"); retval = inode_change_ok(dentry->d_inode, iattr); if (retval) return retval; p9attr.valid = iattr->ia_valid; p9attr.mode = iattr->ia_mode; p9attr.uid = iattr->ia_uid; p9attr.gid = iattr->ia_gid; p9attr.size = iattr->ia_size; p9attr.atime_sec = iattr->ia_atime.tv_sec; p9attr.atime_nsec = iattr->ia_atime.tv_nsec; p9attr.mtime_sec = iattr->ia_mtime.tv_sec; p9attr.mtime_nsec = iattr->ia_mtime.tv_nsec; retval = -EPERM; v9ses = v9fs_dentry2v9ses(dentry); fid = v9fs_fid_lookup(dentry); if (IS_ERR(fid)) return PTR_ERR(fid); /* Write all dirty data */ if (S_ISREG(dentry->d_inode->i_mode)) filemap_write_and_wait(dentry->d_inode->i_mapping); retval = p9_client_setattr(fid, &p9attr); if (retval < 0) return retval; if ((iattr->ia_valid & ATTR_SIZE) && iattr->ia_size != i_size_read(dentry->d_inode)) truncate_setsize(dentry->d_inode, iattr->ia_size); v9fs_invalidate_inode_attr(dentry->d_inode); setattr_copy(dentry->d_inode, iattr); mark_inode_dirty(dentry->d_inode); if (iattr->ia_valid & ATTR_MODE) { /* We also want to update ACL when we update mode bits */ retval = v9fs_acl_chmod(dentry); if (retval < 0) return retval; } return 0; }
int v9fs_dir_release(struct inode *inode, struct file *filp) { struct p9_fid *fid; fid = filp->private_data; P9_DPRINTK(P9_DEBUG_VFS, "v9fs_dir_release: inode: %p filp: %p fid: %d\n", inode, filp, fid ? fid->fid : -1); filemap_write_and_wait(inode->i_mapping); if (fid) p9_client_clunk(fid); return 0; }
/* * v9fs_xattr_get() * * Copy an extended attribute into the buffer * provided, or compute the buffer size required. * Buffer is NULL to compute the size of the buffer required. * * Returns a negative error number on failure, or the number of bytes * used / required on success. */ ssize_t v9fs_xattr_get(struct dentry *dentry, const char *name, void *buffer, size_t buffer_size) { struct p9_fid *fid; P9_DPRINTK(P9_DEBUG_VFS, "%s: name = %s value_len = %zu\n", __func__, name, buffer_size); fid = v9fs_fid_lookup(dentry); if (IS_ERR(fid)) return PTR_ERR(fid); return v9fs_fid_xattr_get(fid, name, buffer, buffer_size); }
static void p9_fid_destroy(struct p9_fid *fid) { struct p9_client *clnt; unsigned long flags; P9_DPRINTK(P9_DEBUG_FID, "fid %d\n", fid->fid); clnt = fid->clnt; p9_idpool_put(fid->fid, clnt->fidpool); spin_lock_irqsave(&clnt->lock, flags); list_del(&fid->flist); spin_unlock_irqrestore(&clnt->lock, flags); kfree(fid); }
static void p9_fid_destroy(struct p9_fid *fid) { struct p9_client *clnt; P9_DPRINTK(P9_DEBUG_9P, "fid %d\n", fid->fid); clnt = fid->clnt; p9_idpool_put(fid->fid, clnt->fidpool); spin_lock(&clnt->lock); list_del(&fid->flist); spin_unlock(&clnt->lock); kfree(fid->rdir_fcall); kfree(fid); }
int v9fs_file_open(struct inode *inode, struct file *file) { int err; struct v9fs_session_info *v9ses; struct p9_fid *fid; int omode; P9_DPRINTK(P9_DEBUG_VFS, "inode: %p file: %p \n", inode, file); v9ses = v9fs_inode2v9ses(inode); omode = v9fs_uflags2omode(file->f_flags); fid = file->private_data; if (!fid) { fid = v9fs_fid_clone(file->f_path.dentry); if (IS_ERR(fid)) return PTR_ERR(fid); err = p9_client_open(fid, omode); if (err < 0) { p9_client_clunk(fid); return err; } if (omode & P9_OTRUNC) { inode->i_size = 0; inode->i_blocks = 0; } } file->private_data = fid; if ((fid->qid.version) && (v9ses->cache)) { P9_DPRINTK(P9_DEBUG_VFS, "cached"); /* enable cached file options */ if(file->f_op == &v9fs_file_operations) file->f_op = &v9fs_cached_file_operations; } return 0; }
ssize_t v9fs_fid_xattr_get(struct p9_fid *fid, const char *name, void *buffer, size_t buffer_size) { ssize_t retval; int msize, read_count; u64 offset = 0, attr_size; struct p9_fid *attr_fid; attr_fid = p9_client_xattrwalk(fid, name, &attr_size); if (IS_ERR(attr_fid)) { retval = PTR_ERR(attr_fid); P9_DPRINTK(P9_DEBUG_VFS, "p9_client_attrwalk failed %zd\n", retval); attr_fid = NULL; goto error; } if (!buffer_size) { /* request to get the attr_size */ retval = attr_size; goto error; } if (attr_size > buffer_size) { retval = -ERANGE; goto error; } msize = attr_fid->clnt->msize; while (attr_size) { if (attr_size > (msize - P9_IOHDRSZ)) read_count = msize - P9_IOHDRSZ; else read_count = attr_size; read_count = p9_client_read(attr_fid, ((char *)buffer)+offset, NULL, offset, read_count); if (read_count < 0) { /* error in xattr read */ retval = read_count; goto error; } offset += read_count; attr_size -= read_count; } /* Total read xattr bytes */ retval = offset; error: if (attr_fid) p9_client_clunk(attr_fid); return retval; }
static int p9_check_errors(struct p9_client *c, struct p9_req_t *req) { int8_t type; int err; err = p9_parse_header(req->rc, NULL, &type, NULL, 0); if (err) { P9_DPRINTK(P9_DEBUG_ERROR, "couldn't parse header %d\n", err); return err; } if (type == P9_RERROR) { int ecode; char *ename; err = p9pdu_readf(req->rc, c->dotu, "s?d", &ename, &ecode); if (err) { P9_DPRINTK(P9_DEBUG_ERROR, "couldn't parse error%d\n", err); return err; } if (c->dotu) err = -ecode; if (!err || !IS_ERR_VALUE(err)) err = p9_errstr2errno(ename, strlen(ename)); P9_DPRINTK(P9_DEBUG_9P, "<<< RERROR (%d) %s\n", -ecode, ename); kfree(ename); } else err = 0; return err; }
/** * v9fs_file_read - read from a file * @filep: file pointer to read * @data: data buffer to read data into * @count: size of buffer * @offset: offset at which to read data * */ static ssize_t v9fs_file_read(struct file *filp, char __user * data, size_t count, loff_t * offset) { int ret; struct p9_fid *fid; P9_DPRINTK(P9_DEBUG_VFS, "\n"); fid = filp->private_data; ret = p9_client_uread(fid, data, *offset, count); if (ret > 0) *offset += ret; return ret; }
static void p9_free_req(struct p9_client *c, struct p9_req_t *r) { int tag = r->tc->tag; P9_DPRINTK(P9_DEBUG_MUX, "clnt %p req %p tag: %d\n", c, r, tag); r->status = REQ_STATUS_IDLE; if (tag != P9_NOTAG && p9_idpool_check(tag, c->tagpool)) p9_idpool_put(tag, c->tagpool); /* if this was a flush request we have to free response fcall */ if (r->rc->id == P9_RFLUSH) { kfree(r->tc); kfree(r->rc); } }
int p9_client_remove(struct p9_fid *fid) { int err; struct p9_client *clnt; struct p9_req_t *req; P9_DPRINTK(P9_DEBUG_9P, ">>> TREMOVE fid %d\n", fid->fid); err = 0; clnt = fid->clnt; req = p9_client_rpc(clnt, P9_TREMOVE, "d", fid->fid); if (IS_ERR(req)) { err = PTR_ERR(req); goto error; } P9_DPRINTK(P9_DEBUG_9P, "<<< RREMOVE fid %d\n", fid->fid); p9_free_req(clnt, req); p9_fid_destroy(fid); error: return err; }
static int v9fs_file_lock(struct file *filp, int cmd, struct file_lock *fl) { int res = 0; struct inode *inode = filp->f_path.dentry->d_inode; P9_DPRINTK(P9_DEBUG_VFS, "filp: %p lock: %p\n", filp, fl); /* No mandatory locks */ if (__mandatory_lock(inode) && fl->fl_type != F_UNLCK) return -ENOLCK; if ((IS_SETLK(cmd) || IS_SETLKW(cmd)) && fl->fl_type != F_UNLCK) { filemap_write_and_wait(inode->i_mapping); invalidate_mapping_pages(&inode->i_data, 0, -1); } return res; }
int p9stat_read(char *buf, int len, struct p9_wstat *st, int proto_version) { struct p9_fcall fake_pdu; int ret; fake_pdu.size = len; fake_pdu.capacity = len; fake_pdu.sdata = buf; fake_pdu.offset = 0; ret = p9pdu_readf(&fake_pdu, proto_version, "S", st); if (ret) { P9_DPRINTK(P9_DEBUG_9P, "<<< p9stat_read failed: %d\n", ret); p9pdu_dump(1, &fake_pdu); } return ret; }
struct p9_fid *p9_client_attach(struct p9_client *clnt, struct p9_fid *afid, char *uname, u32 n_uname, char *aname) { int err; struct p9_fcall *tc, *rc; struct p9_fid *fid; P9_DPRINTK(P9_DEBUG_9P, "clnt %p afid %d uname %s aname %s\n", clnt, afid?afid->fid:-1, uname, aname); err = 0; tc = NULL; rc = NULL; fid = p9_fid_create(clnt); if (IS_ERR(fid)) { err = PTR_ERR(fid); fid = NULL; goto error; } tc = p9_create_tattach(fid->fid, afid?afid->fid:P9_NOFID, uname, aname, n_uname, clnt->dotu); if (IS_ERR(tc)) { err = PTR_ERR(tc); tc = NULL; goto error; } err = p9_conn_rpc(clnt->conn, tc, &rc); if (err) goto error; memmove(&fid->qid, &rc->params.rattach.qid, sizeof(struct p9_qid)); kfree(tc); kfree(rc); return fid; error: kfree(tc); kfree(rc); if (fid) p9_fid_destroy(fid); return ERR_PTR(err); }
static ssize_t v9fs_file_write(struct file *filp, const char __user * data, size_t count, loff_t * offset) { int n, rsize, total = 0; struct p9_fid *fid; struct p9_client *clnt; struct inode *inode = filp->f_path.dentry->d_inode; loff_t origin = *offset; unsigned long pg_start, pg_end; P9_DPRINTK(P9_DEBUG_VFS, "data %p count %d offset %x\n", data, (int)count, (int)*offset); fid = filp->private_data; clnt = fid->clnt; rsize = fid->iounit; if (!rsize || rsize > clnt->msize-P9_IOHDRSZ) rsize = clnt->msize - P9_IOHDRSZ; do { if (count < rsize) rsize = count; n = p9_client_write(fid, NULL, data+total, origin+total, rsize); if (n <= 0) break; count -= n; total += n; } while (count > 0); if (total > 0) { pg_start = origin >> PAGE_CACHE_SHIFT; pg_end = (origin + total - 1) >> PAGE_CACHE_SHIFT; if (inode->i_mapping && inode->i_mapping->nrpages) invalidate_inode_pages2_range(inode->i_mapping, pg_start, pg_end); *offset += total; i_size_write(inode, i_size_read(inode) + total); inode->i_blocks = (i_size_read(inode) + 512 - 1) >> 9; }
/** * p9_fd_read- read from a fd * @v9ses: session information * @v: buffer to receive data into * @len: size of receive buffer * */ static int p9_fd_read(struct p9_transport *trans, void *v, int len) { int ret; struct p9_trans_fd *ts = NULL; if (trans && trans->status != Disconnected) ts = trans->priv; if (!ts) return -EREMOTEIO; if (!(ts->rd->f_flags & O_NONBLOCK)) P9_DPRINTK(P9_DEBUG_ERROR, "blocking read ...\n"); ret = kernel_read(ts->rd, ts->rd->f_pos, v, len); if (ret <= 0 && ret != -ERESTARTSYS && ret != -EAGAIN) trans->status = Disconnected; return ret; }
int p9pdu_finalize(struct p9_fcall *pdu) { int size = pdu->size; int err; pdu->size = 0; err = p9pdu_writef(pdu, 0, "d", size); pdu->size = size; #ifdef CONFIG_NET_9P_DEBUG if ((p9_debug_level & P9_DEBUG_PKT) == P9_DEBUG_PKT) p9pdu_dump(0, pdu); #endif P9_DPRINTK(P9_DEBUG_9P, ">>> size=%d type: %d tag: %d\n", pdu->size, pdu->id, pdu->tag); return err; }
struct p9_stat *p9_client_stat(struct p9_fid *fid) { int err; struct p9_fcall *tc, *rc; struct p9_client *clnt; struct p9_stat *ret; P9_DPRINTK(P9_DEBUG_9P, "fid %d\n", fid->fid); err = 0; tc = NULL; rc = NULL; ret = NULL; clnt = fid->clnt; tc = p9_create_tstat(fid->fid); if (IS_ERR(tc)) { err = PTR_ERR(tc); tc = NULL; goto error; } err = p9_conn_rpc(clnt->conn, tc, &rc); if (err) goto error; ret = p9_clone_stat(&rc->params.rstat.stat, clnt->dotu); if (IS_ERR(ret)) { err = PTR_ERR(ret); ret = NULL; goto error; } kfree(tc); kfree(rc); return ret; error: kfree(tc); kfree(rc); kfree(ret); return ERR_PTR(err); }
static ssize_t v9fs_file_read(struct file *filp, char __user *udata, size_t count, loff_t * offset) { int ret; struct p9_fid *fid; P9_DPRINTK(P9_DEBUG_VFS, "count %zu offset %lld\n", count, *offset); fid = filp->private_data; if (count > (fid->clnt->msize - P9_IOHDRSZ)) ret = v9fs_file_readn(filp, NULL, udata, count, *offset); else ret = p9_client_read(fid, NULL, udata, *offset, count); if (ret > 0) *offset += ret; return ret; }
struct inode *v9fs_get_inode(struct super_block *sb, int mode, dev_t rdev) { int err; struct inode *inode; struct v9fs_session_info *v9ses = sb->s_fs_info; P9_DPRINTK(P9_DEBUG_VFS, "super block: %p mode: %o\n", sb, mode); inode = new_inode(sb); if (!inode) { P9_EPRINTK(KERN_WARNING, "Problem allocating inode\n"); return ERR_PTR(-ENOMEM); } err = v9fs_init_inode(v9ses, inode, mode, rdev); if (err) { iput(inode); return ERR_PTR(err); } return inode; }
void v9fs_cache_inode_get_cookie(struct inode *inode) { struct v9fs_inode *v9inode; struct v9fs_session_info *v9ses; if (!S_ISREG(inode->i_mode)) return; v9inode = V9FS_I(inode); if (v9inode->fscache) return; v9ses = v9fs_inode2v9ses(inode); v9inode->fscache = fscache_acquire_cookie(v9ses->fscache, &v9fs_cache_inode_index_def, v9inode); P9_DPRINTK(P9_DEBUG_FSC, "inode %p get cookie %p", inode, v9inode->fscache); }
static int v9fs_write_inode_dotl(struct inode *inode, struct writeback_control *wbc) { int ret; struct v9fs_inode *v9inode; /* * send an fsync request to server irrespective of * wbc->sync_mode. */ P9_DPRINTK(P9_DEBUG_VFS, "%s: inode %p\n", __func__, inode); v9inode = V9FS_I(inode); if (!v9inode->writeback_fid) return 0; ret = p9_client_fsync(v9inode->writeback_fid, 0); if (ret < 0) { __mark_inode_dirty(inode, I_DIRTY_DATASYNC); return ret; } return 0; }
static ssize_t v9fs_file_write(struct file *filp, const char __user * data, size_t count, loff_t * offset) { int ret; struct p9_fid *fid; struct inode *inode = filp->f_path.dentry->d_inode; P9_DPRINTK(P9_DEBUG_VFS, "data %p count %d offset %x\n", data, (int)count, (int)*offset); fid = filp->private_data; ret = p9_client_uwrite(fid, data, *offset, count); if (ret > 0) *offset += ret; if (*offset > inode->i_size) { inode->i_size = *offset; inode->i_blocks = (inode->i_size + 512 - 1) >> 9; }
void p9_client_destroy(struct p9_client *clnt) { struct p9_fid *fid, *fidptr; P9_DPRINTK(P9_DEBUG_MUX, "clnt %p\n", clnt); if (clnt->trans_mod) clnt->trans_mod->close(clnt); v9fs_put_trans(clnt->trans_mod); list_for_each_entry_safe(fid, fidptr, &clnt->fidlist, flist) p9_fid_destroy(fid); if (clnt->fidpool) p9_idpool_destroy(clnt->fidpool); p9_tag_cleanup(clnt); kfree(clnt); }
static int p9_client_flush(struct p9_client *c, struct p9_req_t *oldreq) { struct p9_req_t *req; int16_t oldtag; int err; err = p9_parse_header(oldreq->tc, NULL, NULL, &oldtag, 1); if (err) return err; P9_DPRINTK(P9_DEBUG_9P, ">>> TFLUSH tag %d\n", oldtag); req = p9_client_rpc(c, P9_TFLUSH, "w", oldtag); if (IS_ERR(req)) return PTR_ERR(req); req->flush_tag = oldtag; /* we don't free anything here because RPC isn't complete */ return 0; }