在一个容器中,删除一个目录,失败:

bash-4.2# pwd
/home/zxcdn/ottcache/tomcat
bash-4.2# uname -a
Linux 3516b6c97679 3.10.-327.22..el7.x86_64 # SMP Fri Sep :: CST x86_64 x86_64 x86_64 GNU/Linux
bash-4.2# whoami
root bash-4.2# ls -alrt bin
total
drwxr-xr-x. root root Dec : .
drwxr-xr-x. root root Dec : .. bash-4.2# rm -rf bin
bash-4.2# ls -i
bin
bash-4.2# rm -rf bin
bash-4.2# ls -i
bin

相关docker版本信息:

[root@host---- caq]# docker info
Containers:
Running:
Paused:
Stopped:
Images:
Server Version: 1.13.
Storage Driver: overlay2----------存储引擎
Backing Filesystem: extfs--------底层文件系统
Supports d_type: true
Native Overlay Diff: false
Logging Driver: journald
Cgroup Driver: systemd
Plugins:
Volume: local
Network: bridge host macvlan null overlay
Swarm: inactive
Runtimes: docker-runc runc
Default Runtime: docker-runc
Init Binary: /usr/libexec/docker/docker-init-current
containerd version: (expected: aa8187dbd3b7ad67d8e5e3a15115d3eef43a7ed1)
runc version: 5eda6f6fd0c2884c2c8e78a6e7119e8d0ecedb77 (expected: 9df8b306d01f59d3a8029be411de015b7304dd8f)
init version: fec3683b971d9c3ef73f284f176672c44b448662 (expected: 949e6facb77383876aeff8a6944dde66b3089574)
Security Options:
seccomp
WARNING: You're not using the default seccomp profile
Profile: /etc/docker/seccomp.json
Kernel Version: 3.10.-327.22..el7.x86_64
Operating System: Carrier Grade Server Linux
OSType: linux
Architecture: x86_64
Number of Docker Hooks:
CPUs:
Total Memory: 3.703 GiB
Name: host----
ID: 4CV6:Y3Q4:NYGV:PABH:VG42:3CN7:CKET:SEIV:4SYF:63PI:HYAB:AZR2
Docker Root Dir: /var/lib/docker
Debug Mode (client): false
Debug Mode (server): false
Registry: https://index.docker.io/v1/
WARNING: bridge-nf-call-iptables is disabled
WARNING: bridge-nf-call-ip6tables is disabled
Experimental: false
Insecure Registries:
0.0.0.0/
127.0.0.0/
Live Restore Enabled: false
Registries: docker.io (secure)

发现删除不了这个空目录,strace跟踪一下,报错如下:

fcntl(, F_GETFL)                       = 0x38800 (flags O_RDONLY|O_NONBLOCK|O_LARGEFILE|O_DIRECTORY|O_NOFOLLOW)
fcntl(, F_SETFD, FD_CLOEXEC) =
getdents(, /* 2 entries */, ) =
getdents(, /* 0 entries */, ) =
close() =
unlinkat(AT_FDCWD, "bin", AT_REMOVEDIR) = - EINVAL (Invalid argument)
lseek(, , SEEK_CUR) = - ESPIPE (Illegal seek)

原来是unlinkat报错,然后内核打点跟踪,堆栈如下:

Returning from:  0xffffffff811ed500 : vfs_rename+0x0/0x790 [kernel]
Returning to : 0xffffffffa039860b : ovl_do_rename+0x3b/0xa0 [overlay]
0xffffffffa0398e4e : ovl_clear_empty+0x27e/0x2e0 [overlay]
0xffffffffa0398f28 : ovl_check_empty_and_clear+0x78/0x90 [overlay]
0xffffffffa039999c : ovl_do_remove+0x1ec/0x470 [overlay]
0xffffffffa0399c36 : ovl_rmdir+0x16/0x20 [overlay]
0xffffffff811ec738 : vfs_rmdir+0xa8/0x100 [kernel]
0xffffffff811f16d5 : do_rmdir+0x1a5/0x200 [kernel]
0xffffffff811f28b5 : SyS_unlinkat+0x25/0x40 [kernel]
0xffffffff81649909 : system_call_fastpath+0x16/0x1b [kernel]

看下确定是vfs_rename出错了,具体按行号打点:

probe kernel.statement("vfs_rename@namei.c:4122")
{
p_my=@cast($old_dir,"struct inode")->i_op;
iflags=@cast($old_dir,"struct inode")->i_flags;
printf("line 4122 flags=%u,rename2=%x,iflags=%u\r\n",$flags,@cast(p_my,"struct inode_operations_wrapper")->rename2,iflags);
print_backtrace();
}

对应的内核源码:

int vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
struct inode *new_dir, struct dentry *new_dentry,
struct inode **delegated_inode, unsigned int flags)
{
。。。。
rename2 = get_rename2_iop(old_dir);---------------4118行
if (!old_dir->i_op->rename && !rename2)
return -EPERM; if (flags && !rename2)----------------------------4122行
return -EINVAL;
。。。。
}

一开始我直接取的rename2,发现不为NULL,按道理进不去4122行,后来经细心的谈虎走查,才发现是进入了如下的判断条件:

static inline const struct inode_operations_wrapper *get_iop_wrapper(struct inode *inode,
unsigned version)
{
const struct inode_operations_wrapper *wrapper; if (!IS_IOPS_WRAPPER(inode))------------最终是这个条件起作用了
return NULL;
wrapper = container_of(inode->i_op, const struct inode_operations_wrapper, ops);
if (wrapper->version < version)
return NULL;
return wrapper;
} static inline iop_rename2_t get_rename2_iop(struct inode *inode)
{
const struct inode_operations_wrapper *wrapper = get_iop_wrapper(inode, );
return wrapper ? wrapper->rename2 : NULL;
}

