From: Petr Vandrovec It decreases stack consumption in one of ncpfs's paths from 3000 to 2200 bytes (and stack portion in ncpfs ioctl code from 1336 to 452 bytes). - some code used large structure (with embeded 256 bytes for filename) while it never passed filename around. Use something smaller in ncp_conn_logged_in. Decrease 616 => 300. - gcc-3.3 is very bad when it comes to parallel blocks in ioctl. Split some branches from large switch to separate functions. ncp_ioctl now uses 152 bytes of stack (instead of 720) and biggest child 64. Signed-off-by: Petr Vandrovec Signed-off-by: Andrew Morton --- 25-akpm/fs/ncpfs/dir.c | 10 - 25-akpm/fs/ncpfs/ioctl.c | 317 +++++++++++++++++++-------------------- 25-akpm/fs/ncpfs/ncplib_kernel.c | 42 +++-- 25-akpm/fs/ncpfs/ncplib_kernel.h | 8 4 files changed, 197 insertions(+), 180 deletions(-) diff -puN fs/ncpfs/dir.c~decrease-stack-usage-in-ncpfss-ioctl fs/ncpfs/dir.c --- 25/fs/ncpfs/dir.c~decrease-stack-usage-in-ncpfss-ioctl Wed Jun 9 17:19:14 2004 +++ 25-akpm/fs/ncpfs/dir.c Wed Jun 9 17:19:14 2004 @@ -762,12 +762,12 @@ ncp_do_readdir(struct file *filp, void * int ncp_conn_logged_in(struct super_block *sb) { struct ncp_server* server = NCP_SBP(sb); - struct nw_info_struct i; int result; if (ncp_single_volume(server)) { int len; struct dentry* dent; + __u32 volNumber, dirEntNum, DosDirNum; __u8 __name[NCP_MAXPATHLEN + 1]; len = sizeof(__name); @@ -776,7 +776,7 @@ int ncp_conn_logged_in(struct super_bloc if (result) goto out; result = -ENOENT; - if (ncp_lookup_volume(server, __name, &i)) { + if (ncp_get_volume_root(server, __name, &volNumber, &dirEntNum, &DosDirNum)) { PPRINTK("ncp_conn_logged_in: %s not found\n", server->m.mounted_vol); goto out; @@ -785,9 +785,9 @@ int ncp_conn_logged_in(struct super_bloc if (dent) { struct inode* ino = dent->d_inode; if (ino) { - NCP_FINFO(ino)->volNumber = i.volNumber; - NCP_FINFO(ino)->dirEntNum = i.dirEntNum; - NCP_FINFO(ino)->DosDirNum = i.DosDirNum; + NCP_FINFO(ino)->volNumber = volNumber; + NCP_FINFO(ino)->dirEntNum = dirEntNum; + NCP_FINFO(ino)->DosDirNum = DosDirNum; } else { DPRINTK("ncpfs: sb->s_root->d_inode == NULL!\n"); } diff -puN fs/ncpfs/ioctl.c~decrease-stack-usage-in-ncpfss-ioctl fs/ncpfs/ioctl.c --- 25/fs/ncpfs/ioctl.c~decrease-stack-usage-in-ncpfss-ioctl Wed Jun 9 17:19:14 2004 +++ 25-akpm/fs/ncpfs/ioctl.c Wed Jun 9 17:19:14 2004 @@ -29,6 +29,155 @@ /* maximum negotiable packet size */ #define NCP_PACKET_SIZE_INTERNAL 65536 +static int +ncp_get_fs_info(struct ncp_server* server, struct inode* inode, struct ncp_fs_info* arg) +{ + struct ncp_fs_info info; + + if ((permission(inode, MAY_WRITE, NULL) != 0) + && (current->uid != server->m.mounted_uid)) { + return -EACCES; + } + if (copy_from_user(&info, arg, sizeof(info))) + return -EFAULT; + + if (info.version != NCP_GET_FS_INFO_VERSION) { + DPRINTK("info.version invalid: %d\n", info.version); + return -EINVAL; + } + /* TODO: info.addr = server->m.serv_addr; */ + SET_UID(info.mounted_uid, server->m.mounted_uid); + info.connection = server->connection; + info.buffer_size = server->buffer_size; + info.volume_number = NCP_FINFO(inode)->volNumber; + info.directory_id = NCP_FINFO(inode)->DosDirNum; + + if (copy_to_user(arg, &info, sizeof(info))) + return -EFAULT; + return 0; +} + +static int +ncp_get_fs_info_v2(struct ncp_server* server, struct inode* inode, struct ncp_fs_info_v2* arg) +{ + struct ncp_fs_info_v2 info2; + + if ((permission(inode, MAY_WRITE, NULL) != 0) + && (current->uid != server->m.mounted_uid)) { + return -EACCES; + } + if (copy_from_user(&info2, arg, sizeof(info2))) + return -EFAULT; + + if (info2.version != NCP_GET_FS_INFO_VERSION_V2) { + DPRINTK("info.version invalid: %d\n", info2.version); + return -EINVAL; + } + info2.mounted_uid = server->m.mounted_uid; + info2.connection = server->connection; + info2.buffer_size = server->buffer_size; + info2.volume_number = NCP_FINFO(inode)->volNumber; + info2.directory_id = NCP_FINFO(inode)->DosDirNum; + info2.dummy1 = info2.dummy2 = info2.dummy3 = 0; + + if (copy_to_user(arg, &info2, sizeof(info2))) + return -EFAULT; + return 0; +} + +#ifdef CONFIG_NCPFS_NLS +/* Here we are select the iocharset and the codepage for NLS. + * Thanks Petr Vandrovec for idea and many hints. + */ +static int +ncp_set_charsets(struct ncp_server* server, struct ncp_nls_ioctl* arg) +{ + struct ncp_nls_ioctl user; + struct nls_table *codepage; + struct nls_table *iocharset; + struct nls_table *oldset_io; + struct nls_table *oldset_cp; + + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + if (server->root_setuped) + return -EBUSY; + + if (copy_from_user(&user, arg, sizeof(user))) + return -EFAULT; + + codepage = NULL; + user.codepage[NCP_IOCSNAME_LEN] = 0; + if (!user.codepage[0] || !strcmp(user.codepage, "default")) + codepage = load_nls_default(); + else { + codepage = load_nls(user.codepage); + if (!codepage) { + return -EBADRQC; + } + } + + iocharset = NULL; + user.iocharset[NCP_IOCSNAME_LEN] = 0; + if (!user.iocharset[0] || !strcmp(user.iocharset, "default")) { + iocharset = load_nls_default(); + NCP_CLR_FLAG(server, NCP_FLAG_UTF8); + } else if (!strcmp(user.iocharset, "utf8")) { + iocharset = load_nls_default(); + NCP_SET_FLAG(server, NCP_FLAG_UTF8); + } else { + iocharset = load_nls(user.iocharset); + if (!iocharset) { + unload_nls(codepage); + return -EBADRQC; + } + NCP_CLR_FLAG(server, NCP_FLAG_UTF8); + } + + oldset_cp = server->nls_vol; + server->nls_vol = codepage; + oldset_io = server->nls_io; + server->nls_io = iocharset; + + if (oldset_cp) + unload_nls(oldset_cp); + if (oldset_io) + unload_nls(oldset_io); + + return 0; +} + +static int +ncp_get_charsets(struct ncp_server* server, struct ncp_nls_ioctl* arg) +{ + struct ncp_nls_ioctl user; + int len; + + memset(&user, 0, sizeof(user)); + if (server->nls_vol && server->nls_vol->charset) { + len = strlen(server->nls_vol->charset); + if (len > NCP_IOCSNAME_LEN) + len = NCP_IOCSNAME_LEN; + strncpy(user.codepage, server->nls_vol->charset, len); + user.codepage[len] = 0; + } + + if (NCP_IS_FLAG(server, NCP_FLAG_UTF8)) + strcpy(user.iocharset, "utf8"); + else if (server->nls_io && server->nls_io->charset) { + len = strlen(server->nls_io->charset); + if (len > NCP_IOCSNAME_LEN) + len = NCP_IOCSNAME_LEN; + strncpy(user.iocharset, server->nls_io->charset, len); + user.iocharset[len] = 0; + } + + if (copy_to_user(arg, &user, sizeof(user))) + return -EFAULT; + return 0; +} +#endif /* CONFIG_NCPFS_NLS */ + int ncp_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { @@ -96,60 +245,10 @@ int ncp_ioctl(struct inode *inode, struc return ncp_conn_logged_in(inode->i_sb); case NCP_IOC_GET_FS_INFO: - { - struct ncp_fs_info info; - - if ((permission(inode, MAY_WRITE, NULL) != 0) - && (current->uid != server->m.mounted_uid)) { - return -EACCES; - } - if (copy_from_user(&info, (struct ncp_fs_info *) arg, - sizeof(info))) - return -EFAULT; - - if (info.version != NCP_GET_FS_INFO_VERSION) { - DPRINTK("info.version invalid: %d\n", info.version); - return -EINVAL; - } - /* TODO: info.addr = server->m.serv_addr; */ - SET_UID(info.mounted_uid, server->m.mounted_uid); - info.connection = server->connection; - info.buffer_size = server->buffer_size; - info.volume_number = NCP_FINFO(inode)->volNumber; - info.directory_id = NCP_FINFO(inode)->DosDirNum; - - if (copy_to_user((struct ncp_fs_info *) arg, &info, - sizeof(info))) return -EFAULT; - return 0; - } + return ncp_get_fs_info(server, inode, (struct ncp_fs_info *)arg); case NCP_IOC_GET_FS_INFO_V2: - { - struct ncp_fs_info_v2 info2; - - if ((permission(inode, MAY_WRITE, NULL) != 0) - && (current->uid != server->m.mounted_uid)) { - return -EACCES; - } - if (copy_from_user(&info2, (struct ncp_fs_info_v2 *) arg, - sizeof(info2))) - return -EFAULT; - - if (info2.version != NCP_GET_FS_INFO_VERSION_V2) { - DPRINTK("info.version invalid: %d\n", info2.version); - return -EINVAL; - } - info2.mounted_uid = server->m.mounted_uid; - info2.connection = server->connection; - info2.buffer_size = server->buffer_size; - info2.volume_number = NCP_FINFO(inode)->volNumber; - info2.directory_id = NCP_FINFO(inode)->DosDirNum; - info2.dummy1 = info2.dummy2 = info2.dummy3 = 0; - - if (copy_to_user((struct ncp_fs_info_v2 *) arg, &info2, - sizeof(info2))) return -EFAULT; - return 0; - } + return ncp_get_fs_info_v2(server, inode, (struct ncp_fs_info_v2 *)arg); case NCP_IOC_GETMOUNTUID2: { @@ -201,7 +300,7 @@ int ncp_ioctl(struct inode *inode, struc case NCP_IOC_SETROOT: { struct ncp_setroot_ioctl sr; - unsigned int vnum, de, dosde; + __u32 vnum, de, dosde; struct dentry* dentry; if (!capable(CAP_SYS_ADMIN)) @@ -219,15 +318,10 @@ int ncp_ioctl(struct inode *inode, struc dosde = 0; } else if (sr.volNumber >= NCP_NUMBER_OF_VOLUMES) { return -EINVAL; - } else { - struct nw_info_struct ni; - - if (ncp_mount_subdir(server, &ni, sr.volNumber, - sr.namespace, sr.dirEntNum)) - return -ENOENT; - vnum = ni.volNumber; - de = ni.dirEntNum; - dosde = ni.DosDirNum; + } else if (ncp_mount_subdir(server, sr.volNumber, + sr.namespace, sr.dirEntNum, + &vnum, &de, &dosde)) { + return -ENOENT; } dentry = inode->i_sb->s_root; @@ -508,105 +602,14 @@ outrel: } #ifdef CONFIG_NCPFS_NLS -/* Here we are select the iocharset and the codepage for NLS. - * Thanks Petr Vandrovec for idea and many hints. - */ case NCP_IOC_SETCHARSETS: - if (!capable(CAP_SYS_ADMIN)) - return -EACCES; - if (server->root_setuped) - return -EBUSY; - - { - struct ncp_nls_ioctl user; - struct nls_table *codepage; - struct nls_table *iocharset; - struct nls_table *oldset_io; - struct nls_table *oldset_cp; - - if (copy_from_user(&user, (struct ncp_nls_ioctl*)arg, - sizeof(user))) - return -EFAULT; - - codepage = NULL; - user.codepage[NCP_IOCSNAME_LEN] = 0; - if (!user.codepage[0] || - !strcmp(user.codepage, "default")) - codepage = load_nls_default(); - else { - codepage = load_nls(user.codepage); - if (!codepage) { - return -EBADRQC; - } - } - - iocharset = NULL; - user.iocharset[NCP_IOCSNAME_LEN] = 0; - if (!user.iocharset[0] || - !strcmp(user.iocharset, "default")) { - iocharset = load_nls_default(); - NCP_CLR_FLAG(server, NCP_FLAG_UTF8); - } else { - if (!strcmp(user.iocharset, "utf8")) { - iocharset = load_nls_default(); - NCP_SET_FLAG(server, NCP_FLAG_UTF8); - } else { - iocharset = load_nls(user.iocharset); - if (!iocharset) { - unload_nls(codepage); - return -EBADRQC; - } - NCP_CLR_FLAG(server, NCP_FLAG_UTF8); - } - } - - oldset_cp = server->nls_vol; - server->nls_vol = codepage; - oldset_io = server->nls_io; - server->nls_io = iocharset; - - if (oldset_cp) - unload_nls(oldset_cp); - if (oldset_io) - unload_nls(oldset_io); - - return 0; - } + return ncp_set_charsets(server, (struct ncp_nls_ioctl *)arg); - case NCP_IOC_GETCHARSETS: /* not tested */ - { - struct ncp_nls_ioctl user; - int len; - - memset(&user, 0, sizeof(user)); - if (server->nls_vol && server->nls_vol->charset) { - len = strlen(server->nls_vol->charset); - if (len > NCP_IOCSNAME_LEN) - len = NCP_IOCSNAME_LEN; - strncpy(user.codepage, - server->nls_vol->charset, len); - user.codepage[len] = 0; - } + case NCP_IOC_GETCHARSETS: + return ncp_get_charsets(server, (struct ncp_nls_ioctl *)arg); - if (NCP_IS_FLAG(server, NCP_FLAG_UTF8)) - strcpy(user.iocharset, "utf8"); - else - if (server->nls_io && server->nls_io->charset) { - len = strlen(server->nls_io->charset); - if (len > NCP_IOCSNAME_LEN) - len = NCP_IOCSNAME_LEN; - strncpy(user.iocharset, - server->nls_io->charset, len); - user.iocharset[len] = 0; - } - - if (copy_to_user((struct ncp_nls_ioctl*)arg, &user, - sizeof(user))) - return -EFAULT; - - return 0; - } #endif /* CONFIG_NCPFS_NLS */ + case NCP_IOC_SETDENTRYTTL: if ((permission(inode, MAY_WRITE, NULL) != 0) && (current->uid != server->m.mounted_uid)) diff -puN fs/ncpfs/ncplib_kernel.c~decrease-stack-usage-in-ncpfss-ioctl fs/ncpfs/ncplib_kernel.c --- 25/fs/ncpfs/ncplib_kernel.c~decrease-stack-usage-in-ncpfss-ioctl Wed Jun 9 17:19:14 2004 +++ 25-akpm/fs/ncpfs/ncplib_kernel.c Wed Jun 9 17:19:14 2004 @@ -536,37 +536,34 @@ ncp_ObtainSpecificDirBase(struct ncp_ser } int -ncp_mount_subdir(struct ncp_server *server, struct nw_info_struct *i, - __u8 volNumber, __u8 srcNS, __u32 dirEntNum) +ncp_mount_subdir(struct ncp_server *server, + __u8 volNumber, __u8 srcNS, __u32 dirEntNum, + __u32* volume, __u32* newDirEnt, __u32* newDosEnt) { int dstNS; int result; - __u32 newDirEnt; - __u32 newDosEnt; dstNS = ncp_get_known_namespace(server, volNumber); if ((result = ncp_ObtainSpecificDirBase(server, srcNS, dstNS, volNumber, - dirEntNum, NULL, &newDirEnt, &newDosEnt)) != 0) + dirEntNum, NULL, newDirEnt, newDosEnt)) != 0) { return result; } server->name_space[volNumber] = dstNS; - i->volNumber = volNumber; - i->dirEntNum = newDirEnt; - i->DosDirNum = newDosEnt; + *volume = volNumber; server->m.mounted_vol[1] = 0; server->m.mounted_vol[0] = 'X'; return 0; } int -ncp_lookup_volume(struct ncp_server *server, char *volname, - struct nw_info_struct *target) +ncp_get_volume_root(struct ncp_server *server, const char *volname, + __u32* volume, __u32* dirent, __u32* dosdirent) { int result; - int volnum; + __u8 volnum; - DPRINTK("ncp_lookup_volume: looking up vol %s\n", volname); + DPRINTK("ncp_get_volume_root: looking up vol %s\n", volname); ncp_init_request(server); ncp_add_byte(server, 22); /* Subfunction: Generate dir handle */ @@ -585,16 +582,31 @@ ncp_lookup_volume(struct ncp_server *ser ncp_unlock_server(server); return result; } - memset(target, 0, sizeof(*target)); - target->DosDirNum = target->dirEntNum = ncp_reply_dword(server, 4); - target->volNumber = volnum = ncp_reply_byte(server, 8); + *dirent = *dosdirent = ncp_reply_dword(server, 4); + volnum = ncp_reply_byte(server, 8); ncp_unlock_server(server); + *volume = volnum; server->name_space[volnum] = ncp_get_known_namespace(server, volnum); DPRINTK("lookup_vol: namespace[%d] = %d\n", volnum, server->name_space[volnum]); + return 0; +} + +int +ncp_lookup_volume(struct ncp_server *server, const char *volname, + struct nw_info_struct *target) +{ + int result; + + memset(target, 0, sizeof(*target)); + result = ncp_get_volume_root(server, volname, + &target->volNumber, &target->dirEntNum, &target->DosDirNum); + if (result) { + return result; + } target->nameLen = strlen(volname); memcpy(target->entryName, volname, target->nameLen+1); target->attributes = aDIR; diff -puN fs/ncpfs/ncplib_kernel.h~decrease-stack-usage-in-ncpfss-ioctl fs/ncpfs/ncplib_kernel.h --- 25/fs/ncpfs/ncplib_kernel.h~decrease-stack-usage-in-ncpfss-ioctl Wed Jun 9 17:19:14 2004 +++ 25-akpm/fs/ncpfs/ncplib_kernel.h Wed Jun 9 17:19:14 2004 @@ -70,7 +70,9 @@ void ncp_extract_file_info(void* src, st int ncp_obtain_info(struct ncp_server *server, struct inode *, char *, struct nw_info_struct *target); int ncp_obtain_nfs_info(struct ncp_server *server, struct nw_info_struct *target); -int ncp_lookup_volume(struct ncp_server *, char *, struct nw_info_struct *); +int ncp_get_volume_root(struct ncp_server *server, const char *volname, + __u32 *volume, __u32 *dirent, __u32 *dosdirent); +int ncp_lookup_volume(struct ncp_server *, const char *, struct nw_info_struct *); int ncp_modify_file_or_subdir_dos_info(struct ncp_server *, struct inode *, __u32, const struct nw_modify_dos_info *info); int ncp_modify_file_or_subdir_dos_info_path(struct ncp_server *, struct inode *, @@ -111,8 +113,8 @@ ncp_ClearPhysicalRecord(struct ncp_serve #endif /* CONFIG_NCPFS_IOCTL_LOCKING */ int -ncp_mount_subdir(struct ncp_server *, struct nw_info_struct *, - __u8, __u8, __u32); +ncp_mount_subdir(struct ncp_server *, __u8, __u8, __u32, + __u32* volume, __u32* dirent, __u32* dosdirent); int ncp_dirhandle_alloc(struct ncp_server *, __u8 vol, __u32 dirent, __u8 *dirhandle); int ncp_dirhandle_free(struct ncp_server *, __u8 dirhandle); _