X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=fs%2Fsmbfs%2Fproc.c;h=feac46050619075aa90a88f71e4a8e4a31b5cda5;hb=97bf2856c6014879bd04983a3e9dfcdac1e7fe85;hp=21c90222bcb4fc89166715594cd6f19201ec4bdc;hpb=5273a3df6485dc2ad6aa7ddd441b9a21970f003b;p=linux-2.6.git diff --git a/fs/smbfs/proc.c b/fs/smbfs/proc.c index 21c90222b..feac46050 100644 --- a/fs/smbfs/proc.c +++ b/fs/smbfs/proc.c @@ -8,6 +8,7 @@ */ #include +#include #include #include #include @@ -56,6 +57,7 @@ static struct smb_ops smb_ops_os2; static struct smb_ops smb_ops_win95; static struct smb_ops smb_ops_winNT; static struct smb_ops smb_ops_unix; +static struct smb_ops smb_ops_null; static void smb_init_dirent(struct smb_sb_info *server, struct smb_fattr *fattr); @@ -73,7 +75,7 @@ smb_proc_setattr_core(struct smb_sb_info *server, struct dentry *dentry, static int smb_proc_setattr_ext(struct smb_sb_info *server, struct inode *inode, struct smb_fattr *fattr); -int +static int smb_proc_query_cifsunix(struct smb_sb_info *server); static void install_ops(struct smb_ops *dst, struct smb_ops *src); @@ -871,11 +873,11 @@ smb_newconn(struct smb_sb_info *server, struct smb_conn_opt *opt) filp = fget(opt->fd); if (!filp) goto out; - if (!smb_valid_socket(filp->f_dentry->d_inode)) + if (!smb_valid_socket(filp->f_path.dentry->d_inode)) goto out_putf; server->sock_file = filp; - server->conn_pid = current->pid; + server->conn_pid = get_pid(task_pid(current)); server->opt = *opt; server->generation += 1; server->state = CONN_VALID; @@ -896,7 +898,7 @@ smb_newconn(struct smb_sb_info *server, struct smb_conn_opt *opt) /* * Store the server in sock user_data (Only used by sunrpc) */ - sk = SOCKET_I(filp->f_dentry->d_inode)->sk; + sk = SOCKET_I(filp->f_path.dentry->d_inode)->sk; sk->sk_user_data = server; /* chain into the data_ready callback */ @@ -969,8 +971,8 @@ smb_newconn(struct smb_sb_info *server, struct smb_conn_opt *opt) } VERBOSE("protocol=%d, max_xmit=%d, pid=%d capabilities=0x%x\n", - server->opt.protocol, server->opt.max_xmit, server->conn_pid, - server->opt.capabilities); + server->opt.protocol, server->opt.max_xmit, + pid_nr(server->conn_pid), server->opt.capabilities); /* FIXME: this really should be done by smbmount. */ if (server->opt.max_xmit > SMB_MAX_PACKET_SIZE) { @@ -981,6 +983,9 @@ smb_newconn(struct smb_sb_info *server, struct smb_conn_opt *opt) smbiod_wake_up(); if (server->opt.capabilities & SMB_CAP_UNIX) smb_proc_query_cifsunix(server); + + server->conn_complete++; + wake_up_interruptible_all(&server->conn_wq); return error; out: @@ -1423,9 +1428,9 @@ smb_proc_readX_data(struct smb_request *req) * So we must first calculate the amount of padding used by the server. */ data_off -= hdrlen; - if (data_off > SMB_READX_MAX_PAD) { - PARANOIA("offset is larger than max pad!\n"); - PARANOIA("%d > %d\n", data_off, SMB_READX_MAX_PAD); + if (data_off > SMB_READX_MAX_PAD || data_off < 0) { + PARANOIA("offset is larger than SMB_READX_MAX_PAD or negative!\n"); + PARANOIA("%d > %d || %d < 0\n", data_off, SMB_READX_MAX_PAD, data_off); req->rq_rlen = req->rq_bufsize + 1; return; } @@ -1821,7 +1826,6 @@ smb_init_dirent(struct smb_sb_info *server, struct smb_fattr *fattr) fattr->f_nlink = 1; fattr->f_uid = server->mnt->uid; fattr->f_gid = server->mnt->gid; - fattr->f_blksize = SMB_ST_BLKSIZE; fattr->f_unix = 0; } @@ -1848,12 +1852,13 @@ smb_finish_dirent(struct smb_sb_info *server, struct smb_fattr *fattr) } void -smb_init_root_dirent(struct smb_sb_info *server, struct smb_fattr *fattr) +smb_init_root_dirent(struct smb_sb_info *server, struct smb_fattr *fattr, + struct super_block *sb) { smb_init_dirent(server, fattr); fattr->attr = aDIR; fattr->f_ino = 2; /* traditional root inode number */ - fattr->f_mtime = CURRENT_TIME; + fattr->f_mtime = current_fs_time(sb); smb_finish_dirent(server, fattr); } @@ -1934,7 +1939,7 @@ static int smb_proc_readdir_short(struct file *filp, void *dirent, filldir_t filldir, struct smb_cache_control *ctl) { - struct dentry *dir = filp->f_dentry; + struct dentry *dir = filp->f_path.dentry; struct smb_sb_info *server = server_from_dentry(dir); struct qstr qname; struct smb_fattr fattr; @@ -2070,8 +2075,10 @@ out: return result; } -void smb_decode_unix_basic(struct smb_fattr *fattr, char *p) +static void smb_decode_unix_basic(struct smb_fattr *fattr, struct smb_sb_info *server, char *p) { + u64 size, disk_bytes; + /* FIXME: verify nls support. all is sent as utf8? */ fattr->f_unix = 1; @@ -2089,13 +2096,33 @@ void smb_decode_unix_basic(struct smb_fattr *fattr, char *p) /* 84 L permissions */ /* 92 L link count */ - fattr->f_size = LVAL(p, 0); - fattr->f_blocks = LVAL(p, 8); + size = LVAL(p, 0); + disk_bytes = LVAL(p, 8); + + /* + * Some samba versions round up on-disk byte usage + * to 1MB boundaries, making it useless. When seeing + * that, use the size instead. + */ + if (!(disk_bytes & 0xfffff)) + disk_bytes = size+511; + + fattr->f_size = size; + fattr->f_blocks = disk_bytes >> 9; fattr->f_ctime = smb_ntutc2unixutc(LVAL(p, 16)); fattr->f_atime = smb_ntutc2unixutc(LVAL(p, 24)); fattr->f_mtime = smb_ntutc2unixutc(LVAL(p, 32)); - fattr->f_uid = LVAL(p, 40); - fattr->f_gid = LVAL(p, 48); + + if (server->mnt->flags & SMB_MOUNT_UID) + fattr->f_uid = server->mnt->uid; + else + fattr->f_uid = LVAL(p, 40); + + if (server->mnt->flags & SMB_MOUNT_GID) + fattr->f_gid = server->mnt->gid; + else + fattr->f_gid = LVAL(p, 48); + fattr->f_mode |= smb_filetype_to_mode(WVAL(p, 56)); if (S_ISBLK(fattr->f_mode) || S_ISCHR(fattr->f_mode)) { @@ -2104,10 +2131,20 @@ void smb_decode_unix_basic(struct smb_fattr *fattr, char *p) fattr->f_rdev = MKDEV(major & 0xffffffff, minor & 0xffffffff); if (MAJOR(fattr->f_rdev) != (major & 0xffffffff) || - MINOR(fattr->f_rdev) != (minor & 0xffffffff)) + MINOR(fattr->f_rdev) != (minor & 0xffffffff)) fattr->f_rdev = 0; } + fattr->f_mode |= LVAL(p, 84); + + if ( (server->mnt->flags & SMB_MOUNT_DMODE) && + (S_ISDIR(fattr->f_mode)) ) + fattr->f_mode = (server->mnt->dir_mode & S_IRWXUGO) | S_IFDIR; + else if ( (server->mnt->flags & SMB_MOUNT_FMODE) && + !(S_ISDIR(fattr->f_mode)) ) + fattr->f_mode = (server->mnt->file_mode & S_IRWXUGO) | + (fattr->f_mode & S_IFMT); + } /* @@ -2193,7 +2230,7 @@ smb_decode_long_dirent(struct smb_sb_info *server, char *p, int level, /* FIXME: should we check the length?? */ p += 8; - smb_decode_unix_basic(fattr, p); + smb_decode_unix_basic(fattr, server, p); VERBOSE("info SMB_FIND_FILE_UNIX at %p, len=%d, name=%.*s\n", p, len, len, qname->name); break; @@ -2254,7 +2291,7 @@ static int smb_proc_readdir_long(struct file *filp, void *dirent, filldir_t filldir, struct smb_cache_control *ctl) { - struct dentry *dir = filp->f_dentry; + struct dentry *dir = filp->f_path.dentry; struct smb_sb_info *server = server_from_dentry(dir); struct qstr qname; struct smb_fattr fattr; @@ -2305,16 +2342,14 @@ smb_proc_readdir_long(struct file *filp, void *dirent, filldir_t filldir, */ mask = param + 12; - mask_len = smb_encode_path(server, mask, SMB_MAXPATHLEN+1, dir, &star); - if (mask_len < 0) { - result = mask_len; + result = smb_encode_path(server, mask, SMB_MAXPATHLEN+1, dir, &star); + if (result <= 0) goto out_free; - } - mask_len--; /* mask_len is strlen, not #bytes */ + mask_len = result - 1; /* mask_len is strlen, not #bytes */ + result = 0; first = 1; VERBOSE("starting mask_len=%d, mask=%s\n", mask_len, mask); - result = 0; entries_seen = 2; ff_eos = 0; @@ -2362,15 +2397,14 @@ smb_proc_readdir_long(struct file *filp, void *dirent, filldir_t filldir, if (req->rq_rcls == ERRSRV && req->rq_err == ERRerror) { /* a damn Win95 bug - sometimes it clags if you ask it too fast */ - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(HZ/5); + schedule_timeout_interruptible(msecs_to_jiffies(200)); continue; } if (req->rq_rcls != 0) { result = smb_errno(req); PARANOIA("name=%s, result=%d, rcls=%d, err=%d\n", - mask, result, server->rcls, server->err); + mask, result, req->rq_rcls, req->rq_err); break; } @@ -2460,8 +2494,6 @@ smb_proc_readdir_long(struct file *filp, void *dirent, filldir_t filldir, /* * Update the mask string for the next message. */ - if (mask_len < 0) - mask_len = 0; if (mask_len > 255) mask_len = 255; if (mask_len) @@ -2526,7 +2558,7 @@ smb_proc_getattr_ff(struct smb_sb_info *server, struct dentry *dentry, result = smb_add_request(req); if (result < 0) goto out_free; - if (server->rcls != 0) { + if (req->rq_rcls != 0) { result = smb_errno(req); #ifdef SMBFS_PARANOIA if (result != -ENOENT) @@ -2639,7 +2671,7 @@ smb_proc_getattr_trans2(struct smb_sb_info *server, struct dentry *dir, result = smb_add_request(req); if (result < 0) goto out; - if (server->rcls != 0) { + if (req->rq_rcls != 0) { VERBOSE("for %s: result=%d, rcls=%d, err=%d\n", ¶m[6], result, req->rq_rcls, req->rq_err); result = smb_errno(req); @@ -2756,7 +2788,7 @@ smb_proc_getattr_unix(struct smb_sb_info *server, struct dentry *dir, if (result < 0) goto out_free; - smb_decode_unix_basic(attr, req->rq_data); + smb_decode_unix_basic(attr, server, req->rq_data); out_free: smb_rput(req); @@ -2793,11 +2825,46 @@ out: return result; } +static int +smb_proc_ops_wait(struct smb_sb_info *server) +{ + int result; + + result = wait_event_interruptible_timeout(server->conn_wq, + server->conn_complete, 30*HZ); + + if (!result || signal_pending(current)) + return -EIO; + + return 0; +} + static int smb_proc_getattr_null(struct smb_sb_info *server, struct dentry *dir, - struct smb_fattr *attr) + struct smb_fattr *fattr) { - return -EIO; + int result; + + if (smb_proc_ops_wait(server) < 0) + return -EIO; + + smb_init_dirent(server, fattr); + result = server->ops->getattr(server, dir, fattr); + smb_finish_dirent(server, fattr); + + return result; +} + +static int +smb_proc_readdir_null(struct file *filp, void *dirent, filldir_t filldir, + struct smb_cache_control *ctl) +{ + struct smb_sb_info *server = server_from_dentry(filp->f_path.dentry); + + if (smb_proc_ops_wait(server) < 0) + return -EIO; + + return server->ops->readdir(filp, dirent, filldir, ctl); } int @@ -3046,7 +3113,7 @@ smb_proc_setattr_unix(struct dentry *d, struct iattr *attr, LSET(data, 32, SMB_TIME_NO_CHANGE); LSET(data, 40, SMB_UID_NO_CHANGE); LSET(data, 48, SMB_GID_NO_CHANGE); - LSET(data, 56, smb_filetype_from_mode(attr->ia_mode)); + DSET(data, 56, smb_filetype_from_mode(attr->ia_mode)); LSET(data, 60, major); LSET(data, 68, minor); LSET(data, 76, 0); @@ -3158,9 +3225,9 @@ smb_proc_settime(struct dentry *dentry, struct smb_fattr *fattr) } int -smb_proc_dskattr(struct super_block *sb, struct kstatfs *attr) +smb_proc_dskattr(struct dentry *dentry, struct kstatfs *attr) { - struct smb_sb_info *server = SMB_SB(sb); + struct smb_sb_info *server = SMB_SB(dentry->d_sb); int result; char *p; long unit; @@ -3218,7 +3285,7 @@ smb_proc_read_link(struct smb_sb_info *server, struct dentry *d, if (result < 0) goto out_free; DEBUG1("for %s: result=%d, rcls=%d, err=%d\n", - ¶m[6], result, server->rcls, server->err); + ¶m[6], result, req->rq_rcls, req->rq_err); /* copy data up to the \0 or buffer length */ result = len; @@ -3268,7 +3335,7 @@ smb_proc_symlink(struct smb_sb_info *server, struct dentry *d, goto out_free; DEBUG1("for %s: result=%d, rcls=%d, err=%d\n", - ¶m[6], result, server->rcls, server->err); + ¶m[6], result, req->rq_rcls, req->rq_err); result = 0; out_free: @@ -3315,7 +3382,7 @@ smb_proc_link(struct smb_sb_info *server, struct dentry *dentry, goto out_free; DEBUG1("for %s: result=%d, rcls=%d, err=%d\n", - ¶m[6], result, server->rcls, server->err); + ¶m[6], result, req->rq_rcls, req->rq_err); result = 0; out_free: @@ -3324,7 +3391,7 @@ out: return result; } -int +static int smb_proc_query_cifsunix(struct smb_sb_info *server) { int result; @@ -3431,6 +3498,7 @@ static struct smb_ops smb_ops_unix = /* Place holder until real ops are in place */ static struct smb_ops smb_ops_null = { + .readdir = smb_proc_readdir_null, .getattr = smb_proc_getattr_null, };