看起来,该内核版本的overlay存储引擎,对ext3的底层文件系统,兼容性存在一些问题。后来使用device-mapper来解决了该问题。

ext4里面,ext4_iget的时候,对目录操作的时候,inode的i_flags是设置了S_IOPS_WRAPPER属性的,
} else if (S_ISDIR(inode->i_mode)) {
inode->i_op = &ext4_dir_inode_operations.ops;
inode->i_fop = &ext4_dir_operations;
inode->i_flags |= S_IOPS_WRAPPER;

但是ext3没有设置。

一个docker镜像中的目录删除不了问题的更多相关文章

  1. 在docker镜像中加入环境变量

    原文链接 前言 reference:https://vsupalov.com/docker-build-time-env-values/ 很多时候,我们需要在docker镜像中加入环境变量,本人了解的 ...

  2. 给Ocelot做一个Docker 镜像

    写在前面 在微服务架构中,ApiGateway起到了承前启后,不仅可以根据客户端进行分类,也可以根据功能业务进行分类,而且对于服务调用服务也起到了很好的接口作用.目前在各个云端中,基本上都提供了Api ...

  3. Docker镜像的获取与删除

    Docker运行容器前需要本地存在对应的镜像,如果镜像不存在本地,Docker会尝试先从默认镜像仓库下载(默认使用Dicker Hub公共注册服务器中的仓库),用户也可以通过配置,使用自定义的镜像仓库 ...

  4. Docker镜像中的base镜像理解

    base 镜像有两层含义: 不依赖其他镜像,从 scratch 构建. 其他镜像可以之为基础进行扩展. 所以,能称作 base 镜像的通常都是各种 Linux 发行版的 Docker 镜像,比如 Ub ...

  5. springboot程序构建一个docker镜像(十一)

    准备工作 环境: linux环境或mac,不要用windows jdk 8 maven 3.0 docker 对docker一无所知的看docker教程. 创建一个springboot工程 引入web ...

  6. (转)Docker镜像中的base镜像理解

    base 镜像有两层含义: 不依赖其他镜像,从 scratch 构建. 其他镜像可以之为基础进行扩展. 所以,能称作 base 镜像的通常都是各种 Linux 发行版的 Docker 镜像,比如 Ub ...

  7. Spring Boot教程(十一) springboot程序构建一个docker镜像

    准备工作 环境: linux环境或mac,不要用windows jdk 8 maven 3.0 docker 对docker一无所知的看docker教程. 创建一个springboot工程 引入web ...

  8. docker镜像中文件丢失

    背景介绍 笔者创建了一个镜像,然后在不同的主机上启动,发现有的能启动,有的却不行,报错信息为找不到文件. 犹记得当初有人介绍,只要docker镜像做好了,拿到任何地方都可以用,此处好像不成呢,好诡异的 ...

  9. 向docker镜像中传递变量的两种方式

    测试用到的python文件: #!/usr/bin/env python3 #conding: utf-8 from http.server import HTTPServer, BaseHTTPRe ...

随机推荐

  1. [UE4]蓝图调试小心得

    假设某个功能由10个蓝图步骤组成,在第10步的某个蓝图函数的其中一个参数为none,可以使用not equal(Object)和Print从第10步开始,一步一步倒退到第一步检查,看看是哪一个步骤参数 ...

  2. [UE4]增加观察者

    角色死亡以后,让控制器控制另外一个只能移动,没有实体的Character角色 使用“Possess”函数让控制器控制新生成的观察者对象.如上图所示要使用Delay延迟1秒再生成观察者,是因为死亡的时候 ...

  3. Java中的Future相关

    先上一个场景:假如你突然想做饭,但是没有厨具,也没有食材.网上购买厨具比较方便,食材去超市买更放心. 实现分析:在快递员送厨具的期间,我们肯定不会闲着,可以去超市买食材.所以,在主线程里面另起一个子线 ...

  4. 图片Alpha预乘的作用[转]

    Premultiplied Alpha 这个概念做游戏开发的人都不会不知道.Xcode 的工程选项里有一项 Compress PNG Files,会对 PNG 进行 Premultiplied Alp ...

  5. Hive UDF作业

    说到这次作业,看似简单的几个步骤,对于我这样的菜鸟来说可真是一波三折啊.下面来说说这次的步骤和我遇到的问题. 首先准备工作,搭建好hive环境,保证hadoop集群是启动的.这个就不多说了. 第一步: ...

  6. Centos下安装Docker集群管理工具Shipyard

    一. Docker Shipyard是什么 ? shipyard是一个开源的docker管理平台,其特性主要包括: 支持镜像管理.容器管理. 支持控制台命令 容器资源消耗监控 支持集群swarm,可以 ...

  7. Linux性能优化 第四章 性能工具:特定进程CPU

    4.1进程性能统计信息 4.1.1. 内核时间VS用户时间 一个应用程序所耗时间最基本的划分是内核时间与用户时间.内核时间是消耗在Linux内核上的时间,而用户时间则是消耗在应用程序或库代码上的时间. ...

  8. 查看linux文件目录的大小和文件夹包含的文件数

    du -h --max-depth=|sort -n du -h --max-depth=|grep G|sort -n df -h 清理/var/log # 清除 # 一定要以root身份来运行这个 ...

  9. python开发学习(元组、字符串、列表、字典深入)

    https://www.cnblogs.com/songqingbo/p/5129116.html(转载学习)

  10. centos7 安装 nvm

    cd 到 /usr/local下创建nvm文件夹,并进入nvm目录, 执行命令: wget -qO- https://raw.githubusercontent.com/creationix/nvm/ ...